source: trip-planner-front/node_modules/json3/lib/json3.js@ fa375fe

Last change on this file since fa375fe was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

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