@chubbyts/chubbyts-decode-encode
Version:
A simple decode/encode solution for json / jsonx / url-encoded / xml / yaml.
174 lines (173 loc) • 4.5 kB
JavaScript
import { XMLBuilder } from 'fast-xml-parser';
import { throwableToError } from '@chubbyts/chubbyts-throwable-to-error/dist/throwable-to-error';
import { isArray, isBoolean, isNumber, isObject, isString, isNull } from '../index.js';
import { DATATYPE_ARRAY, DATATYPE_BOOLEAN, DATATYPE_NULL, DATATYPE_NUMBER, DATATYPE_OBJECT, DATATYPE_STRING, } from '../jsonx-datatypes.js';
import { EncodeError } from './index.js';
const encodeHtmlEntities = (string) => string.replace(/[\u00A0-\u9999<>&]/g, (i) => '&#' + i.charCodeAt(0) + ';');
const createXmlNode = () => {
return {
'?xml': [
{
'#text': '',
},
],
':@': {
'@_version': '1.0',
'@_encoding': 'UTF-8',
},
};
};
const createJsonxAttributes = () => {
return {
':@': {
'@_xsi:schemaLocation': 'http://www.datapower.com/schemas/json jsonx.xsd',
'@_xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
'@_xmlns:json': 'http://www.ibm.com/xmlns/prod/2009/jsonx',
},
};
};
const createNullNode = (key = undefined) => {
const node = {
[DATATYPE_NULL]: [],
};
if (key === undefined) {
return node;
}
return {
...node,
':@': {
'@_name': key,
},
};
};
const createBooleanNode = (value, key = undefined) => {
const node = {
[DATATYPE_BOOLEAN]: [
{
'#text': value,
},
],
};
if (key === undefined) {
return node;
}
return {
...node,
':@': {
'@_name': key,
},
};
};
const createNumberNode = (value, key = undefined) => {
const node = {
[DATATYPE_NUMBER]: [
{
'#text': value,
},
],
};
if (key === undefined) {
return node;
}
return {
...node,
':@': {
'@_name': key,
},
};
};
const createStringNode = (value, key = undefined) => {
const node = {
[DATATYPE_STRING]: [
{
'#text': value === value.trim() ? encodeHtmlEntities(value) : `<![CDATA[${encodeHtmlEntities(value)}]]>`,
},
],
};
if (key === undefined) {
return node;
}
return {
...node,
':@': {
'@_name': key,
},
};
};
const createNode = (value, key = undefined) => {
if (isObject(value)) {
return createObjectNode(value, key);
}
else if (isArray(value)) {
return createArrayNode(value, key);
}
else if (isString(value)) {
return createStringNode(value, key);
}
else if (isNumber(value)) {
return createNumberNode(value, key);
}
else if (isBoolean(value)) {
return createBooleanNode(value, key);
}
else if (isNull(value)) {
return createNullNode(key);
}
throw new Error(`Unsupported value: ${JSON.stringify(value)}`);
};
const createArrayNode = (value, key = undefined) => {
const elements = value.map((subValue) => createNode(subValue));
const node = {
[DATATYPE_ARRAY]: elements,
};
if (key === undefined) {
return node;
}
return {
...node,
':@': {
'@_name': key,
},
};
};
const createObjectNode = (value, key = undefined) => {
const elements = Object.entries(value).map(([subKey, subValue]) => createNode(subValue, subKey));
const node = {
[DATATYPE_OBJECT]: elements,
};
if (key === undefined) {
return node;
}
return {
...node,
':@': {
'@_name': key,
},
};
};
export const createJsonxTypeEncoder = (prettyPrint = false) => {
const builder = new XMLBuilder({
preserveOrder: true,
ignoreAttributes: false,
processEntities: false,
format: prettyPrint,
});
return {
encode: (data) => {
try {
return builder.build([
createXmlNode(),
{
...createNode(data),
...createJsonxAttributes(),
},
]);
}
catch (e) {
const error = throwableToError(e);
throw new EncodeError(error.message, error.stack);
}
},
contentType: 'application/jsonx+xml',
};
};