Skip to content

Commit ff5aa19

Browse files
committed
json-parse-with-source: JSON.parse reviver context argument
1 parent 5b5ad5a commit ff5aa19

File tree

4 files changed

+132
-220
lines changed

4 files changed

+132
-220
lines changed

test/built-ins/JSON/parse/reviver-context-source-array-literal.js

Lines changed: 0 additions & 58 deletions
This file was deleted.

test/built-ins/JSON/parse/reviver-context-source-object-literal.js

Lines changed: 0 additions & 73 deletions
This file was deleted.

test/built-ins/JSON/parse/reviver-context-source-primitive-literal.js

Lines changed: 0 additions & 89 deletions
This file was deleted.
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// Copyright (C) 2023 the V8 project authors. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
esid: sec-json.parse
6+
description: >
7+
Context argument and its source property behave as expected
8+
info: |
9+
JSON.parse ( _text_ [ , _reviver_ ] )
10+
1. Let _jsonString_ be ? ToString(_text_).
11+
2. Let _parseResult_ be ? ParseJSON(_jsonString_).
12+
3. Let _unfiltered_ be _parseResult_.[[Value]].
13+
4. If IsCallable(_reviver_) is *true*, then
14+
a. Let _root_ be OrdinaryObjectCreate(%Object.prototype%).
15+
b. Let _rootName_ be the empty String.
16+
c. Perform ! CreateDataPropertyOrThrow(_root_, _rootName_, _unfiltered_).
17+
d. Let _snapshot_ be <emu-meta suppress-effects="user-code">CreateJSONParseRecord(_parseResult_.[[ParseNode]], _rootName_, _unfiltered_)</emu-meta>.
18+
e. Return ? InternalizeJSONProperty(_root_, _rootName_, _reviver_, _snapshot_).
19+
20+
InternalizeJSONProperty ( _holder_, _name_, _reviver_, _parseRecord_ )
21+
1. Let _val_ be ? Get(_holder_, _name_).
22+
2. Let _context_ be OrdinaryObjectCreate(%Object.prototype%).
23+
3. If _parseRecord_ is a JSON Parse Record and SameValue(_parseRecord_.[[Value]], _val_) is *true*, then
24+
a. If _val_ is not an Object, then
25+
i. Let _parseNode_ be _parseRecord_.[[ParseNode]].
26+
ii. Assert: _parseNode_ is not an |ArrayLiteral| Parse Node and not an |ObjectLiteral| Parse Node.
27+
iii. Let _sourceText_ be the source text matched by _parseNode_.
28+
iv. Perform ! CreateDataPropertyOrThrow(_context_, *"source"*, CodePointsToString(_sourceText_)).
29+
b. Let _elementRecords_ be _parseRecord_.[[Elements]].
30+
c. Let _entryRecords_ be _parseRecord_.[[Entries]].
31+
...
32+
6. Return ? Call(_reviver_, _holder_, « _name_, _val_, _context_ »).
33+
34+
includes: [compareArray.js, propertyHelper.js]
35+
features: [json-parse-with-source]
36+
---*/
37+
38+
function assertOnlyOwnProperties(object, expectNames, message) {
39+
assert.compareArray(Object.getOwnPropertyNames(object), expectNames, message);
40+
assert.compareArray(Object.getOwnPropertySymbols(object), [], message);
41+
}
42+
43+
function reviverWithExpectedSources(label, expectedSources) {
44+
var i = -1;
45+
return function reviver(key, value, context) {
46+
i++;
47+
var prefix = label + " invocation index " + i + " context ";
48+
assert.sameValue(typeof context, "object", prefix + "should be an object");
49+
assert.sameValue(Object.getPrototypeOf(context), Object.prototype,
50+
prefix + "should be a plain object");
51+
var expectedSource = expectedSources[i];
52+
if (expectedSource === undefined) {
53+
assertOnlyOwnProperties(context, [], prefix + "should have no properties");
54+
return value;
55+
}
56+
assertOnlyOwnProperties(context, ["source"], prefix + "should have a source property");
57+
assert.sameValue(context.source, expectedSource, prefix + "source");
58+
verifyProperty(context, "source", {
59+
value: expectedSource,
60+
configurable: true,
61+
enumerable: true,
62+
writable: true,
63+
});
64+
return value;
65+
};
66+
}
67+
68+
function verifyParsedPrimitive(jsonText, expectedResult) {
69+
var reviver = reviverWithExpectedSources(jsonText, [jsonText]);
70+
var parseResult = JSON.parse(' ' + jsonText + '\t', reviver);
71+
assert.sameValue(parseResult, expectedResult, jsonText);
72+
}
73+
74+
verifyParsedPrimitive('null', null);
75+
verifyParsedPrimitive('false', false);
76+
verifyParsedPrimitive('true', true);
77+
78+
verifyParsedPrimitive('""', '');
79+
verifyParsedPrimitive('"foo"', 'foo');
80+
verifyParsedPrimitive('"\\u00bD"', '\u00bd');
81+
82+
verifyParsedPrimitive('1', 1);
83+
verifyParsedPrimitive('-1', -1);
84+
verifyParsedPrimitive('-1.2', -1.2);
85+
verifyParsedPrimitive('-0', -0);
86+
verifyParsedPrimitive('1e0', 1);
87+
verifyParsedPrimitive('1E1', 10);
88+
verifyParsedPrimitive('1.23e+1', 12.3);
89+
verifyParsedPrimitive('1.23E-1', 0.123);
90+
91+
function verifyParsedArray(jsonText, expectedSources, expectedResult) {
92+
var reviver = reviverWithExpectedSources(jsonText, expectedSources);
93+
var parseResult = JSON.parse(jsonText, reviver);
94+
assert(parseResult instanceof Array, jsonText);
95+
for (var i = 0; i < parseResult.length; i++) {
96+
var element = parseResult[i];
97+
// compareArray only works with primitives, so stringify objects.
98+
if (element && typeof element === 'object') {
99+
parseResult[i] = JSON.stringify(element);
100+
}
101+
}
102+
assert.compareArray(parseResult, expectedResult, jsonText);
103+
}
104+
105+
verifyParsedArray('[ ]', [], []);
106+
verifyParsedArray('[ -1.00, -0.00, -0 ]', ['-1.00', '-0.00', '-0'], [-1, -0, -0]);
107+
verifyParsedArray(
108+
'[1e3, "2e2", "\\u00bD", null, false, true, {"x": 3e+2, "y": 0.40}, []]',
109+
['1e3', '"2e2"', '"\\u00bD"', 'null', 'false', 'true', '3e+2', '0.40'],
110+
[1000, '2e2', '\u00bd', null, false, true, '{"x":300,"y":0.4}', '[]']
111+
);
112+
113+
function verifyParsedObject(jsonText, expectedSources, expectedKeys) {
114+
var reviver = reviverWithExpectedSources(jsonText, expectedSources);
115+
var parseResult = JSON.parse(jsonText, reviver);
116+
assertOnlyOwnProperties(parseResult, expectedKeys, jsonText);
117+
return parseResult;
118+
}
119+
120+
verifyParsedObject('{}', [], []);
121+
var singleProp = verifyParsedObject('{ "42": 42E-1 }', ["42E-1"], ["42"]);
122+
assert.sameValue(singleProp['42'], 4.2, 'singleProp[onlyKey]');
123+
var deep = verifyParsedObject(
124+
'{ "x": [1.0, 2.0], "y": [{ "value": 3.0 }, 4.0] }',
125+
['1.0', '2.0', /* [1.0, 2.0] */ undefined, '3.0', /* { value: 3.0 } */ undefined, '4.0'],
126+
['x', 'y']
127+
);
128+
assert.compareArray(deep.x, [1, 2], 'deep.x');
129+
assert.sameValue(deep.y.length, 2, 'deep.y');
130+
assertOnlyOwnProperties(deep.y[0], ['value'], 'deep.y[0]');
131+
assert.sameValue(deep.y[1], 4, 'deep.y[1]');
132+
assert.sameValue(JSON.stringify(deep), '{"x":[1,2],"y":[{"value":3},4]}', 'deep');

0 commit comments

Comments
 (0)