'use strict'; var array = [].constructor; /** * @ngdoc function * @name angular.toJson * @function * * @description * Serializes input into a JSON-formatted string. * * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON. * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace. * @returns {string} Jsonified string representing `obj`. */ function toJson(obj, pretty) { var buf = []; toJsonArray(buf, obj, pretty ? "\n " : null, []); return buf.join(''); } /** * @ngdoc function * @name angular.fromJson * @function * * @description * Deserializes a JSON string. * * @param {string} json JSON string to deserialize. * @param {boolean} [useNative=false] Use native JSON parser, if available. * @returns {Object|Array|Date|string|number} Deserialized thingy. */ function fromJson(json, useNative) { if (!isString(json)) return json; var obj; if (useNative && window.JSON && window.JSON.parse) { obj = JSON.parse(json); } else { obj = parseJson(json, true)(); } return transformDates(obj); // TODO make forEach optionally recursive and remove this function // TODO(misko): remove this once the $http service is checked in. function transformDates(obj) { if (isString(obj) && obj.length === DATE_ISOSTRING_LN) { return jsonStringToDate(obj); } else if (isArray(obj) || isObject(obj)) { forEach(obj, function(val, name) { obj[name] = transformDates(val); }); } return obj; } } var R_ISO8061_STR = /^(\d{4})-(\d\d)-(\d\d)(?:T(\d\d)(?:\:(\d\d)(?:\:(\d\d)(?:\.(\d{3}))?)?)?Z)?$/; function jsonStringToDate(string){ var match; if (isString(string) && (match = string.match(R_ISO8061_STR))){ var date = new Date(0); date.setUTCFullYear(match[1], match[2] - 1, match[3]); date.setUTCHours(match[4]||0, match[5]||0, match[6]||0, match[7]||0); return date; } return string; } function jsonDateToString(date){ if (!date) return date; var isoString = date.toISOString ? date.toISOString() : ''; return (isoString.length==24) ? isoString : padNumber(date.getUTCFullYear(), 4) + '-' + padNumber(date.getUTCMonth() + 1, 2) + '-' + padNumber(date.getUTCDate(), 2) + 'T' + padNumber(date.getUTCHours(), 2) + ':' + padNumber(date.getUTCMinutes(), 2) + ':' + padNumber(date.getUTCSeconds(), 2) + '.' + padNumber(date.getUTCMilliseconds(), 3) + 'Z'; } function quoteUnicode(string) { var chars = ['"']; for ( var i = 0; i < string.length; i++) { var code = string.charCodeAt(i); var ch = string.charAt(i); switch(ch) { case '"': chars.push('\\"'); break; case '\\': chars.push('\\\\'); break; case '\n': chars.push('\\n'); break; case '\f': chars.push('\\f'); break; case '\r': chars.push(ch = '\\r'); break; case '\t': chars.push(ch = '\\t'); break; default: if (32 <= code && code <= 126) { chars.push(ch); } else { var encode = "000" + code.toString(16); chars.push("\\u" + encode.substring(encode.length - 4)); } } } chars.push('"'); return chars.join(''); } function toJsonArray(buf, obj, pretty, stack) { if (isObject(obj)) { if (obj === window) { buf.push('WINDOW'); return; } if (obj === document) { buf.push('DOCUMENT'); return; } if (includes(stack, obj)) { buf.push('RECURSION'); return; } stack.push(obj); } if (obj === null) { buf.push('null'); } else if (obj instanceof RegExp) { buf.push(quoteUnicode(obj.toString())); } else if (isFunction(obj)) { return; } else if (isBoolean(obj)) { buf.push('' + obj); } else if (isNumber(obj)) { if (isNaN(obj)) { buf.push('null'); } else { buf.push('' + obj); } } else if (isString(obj)) { return buf.push(quoteUnicode(obj)); } else if (isObject(obj)) { if (isArray(obj)) { buf.push("["); var len = obj.length; var sep = false; for(var i=0; i