aboutsummaryrefslogtreecommitdiff
path: root/node_modules/structured-clone/serialize.js
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2017-08-14 05:01:11 +0200
committerFlorian Dold <florian.dold@gmail.com>2017-08-14 05:02:09 +0200
commit363723fc84f7b8477592e0105aeb331ec9a017af (patch)
tree29f92724f34131bac64d6a318dd7e30612e631c7 /node_modules/structured-clone/serialize.js
parent5634e77ad96bfe1818f6b6ee70b7379652e5487f (diff)
node_modules
Diffstat (limited to 'node_modules/structured-clone/serialize.js')
-rw-r--r--node_modules/structured-clone/serialize.js223
1 files changed, 223 insertions, 0 deletions
diff --git a/node_modules/structured-clone/serialize.js b/node_modules/structured-clone/serialize.js
new file mode 100644
index 000000000..44c984f38
--- /dev/null
+++ b/node_modules/structured-clone/serialize.js
@@ -0,0 +1,223 @@
+// Implements serialize/deserialize of structured clones.
+// Also resolves cycles (code based on cycle.js by Douglas Crockford)
+
+function encodeRegExp (regexp)
+{
+ var flags = '';
+ if (regexp.global) flags += 'g';
+ if (regexp.multiline) flags += 'm';
+ if (regexp.ignoreCase) flags += 'i';
+ return [flags, regexp.source].join(',');
+}
+
+function decodeRegExp (str)
+{
+ var flags = str.match(/^[^,]*/)[0];
+ var source = str.substr(flags.length + 1);
+ return new RegExp(source, flags);
+}
+
+
+// The derez recurses through the object, producing the deep copy.
+
+function derez(value, path, objects, paths, buffers)
+{
+ if (Buffer.isBuffer(value)) {
+ var start = Buffer.concat(buffers).length;
+ buffers.push(value);
+ return '\x10b' + [start, value.length].join(',')
+ }
+ if (value instanceof Date) {
+ return '\x10d' + value.toJSON();
+ }
+ if (value instanceof RegExp) {
+ return '\x10r' + encodeRegExp(value);
+ }
+ if (value instanceof Error) {
+ return '\x10e' + value.message
+ }
+ if (typeof value == 'string') {
+ return value.charAt(0) == '\x10' ? '\x10s' + value : value;
+ }
+
+ var i, // The loop counter
+ name, // Property name
+ nu; // The new object or array
+
+// typeof null === 'object', so go on if this value is really an object but not
+// one of the weird builtin objects.
+
+ if (typeof value === 'object' && value !== null &&
+ !(value instanceof Boolean) &&
+ !(value instanceof Number) &&
+ !(value instanceof String)) {
+
+// If the value is an object or array, look to see if we have already
+// encountered it. If so, return a $ref/path object. This is a hard way,
+// linear search that will get slower as the number of unique objects grows.
+
+ i = objects.indexOf(value);
+ if (i !== -1) {
+ return '\x10j' + paths[i];
+ }
+
+// Otherwise, accumulate the unique value and its path.
+
+ objects.push(value);
+ paths.push(path);
+
+// If it is an array, replicate the array.
+
+ if (Array.isArray(value)) {
+ nu = [];
+ for (i = 0; i < value.length; i += 1) {
+ nu[i] = derez(value[i],
+ path + '[' + i + ']',
+ objects, paths, buffers);
+ }
+ } else {
+
+// If it is an object, replicate the object.
+
+ nu = {};
+ for (name in value) {
+ if (Object.prototype.hasOwnProperty.call(value, name) && value != '__proto__') {
+ nu[name] = derez(value[name],
+ path + '[' + JSON.stringify(name) + ']',
+ objects, paths, buffers);
+ }
+ }
+ }
+ return nu;
+ }
+
+ return value;
+}
+
+
+function rerez($, $$)
+{
+
+// Restore an object that was reduced by decycle. Members whose values are
+// objects of the form
+// {$ref: PATH}
+// are replaced with references to the value found by the PATH. This will
+// restore cycles. The object will be mutated.
+
+// The eval function is used to locate the values described by a PATH. The
+// root object is kept in a $ variable. A regular expression is used to
+// assure that the PATH is extremely well formed. The regexp contains nested
+// * quantifiers. That has been known to have extremely bad performance
+// problems on some browsers for very long strings. A PATH is expected to be
+// reasonably short. A PATH is allowed to belong to a very restricted subset of
+// Goessner's JSONPath.
+
+// So,
+// var s = '[{"$ref":"$"}]';
+// return JSON.retrocycle(JSON.parse(s));
+// produces an array containing a single element which is the array itself.
+
+ var px =
+ /^\${1,4}(?:\[(?:\d+|\"(?:[^\\\"\u0000-\u001f]|\\([\\\"\/bfnrt]|u[0-9a-zA-Z]{4}))*\")\])*$/;
+
+ function redo (item) {
+ if (typeof item == 'string' && item.charAt(0) == '\x10') {
+ switch (item.charAt(1)) {
+ case 's':
+ return item.substr(2);
+ case 'b':
+ var bounds = item.substr(2).split(',', 2);
+ return $$.slice(bounds[0] || 0, (bounds[0] || 0) + (bounds[1] || [0]));
+ case 'd':
+ return new Date(item.substr(2));
+ case 'r':
+ return decodeRegExp(item.substr(2));
+ case 'e':
+ return new Error(item.substr(2));
+ case 'j':
+ var path = item.substr(2);
+ if (px.test(path)) {
+ return eval(path);
+ }
+ default: return null;
+ }
+ }
+
+ if (item && typeof item === 'object') {
+ rez(item, $$);
+ }
+ return item;
+ }
+
+ function rez(value) {
+
+// The rez function walks recursively through the object looking for $ref
+// properties. When it finds one that has a value that is a path, then it
+// replaces the $ref object with a reference to the value that is found by
+// the path.
+
+ var i, name;
+
+ if (value && typeof value === 'object') {
+ if (Array.isArray(value)) {
+ for (i = 0; i < value.length; i += 1) {
+ value[i] = redo(value[i]);
+ }
+ } else {
+ for (name in value) {
+ value[name] = redo(value[name]);
+ }
+ }
+ }
+ }
+
+ $ = redo($)
+
+ return $;
+};
+
+
+// Public API
+
+exports.serialize = function (object) {
+ var objects = [], // Keep a reference to each unique object or array
+ paths = [], // Keep the path to each unique object or array
+ buffers = []; // Returned buffers
+
+ var nilbyte = new Buffer([0x00]);
+
+ if (Buffer.isBuffer(object)) {
+ return Buffer.concat([
+ nilbyte,
+ object
+ ]);
+ }
+
+ var json = new Buffer(JSON.stringify(derez(object, '$', objects, paths, buffers)));
+ if (buffers.length == 0) {
+ return json;
+ }
+
+ return Buffer.concat([
+ json,
+ nilbyte,
+ Buffer.concat(buffers)
+ ]);
+}
+
+exports.deserialize = function (buf) {
+ for (var i = 0; i <= buf.length; i++) {
+ if (buf[i] == 0x00 || buf[i] == null) {
+ break;
+ }
+ }
+ var jsonbuf = buf.slice(0, i);
+ var bufbuf = buf.slice(i + 1);
+
+ // Shortcut for only encoding a root buffer.
+ if (jsonbuf.length == 0) {
+ return bufbuf;
+ }
+
+ return rerez(JSON.parse(jsonbuf.toString('utf-8')), bufbuf);
+} \ No newline at end of file