JAVASCRIPT   18

JSON3

Guest on 9th July 2022 07:06:50 AM

  1. (function () {
  2. var exports = {};
  3. // Create a JSON object only if one does not already exist. We create the
  4. // methods in a closure to avoid creating global variables.
  5. /*! JSON v3.3.2 | http://bestiejs.github.io/json3 | Copyright 2012-2014, Kit Cambridge | http://kit.mit-license.org */
  6.     (function () {
  7.         // Detect the `define` function exposed by asynchronous module loaders. The
  8.         // strict `define` check is necessary for compatibility with `r.js`.
  9.         var isLoader = typeof define === "function" && define.amd;
  10.  
  11.         // A set of types used to distinguish objects from primitives.
  12.         var objectTypes = {
  13.             "function": true,
  14.             "object": true
  15.         };
  16.  
  17.         // Detect the `exports` object exposed by CommonJS implementations.
  18.         var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
  19.  
  20.         // Use the `global` object exposed by Node (including Browserify via
  21.         // `insert-module-globals`), Narwhal, and Ringo as the default context,
  22.         // and the `window` object in browsers. Rhino exports a `global` function
  23.         // instead.
  24.         var root = objectTypes[typeof window] && window || this,
  25.             freeGlobal = freeExports && objectTypes[typeof module] && module && !module.nodeType && typeof global == "object" && global;
  26.  
  27.         if (freeGlobal && (freeGlobal["global"] === freeGlobal || freeGlobal["window"] === freeGlobal || freeGlobal["self"] === freeGlobal)) {
  28.             root = freeGlobal;
  29.         }
  30.  
  31.         // Public: Initializes JSON 3 using the given `context` object, attaching the
  32.         // `stringify` and `parse` functions to the specified `exports` object.
  33.         function runInContext(context, exports) {
  34.             context || (context = root["Object"]());
  35.             exports || (exports = root["Object"]());
  36.  
  37.             // Native constructor aliases.
  38.             var Number = context["Number"] || root["Number"],
  39.                 String = context["String"] || root["String"],
  40.                 Object = context["Object"] || root["Object"],
  41.                 Date = context["Date"] || root["Date"],
  42.                 SyntaxError = context["SyntaxError"] || root["SyntaxError"],
  43.                 TypeError = context["TypeError"] || root["TypeError"],
  44.                 Math = context["Math"] || root["Math"],
  45.                 nativeJSON = context["JSON"] || root["JSON"];
  46.  
  47.             // Delegate to the native `stringify` and `parse` implementations.
  48.             if (typeof nativeJSON == "object" && nativeJSON) {
  49.                 exports.stringify = nativeJSON.stringify;
  50.                 exports.parse = nativeJSON.parse;
  51.             }
  52.  
  53.             // Convenience aliases.
  54.             var objectProto = Object.prototype,
  55.                 getClass = objectProto.toString,
  56.                 isProperty, forEach, undef;
  57.  
  58.             // Test the `Date#getUTC*` methods. Based on work by @Yaffle.
  59.             var isExtended = new Date(-3509827334573292);
  60.             try {
  61.                 // The `getUTCFullYear`, `Month`, and `Date` methods return nonsensical
  62.                 // results for certain dates in Opera >= 10.53.
  63.                 isExtended = isExtended.getUTCFullYear() == -109252 && isExtended.getUTCMonth() === 0 && isExtended.getUTCDate() === 1 &&
  64.                         // Safari < 2.0.2 stores the internal millisecond time value correctly,
  65.                         // but clips the values returned by the date methods to the range of
  66.                         // signed 32-bit integers ([-2 ** 31, 2 ** 31 - 1]).
  67.                     isExtended.getUTCHours() == 10 && isExtended.getUTCMinutes() == 37 && isExtended.getUTCSeconds() == 6 && isExtended.getUTCMilliseconds() == 708;
  68.             } catch (exception) {}
  69.  
  70.             // Internal: Determines whether the native `JSON.stringify` and `parse`
  71.             // implementations are spec-compliant. Based on work by Ken Snyder.
  72.             function has(name) {
  73.                 if (has[name] !== undef) {
  74.                     // Return cached feature test result.
  75.                     return has[name];
  76.                 }
  77.                 var isSupported;
  78.                 if (name == "bug-string-char-index") {
  79.                     // IE <= 7 doesn't support accessing string characters using square
  80.                     // bracket notation. IE 8 only supports this for primitives.
  81.                     isSupported = "a"[0] != "a";
  82.                 } else if (name == "json") {
  83.                     // Indicates whether both `JSON.stringify` and `JSON.parse` are
  84.                     // supported.
  85.                     isSupported = has("json-stringify") && has("json-parse");
  86.                 } else {
  87.                     var value, serialized = '{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}';
  88.                     // Test `JSON.stringify`.
  89.                     if (name == "json-stringify") {
  90.                         var stringify = exports.stringify, stringifySupported = typeof stringify == "function" && isExtended;
  91.                         if (stringifySupported) {
  92.                             // A test function object with a custom `toJSON` method.
  93.                             (value = function () {
  94.                                 return 1;
  95.                             }).toJSON = value;
  96.                             try {
  97.                                 stringifySupported =
  98.                                     // Firefox 3.1b1 and b2 serialize string, number, and boolean
  99.                                     // primitives as object literals.
  100.                                     stringify(0) === "0" &&
  101.                                         // FF 3.1b1, b2, and JSON 2 serialize wrapped primitives as object
  102.                                         // literals.
  103.                                     stringify(new Number()) === "0" &&
  104.                                     stringify(new String()) == '""' &&
  105.                                         // FF 3.1b1, 2 throw an error if the value is `null`, `undefined`, or
  106.                                         // does not define a canonical JSON representation (this applies to
  107.                                         // objects with `toJSON` properties as well, *unless* they are nested
  108.                                         // within an object or array).
  109.                                     stringify(getClass) === undef &&
  110.                                         // IE 8 serializes `undefined` as `"undefined"`. Safari <= 5.1.7 and
  111.                                         // FF 3.1b3 pass this test.
  112.                                     stringify(undef) === undef &&
  113.                                         // Safari <= 5.1.7 and FF 3.1b3 throw `Error`s and `TypeError`s,
  114.                                         // respectively, if the value is omitted entirely.
  115.                                     stringify() === undef &&
  116.                                         // FF 3.1b1, 2 throw an error if the given value is not a number,
  117.                                         // string, array, object, Boolean, or `null` literal. This applies to
  118.                                         // objects with custom `toJSON` methods as well, unless they are nested
  119.                                         // inside object or array literals. YUI 3.0.0b1 ignores custom `toJSON`
  120.                                         // methods entirely.
  121.                                     stringify(value) === "1" &&
  122.                                     stringify([value]) == "[1]" &&
  123.                                         // Prototype <= 1.6.1 serializes `[undefined]` as `"[]"` instead of
  124.                                         // `"[null]"`.
  125.                                     stringify([undef]) == "[null]" &&
  126.                                         // YUI 3.0.0b1 fails to serialize `null` literals.
  127.                                     stringify(null) == "null" &&
  128.                                         // FF 3.1b1, 2 halts serialization if an array contains a function:
  129.                                         // `[1, true, getClass, 1]` serializes as "[1,true,],". FF 3.1b3
  130.                                         // elides non-JSON values from objects and arrays, unless they
  131.                                         // define custom `toJSON` methods.
  132.                                     stringify([undef, getClass, null]) == "[null,null,null]" &&
  133.                                         // Simple serialization test. FF 3.1b1 uses Unicode escape sequences
  134.                                         // where character escape codes are expected (e.g., `\b` => `\u0008`).
  135.                                     stringify({ "a": [value, true, false, null, "\x00\b\n\f\r\t"] }) == serialized &&
  136.                                         // FF 3.1b1 and b2 ignore the `filter` and `width` arguments.
  137.                                     stringify(null, value) === "1" &&
  138.                                     stringify([1, 2], null, 1) == "[\n 1,\n 2\n]" &&
  139.                                         // JSON 2, Prototype <= 1.7, and older WebKit builds incorrectly
  140.                                         // serialize extended years.
  141.                                     stringify(new Date(-8.64e15)) == '"-271821-04-20T00:00:00.000Z"' &&
  142.                                         // The milliseconds are optional in ES 5, but required in 5.1.
  143.                                     stringify(new Date(8.64e15)) == '"+275760-09-13T00:00:00.000Z"' &&
  144.                                         // Firefox <= 11.0 incorrectly serializes years prior to 0 as negative
  145.                                         // four-digit years instead of six-digit years. Credits: @Yaffle.
  146.                                     stringify(new Date(-621987552e5)) == '"-000001-01-01T00:00:00.000Z"' &&
  147.                                         // Safari <= 5.1.5 and Opera >= 10.53 incorrectly serialize millisecond
  148.                                         // values less than 1000. Credits: @Yaffle.
  149.                                     stringify(new Date(-1)) == '"1969-12-31T23:59:59.999Z"';
  150.                             } catch (exception) {
  151.                                 stringifySupported = false;
  152.                             }
  153.                         }
  154.                         isSupported = stringifySupported;
  155.                     }
  156.                     // Test `JSON.parse`.
  157.                     if (name == "json-parse") {
  158.                         var parse = exports.parse;
  159.                         if (typeof parse == "function") {
  160.                             try {
  161.                                 // FF 3.1b1, b2 will throw an exception if a bare literal is provided.
  162.                                 // Conforming implementations should also coerce the initial argument to
  163.                                 // a string prior to parsing.
  164.                                 if (parse("0") === 0 && !parse(false)) {
  165.                                     // Simple parsing test.
  166.                                     value = parse(serialized);
  167.                                     var parseSupported = value["a"].length == 5 && value["a"][0] === 1;
  168.                                     if (parseSupported) {
  169.                                         try {
  170.                                             // Safari <= 5.1.2 and FF 3.1b1 allow unescaped tabs in strings.
  171.                                             parseSupported = !parse('"\t"');
  172.                                         } catch (exception) {}
  173.                                         if (parseSupported) {
  174.                                             try {
  175.                                                 // FF 4.0 and 4.0.1 allow leading `+` signs and leading
  176.                                                 // decimal points. FF 4.0, 4.0.1, and IE 9-10 also allow
  177.                                                 // certain octal literals.
  178.                                                 parseSupported = parse("01") !== 1;
  179.                                             } catch (exception) {}
  180.                                         }
  181.                                         if (parseSupported) {
  182.                                             try {
  183.                                                 // FF 4.0, 4.0.1, and Rhino 1.7R3-R4 allow trailing decimal
  184.                                                 // points. These environments, along with FF 3.1b1 and 2,
  185.                                                 // also allow trailing commas in JSON objects and arrays.
  186.                                                 parseSupported = parse("1.") !== 1;
  187.                                             } catch (exception) {}
  188.                                         }
  189.                                     }
  190.                                 }
  191.                             } catch (exception) {
  192.                                 parseSupported = false;
  193.                             }
  194.                         }
  195.                         isSupported = parseSupported;
  196.                     }
  197.                 }
  198.                 return has[name] = !!isSupported;
  199.             }
  200.  
  201.             if (!has("json")) {
  202.                 // Common `[[Class]]` name aliases.
  203.                 var functionClass = "[object Function]",
  204.                     dateClass = "[object Date]",
  205.                     numberClass = "[object Number]",
  206.                     stringClass = "[object String]",
  207.                     arrayClass = "[object Array]",
  208.                     booleanClass = "[object Boolean]";
  209.  
  210.                 // Detect incomplete support for accessing string characters by index.
  211.                 var charIndexBuggy = has("bug-string-char-index");
  212.  
  213.                 // Define additional utility methods if the `Date` methods are buggy.
  214.                 if (!isExtended) {
  215.                     var floor = Math.floor;
  216.                     // A mapping between the months of the year and the number of days between
  217.                     // January 1st and the first of the respective month.
  218.                     var Months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
  219.                     // Internal: Calculates the number of days between the Unix epoch and the
  220.                     // first day of the given month.
  221.                     var getDay = function (year, month) {
  222.                         return Months[month] + 365 * (year - 1970) + floor((year - 1969 + (month = +(month > 1))) / 4) - floor((year - 1901 + month) / 100) + floor((year - 1601 + month) / 400);
  223.                     };
  224.                 }
  225.  
  226.                 // Internal: Determines if a property is a direct property of the given
  227.                 // object. Delegates to the native `Object#hasOwnProperty` method.
  228.                 if (!(isProperty = objectProto.hasOwnProperty)) {
  229.                     isProperty = function (property) {
  230.                         var members = {}, constructor;
  231.                         if ((members.__proto__ = null, members.__proto__ = {
  232.                                 // The *proto* property cannot be set multiple times in recent
  233.                                 // versions of Firefox and SeaMonkey.
  234.                                 "toString": 1
  235.                             }, members).toString != getClass) {
  236.                             // Safari <= 2.0.3 doesn't implement `Object#hasOwnProperty`, but
  237.                             // supports the mutable *proto* property.
  238.                             isProperty = function (property) {
  239.                                 // Capture and break the object's prototype chain (see section 8.6.2
  240.                                 // of the ES 5.1 spec). The parenthesized expression prevents an
  241.                                 // unsafe transformation by the Closure Compiler.
  242.                                 var original = this.__proto__, result = property in (this.__proto__ = null, this);
  243.                                 // Restore the original prototype chain.
  244.                                 this.__proto__ = original;
  245.                                 return result;
  246.                             };
  247.                         } else {
  248.                             // Capture a reference to the top-level `Object` constructor.
  249.                             constructor = members.constructor;
  250.                             // Use the `constructor` property to simulate `Object#hasOwnProperty` in
  251.                             // other environments.
  252.                             isProperty = function (property) {
  253.                                 var parent = (this.constructor || constructor).prototype;
  254.                                 return property in this && !(property in parent && this[property] === parent[property]);
  255.                             };
  256.                         }
  257.                         members = null;
  258.                         return isProperty.call(this, property);
  259.                     };
  260.                 }
  261.  
  262.                 // Internal: Normalizes the `for...in` iteration algorithm across
  263.                 // environments. Each enumerated key is yielded to a `callback` function.
  264.                 forEach = function (object, callback) {
  265.                     var size = 0, Properties, members, property;
  266.  
  267.                     // Tests for bugs in the current environment's `for...in` algorithm. The
  268.                     // `valueOf` property inherits the non-enumerable flag from
  269.                     // `Object.prototype` in older versions of IE, Netscape, and Mozilla.
  270.                     (Properties = function () {
  271.                         this.valueOf = 0;
  272.                     }).prototype.valueOf = 0;
  273.  
  274.                     // Iterate over a new instance of the `Properties` class.
  275.                     members = new Properties();
  276.                     for (property in members) {
  277.                         // Ignore all properties inherited from `Object.prototype`.
  278.                         if (isProperty.call(members, property)) {
  279.                             size++;
  280.                         }
  281.                     }
  282.                     Properties = members = null;
  283.  
  284.                     // Normalize the iteration algorithm.
  285.                     if (!size) {
  286.                         // A list of non-enumerable properties inherited from `Object.prototype`.
  287.                         members = ["valueOf", "toString", "toLocaleString", "propertyIsEnumerable", "isPrototypeOf", "hasOwnProperty", "constructor"];
  288.                         // IE <= 8, Mozilla 1.0, and Netscape 6.2 ignore shadowed non-enumerable
  289.                         // properties.
  290.                         forEach = function (object, callback) {
  291.                             var isFunction = getClass.call(object) == functionClass, property, length;
  292.                             var hasProperty = !isFunction && typeof object.constructor != "function" && objectTypes[typeof object.hasOwnProperty] && object.hasOwnProperty || isProperty;
  293.                             for (property in object) {
  294.                                 // Gecko <= 1.0 enumerates the `prototype` property of functions under
  295.                                 // certain conditions; IE does not.
  296.                                 if (!(isFunction && property == "prototype") && hasProperty.call(object, property)) {
  297.                                     callback(property);
  298.                                 }
  299.                             }
  300.                             // Manually invoke the callback for each non-enumerable property.
  301.                             for (length = members.length; property = members[--length]; hasProperty.call(object, property) && callback(property));
  302.                         };
  303.                     } else if (size == 2) {
  304.                         // Safari <= 2.0.4 enumerates shadowed properties twice.
  305.                         forEach = function (object, callback) {
  306.                             // Create a set of iterated properties.
  307.                             var members = {}, isFunction = getClass.call(object) == functionClass, property;
  308.                             for (property in object) {
  309.                                 // Store each property name to prevent double enumeration. The
  310.                                 // `prototype` property of functions is not enumerated due to cross-
  311.                                 // environment inconsistencies.
  312.                                 if (!(isFunction && property == "prototype") && !isProperty.call(members, property) && (members[property] = 1) && isProperty.call(object, property)) {
  313.                                     callback(property);
  314.                                 }
  315.                             }
  316.                         };
  317.                     } else {
  318.                         // No bugs detected; use the standard `for...in` algorithm.
  319.                         forEach = function (object, callback) {
  320.                             var isFunction = getClass.call(object) == functionClass, property, isConstructor;
  321.                             for (property in object) {
  322.                                 if (!(isFunction && property == "prototype") && isProperty.call(object, property) && !(isConstructor = property === "constructor")) {
  323.                                     callback(property);
  324.                                 }
  325.                             }
  326.                             // Manually invoke the callback for the `constructor` property due to
  327.                             // cross-environment inconsistencies.
  328.                             if (isConstructor || isProperty.call(object, (property = "constructor"))) {
  329.                                 callback(property);
  330.                             }
  331.                         };
  332.                     }
  333.                     return forEach(object, callback);
  334.                 };
  335.  
  336.                 // Public: Serializes a JavaScript `value` as a JSON string. The optional
  337.                 // `filter` argument may specify either a function that alters how object and
  338.                 // array members are serialized, or an array of strings and numbers that
  339.                 // indicates which properties should be serialized. The optional `width`
  340.                 // argument may be either a string or number that specifies the indentation
  341.                 // level of the output.
  342.                 if (!has("json-stringify")) {
  343.                     // Internal: A map of control characters and their escaped equivalents.
  344.                     var Escapes = {
  345.                         92: "\\\\",
  346.                         34: '\\"',
  347.                         8: "\\b",
  348.                         12: "\\f",
  349.                         10: "\\n",
  350.                         13: "\\r",
  351.                         9: "\\t"
  352.                     };
  353.  
  354.                     // Internal: Converts `value` into a zero-padded string such that its
  355.                     // length is at least equal to `width`. The `width` must be <= 6.
  356.                     var leadingZeroes = "000000";
  357.                     var toPaddedString = function (width, value) {
  358.                         // The `|| 0` expression is necessary to work around a bug in
  359.                         // Opera <= 7.54u2 where `0 == -0`, but `String(-0) !== "0"`.
  360.                         return (leadingZeroes + (value || 0)).slice(-width);
  361.                     };
  362.  
  363.                     // Internal: Double-quotes a string `value`, replacing all ASCII control
  364.                     // characters (characters with code unit values between 0 and 31) with
  365.                     // their escaped equivalents. This is an implementation of the
  366.                     // `Quote(value)` operation defined in ES 5.1 section 15.12.3.
  367.                     var unicodePrefix = "\\u00";
  368.                     var quote = function (value) {
  369.                         var result = '"', index = 0, length = value.length, useCharIndex = !charIndexBuggy || length > 10;
  370.                         var symbols = useCharIndex && (charIndexBuggy ? value.split("") : value);
  371.                         for (; index < length; index++) {
  372.                             var charCode = value.charCodeAt(index);
  373.                             // If the character is a control character, append its Unicode or
  374.                             // shorthand escape sequence; otherwise, append the character as-is.
  375.                             switch (charCode) {
  376.                                 case 8: case 9: case 10: case 12: case 13: case 34: case 92:
  377.                                 result += Escapes[charCode];
  378.                                 break;
  379.                                 default:
  380.                                     if (charCode < 32) {
  381.                                         result += unicodePrefix + toPaddedString(2, charCode.toString(16));
  382.                                         break;
  383.                                     }
  384.                                     result += useCharIndex ? symbols[index] : value.charAt(index);
  385.                             }
  386.                         }
  387.                         return result + '"';
  388.                     };
  389.  
  390.                     // Internal: Recursively serializes an object. Implements the
  391.                     // `Str(key, holder)`, `JO(value)`, and `JA(value)` operations.
  392.                     var serialize = function (property, object, callback, properties, whitespace, indentation, stack) {
  393.                         var value, className, year, month, date, time, hours, minutes, seconds, milliseconds, results, element, index, length, prefix, result;
  394.                         try {
  395.                             // Necessary for host object support.
  396.                             value = object[property];
  397.                         } catch (exception) {}
  398.                         if (typeof value == "object" && value) {
  399.                             className = getClass.call(value);
  400.                             if (className == dateClass && !isProperty.call(value, "toJSON")) {
  401.                                 if (value > -1 / 0 && value < 1 / 0) {
  402.                                     // Dates are serialized according to the `Date#toJSON` method
  403.                                     // specified in ES 5.1 section 15.9.5.44. See section 15.9.1.15
  404.                                     // for the ISO 8601 date time string format.
  405.                                     if (getDay) {
  406.                                         // Manually compute the year, month, date, hours, minutes,
  407.                                         // seconds, and milliseconds if the `getUTC*` methods are
  408.                                         // buggy. Adapted from @Yaffle's `date-shim` project.
  409.                                         date = floor(value / 864e5);
  410.                                         for (year = floor(date / 365.2425) + 1970 - 1; getDay(year + 1, 0) <= date; year++);
  411.                                         for (month = floor((date - getDay(year, 0)) / 30.42); getDay(year, month + 1) <= date; month++);
  412.                                         date = 1 + date - getDay(year, month);
  413.                                         // The `time` value specifies the time within the day (see ES
  414.                                         // 5.1 section 15.9.1.2). The formula `(A % B + B) % B` is used
  415.                                         // to compute `A modulo B`, as the `%` operator does not
  416.                                         // correspond to the `modulo` operation for negative numbers.
  417.                                         time = (value % 864e5 + 864e5) % 864e5;
  418.                                         // The hours, minutes, seconds, and milliseconds are obtained by
  419.                                         // decomposing the time within the day. See section 15.9.1.10.
  420.                                         hours = floor(time / 36e5) % 24;
  421.                                         minutes = floor(time / 6e4) % 60;
  422.                                         seconds = floor(time / 1e3) % 60;
  423.                                         milliseconds = time % 1e3;
  424.                                     } else {
  425.                                         year = value.getUTCFullYear();
  426.                                         month = value.getUTCMonth();
  427.                                         date = value.getUTCDate();
  428.                                         hours = value.getUTCHours();
  429.                                         minutes = value.getUTCMinutes();
  430.                                         seconds = value.getUTCSeconds();
  431.                                         milliseconds = value.getUTCMilliseconds();
  432.                                     }
  433.                                     // Serialize extended years correctly.
  434.                                     value = (year <= 0 || year >= 1e4 ? (year < 0 ? "-" : "+") + toPaddedString(6, year < 0 ? -year : year) : toPaddedString(4, year)) +
  435.                                         "-" + toPaddedString(2, month + 1) + "-" + toPaddedString(2, date) +
  436.                                             // Months, dates, hours, minutes, and seconds should have two
  437.                                             // digits; milliseconds should have three.
  438.                                         "T" + toPaddedString(2, hours) + ":" + toPaddedString(2, minutes) + ":" + toPaddedString(2, seconds) +
  439.                                             // Milliseconds are optional in ES 5.0, but required in 5.1.
  440.                                         "." + toPaddedString(3, milliseconds) + "Z";
  441.                                 } else {
  442.                                     value = null;
  443.                                 }
  444.                             } else if (typeof value.toJSON == "function" && ((className != numberClass && className != stringClass && className != arrayClass) || isProperty.call(value, "toJSON"))) {
  445.                                 // Prototype <= 1.6.1 adds non-standard `toJSON` methods to the
  446.                                 // `Number`, `String`, `Date`, and `Array` prototypes. JSON 3
  447.                                 // ignores all `toJSON` methods on these objects unless they are
  448.                                 // defined directly on an instance.
  449.                                 value = value.toJSON(property);
  450.                             }
  451.                         }
  452.                         if (callback) {
  453.                             // If a replacement function was provided, call it to obtain the value
  454.                             // for serialization.
  455.                             value = callback.call(object, property, value);
  456.                         }
  457.                         if (value === null) {
  458.                             return "null";
  459.                         }
  460.                         className = getClass.call(value);
  461.                         if (className == booleanClass) {
  462.                             // Booleans are represented literally.
  463.                             return "" + value;
  464.                         } else if (className == numberClass) {
  465.                             // JSON numbers must be finite. `Infinity` and `NaN` are serialized as
  466.                             // `"null"`.
  467.                             return value > -1 / 0 && value < 1 / 0 ? "" + value : "null";
  468.                         } else if (className == stringClass) {
  469.                             // Strings are double-quoted and escaped.
  470.                             return quote("" + value);
  471.                         }
  472.                         // Recursively serialize objects and arrays.
  473.                         if (typeof value == "object") {
  474.                             // Check for cyclic structures. This is a linear search; performance
  475.                             // is inversely proportional to the number of unique nested objects.
  476.                             for (length = stack.length; length--;) {
  477.                                 if (stack[length] === value) {
  478.                                     // Cyclic structures cannot be serialized by `JSON.stringify`.
  479.                                     throw TypeError();
  480.                                 }
  481.                             }
  482.                             // Add the object to the stack of traversed objects.
  483.                             stack.push(value);
  484.                             results = [];
  485.                             // Save the current indentation level and indent one additional level.
  486.                             prefix = indentation;
  487.                             indentation += whitespace;
  488.                             if (className == arrayClass) {
  489.                                 // Recursively serialize array elements.
  490.                                 for (index = 0, length = value.length; index < length; index++) {
  491.                                     element = serialize(index, value, callback, properties, whitespace, indentation, stack);
  492.                                     results.push(element === undef ? "null" : element);
  493.                                 }
  494.                                 result = results.length ? (whitespace ? "[\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "]" : ("[" + results.join(",") + "]")) : "[]";
  495.                             } else {
  496.                                 // Recursively serialize object members. Members are selected from
  497.                                 // either a user-specified list of property names, or the object
  498.                                 // itself.
  499.                                 forEach(properties || value, function (property) {
  500.                                     var element = serialize(property, value, callback, properties, whitespace, indentation, stack);
  501.                                     if (element !== undef) {
  502.                                         // According to ES 5.1 section 15.12.3: "If `gap` {whitespace}
  503.                                         // is not the empty string, let `member` {quote(property) + ":"}
  504.                                         // be the concatenation of `member` and the `space` character."
  505.                                         // The "`space` character" refers to the literal space
  506.                                         // character, not the `space` {width} argument provided to
  507.                                         // `JSON.stringify`.
  508.                                         results.push(quote(property) + ":" + (whitespace ? " " : "") + element);
  509.                                     }
  510.                                 });
  511.                                 result = results.length ? (whitespace ? "{\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "}" : ("{" + results.join(",") + "}")) : "{}";
  512.                             }
  513.                             // Remove the object from the traversed object stack.
  514.                             stack.pop();
  515.                             return result;
  516.                         }
  517.                     };
  518.  
  519.                     // Public: `JSON.stringify`. See ES 5.1 section 15.12.3.
  520.                     exports.stringify = function (source, filter, width) {
  521.                         var whitespace, callback, properties, className;
  522.                         if (objectTypes[typeof filter] && filter) {
  523.                             if ((className = getClass.call(filter)) == functionClass) {
  524.                                 callback = filter;
  525.                             } else if (className == arrayClass) {
  526.                                 // Convert the property names array into a makeshift set.
  527.                                 properties = {};
  528.                                 for (var index = 0, length = filter.length, value; index < length; value = filter[index++], ((className = getClass.call(value)), className == stringClass || className == numberClass) && (properties[value] = 1));
  529.                             }
  530.                         }
  531.                         if (width) {
  532.                             if ((className = getClass.call(width)) == numberClass) {
  533.                                 // Convert the `width` to an integer and create a string containing
  534.                                 // `width` number of space characters.
  535.                                 if ((width -= width % 1) > 0) {
  536.                                     for (whitespace = "", width > 10 && (width = 10); whitespace.length < width; whitespace += " ");
  537.                                 }
  538.                             } else if (className == stringClass) {
  539.                                 whitespace = width.length <= 10 ? width : width.slice(0, 10);
  540.                             }
  541.                         }
  542.                         // Opera <= 7.54u2 discards the values associated with empty string keys
  543.                         // (`""`) only if they are used directly within an object member list
  544.                         // (e.g., `!("" in { "": 1})`).
  545.                         return serialize("", (value = {}, value[""] = source, value), callback, properties, whitespace, "", []);
  546.                     };
  547.                 }
  548.  
  549.                 // Public: Parses a JSON source string.
  550.                 if (!has("json-parse")) {
  551.                     var fromCharCode = String.fromCharCode;
  552.  
  553.                     // Internal: A map of escaped control characters and their unescaped
  554.                     // equivalents.
  555.                     var Unescapes = {
  556.                         92: "\\",
  557.                         34: '"',
  558.                         47: "/",
  559.                         98: "\b",
  560.                         116: "\t",
  561.                         110: "\n",
  562.                         102: "\f",
  563.                         114: "\r"
  564.                     };
  565.  
  566.                     // Internal: Stores the parser state.
  567.                     var Index, Source;
  568.  
  569.                     // Internal: Resets the parser state and throws a `SyntaxError`.
  570.                     var abort = function () {
  571.                         Index = Source = null;
  572.                         throw SyntaxError();
  573.                     };
  574.  
  575.                     // Internal: Returns the next token, or `"$"` if the parser has reached
  576.                     // the end of the source string. A token may be a string, number, `null`
  577.                     // literal, or Boolean literal.
  578.                     var lex = function () {
  579.                         var source = Source, length = source.length, value, begin, position, isSigned, charCode;
  580.                         while (Index < length) {
  581.                             charCode = source.charCodeAt(Index);
  582.                             switch (charCode) {
  583.                                 case 9: case 10: case 13: case 32:
  584.                                 // Skip whitespace tokens, including tabs, carriage returns, line
  585.                                 // feeds, and space characters.
  586.                                 Index++;
  587.                                 break;
  588.                                 case 123: case 125: case 91: case 93: case 58: case 44:
  589.                                 // Parse a punctuator token (`{`, `}`, `[`, `]`, `:`, or `,`) at
  590.                                 // the current position.
  591.                                 value = charIndexBuggy ? source.charAt(Index) : source[Index];
  592.                                 Index++;
  593.                                 return value;
  594.                                 case 34:
  595.                                     // `"` delimits a JSON string; advance to the next character and
  596.                                     // begin parsing the string. String tokens are prefixed with the
  597.                                     // sentinel `@` character to distinguish them from punctuators and
  598.                                     // end-of-string tokens.
  599.                                     for (value = "@", Index++; Index < length;) {
  600.                                         charCode = source.charCodeAt(Index);
  601.                                         if (charCode < 32) {
  602.                                             // Unescaped ASCII control characters (those with a code unit
  603.                                             // less than the space character) are not permitted.
  604.                                             abort();
  605.                                         } else if (charCode == 92) {
  606.                                             // A reverse solidus (`\`) marks the beginning of an escaped
  607.                                             // control character (including `"`, `\`, and `/`) or Unicode
  608.                                             // escape sequence.
  609.                                             charCode = source.charCodeAt(++Index);
  610.                                             switch (charCode) {
  611.                                                 case 92: case 34: case 47: case 98: case 116: case 110: case 102: case 114:
  612.                                                 // Revive escaped control characters.
  613.                                                 value += Unescapes[charCode];
  614.                                                 Index++;
  615.                                                 break;
  616.                                                 case 117:
  617.                                                     // `\u` marks the beginning of a Unicode escape sequence.
  618.                                                     // Advance to the first character and validate the
  619.                                                     // four-digit code point.
  620.                                                     begin = ++Index;
  621.                                                     for (position = Index + 4; Index < position; Index++) {
  622.                                                         charCode = source.charCodeAt(Index);
  623.                                                         // A valid sequence comprises four hexdigits (case-
  624.                                                         // insensitive) that form a single hexadecimal value.
  625.                                                         if (!(charCode >= 48 && charCode <= 57 || charCode >= 97 && charCode <= 102 || charCode >= 65 && charCode <= 70)) {
  626.                                                             // Invalid Unicode escape sequence.
  627.                                                             abort();
  628.                                                         }
  629.                                                     }
  630.                                                     // Revive the escaped character.
  631.                                                     value += fromCharCode("0x" + source.slice(begin, Index));
  632.                                                     break;
  633.                                                 default:
  634.                                                     // Invalid escape sequence.
  635.                                                     abort();
  636.                                             }
  637.                                         } else {
  638.                                             if (charCode == 34) {
  639.                                                 // An unescaped double-quote character marks the end of the
  640.                                                 // string.
  641.                                                 break;
  642.                                             }
  643.                                             charCode = source.charCodeAt(Index);
  644.                                             begin = Index;
  645.                                             // Optimize for the common case where a string is valid.
  646.                                             while (charCode >= 32 && charCode != 92 && charCode != 34) {
  647.                                                 charCode = source.charCodeAt(++Index);
  648.                                             }
  649.                                             // Append the string as-is.
  650.                                             value += source.slice(begin, Index);
  651.                                         }
  652.                                     }
  653.                                     if (source.charCodeAt(Index) == 34) {
  654.                                         // Advance to the next character and return the revived string.
  655.                                         Index++;
  656.                                         return value;
  657.                                     }
  658.                                     // Unterminated string.
  659.                                     abort();
  660.                                 default:
  661.                                     // Parse numbers and literals.
  662.                                     begin = Index;
  663.                                     // Advance past the negative sign, if one is specified.
  664.                                     if (charCode == 45) {
  665.                                         isSigned = true;
  666.                                         charCode = source.charCodeAt(++Index);
  667.                                     }
  668.                                     // Parse an integer or floating-point value.
  669.                                     if (charCode >= 48 && charCode <= 57) {
  670.                                         // Leading zeroes are interpreted as octal literals.
  671.                                         if (charCode == 48 && ((charCode = source.charCodeAt(Index + 1)), charCode >= 48 && charCode <= 57)) {
  672.                                             // Illegal octal literal.
  673.                                             abort();
  674.                                         }
  675.                                         isSigned = false;
  676.                                         // Parse the integer component.
  677.                                         for (; Index < length && ((charCode = source.charCodeAt(Index)), charCode >= 48 && charCode <= 57); Index++);
  678.                                         // Floats cannot contain a leading decimal point; however, this
  679.                                         // case is already accounted for by the parser.
  680.                                         if (source.charCodeAt(Index) == 46) {
  681.                                             position = ++Index;
  682.                                             // Parse the decimal component.
  683.                                             for (; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++);
  684.                                             if (position == Index) {
  685.                                                 // Illegal trailing decimal.
  686.                                                 abort();
  687.                                             }
  688.                                             Index = position;
  689.                                         }
  690.                                         // Parse exponents. The `e` denoting the exponent is
  691.                                         // case-insensitive.
  692.                                         charCode = source.charCodeAt(Index);
  693.                                         if (charCode == 101 || charCode == 69) {
  694.                                             charCode = source.charCodeAt(++Index);
  695.                                             // Skip past the sign following the exponent, if one is
  696.                                             // specified.
  697.                                             if (charCode == 43 || charCode == 45) {
  698.                                                 Index++;
  699.                                             }
  700.                                             // Parse the exponential component.
  701.                                             for (position = Index; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++);
  702.                                             if (position == Index) {
  703.                                                 // Illegal empty exponent.
  704.                                                 abort();
  705.                                             }
  706.                                             Index = position;
  707.                                         }
  708.                                         // Coerce the parsed value to a JavaScript number.
  709.                                         return +source.slice(begin, Index);
  710.                                     }
  711.                                     // A negative sign may only precede numbers.
  712.                                     if (isSigned) {
  713.                                         abort();
  714.                                     }
  715.                                     // `true`, `false`, and `null` literals.
  716.                                     if (source.slice(Index, Index + 4) == "true") {
  717.                                         Index += 4;
  718.                                         return true;
  719.                                     } else if (source.slice(Index, Index + 5) == "false") {
  720.                                         Index += 5;
  721.                                         return false;
  722.                                     } else if (source.slice(Index, Index + 4) == "null") {
  723.                                         Index += 4;
  724.                                         return null;
  725.                                     }
  726.                                     // Unrecognized token.
  727.                                     abort();
  728.                             }
  729.                         }
  730.                         // Return the sentinel `$` character if the parser has reached the end
  731.                         // of the source string.
  732.                         return "$";
  733.                     };
  734.  
  735.                     // Internal: Parses a JSON `value` token.
  736.                     var get = function (value) {
  737.                         var results, hasMembers;
  738.                         if (value == "$") {
  739.                             // Unexpected end of input.
  740.                             abort();
  741.                         }
  742.                         if (typeof value == "string") {
  743.                             if ((charIndexBuggy ? value.charAt(0) : value[0]) == "@") {
  744.                                 // Remove the sentinel `@` character.
  745.                                 return value.slice(1);
  746.                             }
  747.                             // Parse object and array literals.
  748.                             if (value == "[") {
  749.                                 // Parses a JSON array, returning a new JavaScript array.
  750.                                 results = [];
  751.                                 for (;; hasMembers || (hasMembers = true)) {
  752.                                     value = lex();
  753.                                     // A closing square bracket marks the end of the array literal.
  754.                                     if (value == "]") {
  755.                                         break;
  756.                                     }
  757.                                     // If the array literal contains elements, the current token
  758.                                     // should be a comma separating the previous element from the
  759.                                     // next.
  760.                                     if (hasMembers) {
  761.                                         if (value == ",") {
  762.                                             value = lex();
  763.                                             if (value == "]") {
  764.                                                 // Unexpected trailing `,` in array literal.
  765.                                                 abort();
  766.                                             }
  767.                                         } else {
  768.                                             // A `,` must separate each array element.
  769.                                             abort();
  770.                                         }
  771.                                     }
  772.                                     // Elisions and leading commas are not permitted.
  773.                                     if (value == ",") {
  774.                                         abort();
  775.                                     }
  776.                                     results.push(get(value));
  777.                                 }
  778.                                 return results;
  779.                             } else if (value == "{") {
  780.                                 // Parses a JSON object, returning a new JavaScript object.
  781.                                 results = {};
  782.                                 for (;; hasMembers || (hasMembers = true)) {
  783.                                     value = lex();
  784.                                     // A closing curly brace marks the end of the object literal.
  785.                                     if (value == "}") {
  786.                                         break;
  787.                                     }
  788.                                     // If the object literal contains members, the current token
  789.                                     // should be a comma separator.
  790.                                     if (hasMembers) {
  791.                                         if (value == ",") {
  792.                                             value = lex();
  793.                                             if (value == "}") {
  794.                                                 // Unexpected trailing `,` in object literal.
  795.                                                 abort();
  796.                                             }
  797.                                         } else {
  798.                                             // A `,` must separate each object member.
  799.                                             abort();
  800.                                         }
  801.                                     }
  802.                                     // Leading commas are not permitted, object property names must be
  803.                                     // double-quoted strings, and a `:` must separate each property
  804.                                     // name and value.
  805.                                     if (value == "," || typeof value != "string" || (charIndexBuggy ? value.charAt(0) : value[0]) != "@" || lex() != ":") {
  806.                                         abort();
  807.                                     }
  808.                                     results[value.slice(1)] = get(lex());
  809.                                 }
  810.                                 return results;
  811.                             }
  812.                             // Unexpected token encountered.
  813.                             abort();
  814.                         }
  815.                         return value;
  816.                     };
  817.  
  818.                     // Internal: Updates a traversed object member.
  819.                     var update = function (source, property, callback) {
  820.                         var element = walk(source, property, callback);
  821.                         if (element === undef) {
  822.                             delete source[property];
  823.                         } else {
  824.                             source[property] = element;
  825.                         }
  826.                     };
  827.  
  828.                     // Internal: Recursively traverses a parsed JSON object, invoking the
  829.                     // `callback` function for each value. This is an implementation of the
  830.                     // `Walk(holder, name)` operation defined in ES 5.1 section 15.12.2.
  831.                     var walk = function (source, property, callback) {
  832.                         var value = source[property], length;
  833.                         if (typeof value == "object" && value) {
  834.                             // `forEach` can't be used to traverse an array in Opera <= 8.54
  835.                             // because its `Object#hasOwnProperty` implementation returns `false`
  836.                             // for array indices (e.g., `![1, 2, 3].hasOwnProperty("0")`).
  837.                             if (getClass.call(value) == arrayClass) {
  838.                                 for (length = value.length; length--;) {
  839.                                     update(value, length, callback);
  840.                                 }
  841.                             } else {
  842.                                 forEach(value, function (property) {
  843.                                     update(value, property, callback);
  844.                                 });
  845.                             }
  846.                         }
  847.                         return callback.call(source, property, value);
  848.                     };
  849.  
  850.                     // Public: `JSON.parse`. See ES 5.1 section 15.12.2.
  851.                     exports.parse = function (source, callback) {
  852.                         var result, value;
  853.                         Index = 0;
  854.                         Source = "" + source;
  855.                         result = get(lex());
  856.                         // If a JSON string contains multiple tokens, it is invalid.
  857.                         if (lex() != "$") {
  858.                             abort();
  859.                         }
  860.                         // Reset the parser state.
  861.                         Index = Source = null;
  862.                         return callback && getClass.call(callback) == functionClass ? walk((value = {}, value[""] = result, value), "", callback) : result;
  863.                     };
  864.                 }
  865.             }
  866.  
  867.             exports["runInContext"] = runInContext;
  868.             return exports;
  869.         }
  870.  
  871.         if (freeExports && !isLoader) {
  872.             // Export for CommonJS environments.
  873.             runInContext(root, freeExports);
  874.         } else {
  875.             // Export for web browsers and JavaScript engines.
  876.             var nativeJSON = root.JSON,
  877.                 previousJSON = root["JSON3"],
  878.                 isRestored = false;
  879.  
  880.             var JSON3 = runInContext(root, (root["JSON3"] = {
  881.                 // Public: Restores the original value of the global `JSON` object and
  882.                 // returns a reference to the `JSON3` object.
  883.                 "noConflict": function () {
  884.                     if (!isRestored) {
  885.                         isRestored = true;
  886.                         root.JSON = nativeJSON;
  887.                         root["JSON3"] = previousJSON;
  888.                         nativeJSON = previousJSON = null;
  889.                     }
  890.                     return JSON3;
  891.                 }
  892.             }));
  893.  
  894.             root.JSON = {
  895.                 "parse": JSON3.parse,
  896.                 "stringify": JSON3.stringify
  897.             };
  898.         }
  899.  
  900.         // Export for asynchronous module loaders.
  901.         if (isLoader) {
  902.             define(function () {
  903.                 return JSON3;
  904.             });
  905.         }
  906.     }).call(this);
  907. /************************************************************
  908.  * end JSON
  909.  ************************************************************/
  910. if (typeof JSON_WSM == 'undefined'){
  911.     JSON_WSM = exports;
  912. }
  913. })();

Raw Paste


Login or Register to edit or fork this paste. It's free.