[79a0317] | 1 | 'use strict';
|
---|
| 2 | var $ = require('../internals/export');
|
---|
| 3 | var DESCRIPTORS = require('../internals/descriptors');
|
---|
| 4 | var globalThis = require('../internals/global-this');
|
---|
| 5 | var getBuiltIn = require('../internals/get-built-in');
|
---|
| 6 | var uncurryThis = require('../internals/function-uncurry-this');
|
---|
| 7 | var call = require('../internals/function-call');
|
---|
| 8 | var isCallable = require('../internals/is-callable');
|
---|
| 9 | var isObject = require('../internals/is-object');
|
---|
| 10 | var isArray = require('../internals/is-array');
|
---|
| 11 | var hasOwn = require('../internals/has-own-property');
|
---|
| 12 | var toString = require('../internals/to-string');
|
---|
| 13 | var lengthOfArrayLike = require('../internals/length-of-array-like');
|
---|
| 14 | var createProperty = require('../internals/create-property');
|
---|
| 15 | var fails = require('../internals/fails');
|
---|
| 16 | var parseJSONString = require('../internals/parse-json-string');
|
---|
| 17 | var NATIVE_SYMBOL = require('../internals/symbol-constructor-detection');
|
---|
| 18 |
|
---|
| 19 | var JSON = globalThis.JSON;
|
---|
| 20 | var Number = globalThis.Number;
|
---|
| 21 | var SyntaxError = globalThis.SyntaxError;
|
---|
| 22 | var nativeParse = JSON && JSON.parse;
|
---|
| 23 | var enumerableOwnProperties = getBuiltIn('Object', 'keys');
|
---|
| 24 | // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
|
---|
| 25 | var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
|
---|
| 26 | var at = uncurryThis(''.charAt);
|
---|
| 27 | var slice = uncurryThis(''.slice);
|
---|
| 28 | var exec = uncurryThis(/./.exec);
|
---|
| 29 | var push = uncurryThis([].push);
|
---|
| 30 |
|
---|
| 31 | var IS_DIGIT = /^\d$/;
|
---|
| 32 | var IS_NON_ZERO_DIGIT = /^[1-9]$/;
|
---|
| 33 | var IS_NUMBER_START = /^[\d-]$/;
|
---|
| 34 | var IS_WHITESPACE = /^[\t\n\r ]$/;
|
---|
| 35 |
|
---|
| 36 | var PRIMITIVE = 0;
|
---|
| 37 | var OBJECT = 1;
|
---|
| 38 |
|
---|
| 39 | var $parse = function (source, reviver) {
|
---|
| 40 | source = toString(source);
|
---|
| 41 | var context = new Context(source, 0, '');
|
---|
| 42 | var root = context.parse();
|
---|
| 43 | var value = root.value;
|
---|
| 44 | var endIndex = context.skip(IS_WHITESPACE, root.end);
|
---|
| 45 | if (endIndex < source.length) {
|
---|
| 46 | throw new SyntaxError('Unexpected extra character: "' + at(source, endIndex) + '" after the parsed data at: ' + endIndex);
|
---|
| 47 | }
|
---|
| 48 | return isCallable(reviver) ? internalize({ '': value }, '', reviver, root) : value;
|
---|
| 49 | };
|
---|
| 50 |
|
---|
| 51 | var internalize = function (holder, name, reviver, node) {
|
---|
| 52 | var val = holder[name];
|
---|
| 53 | var unmodified = node && val === node.value;
|
---|
| 54 | var context = unmodified && typeof node.source == 'string' ? { source: node.source } : {};
|
---|
| 55 | var elementRecordsLen, keys, len, i, P;
|
---|
| 56 | if (isObject(val)) {
|
---|
| 57 | var nodeIsArray = isArray(val);
|
---|
| 58 | var nodes = unmodified ? node.nodes : nodeIsArray ? [] : {};
|
---|
| 59 | if (nodeIsArray) {
|
---|
| 60 | elementRecordsLen = nodes.length;
|
---|
| 61 | len = lengthOfArrayLike(val);
|
---|
| 62 | for (i = 0; i < len; i++) {
|
---|
| 63 | internalizeProperty(val, i, internalize(val, '' + i, reviver, i < elementRecordsLen ? nodes[i] : undefined));
|
---|
| 64 | }
|
---|
| 65 | } else {
|
---|
| 66 | keys = enumerableOwnProperties(val);
|
---|
| 67 | len = lengthOfArrayLike(keys);
|
---|
| 68 | for (i = 0; i < len; i++) {
|
---|
| 69 | P = keys[i];
|
---|
| 70 | internalizeProperty(val, P, internalize(val, P, reviver, hasOwn(nodes, P) ? nodes[P] : undefined));
|
---|
| 71 | }
|
---|
| 72 | }
|
---|
| 73 | }
|
---|
| 74 | return call(reviver, holder, name, val, context);
|
---|
| 75 | };
|
---|
| 76 |
|
---|
| 77 | var internalizeProperty = function (object, key, value) {
|
---|
| 78 | if (DESCRIPTORS) {
|
---|
| 79 | var descriptor = getOwnPropertyDescriptor(object, key);
|
---|
| 80 | if (descriptor && !descriptor.configurable) return;
|
---|
| 81 | }
|
---|
| 82 | if (value === undefined) delete object[key];
|
---|
| 83 | else createProperty(object, key, value);
|
---|
| 84 | };
|
---|
| 85 |
|
---|
| 86 | var Node = function (value, end, source, nodes) {
|
---|
| 87 | this.value = value;
|
---|
| 88 | this.end = end;
|
---|
| 89 | this.source = source;
|
---|
| 90 | this.nodes = nodes;
|
---|
| 91 | };
|
---|
| 92 |
|
---|
| 93 | var Context = function (source, index) {
|
---|
| 94 | this.source = source;
|
---|
| 95 | this.index = index;
|
---|
| 96 | };
|
---|
| 97 |
|
---|
| 98 | // https://www.json.org/json-en.html
|
---|
| 99 | Context.prototype = {
|
---|
| 100 | fork: function (nextIndex) {
|
---|
| 101 | return new Context(this.source, nextIndex);
|
---|
| 102 | },
|
---|
| 103 | parse: function () {
|
---|
| 104 | var source = this.source;
|
---|
| 105 | var i = this.skip(IS_WHITESPACE, this.index);
|
---|
| 106 | var fork = this.fork(i);
|
---|
| 107 | var chr = at(source, i);
|
---|
| 108 | if (exec(IS_NUMBER_START, chr)) return fork.number();
|
---|
| 109 | switch (chr) {
|
---|
| 110 | case '{':
|
---|
| 111 | return fork.object();
|
---|
| 112 | case '[':
|
---|
| 113 | return fork.array();
|
---|
| 114 | case '"':
|
---|
| 115 | return fork.string();
|
---|
| 116 | case 't':
|
---|
| 117 | return fork.keyword(true);
|
---|
| 118 | case 'f':
|
---|
| 119 | return fork.keyword(false);
|
---|
| 120 | case 'n':
|
---|
| 121 | return fork.keyword(null);
|
---|
| 122 | } throw new SyntaxError('Unexpected character: "' + chr + '" at: ' + i);
|
---|
| 123 | },
|
---|
| 124 | node: function (type, value, start, end, nodes) {
|
---|
| 125 | return new Node(value, end, type ? null : slice(this.source, start, end), nodes);
|
---|
| 126 | },
|
---|
| 127 | object: function () {
|
---|
| 128 | var source = this.source;
|
---|
| 129 | var i = this.index + 1;
|
---|
| 130 | var expectKeypair = false;
|
---|
| 131 | var object = {};
|
---|
| 132 | var nodes = {};
|
---|
| 133 | while (i < source.length) {
|
---|
| 134 | i = this.until(['"', '}'], i);
|
---|
| 135 | if (at(source, i) === '}' && !expectKeypair) {
|
---|
| 136 | i++;
|
---|
| 137 | break;
|
---|
| 138 | }
|
---|
| 139 | // Parsing the key
|
---|
| 140 | var result = this.fork(i).string();
|
---|
| 141 | var key = result.value;
|
---|
| 142 | i = result.end;
|
---|
| 143 | i = this.until([':'], i) + 1;
|
---|
| 144 | // Parsing value
|
---|
| 145 | i = this.skip(IS_WHITESPACE, i);
|
---|
| 146 | result = this.fork(i).parse();
|
---|
| 147 | createProperty(nodes, key, result);
|
---|
| 148 | createProperty(object, key, result.value);
|
---|
| 149 | i = this.until([',', '}'], result.end);
|
---|
| 150 | var chr = at(source, i);
|
---|
| 151 | if (chr === ',') {
|
---|
| 152 | expectKeypair = true;
|
---|
| 153 | i++;
|
---|
| 154 | } else if (chr === '}') {
|
---|
| 155 | i++;
|
---|
| 156 | break;
|
---|
| 157 | }
|
---|
| 158 | }
|
---|
| 159 | return this.node(OBJECT, object, this.index, i, nodes);
|
---|
| 160 | },
|
---|
| 161 | array: function () {
|
---|
| 162 | var source = this.source;
|
---|
| 163 | var i = this.index + 1;
|
---|
| 164 | var expectElement = false;
|
---|
| 165 | var array = [];
|
---|
| 166 | var nodes = [];
|
---|
| 167 | while (i < source.length) {
|
---|
| 168 | i = this.skip(IS_WHITESPACE, i);
|
---|
| 169 | if (at(source, i) === ']' && !expectElement) {
|
---|
| 170 | i++;
|
---|
| 171 | break;
|
---|
| 172 | }
|
---|
| 173 | var result = this.fork(i).parse();
|
---|
| 174 | push(nodes, result);
|
---|
| 175 | push(array, result.value);
|
---|
| 176 | i = this.until([',', ']'], result.end);
|
---|
| 177 | if (at(source, i) === ',') {
|
---|
| 178 | expectElement = true;
|
---|
| 179 | i++;
|
---|
| 180 | } else if (at(source, i) === ']') {
|
---|
| 181 | i++;
|
---|
| 182 | break;
|
---|
| 183 | }
|
---|
| 184 | }
|
---|
| 185 | return this.node(OBJECT, array, this.index, i, nodes);
|
---|
| 186 | },
|
---|
| 187 | string: function () {
|
---|
| 188 | var index = this.index;
|
---|
| 189 | var parsed = parseJSONString(this.source, this.index + 1);
|
---|
| 190 | return this.node(PRIMITIVE, parsed.value, index, parsed.end);
|
---|
| 191 | },
|
---|
| 192 | number: function () {
|
---|
| 193 | var source = this.source;
|
---|
| 194 | var startIndex = this.index;
|
---|
| 195 | var i = startIndex;
|
---|
| 196 | if (at(source, i) === '-') i++;
|
---|
| 197 | if (at(source, i) === '0') i++;
|
---|
| 198 | else if (exec(IS_NON_ZERO_DIGIT, at(source, i))) i = this.skip(IS_DIGIT, i + 1);
|
---|
| 199 | else throw new SyntaxError('Failed to parse number at: ' + i);
|
---|
| 200 | if (at(source, i) === '.') i = this.skip(IS_DIGIT, i + 1);
|
---|
| 201 | if (at(source, i) === 'e' || at(source, i) === 'E') {
|
---|
| 202 | i++;
|
---|
| 203 | if (at(source, i) === '+' || at(source, i) === '-') i++;
|
---|
| 204 | var exponentStartIndex = i;
|
---|
| 205 | i = this.skip(IS_DIGIT, i);
|
---|
| 206 | if (exponentStartIndex === i) throw new SyntaxError("Failed to parse number's exponent value at: " + i);
|
---|
| 207 | }
|
---|
| 208 | return this.node(PRIMITIVE, Number(slice(source, startIndex, i)), startIndex, i);
|
---|
| 209 | },
|
---|
| 210 | keyword: function (value) {
|
---|
| 211 | var keyword = '' + value;
|
---|
| 212 | var index = this.index;
|
---|
| 213 | var endIndex = index + keyword.length;
|
---|
| 214 | if (slice(this.source, index, endIndex) !== keyword) throw new SyntaxError('Failed to parse value at: ' + index);
|
---|
| 215 | return this.node(PRIMITIVE, value, index, endIndex);
|
---|
| 216 | },
|
---|
| 217 | skip: function (regex, i) {
|
---|
| 218 | var source = this.source;
|
---|
| 219 | for (; i < source.length; i++) if (!exec(regex, at(source, i))) break;
|
---|
| 220 | return i;
|
---|
| 221 | },
|
---|
| 222 | until: function (array, i) {
|
---|
| 223 | i = this.skip(IS_WHITESPACE, i);
|
---|
| 224 | var chr = at(this.source, i);
|
---|
| 225 | for (var j = 0; j < array.length; j++) if (array[j] === chr) return i;
|
---|
| 226 | throw new SyntaxError('Unexpected character: "' + chr + '" at: ' + i);
|
---|
| 227 | }
|
---|
| 228 | };
|
---|
| 229 |
|
---|
| 230 | var NO_SOURCE_SUPPORT = fails(function () {
|
---|
| 231 | var unsafeInt = '9007199254740993';
|
---|
| 232 | var source;
|
---|
| 233 | nativeParse(unsafeInt, function (key, value, context) {
|
---|
| 234 | source = context.source;
|
---|
| 235 | });
|
---|
| 236 | return source !== unsafeInt;
|
---|
| 237 | });
|
---|
| 238 |
|
---|
| 239 | var PROPER_BASE_PARSE = NATIVE_SYMBOL && !fails(function () {
|
---|
| 240 | // Safari 9 bug
|
---|
| 241 | return 1 / nativeParse('-0 \t') !== -Infinity;
|
---|
| 242 | });
|
---|
| 243 |
|
---|
| 244 | // `JSON.parse` method
|
---|
| 245 | // https://tc39.es/ecma262/#sec-json.parse
|
---|
| 246 | // https://github.com/tc39/proposal-json-parse-with-source
|
---|
| 247 | $({ target: 'JSON', stat: true, forced: NO_SOURCE_SUPPORT }, {
|
---|
| 248 | parse: function parse(text, reviver) {
|
---|
| 249 | return PROPER_BASE_PARSE && !isCallable(reviver) ? nativeParse(text) : $parse(text, reviver);
|
---|
| 250 | }
|
---|
| 251 | });
|
---|