@twec/node-suite
Version:
Generic functionality for connecting to NetSuite Web Services from Node
74 lines (66 loc) • 2.05 kB
JavaScript
const isSomething = x => Boolean(x) || x === 0;
const escapeXmlText = (text) => {
if (!isSomething(text)) {
return '';
}
const str = String(text);
if ((/[&<>]/).test(str)) {
return `<![CDATA[${str.replace(/]]>/, ']]]]><![CDATA[>')}]]>`;
}
return str;
};
const escapeXmlAttribute = attribute => String(attribute)
.replace(/&/g, '&')
.replace(/'/g, ''')
.replace(/"/g, '"')
.replace(/</g, '<')
.replace(/>/g, '>');
const serializeAttributeValue = (value, escapeValue) => {
if (!isSomething(value)) {
return '';
}
return escapeValue ? escapeXmlAttribute(value) : value;
};
const serializeAttribute = (attributeKey, attributeValue, escapeValue, quote) => {
const value = serializeAttributeValue(attributeValue, escapeValue);
return `${attributeKey}=${quote}${value}${quote}`;
};
const serializeAttrs = (attributes, escapeValue, quote) => {
if (!isSomething(attributes)) {
return '';
}
let result = '';
const attrKeys = Object.keys(attributes);
attrKeys.forEach((key) => {
const attributeString = serializeAttribute(key, attributes[key], escapeValue, quote);
result += ` ${attributeString}`;
});
return result;
};
/**
* @param {XmlNode|XmlNode[]} ast
* @return {string}
*/
const xml = (ast, options = {}) => {
const {
escapeAttributes = true,
escapeText = true,
selfClose = true,
quote = '"',
} = options;
if (Array.isArray(ast)) {
return ast.map(astItem => xml(astItem, options)).join('');
}
if (ast.type === 'text') {
return `${escapeText ? escapeXmlText(ast.value) : ast.value}`;
}
const attributes = serializeAttrs(ast.attributes, escapeAttributes, quote);
if ((ast.children || []).length || !selfClose) {
return `<${ast.name}${attributes}>${xml(ast.children, options)}</${ast.name}>`;
}
if (typeof ast.value === 'string') {
return `<${ast.name}${attributes}>${escapeText ? escapeXmlText(ast.value) : ast.value}</${ast.name}>`;
}
return `<${ast.name}${attributes}/>`;
};
module.exports = xml;