@beenotung/tslib
Version:
utils library in Typescript
129 lines (128 loc) • 4.04 kB
JavaScript
;
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));
}