© 2019 Meouzer Consortium

JavaScript: Parse Data String

loading
Well I hate to confess but doing JavaScript is a stress so my editors got to working and after they quit smirking turned my JavaScript into a real mess
Meouzer

Full code at parseDataString.js, which depends on typing.js. But you'll also want Stringify.js.

Introduction

If x is simple-data then parseDataString(serializeSimpleData(x)) is a deep copy of x. This is analogous to what JSON does, but parseDataString() together with serializeSimpleData() is much more powerful than JSON because they can handle all simple-data including typed arrays, ArrayBuffers, DataViews, Maps, and Sets. Furthermore these two functions handle complicated constructs with the greatest of ease. You can have Sets whose members are Maps, whose keys are Arrays, and values are Booleans: The Set can also have properties that are DataViews which in turn have properties that are Maps which in turn have properties that are Numbers.

Simple data was defined in the stringification article.

Like stringify(), parseDataString() uses very complex parsing, and its code will not be displayed. We will instead give examples of deep copying by serializing an object and then deserializing the resulting string.

Examples

Deep Copy Simple Data x through serialization/deserialization on line 21
function WildCircularTest() { const buffer = new ArrayBuffer(4); const view = new DataView(buffer); view.setInt8(0, 127); view.setInt8(1, 11); view.setInt8(2, 17); view.setInt8(3, -17); const map1 = Map.makeMap([ [ [1,2], new Date()], [7,true], ['key1', 'value1'], [buffer, view] ]); const map2 = Map.makeMap([ ['key2', {a:1,b:2}], [new Boolean(true), new Number(7)] ]); map1.buf = buffer; buffer.z = map1; map2.view = view; view.x = new Boolean(true); buffer.x = new Boolean(true); const x = Set.makeSet([map1, map2]); x.a = new Date(1618595373337); x.a.b = Set.makeSet(["cat", "dog", buffer, view, ["a", new String("b")]]); x.a.b.c = x; x.buff = buffer; const deepCopy_x = parseDataString(serializeSimpleData(x)); console.log(stringify(x )); if(stringify(x) === stringify(deepCopy_x) && type(x) === type(deepCopy_x)) { console.log("Wild Circular Test Passed: true"); } else { console.log("Wild Circular Test Passed: false"); } } WildCircularTest();

Open your browser's console window to see the result of the test.

Deep Copy F-Data x through serialization/deserialization
(Three circular gets used)
function TestCircularGets() { const A = {x:{a:{b:{c:1}}}, y:{c:{a:{b:1}}}, z:{}}; // Three circular gets Object.defineProperty(A.z, "x", { get:function(){return A.x;}, }); Object.defineProperty(A.x, "y", { get:function(){return A.y;}, }); Object.defineProperty(A.y, "z", { get:function(){return A.z;}, }); var string = serializeFData(A); function deserializeA() { const evaluator = function(){return eval('(' + arguments[0] + ')');} // The three copied getters need a variable A in context. So we put one // in context and create the deep copy at the same time. var A = parseDataString(string, evaluator); return A; } const B = deserializeA(); console.log("TestCircularGets passed: " + (stringify(B) == stringify(A))); console.log("TestCircularGets ref 1 passed: " + (B.z != A.z)); console.log("TestCircularGets ref 2 passed: " + (B.z.x != A.z.x)); console.log("TestCircularGets ref 3 passed: " + (B.z.x.y != A.z.x.y)); console.log("TestCircularGets ref 4 passed: " + (B.z.x.y.z != A.z.x.y.z)); } TestCircularGets();