UNPKG

@beenotung/tslib

Version:
129 lines (128 loc) 4.04 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.jsonToString = jsonToString; exports.jsonToValues = jsonToValues; exports.valuesToJson = valuesToJson; exports.jsonToValuesString = jsonToValuesString; exports.valuesStringToJson = valuesStringToJson; const type_1 = require("./type"); function jsonToString_helper(o, parent, visited) { const type = (0, type_1.getObjectType)(o); switch (type) { case 'String': case 'Number': case 'Null': case 'Boolean': return JSON.stringify(o); case 'Undefined': if (Array.isArray(parent)) { return JSON.stringify(null); } throw new Error('unsupported json type: Undefined'); case 'Array': case 'Object': { if (visited.has(o)) { throw new TypeError('circular structure, duplicated value: ' + o); } /* clone the set, to allow sibling duplication */ visited = new Set(visited); visited.add(o); if (type === 'Array') { /* is array */ // use explicit loop to include empty slots const xs = o; const n = xs.length; const acc = new Array(n); for (let i = 0; i < n; i++) { acc[i] = jsonToString_helper(xs[i], xs, visited); } return '[' + acc.join(',') + ']'; } else { /* is object */ return ('{' + Object.keys(o) .sort() .map(x => JSON.stringify(x) + ':' + jsonToString_helper(o[x], o, visited)) .join(',') + '}'); } } default: console.error('unsupported data type:', type); throw new TypeError('unsupported data type'); } } function jsonToString(o) { const visited = new Set(); const parent = undefined; return jsonToString_helper(o, parent, visited); } /** * support cyclic reference in json; * also support array with non-positive integer key, e.g. xs[-1.1] * */ function jsonToValues(value) { const value_id_map = new Map(); const values = []; const arrays = []; let n = 0; const encode = (value) => { let id = value_id_map.get(value); if (typeof id === 'number') { return id; } id = n++; value_id_map.set(value, id); if (value === null || typeof value !== 'object') { values[id] = value; return id; } // const ids: any = Array.isArray(value) ? [] : {}; const ids = {}; if (Array.isArray(value)) { arrays.push(id); } const keys = Object.keys(value); for (let i = 0; i < keys.length; i++) { const key = keys[i]; ids[key] = encode(value[key]); } values[id] = ids; return id; }; encode(value); return { values, arrays, }; } function valuesToJson(jsonValues) { const { values, arrays } = jsonValues; const id_value_map = new Map(); const decode = (id) => { if (id_value_map.has(id)) { return id_value_map.get(id); } const ids = values[id]; if (ids === null || typeof ids !== 'object') { return ids; } // const value: any = Array.isArray(ids) ? [] : {}; const value = arrays.includes(id) ? [] : {}; id_value_map.set(id, value); const keys = Object.keys(ids); for (let i = 0; i < keys.length; i++) { const key = keys[i]; value[key] = decode(ids[key]); } return value; }; return decode(0); } function jsonToValuesString(value) { return jsonToString(jsonToValues(value)); } function valuesStringToJson(json) { return valuesToJson(JSON.parse(json)); }