json2.js (lodash-3.0.0) | : | json2.js (lodash-4.0.0) | ||
---|---|---|---|---|
/* | /* | |||
json2.js | json2.js | |||
2014-02-04 | 2015-05-03 | |||
Public Domain. | Public Domain. | |||
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. | NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. | |||
See http://www.JSON.org/js.html | See http://www.JSON.org/js.html | |||
This code should be minified before deployment. | This code should be minified before deployment. | |||
See http://javascript.crockford.com/jsmin.html | See http://javascript.crockford.com/jsmin.html | |||
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO | USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO | |||
NOT CONTROL. | NOT CONTROL. | |||
This file creates a global JSON object containing two methods: stringify | This file creates a global JSON object containing two methods: stringify | |||
and parse. | and parse. This file is provides the ES5 JSON capability to ES3 systems. | |||
If a project might run on IE8 or earlier, then this file should be included. | ||||
This file does nothing on ES5 systems. | ||||
JSON.stringify(value, replacer, space) | JSON.stringify(value, replacer, space) | |||
value any JavaScript value, usually an object or array. | value any JavaScript value, usually an object or array. | |||
replacer an optional parameter that determines how object | replacer an optional parameter that determines how object | |||
values are stringified for objects. It can be a | values are stringified for objects. It can be a | |||
function or an array of strings. | function or an array of strings. | |||
space an optional parameter that specifies the indentation | space an optional parameter that specifies the indentation | |||
of nested structures. If it is omitted, the text will | of nested structures. If it is omitted, the text will | |||
skipping to change at line 49 | skipping to change at line 51 | |||
value represented by the name/value pair that should be serialized, | value represented by the name/value pair that should be serialized, | |||
or undefined if nothing should be serialized. The toJSON method | or undefined if nothing should be serialized. The toJSON method | |||
will be passed the key associated with the value, and this will be | will be passed the key associated with the value, and this will be | |||
bound to the value | bound to the value | |||
For example, this would serialize Dates as ISO strings. | For example, this would serialize Dates as ISO strings. | |||
Date.prototype.toJSON = function (key) { | Date.prototype.toJSON = function (key) { | |||
function f(n) { | function f(n) { | |||
// Format integers to have at least two digits. | // Format integers to have at least two digits. | |||
return n < 10 ? '0' + n : n; | return n < 10 | |||
? '0' + n | ||||
: n; | ||||
} | } | |||
return this.getUTCFullYear() + '-' + | return this.getUTCFullYear() + '-' + | |||
f(this.getUTCMonth() + 1) + '-' + | f(this.getUTCMonth() + 1) + '-' + | |||
f(this.getUTCDate()) + 'T' + | f(this.getUTCDate()) + 'T' + | |||
f(this.getUTCHours()) + ':' + | f(this.getUTCHours()) + ':' + | |||
f(this.getUTCMinutes()) + ':' + | f(this.getUTCMinutes()) + ':' + | |||
f(this.getUTCSeconds()) + 'Z'; | f(this.getUTCSeconds()) + 'Z'; | |||
}; | }; | |||
skipping to change at line 94 | skipping to change at line 98 | |||
Example: | Example: | |||
text = JSON.stringify(['e', {pluribus: 'unum'}]); | text = JSON.stringify(['e', {pluribus: 'unum'}]); | |||
// text is '["e",{"pluribus":"unum"}]' | // text is '["e",{"pluribus":"unum"}]' | |||
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); | text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); | |||
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' | // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' | |||
text = JSON.stringify([new Date()], function (key, value) { | text = JSON.stringify([new Date()], function (key, value) { | |||
return this[key] instanceof Date ? | return this[key] instanceof Date | |||
'Date(' + this[key] + ')' : value; | ? 'Date(' + this[key] + ')' | |||
: value; | ||||
}); | }); | |||
// text is '["Date(---current time---)"]' | // text is '["Date(---current time---)"]' | |||
JSON.parse(text, reviver) | JSON.parse(text, reviver) | |||
This method parses a JSON text to produce an object or array. | This method parses a JSON text to produce an object or array. | |||
It can throw a SyntaxError exception. | It can throw a SyntaxError exception. | |||
The optional reviver parameter is a function that can filter and | The optional reviver parameter is a function that can filter and | |||
transform the results. It receives each of the keys and values, | transform the results. It receives each of the keys and values, | |||
and its return value is used instead of the original value. | and its return value is used instead of the original value. | |||
skipping to change at line 144 | skipping to change at line 149 | |||
return d; | return d; | |||
} | } | |||
} | } | |||
return value; | return value; | |||
}); | }); | |||
This is a reference implementation. You are free to copy, modify, or | This is a reference implementation. You are free to copy, modify, or | |||
redistribute. | redistribute. | |||
*/ | */ | |||
/*jslint evil: true, regexp: true */ | /*jslint | |||
eval, for, this | ||||
*/ | ||||
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, | /*property | |||
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, | JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, | |||
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, | getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, | |||
lastIndex, length, parse, prototype, push, replace, slice, stringify, | lastIndex, length, parse, prototype, push, replace, slice, stringify, | |||
test, toJSON, toString, valueOf | test, toJSON, toString, valueOf | |||
*/ | */ | |||
// Create a JSON object only if one does not already exist. We create the | // Create a JSON object only if one does not already exist. We create the | |||
// methods in a closure to avoid creating global variables. | // methods in a closure to avoid creating global variables. | |||
if (typeof JSON !== 'object') { | if (typeof JSON !== 'object') { | |||
JSON = {}; | JSON = {}; | |||
} | } | |||
(function () { | (function () { | |||
'use strict'; | 'use strict'; | |||
var rx_one = /^[\],:{}\s]*$/, | ||||
rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, | ||||
rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d | ||||
+)?/g, | ||||
rx_four = /(?:^|:|,)(?:\s*\[)+/g, | ||||
rx_escapable = /[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f | ||||
\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, | ||||
rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200 | ||||
f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; | ||||
function f(n) { | function f(n) { | |||
// Format integers to have at least two digits. | // Format integers to have at least two digits. | |||
return n < 10 ? '0' + n : n; | return n < 10 | |||
? '0' + n | ||||
: n; | ||||
} | ||||
function this_value() { | ||||
return this.valueOf(); | ||||
} | } | |||
if (typeof Date.prototype.toJSON !== 'function') { | if (typeof Date.prototype.toJSON !== 'function') { | |||
Date.prototype.toJSON = function () { | Date.prototype.toJSON = function () { | |||
return isFinite(this.valueOf()) | return isFinite(this.valueOf()) | |||
? this.getUTCFullYear() + '-' + | ? this.getUTCFullYear() + '-' + | |||
f(this.getUTCMonth() + 1) + '-' + | f(this.getUTCMonth() + 1) + '-' + | |||
f(this.getUTCDate()) + 'T' + | f(this.getUTCDate()) + 'T' + | |||
f(this.getUTCHours()) + ':' + | f(this.getUTCHours()) + ':' + | |||
f(this.getUTCMinutes()) + ':' + | f(this.getUTCMinutes()) + ':' + | |||
f(this.getUTCSeconds()) + 'Z' | f(this.getUTCSeconds()) + 'Z' | |||
: null; | : null; | |||
}; | }; | |||
String.prototype.toJSON = | Boolean.prototype.toJSON = this_value; | |||
Number.prototype.toJSON = | Number.prototype.toJSON = this_value; | |||
Boolean.prototype.toJSON = function () { | String.prototype.toJSON = this_value; | |||
return this.valueOf(); | ||||
}; | ||||
} | } | |||
var cx, | var gap, | |||
escapable, | ||||
gap, | ||||
indent, | indent, | |||
meta, | meta, | |||
rep; | rep; | |||
function quote(string) { | function quote(string) { | |||
// If the string contains no control characters, no quote characters, and no | // If the string contains no control characters, no quote characters, and no | |||
// backslash characters, then we can safely slap some quotes around it. | // backslash characters, then we can safely slap some quotes around it. | |||
// Otherwise we must also replace the offending characters with safe escape | // Otherwise we must also replace the offending characters with safe escape | |||
// sequences. | // sequences. | |||
escapable.lastIndex = 0; | rx_escapable.lastIndex = 0; | |||
return escapable.test(string) ? '"' + string.replace(escapable, function | return rx_escapable.test(string) | |||
(a) { | ? '"' + string.replace(rx_escapable, function (a) { | |||
var c = meta[a]; | var c = meta[a]; | |||
return typeof c === 'string' | return typeof c === 'string' | |||
? c | ? c | |||
: '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); | : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); | |||
}) + '"' : '"' + string + '"'; | }) + '"' | |||
: '"' + string + '"'; | ||||
} | } | |||
function str(key, holder) { | function str(key, holder) { | |||
// Produce a string from holder[key]. | // Produce a string from holder[key]. | |||
var i, // The loop counter. | var i, // The loop counter. | |||
k, // The member key. | k, // The member key. | |||
v, // The member value. | v, // The member value. | |||
length, | length, | |||
skipping to change at line 248 | skipping to change at line 266 | |||
// What happens next depends on the value's type. | // What happens next depends on the value's type. | |||
switch (typeof value) { | switch (typeof value) { | |||
case 'string': | case 'string': | |||
return quote(value); | return quote(value); | |||
case 'number': | case 'number': | |||
// JSON numbers must be finite. Encode non-finite numbers as null. | // JSON numbers must be finite. Encode non-finite numbers as null. | |||
return isFinite(value) ? String(value) : 'null'; | return isFinite(value) | |||
? String(value) | ||||
: 'null'; | ||||
case 'boolean': | case 'boolean': | |||
case 'null': | case 'null': | |||
// If the value is a boolean or null, convert it to a string. Note: | // If the value is a boolean or null, convert it to a string. Note: | |||
// typeof null does not produce 'null'. The case is included here in | // typeof null does not produce 'null'. The case is included here in | |||
// the remote chance that this gets fixed someday. | // the remote chance that this gets fixed someday. | |||
return String(value); | return String(value); | |||
skipping to change at line 294 | skipping to change at line 314 | |||
for (i = 0; i < length; i += 1) { | for (i = 0; i < length; i += 1) { | |||
partial[i] = str(i, value) || 'null'; | partial[i] = str(i, value) || 'null'; | |||
} | } | |||
// Join all of the elements together, separated with commas, and wrap them in | // Join all of the elements together, separated with commas, and wrap them in | |||
// brackets. | // brackets. | |||
v = partial.length === 0 | v = partial.length === 0 | |||
? '[]' | ? '[]' | |||
: gap | : gap | |||
? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '] | ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind | |||
' | + ']' | |||
: '[' + partial.join(',') + ']'; | : '[' + partial.join(',') + ']'; | |||
gap = mind; | gap = mind; | |||
return v; | return v; | |||
} | } | |||
// If the replacer is an array, use it to select the members to be stringified. | // If the replacer is an array, use it to select the members to be stringified. | |||
if (rep && typeof rep === 'object') { | if (rep && typeof rep === 'object') { | |||
length = rep.length; | length = rep.length; | |||
for (i = 0; i < length; i += 1) { | for (i = 0; i < length; i += 1) { | |||
if (typeof rep[i] === 'string') { | if (typeof rep[i] === 'string') { | |||
k = rep[i]; | k = rep[i]; | |||
v = str(k, value); | v = str(k, value); | |||
if (v) { | if (v) { | |||
partial.push(quote(k) + (gap ? ': ' : ':') + v); | partial.push(quote(k) + ( | |||
gap | ||||
? ': ' | ||||
: ':' | ||||
) + v); | ||||
} | } | |||
} | } | |||
} | } | |||
} else { | } else { | |||
// Otherwise, iterate through all of the keys in the object. | // Otherwise, iterate through all of the keys in the object. | |||
for (k in value) { | for (k in value) { | |||
if (Object.prototype.hasOwnProperty.call(value, k)) { | if (Object.prototype.hasOwnProperty.call(value, k)) { | |||
v = str(k, value); | v = str(k, value); | |||
if (v) { | if (v) { | |||
partial.push(quote(k) + (gap ? ': ' : ':') + v); | partial.push(quote(k) + ( | |||
gap | ||||
? ': ' | ||||
: ':' | ||||
) + v); | ||||
} | } | |||
} | } | |||
} | } | |||
} | } | |||
// Join all of the member texts together, separated with commas, | // Join all of the member texts together, separated with commas, | |||
// and wrap them in braces. | // and wrap them in braces. | |||
v = partial.length === 0 | v = partial.length === 0 | |||
? '{}' | ? '{}' | |||
: gap | : gap | |||
? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' | ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '} | |||
: '{' + partial.join(',') + '}'; | ' | |||
: '{' + partial.join(',') + '}'; | ||||
gap = mind; | gap = mind; | |||
return v; | return v; | |||
} | } | |||
} | } | |||
// If the JSON object does not yet have a stringify method, give it one. | // If the JSON object does not yet have a stringify method, give it one. | |||
if (typeof JSON.stringify !== 'function') { | if (typeof JSON.stringify !== 'function') { | |||
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b 5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; | ||||
meta = { // table of character substitutions | meta = { // table of character substitutions | |||
'\b': '\\b', | '\b': '\\b', | |||
'\t': '\\t', | '\t': '\\t', | |||
'\n': '\\n', | '\n': '\\n', | |||
'\f': '\\f', | '\f': '\\f', | |||
'\r': '\\r', | '\r': '\\r', | |||
'"' : '\\"', | '"': '\\"', | |||
'\\': '\\\\' | '\\': '\\\\' | |||
}; | }; | |||
JSON.stringify = function (value, replacer, space) { | JSON.stringify = function (value, replacer, space) { | |||
// The stringify method takes a value and an optional replacer, and an optional | // The stringify method takes a value and an optional replacer, and an optional | |||
// space parameter, and returns a JSON text. The replacer can be a function | // space parameter, and returns a JSON text. The replacer can be a function | |||
// that can replace values, or an array of strings that will select the keys. | // that can replace values, or an array of strings that will select the keys. | |||
// A default replacer method can be provided. Use of the space parameter can | // A default replacer method can be provided. Use of the space parameter can | |||
// produce text that is more easily readable. | // produce text that is more easily readable. | |||
skipping to change at line 399 | skipping to change at line 426 | |||
// Make a fake root object containing our value under the key of ''. | // Make a fake root object containing our value under the key of ''. | |||
// Return the result of stringifying the value. | // Return the result of stringifying the value. | |||
return str('', {'': value}); | return str('', {'': value}); | |||
}; | }; | |||
} | } | |||
// If the JSON object does not yet have a parse method, give it one. | // If the JSON object does not yet have a parse method, give it one. | |||
if (typeof JSON.parse !== 'function') { | if (typeof JSON.parse !== 'function') { | |||
cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u 202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; | ||||
JSON.parse = function (text, reviver) { | JSON.parse = function (text, reviver) { | |||
// The parse method takes a text and an optional reviver function, and returns | // The parse method takes a text and an optional reviver function, and returns | |||
// a JavaScript value if the text is a valid JSON text. | // a JavaScript value if the text is a valid JSON text. | |||
var j; | var j; | |||
function walk(holder, key) { | function walk(holder, key) { | |||
// The walk method is used to recursively walk the resulting structure so | // The walk method is used to recursively walk the resulting structure so | |||
skipping to change at line 433 | skipping to change at line 459 | |||
} | } | |||
} | } | |||
return reviver.call(holder, key, value); | return reviver.call(holder, key, value); | |||
} | } | |||
// Parsing happens in four stages. In the first stage, we replace certain | // Parsing happens in four stages. In the first stage, we replace certain | |||
// Unicode characters with escape sequences. JavaScript handles many characters | // Unicode characters with escape sequences. JavaScript handles many characters | |||
// incorrectly, either silently deleting them, or treating them as line endings. | // incorrectly, either silently deleting them, or treating them as line endings. | |||
text = String(text); | text = String(text); | |||
cx.lastIndex = 0; | rx_dangerous.lastIndex = 0; | |||
if (cx.test(text)) { | if (rx_dangerous.test(text)) { | |||
text = text.replace(cx, function (a) { | text = text.replace(rx_dangerous, function (a) { | |||
return '\\u' + | return '\\u' + | |||
('0000' + a.charCodeAt(0).toString(16)).slice(-4); | ('0000' + a.charCodeAt(0).toString(16)).slice(-4); | |||
}); | }); | |||
} | } | |||
// In the second stage, we run the text against regular expressions that look | // In the second stage, we run the text against regular expressions that look | |||
// for non-JSON patterns. We are especially concerned with '()' and 'new' | // for non-JSON patterns. We are especially concerned with '()' and 'new' | |||
// because they can cause invocation, and '=' because it can cause mutation. | // because they can cause invocation, and '=' because it can cause mutation. | |||
// But just to be safe, we want to reject all unexpected forms. | // But just to be safe, we want to reject all unexpected forms. | |||
// We split the second stage into 4 regexp operations in order to work around | // We split the second stage into 4 regexp operations in order to work around | |||
// crippling inefficiencies in IE's and Safari's regexp engines. First we | // crippling inefficiencies in IE's and Safari's regexp engines. First we | |||
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we | // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we | |||
// replace all simple value tokens with ']' characters. Third, we delete all | // replace all simple value tokens with ']' characters. Third, we delete all | |||
// open brackets that follow a colon or comma or that begin the text. Finally, | // open brackets that follow a colon or comma or that begin the text. Finally, | |||
// we look to see that the remaining characters are only whitespace or ']' or | // we look to see that the remaining characters are only whitespace or ']' or | |||
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. | // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. | |||
if (/^[\],:{}\s]*$/ | if ( | |||
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@ | rx_one.test( | |||
') | text | |||
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?( | .replace(rx_two, '@') | |||
?:[eE][+\-]?\d+)?/g, ']') | .replace(rx_three, ']') | |||
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { | .replace(rx_four, '') | |||
) | ||||
) { | ||||
// In the third stage we use the eval function to compile the text into a | // In the third stage we use the eval function to compile the text into a | |||
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity | // JavaScript structure. The '{' operator is subject to a syntactic ambiguity | |||
// in JavaScript: it can begin a block or an object literal. We wrap the text | // in JavaScript: it can begin a block or an object literal. We wrap the text | |||
// in parens to eliminate the ambiguity. | // in parens to eliminate the ambiguity. | |||
j = eval('(' + text + ')'); | j = eval('(' + text + ')'); | |||
// In the optional fourth stage, we recursively walk the new structure, passing | // In the optional fourth stage, we recursively walk the new structure, passing | |||
// each name/value pair to a reviver function for possible transformation. | // each name/value pair to a reviver function for possible transformation. | |||
End of changes. 23 change blocks. | ||||
52 lines changed or deleted | 83 lines changed or added |