Merge pull request #114 from patelravi/circular_json_issue

Added flatted library as file.
This commit is contained in:
nixonsam 2019-03-19 16:54:56 +05:30 committed by GitHub
commit b2f3cedb9c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 559 additions and 1 deletions

View file

@ -13,6 +13,7 @@ import { PricingInterface } from "../resources/pricings";
import { RecordingInterface } from "../resources/recordings";
import { Response } from "../utils/plivoxml";
import { validateSignature } from "../utils/security";
import { stringify } from "./../utils/jsonStrinfigier";
exports.Response = function () {
return new Response();
@ -63,6 +64,11 @@ export class Client {
this.pricings = new PricingInterface(client);
this.recordings = new RecordingInterface(client);
}
toJSON() {
// return "hello..";
return stringify.apply(arguments);
}
}
/**

View file

@ -0,0 +1,118 @@
var Flatted = (function (Primitive, primitive) {
/*!
* ISC License
*
* Copyright (c) 2018, Andrea Giammarchi, @WebReflection
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
var Flatted = {
parse: function parse(text, reviver) {
var input = JSON.parse(text, Primitives).map(primitives);
var value = input[0];
var $ = reviver || noop;
var tmp = typeof value === 'object' && value ?
revive(input, new Set, value, $) :
value;
return $.call({ '': tmp }, '', tmp);
},
stringify: function stringify(value, replacer, space) {
for (var
firstRun,
known = new Map,
input = [],
output = [],
$ = replacer && typeof replacer === typeof input ?
function (k, v) {
if (k === '' || -1 < replacer.indexOf(k)) return v;
} :
(replacer || noop),
i = +set(known, input, $.call({ '': value }, '', value)),
replace = function (key, value) {
if (firstRun) {
firstRun = !firstRun;
return value;
// this was invoking twice each root object
// return i < 1 ? value : $.call(this, key, value);
}
var after = $.call(this, key, value);
switch (typeof after) {
case 'object':
if (after === null) return after;
case primitive:
return known.get(after) || set(known, input, after);
}
return after;
};
i < input.length; i++
) {
firstRun = true;
output[i] = JSON.stringify(input[i], replace, space);
}
return '[' + output.join(',') + ']';
}
};
return Flatted;
function noop(key, value) {
return value;
}
function revive(input, parsed, output, $) {
return Object.keys(output).reduce(
function (output, key) {
var value = output[key];
if (value instanceof Primitive) {
var tmp = input[value];
if (typeof tmp === 'object' && !parsed.has(tmp)) {
parsed.add(tmp);
output[key] = $.call(output, key, revive(input, parsed, tmp, $));
} else {
output[key] = $.call(output, key, tmp);
}
} else
output[key] = $.call(output, key, value);
return output;
},
output
);
}
function set(known, input, value) {
var index = Primitive(input.push(value) - 1);
known.set(value, index);
return index;
}
// the two kinds of primitives
// 1. the real one
// 2. the wrapped one
function primitives(value) {
return value instanceof Primitive ? Primitive(value) : value;
}
function Primitives(key, value) {
return typeof value === primitive ? new Primitive(value) : value;
}
}(String, 'string'));
export default Flatted;
export const parse = Flatted.parse;
export const stringify = Flatted.stringify;

View file

@ -1,6 +1,7 @@
var qs = require('querystring');
var xmlBuilder = require('xmlbuilder');
var util = require('util');
var jsonStringifier = require('./jsonStrinfigier');
export class PlivoXMLError extends Error { }
@ -294,7 +295,9 @@ Response.prototype = {
toXML: function () {
return this.elem.toString();
}
},
toJSON: jsonStringifier.stringify
};
/**

View file

@ -0,0 +1,431 @@
import jsonStrinfigier from '../lib/utils/jsonStrinfigier';
import { Client, Response } from '../lib/rest/client';
describe('JSON Stringifier Interface', function () {
it('should get pricings via interface', function () {
var a = [];
var o = {};
console.assert(jsonStrinfigier.stringify(a) === '[[]]', 'empty Array');
console.assert(jsonStrinfigier.stringify(o) === '[{}]', 'empty Object');
a.push(a);
o.o = o;
console.assert(jsonStrinfigier.stringify(a) === '[["0"]]', 'recursive Array');
console.assert(jsonStrinfigier.stringify(o) === '[{"o":"0"}]', 'recursive Object');
var b = jsonStrinfigier.parse(jsonStrinfigier.stringify(a));
console.assert(Array.isArray(b) && b[0] === b, 'restoring recursive Array');
a.push(1, 'two', true);
o.one = 1;
o.two = 'two';
o.three = true;
console.assert(jsonStrinfigier.stringify(a) === '[["0",1,"1",true],"two"]', 'values in Array');
console.assert(jsonStrinfigier.stringify(o) === '[{"o":"0","one":1,"two":"1","three":true},"two"]', 'values in Object');
a.push(o);
o.a = a;
console.assert(jsonStrinfigier.stringify(a) === '[["0",1,"1",true,"2"],"two",{"o":"2","one":1,"two":"1","three":true,"a":"0"}]', 'object in Array');
console.assert(jsonStrinfigier.stringify(o) === '[{"o":"0","one":1,"two":"1","three":true,"a":"2"},"two",["2",1,"1",true,"0"]]', 'array in Object');
a.push({ test: 'OK' }, [1, 2, 3]);
o.test = { test: 'OK' };
o.array = [1, 2, 3];
console.assert(jsonStrinfigier.stringify(a) === '[["0",1,"1",true,"2","3","4"],"two",{"o":"2","one":1,"two":"1","three":true,"a":"0","test":"5","array":"6"},{"test":"7"},[1,2,3],{"test":"7"},[1,2,3],"OK"]', 'objects in Array');
console.assert(jsonStrinfigier.stringify(o) === '[{"o":"0","one":1,"two":"1","three":true,"a":"2","test":"3","array":"4"},"two",["2",1,"1",true,"0","5","6"],{"test":"7"},[1,2,3],{"test":"7"},[1,2,3],"OK"]', 'objects in Object');
a = jsonStrinfigier.parse(jsonStrinfigier.stringify(a));
o = jsonStrinfigier.parse(jsonStrinfigier.stringify(o));
console.assert(a[0] === a, 'parsed Array');
console.assert(o.o === o, 'parsed Object');
console.assert(
a[1] === 1 &&
a[2] === 'two' &&
a[3] === true &&
a[4] instanceof Object &&
JSON.stringify(a[5]) === JSON.stringify({ test: 'OK' }) &&
JSON.stringify(a[6]) === JSON.stringify([1, 2, 3]),
'array values are all OK'
);
console.assert(a[4] === a[4].o && a === a[4].o.a, 'array recursive values are OK');
console.assert(
o.one === 1 &&
o.two === 'two' &&
o.three === true &&
Array.isArray(o.a) &&
JSON.stringify(o.test) === JSON.stringify({ test: 'OK' }) &&
JSON.stringify(o.array) === JSON.stringify([1, 2, 3]),
'object values are all OK'
);
console.assert(o.a === o.a[0] && o === o.a[4], 'object recursive values are OK');
console.assert(jsonStrinfigier.parse(jsonStrinfigier.stringify(1)) === 1, 'numbers can be parsed too');
console.assert(jsonStrinfigier.parse(jsonStrinfigier.stringify(false)) === false, 'booleans can be parsed too');
console.assert(jsonStrinfigier.parse(jsonStrinfigier.stringify(null)) === null, 'null can be parsed too');
console.assert(jsonStrinfigier.parse(jsonStrinfigier.stringify('test')) === 'test', 'strings can be parsed too');
var d = new Date;
console.assert(jsonStrinfigier.parse(jsonStrinfigier.stringify(d)) === d.toISOString(), 'dates can be parsed too');
console.assert(jsonStrinfigier.parse(
jsonStrinfigier.stringify(d),
function (key, value) {
if (typeof value === 'string' && /^[0-9:.ZT-]+$/.test(value))
return new Date(value);
return value;
}
) instanceof Date, 'dates can be revived too');
console.assert(jsonStrinfigier.parse(
jsonStrinfigier.stringify({
sub: {
one23: 123,
date: d
}
}),
function (key, value) {
if (key !== '' && typeof value === 'string' && /^[0-9:.ZT-]+$/.test(value))
return new Date(value);
return value;
}
).sub.date instanceof Date, 'dates can be revived too');
// borrowed from CircularJSON
(function () {
var special = "\\x7e"; // \x7e is ~
//console.log(jsonStrinfigier.stringify({a:special}));
//console.log(jsonStrinfigier.parse(jsonStrinfigier.stringify({a:special})).a);
console.assert(jsonStrinfigier.parse(jsonStrinfigier.stringify({ a: special })).a === special, 'no problem with simulation');
special = "~\\x7e";
console.assert(jsonStrinfigier.parse(jsonStrinfigier.stringify({ a: special })).a === special, 'no problem with special char');
}());
(function () {
var o = { a: 'a', b: 'b', c: function () { }, d: { e: 123 } },
a = JSON.stringify(o),
b = jsonStrinfigier.stringify(o);
console.assert(
JSON.stringify(JSON.parse(a)) === JSON.stringify(jsonStrinfigier.parse(b)),
'works as JSON.parse'
);
console.assert(
jsonStrinfigier.stringify(o, function (key, value) {
if (!key || key === 'a') return value;
}) === '[{"a":"1"},"a"]',
'accept callback'
);
console.assert(
JSON.stringify(
jsonStrinfigier.parse('[{"a":"1"},"a"]', function (key, value) {
if (key === 'a') return 'b';
return value;
})
) === '{"a":"b"}',
'revive callback'
);
}());
(function () {
var o = {}, before, after;
o.a = o;
o.c = {};
o.d = {
a: 123,
b: o
};
o.c.e = o;
o.c.f = o.d;
o.b = o.c;
before = jsonStrinfigier.stringify(o);
o = jsonStrinfigier.parse(before);
console.assert(
o.b === o.c &&
o.c.e === o &&
o.d.a === 123 &&
o.d.b === o &&
o.c.f === o.d &&
o.b === o.c,
'recreated original structure'
);
}());
(function () {
var o = {};
o.a = o;
o.b = o;
console.assert(
jsonStrinfigier.stringify(o, function (key, value) {
if (!key || key === 'a') return value;
}) === '[{"a":"0"}]',
'callback invoked'
);
o = jsonStrinfigier.parse('[{"a":"0"}]', function (key, value) {
if (!key) {
value.b = value;
}
return value;
});
console.assert(
o.a === o && o.b === o,
'reviver invoked'
);
}());
(function () {
var o = {};
o['~'] = o;
o['\\x7e'] = '\\x7e';
o.test = '~';
o = jsonStrinfigier.parse(jsonStrinfigier.stringify(o));
console.assert(o['~'] === o && o.test === '~', 'still intact');
o = {
a: [
'~', '~~', '~~~'
]
};
o.a.push(o);
o.o = o;
o['~'] = o.a;
o['~~'] = o.a;
o['~~~'] = o.a;
o = jsonStrinfigier.parse(jsonStrinfigier.stringify(o));
console.assert(
o === o.a[3] &&
o === o.o &&
o['~'] === o.a &&
o['~~'] === o.a &&
o['~~~'] === o.a &&
o.a === o.a[3].a &&
o.a.pop() === o &&
o.a.join('') === '~~~~~~',
'restructured'
);
}());
(function () {
// make sure only own properties are parsed
Object.prototype.shenanigans = true;
var
item = {
name: 'TEST'
},
original = {
outer: [
{
a: 'b',
c: 'd',
one: item,
many: [item],
e: 'f'
}
]
},
str,
output
;
item.value = item;
str = jsonStrinfigier.stringify(original);
output = jsonStrinfigier.parse(str);
console.assert(str === '[{"outer":"1"},["2"],{"a":"3","c":"4","one":"5","many":"6","e":"7"},"b","d",{"name":"8","value":"5"},["5"],"f","TEST"]', 'string is correct');
console.assert(
original.outer[0].one.name === output.outer[0].one.name &&
original.outer[0].many[0].name === output.outer[0].many[0].name &&
output.outer[0].many[0] === output.outer[0].one,
'object too'
);
delete Object.prototype.shenanigans;
}());
(function () {
var
unique = { a: 'sup' },
nested = {
prop: {
value: 123
},
a: [
{},
{
b: [
{
a: 1,
d: 2,
c: unique,
z: {
g: 2,
a: unique,
b: {
r: 4,
u: unique,
c: 5
},
f: 6
},
h: 1
}
]
}
],
b: {
e: 'f',
t: unique,
p: 4
}
},
str = jsonStrinfigier.stringify(nested),
output
;
console.assert(str === '[{"prop":"1","a":"2","b":"3"},{"value":123},["4","5"],{"e":"6","t":"7","p":4},{},{"b":"8"},"f",{"a":"9"},["10"],"sup",{"a":1,"d":2,"c":"7","z":"11","h":1},{"g":2,"a":"7","b":"12","f":6},{"r":4,"u":"7","c":5}]', 'string is OK');
output = jsonStrinfigier.parse(str);
console.assert(output.b.t.a === 'sup' && output.a[1].b[0].c === output.b.t, 'so is the object');
}());
(function () {
var o = { bar: 'something ~ baz' };
var s = jsonStrinfigier.stringify(o);
console.assert(s === '[{"bar":"1"},"something ~ baz"]', 'string is correct');
var oo = jsonStrinfigier.parse(s);
console.assert(oo.bar === o.bar, 'parse is correct');
}());
(function () {
var o = {};
o.a = {
aa: {
aaa: 'value1'
}
};
o.b = o;
o.c = {
ca: {},
cb: {},
cc: {},
cd: {},
ce: 'value2',
cf: 'value3'
};
o.c.ca.caa = o.c.ca;
o.c.cb.cba = o.c.cb;
o.c.cc.cca = o.c;
o.c.cd.cda = o.c.ca.caa;
var s = jsonStrinfigier.stringify(o);
console.assert(s === '[{"a":"1","b":"0","c":"2"},{"aa":"3"},{"ca":"4","cb":"5","cc":"6","cd":"7","ce":"8","cf":"9"},{"aaa":"10"},{"caa":"4"},{"cba":"5"},{"cca":"2"},{"cda":"4"},"value2","value3","value1"]', 'string is correct');
var oo = jsonStrinfigier.parse(s);
console.assert(
oo.a.aa.aaa = 'value1'
&& oo === oo.b
&& o.c.ca.caa === o.c.ca
&& o.c.cb.cba === o.c.cb
&& o.c.cc.cca === o.c
&& o.c.cd.cda === o.c.ca.caa
&& oo.c.ce === 'value2'
&& oo.c.cf === 'value3',
'parse is correct'
);
}());
(function () {
var
original = {
a1: {
a2: [],
a3: [{ name: 'whatever' }]
},
a4: []
},
json,
restored
;
original.a1.a2[0] = original.a1;
original.a4[0] = original.a1.a3[0];
json = jsonStrinfigier.stringify(original);
restored = jsonStrinfigier.parse(json);
console.assert(restored.a1.a2[0] === restored.a1, '~a1~a2~0 === ~a1');
console.assert(restored.a4[0] = restored.a1.a3[0], '~a4 === ~a1~a3~0');
}());
if (typeof Symbol !== 'undefined') {
(function () {
var o = { a: 1 };
var a = [1, Symbol('test'), 2];
o[Symbol('test')] = 123;
console.assert(('[' + JSON.stringify(o) + ']') === jsonStrinfigier.stringify(o), 'Symbol is OK too');
console.assert(('[' + JSON.stringify(a) + ']') === jsonStrinfigier.stringify(a), 'non symbol is OK too');
}());
}
(function () {
var args = [{ a: [1] }, null, ' '];
console.assert(jsonStrinfigier.stringify.apply(null, args) === "[{\n \"a\": \"1\"\n},[\n 1\n]]", 'extra args same as JSON');
}());
(function () {
var o = { a: 1, b: { a: 1, b: 2 } };
var json = JSON.stringify(o, ['b']);
console.assert(
jsonStrinfigier.stringify(o, ['b']) === '[{"b":"1"},{"b":2}]',
'whitelisted ["b"]: ' + json
);
}());
(function () {
var a = { b: { '': { c: { d: 1 } } } };
a._circular = a.b[''];
var json = jsonStrinfigier.stringify(a);
var nosj = jsonStrinfigier.parse(json);
console.assert(
nosj._circular === nosj.b[''] &&
JSON.stringify(nosj._circular) === JSON.stringify(a._circular),
'empty keys as non root objects work'
);
delete a._circular;
delete nosj._circular;
console.assert(
JSON.stringify(nosj) === JSON.stringify(a),
'objects copied with circular empty keys are the same'
);
}());
});
it('JSon Stringify Plivo Response & Client object', function () {
let authId = "lsdjflkdsjflsdlfdjkl";
let authToken = "lksfkldsfklsjf";
let event = {};
event.plivoResponse = Response();
event.plivoSubApi = new Client(authId, authToken);
event.plivoResponse.addSpeak("The customer disconnected from the conference.");
event.plivoResponse.addHangup({ reason: "rejected", schedule: 0 });
let out = event.plivoResponse.toXML();
let dd = JSON.stringify(event);
});
});