UNPKG

@chubbyts/chubbyts-decode-encode

Version:

A simple decode/encode solution for json / jsonx / url-encoded / xml / yaml.

174 lines (173 loc) 4.5 kB
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', }; };