mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-01-29 06:27:49 +00:00
Inflate dev test dependencies for easier inspection and swap firebug-lite with its debug build for Opera support.
Former-commit-id: 2f9ee3e33384b5ef5ed3da9c9ad5bbe7b561d265
This commit is contained in:
31176
vendor/firebug-lite/src/firebug-lite-debug.js
vendored
Normal file
31176
vendor/firebug-lite/src/firebug-lite-debug.js
vendored
Normal file
File diff suppressed because one or more lines are too long
8257
vendor/firebug-lite/src/firebug-lite.js
vendored
8257
vendor/firebug-lite/src/firebug-lite.js
vendored
File diff suppressed because one or more lines are too long
9440
vendor/jquery/jquery.js
vendored
Normal file
9440
vendor/jquery/jquery.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
vendor/jquery/jquery.min.js
vendored
2
vendor/jquery/jquery.min.js
vendored
File diff suppressed because one or more lines are too long
783
vendor/json3/lib/json3.js
vendored
Normal file
783
vendor/json3/lib/json3.js
vendored
Normal file
@@ -0,0 +1,783 @@
|
||||
/*! JSON v3.2.4 | http://bestiejs.github.com/json3 | Copyright 2012, Kit Cambridge | http://kit.mit-license.org */
|
||||
;(function () {
|
||||
// Convenience aliases.
|
||||
var getClass = {}.toString, isProperty, forEach, undef;
|
||||
|
||||
// Detect the `define` function exposed by asynchronous module loaders. The
|
||||
// strict `define` check is necessary for compatibility with `r.js`.
|
||||
var isLoader = typeof define === "function" && define.amd, JSON3 = !isLoader && typeof exports == "object" && exports;
|
||||
|
||||
if (JSON3 || isLoader) {
|
||||
if (typeof JSON == "object" && JSON) {
|
||||
// Delegate to the native `stringify` and `parse` implementations in
|
||||
// asynchronous module loaders and CommonJS environments.
|
||||
if (isLoader) {
|
||||
JSON3 = JSON;
|
||||
} else {
|
||||
JSON3.stringify = JSON.stringify;
|
||||
JSON3.parse = JSON.parse;
|
||||
}
|
||||
} else if (isLoader) {
|
||||
JSON3 = this.JSON = {};
|
||||
}
|
||||
} else {
|
||||
// Export for web browsers and JavaScript engines.
|
||||
JSON3 = this.JSON || (this.JSON = {});
|
||||
}
|
||||
|
||||
// Local variables.
|
||||
var Escapes, toPaddedString, quote, serialize;
|
||||
var fromCharCode, Unescapes, abort, lex, get, walk, update, Index, Source;
|
||||
|
||||
// Test the `Date#getUTC*` methods. Based on work by @Yaffle.
|
||||
var isExtended = new Date(-3509827334573292), floor, Months, getDay;
|
||||
|
||||
try {
|
||||
// The `getUTCFullYear`, `Month`, and `Date` methods return nonsensical
|
||||
// results for certain dates in Opera >= 10.53.
|
||||
isExtended = isExtended.getUTCFullYear() == -109252 && isExtended.getUTCMonth() === 0 && isExtended.getUTCDate() == 1 &&
|
||||
// Safari < 2.0.2 stores the internal millisecond time value correctly,
|
||||
// but clips the values returned by the date methods to the range of
|
||||
// signed 32-bit integers ([-2 ** 31, 2 ** 31 - 1]).
|
||||
isExtended.getUTCHours() == 10 && isExtended.getUTCMinutes() == 37 && isExtended.getUTCSeconds() == 6 && isExtended.getUTCMilliseconds() == 708;
|
||||
} catch (exception) {}
|
||||
|
||||
// Internal: Determines whether the native `JSON.stringify` and `parse`
|
||||
// implementations are spec-compliant. Based on work by Ken Snyder.
|
||||
function has(name) {
|
||||
var stringifySupported, parseSupported, value, serialized = '{"A":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}', all = name == "json";
|
||||
if (all || name == "json-stringify" || name == "json-parse") {
|
||||
// Test `JSON.stringify`.
|
||||
if (name == "json-stringify" || all) {
|
||||
if ((stringifySupported = typeof JSON3.stringify == "function" && isExtended)) {
|
||||
// A test function object with a custom `toJSON` method.
|
||||
(value = function () {
|
||||
return 1;
|
||||
}).toJSON = value;
|
||||
try {
|
||||
stringifySupported =
|
||||
// Firefox 3.1b1 and b2 serialize string, number, and boolean
|
||||
// primitives as object literals.
|
||||
JSON3.stringify(0) === "0" &&
|
||||
// FF 3.1b1, b2, and JSON 2 serialize wrapped primitives as object
|
||||
// literals.
|
||||
JSON3.stringify(new Number()) === "0" &&
|
||||
JSON3.stringify(new String()) == '""' &&
|
||||
// FF 3.1b1, 2 throw an error if the value is `null`, `undefined`, or
|
||||
// does not define a canonical JSON representation (this applies to
|
||||
// objects with `toJSON` properties as well, *unless* they are nested
|
||||
// within an object or array).
|
||||
JSON3.stringify(getClass) === undef &&
|
||||
// IE 8 serializes `undefined` as `"undefined"`. Safari <= 5.1.7 and
|
||||
// FF 3.1b3 pass this test.
|
||||
JSON3.stringify(undef) === undef &&
|
||||
// Safari <= 5.1.7 and FF 3.1b3 throw `Error`s and `TypeError`s,
|
||||
// respectively, if the value is omitted entirely.
|
||||
JSON3.stringify() === undef &&
|
||||
// FF 3.1b1, 2 throw an error if the given value is not a number,
|
||||
// string, array, object, Boolean, or `null` literal. This applies to
|
||||
// objects with custom `toJSON` methods as well, unless they are nested
|
||||
// inside object or array literals. YUI 3.0.0b1 ignores custom `toJSON`
|
||||
// methods entirely.
|
||||
JSON3.stringify(value) === "1" &&
|
||||
JSON3.stringify([value]) == "[1]" &&
|
||||
// Prototype <= 1.6.1 serializes `[undefined]` as `"[]"` instead of
|
||||
// `"[null]"`.
|
||||
JSON3.stringify([undef]) == "[null]" &&
|
||||
// YUI 3.0.0b1 fails to serialize `null` literals.
|
||||
JSON3.stringify(null) == "null" &&
|
||||
// FF 3.1b1, 2 halts serialization if an array contains a function:
|
||||
// `[1, true, getClass, 1]` serializes as "[1,true,],". These versions
|
||||
// of Firefox also allow trailing commas in JSON objects and arrays.
|
||||
// FF 3.1b3 elides non-JSON values from objects and arrays, unless they
|
||||
// define custom `toJSON` methods.
|
||||
JSON3.stringify([undef, getClass, null]) == "[null,null,null]" &&
|
||||
// Simple serialization test. FF 3.1b1 uses Unicode escape sequences
|
||||
// where character escape codes are expected (e.g., `\b` => `\u0008`).
|
||||
JSON3.stringify({ "A": [value, true, false, null, "\0\b\n\f\r\t"] }) == serialized &&
|
||||
// FF 3.1b1 and b2 ignore the `filter` and `width` arguments.
|
||||
JSON3.stringify(null, value) === "1" &&
|
||||
JSON3.stringify([1, 2], null, 1) == "[\n 1,\n 2\n]" &&
|
||||
// JSON 2, Prototype <= 1.7, and older WebKit builds incorrectly
|
||||
// serialize extended years.
|
||||
JSON3.stringify(new Date(-8.64e15)) == '"-271821-04-20T00:00:00.000Z"' &&
|
||||
// The milliseconds are optional in ES 5, but required in 5.1.
|
||||
JSON3.stringify(new Date(8.64e15)) == '"+275760-09-13T00:00:00.000Z"' &&
|
||||
// Firefox <= 11.0 incorrectly serializes years prior to 0 as negative
|
||||
// four-digit years instead of six-digit years. Credits: @Yaffle.
|
||||
JSON3.stringify(new Date(-621987552e5)) == '"-000001-01-01T00:00:00.000Z"' &&
|
||||
// Safari <= 5.1.5 and Opera >= 10.53 incorrectly serialize millisecond
|
||||
// values less than 1000. Credits: @Yaffle.
|
||||
JSON3.stringify(new Date(-1)) == '"1969-12-31T23:59:59.999Z"';
|
||||
} catch (exception) {
|
||||
stringifySupported = false;
|
||||
}
|
||||
}
|
||||
if (!all) {
|
||||
return stringifySupported;
|
||||
}
|
||||
}
|
||||
// Test `JSON.parse`.
|
||||
if (name == "json-parse" || all) {
|
||||
if (typeof JSON3.parse == "function") {
|
||||
try {
|
||||
// FF 3.1b1, b2 will throw an exception if a bare literal is provided.
|
||||
// Conforming implementations should also coerce the initial argument to
|
||||
// a string prior to parsing.
|
||||
if (JSON3.parse("0") === 0 && !JSON3.parse(false)) {
|
||||
// Simple parsing test.
|
||||
value = JSON3.parse(serialized);
|
||||
if ((parseSupported = value.A.length == 5 && value.A[0] == 1)) {
|
||||
try {
|
||||
// Safari <= 5.1.2 and FF 3.1b1 allow unescaped tabs in strings.
|
||||
parseSupported = !JSON3.parse('"\t"');
|
||||
} catch (exception) {}
|
||||
if (parseSupported) {
|
||||
try {
|
||||
// FF 4.0 and 4.0.1 allow leading `+` signs, and leading and
|
||||
// trailing decimal points. FF 4.0, 4.0.1, and IE 9-10 also
|
||||
// allow certain octal literals.
|
||||
parseSupported = JSON3.parse("01") != 1;
|
||||
} catch (exception) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (exception) {
|
||||
parseSupported = false;
|
||||
}
|
||||
}
|
||||
if (!all) {
|
||||
return parseSupported;
|
||||
}
|
||||
}
|
||||
return stringifySupported && parseSupported;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has("json")) {
|
||||
// Define additional utility methods if the `Date` methods are buggy.
|
||||
if (!isExtended) {
|
||||
floor = Math.floor;
|
||||
// A mapping between the months of the year and the number of days between
|
||||
// January 1st and the first of the respective month.
|
||||
Months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
|
||||
// Internal: Calculates the number of days between the Unix epoch and the
|
||||
// first day of the given month.
|
||||
getDay = function (year, month) {
|
||||
return Months[month] + 365 * (year - 1970) + floor((year - 1969 + (month = +(month > 1))) / 4) - floor((year - 1901 + month) / 100) + floor((year - 1601 + month) / 400);
|
||||
};
|
||||
}
|
||||
|
||||
// Internal: Determines if a property is a direct property of the given
|
||||
// object. Delegates to the native `Object#hasOwnProperty` method.
|
||||
if (!(isProperty = {}.hasOwnProperty)) {
|
||||
isProperty = function (property) {
|
||||
var members = {}, constructor;
|
||||
if ((members.__proto__ = null, members.__proto__ = {
|
||||
// The *proto* property cannot be set multiple times in recent
|
||||
// versions of Firefox and SeaMonkey.
|
||||
"toString": 1
|
||||
}, members).toString != getClass) {
|
||||
// Safari <= 2.0.3 doesn't implement `Object#hasOwnProperty`, but
|
||||
// supports the mutable *proto* property.
|
||||
isProperty = function (property) {
|
||||
// Capture and break the object's prototype chain (see section 8.6.2
|
||||
// of the ES 5.1 spec). The parenthesized expression prevents an
|
||||
// unsafe transformation by the Closure Compiler.
|
||||
var original = this.__proto__, result = property in (this.__proto__ = null, this);
|
||||
// Restore the original prototype chain.
|
||||
this.__proto__ = original;
|
||||
return result;
|
||||
};
|
||||
} else {
|
||||
// Capture a reference to the top-level `Object` constructor.
|
||||
constructor = members.constructor;
|
||||
// Use the `constructor` property to simulate `Object#hasOwnProperty` in
|
||||
// other environments.
|
||||
isProperty = function (property) {
|
||||
var parent = (this.constructor || constructor).prototype;
|
||||
return property in this && !(property in parent && this[property] === parent[property]);
|
||||
};
|
||||
}
|
||||
members = null;
|
||||
return isProperty.call(this, property);
|
||||
};
|
||||
}
|
||||
|
||||
// Internal: Normalizes the `for...in` iteration algorithm across
|
||||
// environments. Each enumerated key is yielded to a `callback` function.
|
||||
forEach = function (object, callback) {
|
||||
var size = 0, Properties, members, property, forEach;
|
||||
|
||||
// Tests for bugs in the current environment's `for...in` algorithm. The
|
||||
// `valueOf` property inherits the non-enumerable flag from
|
||||
// `Object.prototype` in older versions of IE, Netscape, and Mozilla.
|
||||
(Properties = function () {
|
||||
this.valueOf = 0;
|
||||
}).prototype.valueOf = 0;
|
||||
|
||||
// Iterate over a new instance of the `Properties` class.
|
||||
members = new Properties();
|
||||
for (property in members) {
|
||||
// Ignore all properties inherited from `Object.prototype`.
|
||||
if (isProperty.call(members, property)) {
|
||||
size++;
|
||||
}
|
||||
}
|
||||
Properties = members = null;
|
||||
|
||||
// Normalize the iteration algorithm.
|
||||
if (!size) {
|
||||
// A list of non-enumerable properties inherited from `Object.prototype`.
|
||||
members = ["valueOf", "toString", "toLocaleString", "propertyIsEnumerable", "isPrototypeOf", "hasOwnProperty", "constructor"];
|
||||
// IE <= 8, Mozilla 1.0, and Netscape 6.2 ignore shadowed non-enumerable
|
||||
// properties.
|
||||
forEach = function (object, callback) {
|
||||
var isFunction = getClass.call(object) == "[object Function]", property, length;
|
||||
for (property in object) {
|
||||
// Gecko <= 1.0 enumerates the `prototype` property of functions under
|
||||
// certain conditions; IE does not.
|
||||
if (!(isFunction && property == "prototype") && isProperty.call(object, property)) {
|
||||
callback(property);
|
||||
}
|
||||
}
|
||||
// Manually invoke the callback for each non-enumerable property.
|
||||
for (length = members.length; property = members[--length]; isProperty.call(object, property) && callback(property));
|
||||
};
|
||||
} else if (size == 2) {
|
||||
// Safari <= 2.0.4 enumerates shadowed properties twice.
|
||||
forEach = function (object, callback) {
|
||||
// Create a set of iterated properties.
|
||||
var members = {}, isFunction = getClass.call(object) == "[object Function]", property;
|
||||
for (property in object) {
|
||||
// Store each property name to prevent double enumeration. The
|
||||
// `prototype` property of functions is not enumerated due to cross-
|
||||
// environment inconsistencies.
|
||||
if (!(isFunction && property == "prototype") && !isProperty.call(members, property) && (members[property] = 1) && isProperty.call(object, property)) {
|
||||
callback(property);
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
// No bugs detected; use the standard `for...in` algorithm.
|
||||
forEach = function (object, callback) {
|
||||
var isFunction = getClass.call(object) == "[object Function]", property, isConstructor;
|
||||
for (property in object) {
|
||||
if (!(isFunction && property == "prototype") && isProperty.call(object, property) && !(isConstructor = property === "constructor")) {
|
||||
callback(property);
|
||||
}
|
||||
}
|
||||
// Manually invoke the callback for the `constructor` property due to
|
||||
// cross-environment inconsistencies.
|
||||
if (isConstructor || isProperty.call(object, (property = "constructor"))) {
|
||||
callback(property);
|
||||
}
|
||||
};
|
||||
}
|
||||
return forEach(object, callback);
|
||||
};
|
||||
|
||||
// Public: Serializes a JavaScript `value` as a JSON string. The optional
|
||||
// `filter` argument may specify either a function that alters how object and
|
||||
// array members are serialized, or an array of strings and numbers that
|
||||
// indicates which properties should be serialized. The optional `width`
|
||||
// argument may be either a string or number that specifies the indentation
|
||||
// level of the output.
|
||||
if (!has("json-stringify")) {
|
||||
// Internal: A map of control characters and their escaped equivalents.
|
||||
Escapes = {
|
||||
"\\": "\\\\",
|
||||
'"': '\\"',
|
||||
"\b": "\\b",
|
||||
"\f": "\\f",
|
||||
"\n": "\\n",
|
||||
"\r": "\\r",
|
||||
"\t": "\\t"
|
||||
};
|
||||
|
||||
// Internal: Converts `value` into a zero-padded string such that its
|
||||
// length is at least equal to `width`. The `width` must be <= 6.
|
||||
toPaddedString = function (width, value) {
|
||||
// The `|| 0` expression is necessary to work around a bug in
|
||||
// Opera <= 7.54u2 where `0 == -0`, but `String(-0) !== "0"`.
|
||||
return ("000000" + (value || 0)).slice(-width);
|
||||
};
|
||||
|
||||
// Internal: Double-quotes a string `value`, replacing all ASCII control
|
||||
// characters (characters with code unit values between 0 and 31) with
|
||||
// their escaped equivalents. This is an implementation of the
|
||||
// `Quote(value)` operation defined in ES 5.1 section 15.12.3.
|
||||
quote = function (value) {
|
||||
var result = '"', index = 0, symbol;
|
||||
for (; symbol = value.charAt(index); index++) {
|
||||
// Escape the reverse solidus, double quote, backspace, form feed, line
|
||||
// feed, carriage return, and tab characters.
|
||||
result += '\\"\b\f\n\r\t'.indexOf(symbol) > -1 ? Escapes[symbol] :
|
||||
// If the character is a control character, append its Unicode escape
|
||||
// sequence; otherwise, append the character as-is.
|
||||
(Escapes[symbol] = symbol < " " ? "\\u00" + toPaddedString(2, symbol.charCodeAt(0).toString(16)) : symbol);
|
||||
}
|
||||
return result + '"';
|
||||
};
|
||||
|
||||
// Internal: Recursively serializes an object. Implements the
|
||||
// `Str(key, holder)`, `JO(value)`, and `JA(value)` operations.
|
||||
serialize = function (property, object, callback, properties, whitespace, indentation, stack) {
|
||||
var value = object[property], className, year, month, date, time, hours, minutes, seconds, milliseconds, results, element, index, length, prefix, any, result;
|
||||
if (typeof value == "object" && value) {
|
||||
className = getClass.call(value);
|
||||
if (className == "[object Date]" && !isProperty.call(value, "toJSON")) {
|
||||
if (value > -1 / 0 && value < 1 / 0) {
|
||||
// Dates are serialized according to the `Date#toJSON` method
|
||||
// specified in ES 5.1 section 15.9.5.44. See section 15.9.1.15
|
||||
// for the ISO 8601 date time string format.
|
||||
if (getDay) {
|
||||
// Manually compute the year, month, date, hours, minutes,
|
||||
// seconds, and milliseconds if the `getUTC*` methods are
|
||||
// buggy. Adapted from @Yaffle's `date-shim` project.
|
||||
date = floor(value / 864e5);
|
||||
for (year = floor(date / 365.2425) + 1970 - 1; getDay(year + 1, 0) <= date; year++);
|
||||
for (month = floor((date - getDay(year, 0)) / 30.42); getDay(year, month + 1) <= date; month++);
|
||||
date = 1 + date - getDay(year, month);
|
||||
// The `time` value specifies the time within the day (see ES
|
||||
// 5.1 section 15.9.1.2). The formula `(A % B + B) % B` is used
|
||||
// to compute `A modulo B`, as the `%` operator does not
|
||||
// correspond to the `modulo` operation for negative numbers.
|
||||
time = (value % 864e5 + 864e5) % 864e5;
|
||||
// The hours, minutes, seconds, and milliseconds are obtained by
|
||||
// decomposing the time within the day. See section 15.9.1.10.
|
||||
hours = floor(time / 36e5) % 24;
|
||||
minutes = floor(time / 6e4) % 60;
|
||||
seconds = floor(time / 1e3) % 60;
|
||||
milliseconds = time % 1e3;
|
||||
} else {
|
||||
year = value.getUTCFullYear();
|
||||
month = value.getUTCMonth();
|
||||
date = value.getUTCDate();
|
||||
hours = value.getUTCHours();
|
||||
minutes = value.getUTCMinutes();
|
||||
seconds = value.getUTCSeconds();
|
||||
milliseconds = value.getUTCMilliseconds();
|
||||
}
|
||||
// Serialize extended years correctly.
|
||||
value = (year <= 0 || year >= 1e4 ? (year < 0 ? "-" : "+") + toPaddedString(6, year < 0 ? -year : year) : toPaddedString(4, year)) +
|
||||
"-" + toPaddedString(2, month + 1) + "-" + toPaddedString(2, date) +
|
||||
// Months, dates, hours, minutes, and seconds should have two
|
||||
// digits; milliseconds should have three.
|
||||
"T" + toPaddedString(2, hours) + ":" + toPaddedString(2, minutes) + ":" + toPaddedString(2, seconds) +
|
||||
// Milliseconds are optional in ES 5.0, but required in 5.1.
|
||||
"." + toPaddedString(3, milliseconds) + "Z";
|
||||
} else {
|
||||
value = null;
|
||||
}
|
||||
} else if (typeof value.toJSON == "function" && ((className != "[object Number]" && className != "[object String]" && className != "[object Array]") || isProperty.call(value, "toJSON"))) {
|
||||
// Prototype <= 1.6.1 adds non-standard `toJSON` methods to the
|
||||
// `Number`, `String`, `Date`, and `Array` prototypes. JSON 3
|
||||
// ignores all `toJSON` methods on these objects unless they are
|
||||
// defined directly on an instance.
|
||||
value = value.toJSON(property);
|
||||
}
|
||||
}
|
||||
if (callback) {
|
||||
// If a replacement function was provided, call it to obtain the value
|
||||
// for serialization.
|
||||
value = callback.call(object, property, value);
|
||||
}
|
||||
if (value === null) {
|
||||
return "null";
|
||||
}
|
||||
className = getClass.call(value);
|
||||
if (className == "[object Boolean]") {
|
||||
// Booleans are represented literally.
|
||||
return "" + value;
|
||||
} else if (className == "[object Number]") {
|
||||
// JSON numbers must be finite. `Infinity` and `NaN` are serialized as
|
||||
// `"null"`.
|
||||
return value > -1 / 0 && value < 1 / 0 ? "" + value : "null";
|
||||
} else if (className == "[object String]") {
|
||||
// Strings are double-quoted and escaped.
|
||||
return quote(value);
|
||||
}
|
||||
// Recursively serialize objects and arrays.
|
||||
if (typeof value == "object") {
|
||||
// Check for cyclic structures. This is a linear search; performance
|
||||
// is inversely proportional to the number of unique nested objects.
|
||||
for (length = stack.length; length--;) {
|
||||
if (stack[length] === value) {
|
||||
// Cyclic structures cannot be serialized by `JSON.stringify`.
|
||||
throw TypeError();
|
||||
}
|
||||
}
|
||||
// Add the object to the stack of traversed objects.
|
||||
stack.push(value);
|
||||
results = [];
|
||||
// Save the current indentation level and indent one additional level.
|
||||
prefix = indentation;
|
||||
indentation += whitespace;
|
||||
if (className == "[object Array]") {
|
||||
// Recursively serialize array elements.
|
||||
for (index = 0, length = value.length; index < length; any || (any = true), index++) {
|
||||
element = serialize(index, value, callback, properties, whitespace, indentation, stack);
|
||||
results.push(element === undef ? "null" : element);
|
||||
}
|
||||
result = any ? (whitespace ? "[\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "]" : ("[" + results.join(",") + "]")) : "[]";
|
||||
} else {
|
||||
// Recursively serialize object members. Members are selected from
|
||||
// either a user-specified list of property names, or the object
|
||||
// itself.
|
||||
forEach(properties || value, function (property) {
|
||||
var element = serialize(property, value, callback, properties, whitespace, indentation, stack);
|
||||
if (element !== undef) {
|
||||
// According to ES 5.1 section 15.12.3: "If `gap` {whitespace}
|
||||
// is not the empty string, let `member` {quote(property) + ":"}
|
||||
// be the concatenation of `member` and the `space` character."
|
||||
// The "`space` character" refers to the literal space
|
||||
// character, not the `space` {width} argument provided to
|
||||
// `JSON.stringify`.
|
||||
results.push(quote(property) + ":" + (whitespace ? " " : "") + element);
|
||||
}
|
||||
any || (any = true);
|
||||
});
|
||||
result = any ? (whitespace ? "{\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "}" : ("{" + results.join(",") + "}")) : "{}";
|
||||
}
|
||||
// Remove the object from the traversed object stack.
|
||||
stack.pop();
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// Public: `JSON.stringify`. See ES 5.1 section 15.12.3.
|
||||
JSON3.stringify = function (source, filter, width) {
|
||||
var whitespace, callback, properties, index, length, value;
|
||||
if (typeof filter == "function" || typeof filter == "object" && filter) {
|
||||
if (getClass.call(filter) == "[object Function]") {
|
||||
callback = filter;
|
||||
} else if (getClass.call(filter) == "[object Array]") {
|
||||
// Convert the property names array into a makeshift set.
|
||||
properties = {};
|
||||
for (index = 0, length = filter.length; index < length; value = filter[index++], ((getClass.call(value) == "[object String]" || getClass.call(value) == "[object Number]") && (properties[value] = 1)));
|
||||
}
|
||||
}
|
||||
if (width) {
|
||||
if (getClass.call(width) == "[object Number]") {
|
||||
// Convert the `width` to an integer and create a string containing
|
||||
// `width` number of space characters.
|
||||
if ((width -= width % 1) > 0) {
|
||||
for (whitespace = "", width > 10 && (width = 10); whitespace.length < width; whitespace += " ");
|
||||
}
|
||||
} else if (getClass.call(width) == "[object String]") {
|
||||
whitespace = width.length <= 10 ? width : width.slice(0, 10);
|
||||
}
|
||||
}
|
||||
// Opera <= 7.54u2 discards the values associated with empty string keys
|
||||
// (`""`) only if they are used directly within an object member list
|
||||
// (e.g., `!("" in { "": 1})`).
|
||||
return serialize("", (value = {}, value[""] = source, value), callback, properties, whitespace, "", []);
|
||||
};
|
||||
}
|
||||
|
||||
// Public: Parses a JSON source string.
|
||||
if (!has("json-parse")) {
|
||||
fromCharCode = String.fromCharCode;
|
||||
// Internal: A map of escaped control characters and their unescaped
|
||||
// equivalents.
|
||||
Unescapes = {
|
||||
"\\": "\\",
|
||||
'"': '"',
|
||||
"/": "/",
|
||||
"b": "\b",
|
||||
"t": "\t",
|
||||
"n": "\n",
|
||||
"f": "\f",
|
||||
"r": "\r"
|
||||
};
|
||||
|
||||
// Internal: Resets the parser state and throws a `SyntaxError`.
|
||||
abort = function() {
|
||||
Index = Source = null;
|
||||
throw SyntaxError();
|
||||
};
|
||||
|
||||
// Internal: Returns the next token, or `"$"` if the parser has reached
|
||||
// the end of the source string. A token may be a string, number, `null`
|
||||
// literal, or Boolean literal.
|
||||
lex = function () {
|
||||
var source = Source, length = source.length, symbol, value, begin, position, sign;
|
||||
while (Index < length) {
|
||||
symbol = source.charAt(Index);
|
||||
if ("\t\r\n ".indexOf(symbol) > -1) {
|
||||
// Skip whitespace tokens, including tabs, carriage returns, line
|
||||
// feeds, and space characters.
|
||||
Index++;
|
||||
} else if ("{}[]:,".indexOf(symbol) > -1) {
|
||||
// Parse a punctuator token at the current position.
|
||||
Index++;
|
||||
return symbol;
|
||||
} else if (symbol == '"') {
|
||||
// Advance to the next character and parse a JSON string at the
|
||||
// current position. String tokens are prefixed with the sentinel
|
||||
// `@` character to distinguish them from punctuators.
|
||||
for (value = "@", Index++; Index < length;) {
|
||||
symbol = source.charAt(Index);
|
||||
if (symbol < " ") {
|
||||
// Unescaped ASCII control characters are not permitted.
|
||||
abort();
|
||||
} else if (symbol == "\\") {
|
||||
// Parse escaped JSON control characters, `"`, `\`, `/`, and
|
||||
// Unicode escape sequences.
|
||||
symbol = source.charAt(++Index);
|
||||
if ('\\"/btnfr'.indexOf(symbol) > -1) {
|
||||
// Revive escaped control characters.
|
||||
value += Unescapes[symbol];
|
||||
Index++;
|
||||
} else if (symbol == "u") {
|
||||
// Advance to the first character of the escape sequence.
|
||||
begin = ++Index;
|
||||
// Validate the Unicode escape sequence.
|
||||
for (position = Index + 4; Index < position; Index++) {
|
||||
symbol = source.charAt(Index);
|
||||
// A valid sequence comprises four hexdigits that form a
|
||||
// single hexadecimal value.
|
||||
if (!(symbol >= "0" && symbol <= "9" || symbol >= "a" && symbol <= "f" || symbol >= "A" && symbol <= "F")) {
|
||||
// Invalid Unicode escape sequence.
|
||||
abort();
|
||||
}
|
||||
}
|
||||
// Revive the escaped character.
|
||||
value += fromCharCode("0x" + source.slice(begin, Index));
|
||||
} else {
|
||||
// Invalid escape sequence.
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
if (symbol == '"') {
|
||||
// An unescaped double-quote character marks the end of the
|
||||
// string.
|
||||
break;
|
||||
}
|
||||
// Append the original character as-is.
|
||||
value += symbol;
|
||||
Index++;
|
||||
}
|
||||
}
|
||||
if (source.charAt(Index) == '"') {
|
||||
Index++;
|
||||
// Return the revived string.
|
||||
return value;
|
||||
}
|
||||
// Unterminated string.
|
||||
abort();
|
||||
} else {
|
||||
// Parse numbers and literals.
|
||||
begin = Index;
|
||||
// Advance the scanner's position past the sign, if one is
|
||||
// specified.
|
||||
if (symbol == "-") {
|
||||
sign = true;
|
||||
symbol = source.charAt(++Index);
|
||||
}
|
||||
// Parse an integer or floating-point value.
|
||||
if (symbol >= "0" && symbol <= "9") {
|
||||
// Leading zeroes are interpreted as octal literals.
|
||||
if (symbol == "0" && (symbol = source.charAt(Index + 1), symbol >= "0" && symbol <= "9")) {
|
||||
// Illegal octal literal.
|
||||
abort();
|
||||
}
|
||||
sign = false;
|
||||
// Parse the integer component.
|
||||
for (; Index < length && (symbol = source.charAt(Index), symbol >= "0" && symbol <= "9"); Index++);
|
||||
// Floats cannot contain a leading decimal point; however, this
|
||||
// case is already accounted for by the parser.
|
||||
if (source.charAt(Index) == ".") {
|
||||
position = ++Index;
|
||||
// Parse the decimal component.
|
||||
for (; position < length && (symbol = source.charAt(position), symbol >= "0" && symbol <= "9"); position++);
|
||||
if (position == Index) {
|
||||
// Illegal trailing decimal.
|
||||
abort();
|
||||
}
|
||||
Index = position;
|
||||
}
|
||||
// Parse exponents.
|
||||
symbol = source.charAt(Index);
|
||||
if (symbol == "e" || symbol == "E") {
|
||||
// Skip past the sign following the exponent, if one is
|
||||
// specified.
|
||||
symbol = source.charAt(++Index);
|
||||
if (symbol == "+" || symbol == "-") {
|
||||
Index++;
|
||||
}
|
||||
// Parse the exponential component.
|
||||
for (position = Index; position < length && (symbol = source.charAt(position), symbol >= "0" && symbol <= "9"); position++);
|
||||
if (position == Index) {
|
||||
// Illegal empty exponent.
|
||||
abort();
|
||||
}
|
||||
Index = position;
|
||||
}
|
||||
// Coerce the parsed value to a JavaScript number.
|
||||
return +source.slice(begin, Index);
|
||||
}
|
||||
// A negative sign may only precede numbers.
|
||||
if (sign) {
|
||||
abort();
|
||||
}
|
||||
// `true`, `false`, and `null` literals.
|
||||
if (source.slice(Index, Index + 4) == "true") {
|
||||
Index += 4;
|
||||
return true;
|
||||
} else if (source.slice(Index, Index + 5) == "false") {
|
||||
Index += 5;
|
||||
return false;
|
||||
} else if (source.slice(Index, Index + 4) == "null") {
|
||||
Index += 4;
|
||||
return null;
|
||||
}
|
||||
// Unrecognized token.
|
||||
abort();
|
||||
}
|
||||
}
|
||||
// Return the sentinel `$` character if the parser has reached the end
|
||||
// of the source string.
|
||||
return "$";
|
||||
};
|
||||
|
||||
// Internal: Parses a JSON `value` token.
|
||||
get = function (value) {
|
||||
var results, any, key;
|
||||
if (value == "$") {
|
||||
// Unexpected end of input.
|
||||
abort();
|
||||
}
|
||||
if (typeof value == "string") {
|
||||
if (value.charAt(0) == "@") {
|
||||
// Remove the sentinel `@` character.
|
||||
return value.slice(1);
|
||||
}
|
||||
// Parse object and array literals.
|
||||
if (value == "[") {
|
||||
// Parses a JSON array, returning a new JavaScript array.
|
||||
results = [];
|
||||
for (;; any || (any = true)) {
|
||||
value = lex();
|
||||
// A closing square bracket marks the end of the array literal.
|
||||
if (value == "]") {
|
||||
break;
|
||||
}
|
||||
// If the array literal contains elements, the current token
|
||||
// should be a comma separating the previous element from the
|
||||
// next.
|
||||
if (any) {
|
||||
if (value == ",") {
|
||||
value = lex();
|
||||
if (value == "]") {
|
||||
// Unexpected trailing `,` in array literal.
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
// A `,` must separate each array element.
|
||||
abort();
|
||||
}
|
||||
}
|
||||
// Elisions and leading commas are not permitted.
|
||||
if (value == ",") {
|
||||
abort();
|
||||
}
|
||||
results.push(get(value));
|
||||
}
|
||||
return results;
|
||||
} else if (value == "{") {
|
||||
// Parses a JSON object, returning a new JavaScript object.
|
||||
results = {};
|
||||
for (;; any || (any = true)) {
|
||||
value = lex();
|
||||
// A closing curly brace marks the end of the object literal.
|
||||
if (value == "}") {
|
||||
break;
|
||||
}
|
||||
// If the object literal contains members, the current token
|
||||
// should be a comma separator.
|
||||
if (any) {
|
||||
if (value == ",") {
|
||||
value = lex();
|
||||
if (value == "}") {
|
||||
// Unexpected trailing `,` in object literal.
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
// A `,` must separate each object member.
|
||||
abort();
|
||||
}
|
||||
}
|
||||
// Leading commas are not permitted, object property names must be
|
||||
// double-quoted strings, and a `:` must separate each property
|
||||
// name and value.
|
||||
if (value == "," || typeof value != "string" || value.charAt(0) != "@" || lex() != ":") {
|
||||
abort();
|
||||
}
|
||||
results[value.slice(1)] = get(lex());
|
||||
}
|
||||
return results;
|
||||
}
|
||||
// Unexpected token encountered.
|
||||
abort();
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
// Internal: Updates a traversed object member.
|
||||
update = function(source, property, callback) {
|
||||
var element = walk(source, property, callback);
|
||||
if (element === undef) {
|
||||
delete source[property];
|
||||
} else {
|
||||
source[property] = element;
|
||||
}
|
||||
};
|
||||
|
||||
// Internal: Recursively traverses a parsed JSON object, invoking the
|
||||
// `callback` function for each value. This is an implementation of the
|
||||
// `Walk(holder, name)` operation defined in ES 5.1 section 15.12.2.
|
||||
walk = function (source, property, callback) {
|
||||
var value = source[property], length;
|
||||
if (typeof value == "object" && value) {
|
||||
if (getClass.call(value) == "[object Array]") {
|
||||
for (length = value.length; length--;) {
|
||||
update(value, length, callback);
|
||||
}
|
||||
} else {
|
||||
// `forEach` can't be used to traverse an array in Opera <= 8.54,
|
||||
// as `Object#hasOwnProperty` returns `false` for array indices
|
||||
// (e.g., `![1, 2, 3].hasOwnProperty("0")`).
|
||||
forEach(value, function (property) {
|
||||
update(value, property, callback);
|
||||
});
|
||||
}
|
||||
}
|
||||
return callback.call(source, property, value);
|
||||
};
|
||||
|
||||
// Public: `JSON.parse`. See ES 5.1 section 15.12.2.
|
||||
JSON3.parse = function (source, callback) {
|
||||
var result, value;
|
||||
Index = 0;
|
||||
Source = source;
|
||||
result = get(lex());
|
||||
// If a JSON string contains multiple tokens, it is invalid.
|
||||
if (lex() != "$") {
|
||||
abort();
|
||||
}
|
||||
// Reset the parser state.
|
||||
Index = Source = null;
|
||||
return callback && getClass.call(callback) == "[object Function]" ? walk((value = {}, value[""] = result, value), "", callback) : result;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Export for asynchronous module loaders.
|
||||
if (isLoader) {
|
||||
define(function () {
|
||||
return JSON3;
|
||||
});
|
||||
}
|
||||
}).call(this);
|
||||
Reference in New Issue
Block a user