UNPKG

@chubbyts/chubbyts-decode-encode

Version:

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

69 lines (68 loc) 2.43 kB
import { XMLParser } from 'fast-xml-parser'; import { throwableToError } from '@chubbyts/chubbyts-throwable-to-error/dist/throwable-to-error'; import { DATATYPE_ARRAY, DATATYPE_BOOLEAN, DATATYPE_NULL, DATATYPE_NUMBER, DATATYPE_OBJECT, DATATYPE_STRING, } from '../jsonx-datatypes.js'; import { DecodeError } from './decoder.js'; const decodeHtmlEntities = (string) => string.replace(/&#\d+;/gm, (code) => String.fromCharCode(code.match(/\d+/)[0])); const getNodeName = (node) => { return node[':@']?.['@_name']; }; const getNodeType = (node) => { return Object.keys(node)[0]; }; const convertNullNode = () => { return null; }; const convertBooleanNode = (node) => { return node['json:boolean'][0]['#text']; }; const convertNumberNode = (node) => { return node['json:number'][0]['#text']; }; const convertStringNode = (node) => { return decodeHtmlEntities(node['json:string'][0]['#text']); }; const convertNode = (node) => { switch (getNodeType(node)) { case DATATYPE_OBJECT: return convertObjectNode(node); case DATATYPE_ARRAY: return convertArrayNode(node); case DATATYPE_STRING: return convertStringNode(node); case DATATYPE_NUMBER: return convertNumberNode(node); case DATATYPE_BOOLEAN: return convertBooleanNode(node); case DATATYPE_NULL: return convertNullNode(); } throw new Error(`Unsupported node: ${JSON.stringify(node)}`); }; const convertArrayNode = (node) => { return node['json:array'].map(convertNode); }; const convertNodeWithName = (node) => { const name = getNodeName(node); if (undefined === name) { throw new Error(`Unsupported node: ${JSON.stringify(node)}`); } return [name, convertNode(node)]; }; const convertObjectNode = (node) => { return Object.fromEntries(node['json:object'].map(convertNodeWithName)); }; export const createJsonxTypeDecoder = () => { return { decode: (encodedData) => { try { const parser = new XMLParser({ preserveOrder: true, ignoreAttributes: false }); return convertNode(parser.parse(encodedData)[1]); } catch (e) { const error = throwableToError(e); throw new DecodeError(error.message, error.stack); } }, contentType: 'application/jsonx+xml', }; };