quick-json5 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +7 -0
- package/README.md +66 -0
- package/dist/exports/Exports.d.ts +6 -0
- package/dist/exports/Exports.d.ts.map +1 -0
- package/dist/exports/Exports.js +6 -0
- package/dist/exports/Exports.js.map +1 -0
- package/dist/json/JsonEncoder.d.ts +3 -0
- package/dist/json/JsonEncoder.d.ts.map +1 -0
- package/dist/json/JsonEncoder.js +147 -0
- package/dist/json/JsonEncoder.js.map +1 -0
- package/dist/json/JsonParser.d.ts +3 -0
- package/dist/json/JsonParser.d.ts.map +1 -0
- package/dist/json/JsonParser.js +378 -0
- package/dist/json/JsonParser.js.map +1 -0
- package/dist/json5/Json5Encoder.d.ts +3 -0
- package/dist/json5/Json5Encoder.d.ts.map +1 -0
- package/dist/json5/Json5Encoder.js +155 -0
- package/dist/json5/Json5Encoder.js.map +1 -0
- package/dist/json5/Json5Parser.d.ts +3 -0
- package/dist/json5/Json5Parser.d.ts.map +1 -0
- package/dist/json5/Json5Parser.js +781 -0
- package/dist/json5/Json5Parser.js.map +1 -0
- package/dist/tests/Json5EncoderTest.d.ts +2 -0
- package/dist/tests/Json5EncoderTest.d.ts.map +1 -0
- package/dist/tests/Json5EncoderTest.js +44 -0
- package/dist/tests/Json5EncoderTest.js.map +1 -0
- package/dist/tests/Json5ParserTests.d.ts +3 -0
- package/dist/tests/Json5ParserTests.d.ts.map +1 -0
- package/dist/tests/Json5ParserTests.js +211 -0
- package/dist/tests/Json5ParserTests.js.map +1 -0
- package/dist/tests/JsonEncoderTests.d.ts +2 -0
- package/dist/tests/JsonEncoderTests.d.ts.map +1 -0
- package/dist/tests/JsonEncoderTests.js +44 -0
- package/dist/tests/JsonEncoderTests.js.map +1 -0
- package/dist/tests/JsonParserTests.d.ts +3 -0
- package/dist/tests/JsonParserTests.d.ts.map +1 -0
- package/dist/tests/JsonParserTests.js +140 -0
- package/dist/tests/JsonParserTests.js.map +1 -0
- package/dist/tests/Test.d.ts +2 -0
- package/dist/tests/Test.d.ts.map +1 -0
- package/dist/tests/Test.js +9 -0
- package/dist/tests/Test.js.map +1 -0
- package/dist/types/Types.d.ts +8 -0
- package/dist/types/Types.d.ts.map +1 -0
- package/dist/types/Types.js +2 -0
- package/dist/types/Types.js.map +1 -0
- package/dist/unused/Unused.d.ts +2 -0
- package/dist/unused/Unused.d.ts.map +1 -0
- package/dist/unused/Unused.js +47 -0
- package/dist/unused/Unused.js.map +1 -0
- package/dist/utilities/JsonParseError.d.ts +7 -0
- package/dist/utilities/JsonParseError.d.ts.map +1 -0
- package/dist/utilities/JsonParseError.js +10 -0
- package/dist/utilities/JsonParseError.js.map +1 -0
- package/dist/utilities/ObjectUtilities.d.ts +2 -0
- package/dist/utilities/ObjectUtilities.d.ts.map +1 -0
- package/dist/utilities/ObjectUtilities.js +142 -0
- package/dist/utilities/ObjectUtilities.js.map +1 -0
- package/dist/utilities/TypedArray.d.ts +4 -0
- package/dist/utilities/TypedArray.d.ts.map +1 -0
- package/dist/utilities/TypedArray.js +2 -0
- package/dist/utilities/TypedArray.js.map +1 -0
- package/dist/utilities/Utilities.d.ts +17 -0
- package/dist/utilities/Utilities.d.ts.map +1 -0
- package/dist/utilities/Utilities.js +97 -0
- package/dist/utilities/Utilities.js.map +1 -0
- package/package.json +38 -0
- package/src/exports/Exports.ts +7 -0
- package/src/json/JsonEncoder.ts +180 -0
- package/src/json/JsonParser.ts +491 -0
- package/src/json5/Json5Encoder.ts +189 -0
- package/src/json5/Json5Parser.ts +959 -0
- package/src/tests/Json5EncoderTest.ts +51 -0
- package/src/tests/Json5ParserTests.ts +237 -0
- package/src/tests/JsonEncoderTests.ts +51 -0
- package/src/tests/JsonParserTests.ts +159 -0
- package/src/tests/Test.ts +13 -0
- package/src/types/Types.ts +9 -0
- package/src/unused/Unused.ts +51 -0
- package/src/utilities/JsonParseError.ts +7 -0
- package/src/utilities/ObjectUtilities.ts +184 -0
- package/src/utilities/TypedArray.ts +39 -0
- package/src/utilities/Utilities.ts +130 -0
- package/tsconfig.json +55 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright (c) 2026 Rotem Dan
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Quick JSON5
|
|
2
|
+
|
|
3
|
+
Fast JSON5 parser and serializer.
|
|
4
|
+
|
|
5
|
+
* Written in pure TypeScript (JavaScript)
|
|
6
|
+
* Parses up to 10x faster than reference JSON5 implementation
|
|
7
|
+
* Tested for 100% compliance with the official [JSON5 specification](https://spec.json5.org/)
|
|
8
|
+
* Fully supports `replacer` and `space` properties in `stringify`, and `reviver` in `parse` (including the new `context` callback argument)
|
|
9
|
+
* Support several extensions to the JSON5 standard (optional)
|
|
10
|
+
* Improved validation and error reporting. Errors embed machine-readable positional metadata
|
|
11
|
+
* No external dependencies
|
|
12
|
+
|
|
13
|
+
## Support for extended numeric literals, beyond JSON5 (optional)
|
|
14
|
+
|
|
15
|
+
Parser also supports additional numeric literal syntax added in later versions of ECMAScript:
|
|
16
|
+
|
|
17
|
+
* Octal literals (`0o1234567`), and binary literals (`0b1001011`). Introduced in ES2015
|
|
18
|
+
* `BigInt` numeric literals (`123412341234n`). Introduced in ES2020
|
|
19
|
+
* Underscore separators in numeric literals (`123_456_789`, `123.456_789`, `0b0110_1101`). Introduced in ES2021
|
|
20
|
+
|
|
21
|
+
Enabling these extensions requires the `enableExtensions` option to be set to `true` in the `options` argument for `parse` and `stringify`.
|
|
22
|
+
|
|
23
|
+
## Extra: Plain JSON parser and serializer
|
|
24
|
+
|
|
25
|
+
As an extra, also includes an optimized pure JavaScript JSON parser and serializer, with performance approaching to the native `JSON.parse` and `JSON.stringify`.
|
|
26
|
+
|
|
27
|
+
The alternative parser can be useful when detailed metadata is required when handling errors. For example when implementing a syntax checker that needs to highlight the location of errors in the JSON file.
|
|
28
|
+
|
|
29
|
+
You can also use the source code as a starting point for implementing various custom JSON extensions, like adding support for comments (AKA "JSON with comments").
|
|
30
|
+
|
|
31
|
+
## Usage examples
|
|
32
|
+
|
|
33
|
+
Installation:
|
|
34
|
+
```
|
|
35
|
+
npm install quick-json5
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
JSON5 serializer and parser:
|
|
39
|
+
```ts
|
|
40
|
+
import * as JSON5 from 'quick-json5'
|
|
41
|
+
|
|
42
|
+
const json5Str = JSON5.stringify({ 'hello': 123 })
|
|
43
|
+
const parsedObject = JSON5.parse(json5Str)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
JSON5 serializer and parser with extensions enabled:
|
|
47
|
+
```ts
|
|
48
|
+
import * as JSON5 from 'quick-json5'
|
|
49
|
+
|
|
50
|
+
const options = { enableExtensions: true }
|
|
51
|
+
|
|
52
|
+
const json5Str = JSON5.stringify({ 'hello': 12356123456123456n }, undefined, 4, options)
|
|
53
|
+
const parsedObject = JSON5.parse(json5Str, undefined, options)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Plain JSON serializer and parser:
|
|
57
|
+
```ts
|
|
58
|
+
import * as JSON5 from 'quick-json5'
|
|
59
|
+
|
|
60
|
+
const jsonStr = JSON5.stringifyJSON({ 'hello': 123 })
|
|
61
|
+
const parsedObject = JSON5.parseJSON(jsonStr)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## License
|
|
65
|
+
|
|
66
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Exports.d.ts","sourceRoot":"","sources":["../../src/exports/Exports.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AAEvC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AAErC,cAAc,mBAAmB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Exports.js","sourceRoot":"","sources":["../../src/exports/Exports.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AAEvC,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AAErC,cAAc,mBAAmB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsonEncoder.d.ts","sourceRoot":"","sources":["../../src/json/JsonEncoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAG1E,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,gBAAgB,EAAE,KAAK,SAAI,OAsI7E"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { charCodeToHex } from '../utilities/Utilities.js';
|
|
2
|
+
export function stringifyJSON(obj, replacer, space = 0) {
|
|
3
|
+
let replacerFunc;
|
|
4
|
+
if (replacer != null) {
|
|
5
|
+
if (Array.isArray(replacer)) {
|
|
6
|
+
const replacerSet = new Set();
|
|
7
|
+
for (const key of replacer) {
|
|
8
|
+
replacerSet.add(String(key));
|
|
9
|
+
}
|
|
10
|
+
replacerFunc = (key, value) => {
|
|
11
|
+
if (replacerSet.has(key)) {
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
else if (typeof replacer === 'function') {
|
|
17
|
+
replacerFunc = replacer;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
throw new TypeError('Invalid replacer argument.');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const baseIndentString = ' '.repeat(space);
|
|
24
|
+
let currentIndentLevel = 0;
|
|
25
|
+
function getIndentString() {
|
|
26
|
+
if (space === 0) {
|
|
27
|
+
return '';
|
|
28
|
+
}
|
|
29
|
+
const spaces = baseIndentString.repeat(currentIndentLevel);
|
|
30
|
+
return `\n${spaces}`;
|
|
31
|
+
}
|
|
32
|
+
function encode(obj) {
|
|
33
|
+
if (obj === undefined) {
|
|
34
|
+
return '';
|
|
35
|
+
}
|
|
36
|
+
const typeofObj = typeof obj;
|
|
37
|
+
if (obj === null || typeofObj === 'boolean') {
|
|
38
|
+
return String(obj);
|
|
39
|
+
}
|
|
40
|
+
if (typeofObj === 'number') {
|
|
41
|
+
if (isNaN(obj) || obj === Infinity || obj === -Infinity) {
|
|
42
|
+
throw new Error(`NaN and Infinity can't be encoded in JSON`);
|
|
43
|
+
}
|
|
44
|
+
return String(obj);
|
|
45
|
+
}
|
|
46
|
+
if (typeofObj === 'string') {
|
|
47
|
+
return `"${escapeStringIfNeeded(obj)}"`;
|
|
48
|
+
}
|
|
49
|
+
if (typeof obj !== 'object') {
|
|
50
|
+
throw new Error(`Type '${typeof obj}' cannot be encoded in JSON`);
|
|
51
|
+
}
|
|
52
|
+
if (typeof obj.toJSON === 'function') {
|
|
53
|
+
return obj.toJSON();
|
|
54
|
+
}
|
|
55
|
+
if (Array.isArray(obj)) {
|
|
56
|
+
let str = '[';
|
|
57
|
+
let isFirstElement = true;
|
|
58
|
+
for (let i = 0; i < obj.length; i++) {
|
|
59
|
+
const element = obj[i];
|
|
60
|
+
if (element === undefined) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
currentIndentLevel += 1;
|
|
64
|
+
const saparatingComma = isFirstElement === true ? '' : ',';
|
|
65
|
+
const indentString = getIndentString();
|
|
66
|
+
const encodedElement = encode(element);
|
|
67
|
+
str += `${saparatingComma}${indentString}${encodedElement}`;
|
|
68
|
+
currentIndentLevel -= 1;
|
|
69
|
+
isFirstElement = false;
|
|
70
|
+
}
|
|
71
|
+
str += `${getIndentString()}]`;
|
|
72
|
+
return str;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
let str = '{';
|
|
76
|
+
let isFirstEntry = true;
|
|
77
|
+
for (const key in obj) {
|
|
78
|
+
let value = obj[key];
|
|
79
|
+
if (replacerFunc !== undefined) {
|
|
80
|
+
value = replacerFunc(key, value);
|
|
81
|
+
}
|
|
82
|
+
if (value === undefined) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
currentIndentLevel += 1;
|
|
86
|
+
const saparatingComma = isFirstEntry === true ? '' : ',';
|
|
87
|
+
const indentString = getIndentString();
|
|
88
|
+
const escapedKey = escapeStringIfNeeded(key);
|
|
89
|
+
const spaceAfterColons = space > 0 ? ' ' : '';
|
|
90
|
+
const encodedValue = encode(value);
|
|
91
|
+
str += `${saparatingComma}${indentString}"${escapedKey}":${spaceAfterColons}${encodedValue}`;
|
|
92
|
+
currentIndentLevel -= 1;
|
|
93
|
+
isFirstEntry = false;
|
|
94
|
+
}
|
|
95
|
+
str += `${getIndentString()}}`;
|
|
96
|
+
return str;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return encode(obj);
|
|
100
|
+
}
|
|
101
|
+
function escapeStringIfNeeded(str) {
|
|
102
|
+
if (!/["\\\x00-\x1F]/.test(str)) {
|
|
103
|
+
return str;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
return escapeString(str);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function escapeString(str) {
|
|
110
|
+
let escapedStr = '';
|
|
111
|
+
for (let i = 0; i < str.length; i++) {
|
|
112
|
+
const charCode = str.charCodeAt(i);
|
|
113
|
+
if (charCode >= 32) {
|
|
114
|
+
if (charCode === 34) { // '"'
|
|
115
|
+
escapedStr += '\\"';
|
|
116
|
+
}
|
|
117
|
+
else if (charCode === 92) { // '\\'
|
|
118
|
+
escapedStr += '\\\\';
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
escapedStr += String.fromCharCode(charCode);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
if (charCode === 10) { // '\n'
|
|
126
|
+
escapedStr += '\\n';
|
|
127
|
+
}
|
|
128
|
+
else if (charCode === 13) { // '\r'
|
|
129
|
+
escapedStr += '\\r';
|
|
130
|
+
}
|
|
131
|
+
else if (charCode === 9) { // '\t'
|
|
132
|
+
escapedStr += '\\t';
|
|
133
|
+
}
|
|
134
|
+
else if (charCode === 12) { // '\f'
|
|
135
|
+
escapedStr += '\\f';
|
|
136
|
+
}
|
|
137
|
+
else if (charCode === 8) { // '\b'
|
|
138
|
+
escapedStr += '\\b';
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
escapedStr += `\\u${charCodeToHex(charCode)}`;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return escapedStr;
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=JsonEncoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsonEncoder.js","sourceRoot":"","sources":["../../src/json/JsonEncoder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsonParser.d.ts","sourceRoot":"","sources":["../../src/json/JsonParser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAIvD,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,OAse1E"}
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import { JsonParserError } from '../utilities/JsonParseError.js';
|
|
2
|
+
import { getPositionInfo, hexCharCodeToNumber, positivePowersOf10 } from '../utilities/Utilities.js';
|
|
3
|
+
export function parseJSON(jsonString, reviver) {
|
|
4
|
+
if (typeof jsonString !== 'string') {
|
|
5
|
+
throw new TypeError(`Given JSON string argument is not a string.`);
|
|
6
|
+
}
|
|
7
|
+
if (reviver !== undefined && typeof reviver !== 'function') {
|
|
8
|
+
throw new TypeError(`Reviver can only be a function.`);
|
|
9
|
+
}
|
|
10
|
+
let readPosition = 0;
|
|
11
|
+
function parse(initialCharCode) {
|
|
12
|
+
////////////////////////////////////////////////////////////////////////////////////////////
|
|
13
|
+
// Parse string
|
|
14
|
+
////////////////////////////////////////////////////////////////////////////////////////////
|
|
15
|
+
if (initialCharCode === 34) { // '"' for string start
|
|
16
|
+
readPosition += 1;
|
|
17
|
+
// Try to quickly parse the string for the common case where there are no escape patterns
|
|
18
|
+
{
|
|
19
|
+
const match = jsonString.substring(readPosition).match(/^[^\\\x00-\x1F]*?"/);
|
|
20
|
+
if (match !== null) {
|
|
21
|
+
const matchString = match[0];
|
|
22
|
+
const str = matchString.substring(0, matchString.length - 1);
|
|
23
|
+
readPosition += matchString.length;
|
|
24
|
+
return str;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Fallback to slower method if an escape pattern is found or string is unterminated.
|
|
28
|
+
let decodedString = '';
|
|
29
|
+
while (true) {
|
|
30
|
+
const charCode = readCharCodeAndAdvance();
|
|
31
|
+
if (charCode === 34) { // '"'
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
else if (charCode === 92) { // '\\'
|
|
35
|
+
const escapedCharCharcode = readCharCodeAndAdvance();
|
|
36
|
+
if (escapedCharCharcode <= 92) {
|
|
37
|
+
if (escapedCharCharcode === 34 || escapedCharCharcode === 92 || escapedCharCharcode === 47) { // '"', '\' and '/'
|
|
38
|
+
decodedString += String.fromCharCode(escapedCharCharcode);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const positionInfo = getInfoForPosition(readPosition - 2);
|
|
42
|
+
throw new JsonParserError(`Invalid escaped character '${String.fromCharCode(escapedCharCharcode)}' in escape sequence starting at ${positionInfo.positionString}.`, positionInfo);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else if (escapedCharCharcode === 110) { // 'n'
|
|
46
|
+
decodedString += '\n';
|
|
47
|
+
}
|
|
48
|
+
else if (escapedCharCharcode === 114) { // 'r'
|
|
49
|
+
decodedString += '\r';
|
|
50
|
+
}
|
|
51
|
+
else if (escapedCharCharcode === 116) { // 't'
|
|
52
|
+
decodedString += '\t';
|
|
53
|
+
}
|
|
54
|
+
else if (escapedCharCharcode === 117) { // 'u'
|
|
55
|
+
if (readPosition + 4 > jsonString.length) {
|
|
56
|
+
const positionInfo = getInfoForCurrentReadPosition();
|
|
57
|
+
throw new JsonParserError(`Unterminated hexadecimal sequence. Expected 4 hexadecimal characters at ${positionInfo.positionString}.`, positionInfo);
|
|
58
|
+
}
|
|
59
|
+
const codePoint = hexCharCodeToNumber(jsonString.charCodeAt(readPosition + 0)) << 12 |
|
|
60
|
+
hexCharCodeToNumber(jsonString.charCodeAt(readPosition + 1)) << 8 |
|
|
61
|
+
hexCharCodeToNumber(jsonString.charCodeAt(readPosition + 2)) << 4 |
|
|
62
|
+
hexCharCodeToNumber(jsonString.charCodeAt(readPosition + 3));
|
|
63
|
+
decodedString += String.fromCharCode(codePoint);
|
|
64
|
+
readPosition += 4;
|
|
65
|
+
}
|
|
66
|
+
else if (escapedCharCharcode === 102) { // 'f'
|
|
67
|
+
decodedString += '\f';
|
|
68
|
+
}
|
|
69
|
+
else if (escapedCharCharcode === 98) { // 'b'
|
|
70
|
+
decodedString += '\b';
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
const positionInfo = getInfoForPosition(readPosition - 2);
|
|
74
|
+
throw new JsonParserError(`Invalid escaped character '${String.fromCharCode(escapedCharCharcode)}' in escape sequence at ${positionInfo.positionString}.`, positionInfo);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else if (charCode === undefined) {
|
|
78
|
+
const positionInfo = getInfoForPosition(jsonString.length - 1);
|
|
79
|
+
throw new JsonParserError(`Unterminated string literal.`, positionInfo);
|
|
80
|
+
}
|
|
81
|
+
else if (charCode < 32) {
|
|
82
|
+
const positionInfo = getInfoForPosition(readPosition - 1);
|
|
83
|
+
throw new JsonParserError(`Invalid unescaped control character (${charCode}) at ${positionInfo.positionString}.`, positionInfo);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
decodedString += String.fromCharCode(charCode);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return decodedString;
|
|
90
|
+
}
|
|
91
|
+
////////////////////////////////////////////////////////////////////////////////////////////
|
|
92
|
+
// Parse number
|
|
93
|
+
////////////////////////////////////////////////////////////////////////////////////////////
|
|
94
|
+
if (initialCharCode < 91) { // '0'-'9' or '-' for number start
|
|
95
|
+
let numberStringStartPosition = readPosition;
|
|
96
|
+
let charCode = initialCharCode;
|
|
97
|
+
let isNegative;
|
|
98
|
+
if (charCode === 45) { // '-'
|
|
99
|
+
isNegative = true;
|
|
100
|
+
charCode = advanceAndReadCharCode();
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
isNegative = false;
|
|
104
|
+
}
|
|
105
|
+
let concatenatedInteger = 0;
|
|
106
|
+
// Parse integer part
|
|
107
|
+
{
|
|
108
|
+
const digitsStartPosition = readPosition;
|
|
109
|
+
while (charCode >= 48 && charCode <= 57) { // '0'-'9'
|
|
110
|
+
const digitValue = charCode - 48;
|
|
111
|
+
concatenatedInteger = (concatenatedInteger * 10) + digitValue;
|
|
112
|
+
charCode = advanceAndReadCharCode();
|
|
113
|
+
}
|
|
114
|
+
const integerPartDigitCount = readPosition - digitsStartPosition;
|
|
115
|
+
if (integerPartDigitCount === 0) {
|
|
116
|
+
const positionInfo = getInfoForCurrentReadPosition();
|
|
117
|
+
throw new JsonParserError(`Invalid character '${String.fromCharCode(charCode)}' at ${positionInfo.positionString}.`, positionInfo);
|
|
118
|
+
}
|
|
119
|
+
if (integerPartDigitCount > 1 && jsonString[digitsStartPosition] === '0') {
|
|
120
|
+
const positionInfo = getInfoForPosition(digitsStartPosition);
|
|
121
|
+
throw new JsonParserError(`Invalid leading zero found in number literal at ${positionInfo.positionString}.`, positionInfo);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
let fractionalDigitCount = 0;
|
|
125
|
+
// Parse fractional part
|
|
126
|
+
if (charCode === 46) { // '.'
|
|
127
|
+
charCode = advanceAndReadCharCode();
|
|
128
|
+
const digitsStartPosition = readPosition;
|
|
129
|
+
while (charCode >= 48 && charCode <= 57) { // '0'-'9'
|
|
130
|
+
const digitValue = charCode - 48;
|
|
131
|
+
concatenatedInteger = (concatenatedInteger * 10) + digitValue;
|
|
132
|
+
charCode = advanceAndReadCharCode();
|
|
133
|
+
}
|
|
134
|
+
fractionalDigitCount = readPosition - digitsStartPosition;
|
|
135
|
+
if (fractionalDigitCount === 0) {
|
|
136
|
+
const positionInfo = getInfoForCurrentReadPosition();
|
|
137
|
+
throw new JsonParserError(`Invalid character '${String.fromCharCode(charCode)}' at ${positionInfo.positionString}. Exepcted at least one decimal digit following '.'.`, positionInfo);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
let exponent = 0;
|
|
141
|
+
// Parse exponent part
|
|
142
|
+
if (charCode === 101 || charCode === 69) { // 'e' or 'E'
|
|
143
|
+
charCode = advanceAndReadCharCode();
|
|
144
|
+
let isNegativeExponent = false;
|
|
145
|
+
if (charCode === 43) { // '+'
|
|
146
|
+
charCode = advanceAndReadCharCode();
|
|
147
|
+
}
|
|
148
|
+
else if (charCode === 45) { // '-'
|
|
149
|
+
isNegativeExponent = true;
|
|
150
|
+
charCode = advanceAndReadCharCode();
|
|
151
|
+
}
|
|
152
|
+
let exponentDigitsStartPosition = readPosition;
|
|
153
|
+
while (charCode >= 48 && charCode <= 57) { // '0'-'9'
|
|
154
|
+
const digitValue = charCode - 48;
|
|
155
|
+
exponent = (exponent * 10) + digitValue;
|
|
156
|
+
charCode = advanceAndReadCharCode();
|
|
157
|
+
}
|
|
158
|
+
if (readPosition === exponentDigitsStartPosition) {
|
|
159
|
+
const positionInfo = getInfoForCurrentReadPosition();
|
|
160
|
+
throw new JsonParserError(`Invalid character '${String.fromCharCode(charCode)}' at ${positionInfo.positionString}. Exepcted at least one exponent digit.`, positionInfo);
|
|
161
|
+
}
|
|
162
|
+
if (isNegativeExponent) {
|
|
163
|
+
exponent = -exponent;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const adjustedExponent = exponent - fractionalDigitCount;
|
|
167
|
+
// Use fast method for cases where the number can be parsed efficiently,
|
|
168
|
+
// or fall back to slower method if not possible.
|
|
169
|
+
if (concatenatedInteger < 2 ** 53 && adjustedExponent >= -22 && adjustedExponent <= 22) {
|
|
170
|
+
let parsedNumber = concatenatedInteger;
|
|
171
|
+
if (adjustedExponent > 0) {
|
|
172
|
+
parsedNumber *= positivePowersOf10[adjustedExponent];
|
|
173
|
+
}
|
|
174
|
+
else if (adjustedExponent < 0) {
|
|
175
|
+
parsedNumber /= positivePowersOf10[-adjustedExponent];
|
|
176
|
+
}
|
|
177
|
+
if (isNegative) {
|
|
178
|
+
return -parsedNumber;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
return parsedNumber;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
return Number(jsonString.substring(numberStringStartPosition, readPosition));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
////////////////////////////////////////////////////////////////////////////////////////////
|
|
189
|
+
// Parse 'true' literal
|
|
190
|
+
////////////////////////////////////////////////////////////////////////////////////////////
|
|
191
|
+
if (initialCharCode === 116) { // 't' for true
|
|
192
|
+
if (jsonString.charCodeAt(readPosition + 1) !== 114 || // 'r'
|
|
193
|
+
jsonString.charCodeAt(readPosition + 2) !== 117 || // 'u'
|
|
194
|
+
jsonString.charCodeAt(readPosition + 3) !== 101) { // 'e'
|
|
195
|
+
const positionInfo = getInfoForCurrentReadPosition();
|
|
196
|
+
throw new JsonParserError(`Expected 'true' at ${positionInfo.positionString}.`, positionInfo);
|
|
197
|
+
}
|
|
198
|
+
readPosition += 4;
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
////////////////////////////////////////////////////////////////////////////////////////////
|
|
202
|
+
// Parse 'false' literal
|
|
203
|
+
////////////////////////////////////////////////////////////////////////////////////////////
|
|
204
|
+
if (initialCharCode === 102) { // 'f' for false
|
|
205
|
+
if (jsonString.charCodeAt(readPosition + 1) !== 97 || // 'a'
|
|
206
|
+
jsonString.charCodeAt(readPosition + 2) !== 108 || // 'l'
|
|
207
|
+
jsonString.charCodeAt(readPosition + 3) !== 115 || // 's'
|
|
208
|
+
jsonString.charCodeAt(readPosition + 4) !== 101) { // 'e'
|
|
209
|
+
const positionInfo = getInfoForCurrentReadPosition();
|
|
210
|
+
throw new JsonParserError(`Expected 'false' at ${positionInfo.positionString}.`, positionInfo);
|
|
211
|
+
}
|
|
212
|
+
readPosition += 5;
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
////////////////////////////////////////////////////////////////////////////////////////////
|
|
216
|
+
// Parse 'null' literal
|
|
217
|
+
////////////////////////////////////////////////////////////////////////////////////////////
|
|
218
|
+
if (initialCharCode === 110) { // 'n' for null
|
|
219
|
+
if (jsonString.charCodeAt(readPosition + 1) !== 117 || // 'u'
|
|
220
|
+
jsonString.charCodeAt(readPosition + 2) !== 108 || // 'l'
|
|
221
|
+
jsonString.charCodeAt(readPosition + 3) !== 108) { // 'l'
|
|
222
|
+
const positionInfo = getInfoForCurrentReadPosition();
|
|
223
|
+
throw new JsonParserError(`Expected 'null' at ${positionInfo.positionString}.`, positionInfo);
|
|
224
|
+
}
|
|
225
|
+
readPosition += 4;
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
////////////////////////////////////////////////////////////////////////////////////////////
|
|
229
|
+
// Parse array
|
|
230
|
+
////////////////////////////////////////////////////////////////////////////////////////////
|
|
231
|
+
if (initialCharCode === 91) { // '[' for array start
|
|
232
|
+
readPosition += 1;
|
|
233
|
+
let charCode = skipToNextReadableCharCode();
|
|
234
|
+
if (charCode === 93) { // ']' for array end
|
|
235
|
+
readPosition += 1;
|
|
236
|
+
return [];
|
|
237
|
+
}
|
|
238
|
+
const arr = [];
|
|
239
|
+
while (true) {
|
|
240
|
+
const elementStartPosition = readPosition;
|
|
241
|
+
let element = parse(charCode);
|
|
242
|
+
if (reviver !== undefined) {
|
|
243
|
+
element = applyReviver('', element, elementStartPosition);
|
|
244
|
+
}
|
|
245
|
+
arr.push(element);
|
|
246
|
+
charCode = skipToNextReadableCharCode();
|
|
247
|
+
if (charCode === 44) { // ',' for comma
|
|
248
|
+
readPosition += 1;
|
|
249
|
+
charCode = skipToNextReadableCharCode();
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (charCode === 93) { // ']' for array end
|
|
253
|
+
readPosition += 1;
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
{
|
|
257
|
+
const positionInfo = getInfoForCurrentReadPosition();
|
|
258
|
+
throw new JsonParserError(`Invalid character '${String.fromCharCode(charCode)}' in array expression at ${positionInfo.positionString}. Expected ',' or ']'.`, positionInfo);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return arr;
|
|
262
|
+
}
|
|
263
|
+
////////////////////////////////////////////////////////////////////////////////////////////
|
|
264
|
+
// Parse object
|
|
265
|
+
////////////////////////////////////////////////////////////////////////////////////////////
|
|
266
|
+
if (initialCharCode === 123) { // '{' for object start
|
|
267
|
+
readPosition += 1;
|
|
268
|
+
let charCode = skipToNextReadableCharCode();
|
|
269
|
+
if (charCode === 125) { // '}' for object end
|
|
270
|
+
readPosition += 1;
|
|
271
|
+
return {};
|
|
272
|
+
}
|
|
273
|
+
const obj = {};
|
|
274
|
+
while (true) {
|
|
275
|
+
if (charCode !== 34) {
|
|
276
|
+
const positionInfo = getInfoForCurrentReadPosition();
|
|
277
|
+
throw new JsonParserError(`Invalid character '${String.fromCharCode(charCode)}' at ${positionInfo.positionString}. Expected '"'.`, positionInfo);
|
|
278
|
+
}
|
|
279
|
+
const key = parse(charCode);
|
|
280
|
+
charCode = skipToNextReadableCharCode();
|
|
281
|
+
if (charCode !== 58) { // ':'
|
|
282
|
+
const positionInfo = getInfoForCurrentReadPosition();
|
|
283
|
+
throw new JsonParserError(`Invalid character '${String.fromCharCode(charCode)}' at ${positionInfo.positionString}. Expected ':'.`, positionInfo);
|
|
284
|
+
}
|
|
285
|
+
readPosition += 1;
|
|
286
|
+
charCode = skipToNextReadableCharCode();
|
|
287
|
+
const valueStartPosition = readPosition;
|
|
288
|
+
let value = parse(charCode);
|
|
289
|
+
if (reviver !== undefined) {
|
|
290
|
+
value = applyReviver(key, value, valueStartPosition, obj);
|
|
291
|
+
}
|
|
292
|
+
obj[key] = value;
|
|
293
|
+
const commaOrClosingBraceCharCode = skipToNextReadableCharCode();
|
|
294
|
+
if (commaOrClosingBraceCharCode === 44) { // ','
|
|
295
|
+
readPosition += 1;
|
|
296
|
+
charCode = skipToNextReadableCharCode();
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
if (commaOrClosingBraceCharCode === 125) { // '}'
|
|
300
|
+
readPosition += 1;
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
{
|
|
304
|
+
const positionInfo = getInfoForCurrentReadPosition();
|
|
305
|
+
throw new JsonParserError(`Invalid character '${String.fromCharCode(commaOrClosingBraceCharCode)}' in object expression at ${positionInfo.positionString}. Expected ',' or '}'.`, positionInfo);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return obj;
|
|
309
|
+
}
|
|
310
|
+
{
|
|
311
|
+
const positionInfo = getInfoForCurrentReadPosition();
|
|
312
|
+
throw new JsonParserError(`Invalid character '${String.fromCharCode(initialCharCode)}' at ${positionInfo.positionString}.`, positionInfo);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
function advanceAndReadCharCode() {
|
|
316
|
+
return jsonString.charCodeAt(++readPosition);
|
|
317
|
+
}
|
|
318
|
+
function readCharCodeAndAdvance() {
|
|
319
|
+
return jsonString.charCodeAt(readPosition++);
|
|
320
|
+
}
|
|
321
|
+
function skipWhitespace() {
|
|
322
|
+
while (readPosition < jsonString.length) {
|
|
323
|
+
const charCode = jsonString.charCodeAt(readPosition);
|
|
324
|
+
if (charCode > 32 || (charCode !== 32 && charCode !== 10 && charCode !== 13 && charCode !== 9)) {
|
|
325
|
+
return charCode;
|
|
326
|
+
}
|
|
327
|
+
readPosition += 1;
|
|
328
|
+
}
|
|
329
|
+
return undefined;
|
|
330
|
+
}
|
|
331
|
+
function skipToNextReadableCharCode() {
|
|
332
|
+
const nextCharCode = skipWhitespace();
|
|
333
|
+
if (nextCharCode === undefined) {
|
|
334
|
+
const positionInfo = getInfoForPosition(jsonString.length - 1);
|
|
335
|
+
throw new JsonParserError(`Unexpected termination of JSON input.`, positionInfo);
|
|
336
|
+
}
|
|
337
|
+
return nextCharCode;
|
|
338
|
+
}
|
|
339
|
+
function getInfoForCurrentReadPosition() {
|
|
340
|
+
return getInfoForPosition(readPosition);
|
|
341
|
+
}
|
|
342
|
+
function getInfoForPosition(position) {
|
|
343
|
+
return getPositionInfo(jsonString, position);
|
|
344
|
+
}
|
|
345
|
+
function applyReviver(key, value, valueStartPosition, thisArg) {
|
|
346
|
+
if (reviver === undefined) {
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
let context;
|
|
350
|
+
if (typeof value !== 'object' || value === null) {
|
|
351
|
+
context = jsonString.substring(valueStartPosition, readPosition);
|
|
352
|
+
}
|
|
353
|
+
let result;
|
|
354
|
+
if (thisArg) {
|
|
355
|
+
result = reviver.call(thisArg, key, value, context);
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
result = reviver(key, value, context);
|
|
359
|
+
}
|
|
360
|
+
return result;
|
|
361
|
+
}
|
|
362
|
+
// Parse the given string
|
|
363
|
+
{
|
|
364
|
+
const initialCharCode = skipToNextReadableCharCode();
|
|
365
|
+
const documentStartPosition = readPosition;
|
|
366
|
+
let result = parse(initialCharCode);
|
|
367
|
+
if (reviver !== undefined) {
|
|
368
|
+
result = applyReviver('', result, documentStartPosition);
|
|
369
|
+
}
|
|
370
|
+
const finalSkipResult = skipWhitespace();
|
|
371
|
+
if (finalSkipResult !== undefined) {
|
|
372
|
+
const positionInfo = getInfoForCurrentReadPosition();
|
|
373
|
+
throw new JsonParserError(`Unexpected trailing character(s) starting at ${positionInfo.positionString}.`, positionInfo);
|
|
374
|
+
}
|
|
375
|
+
return result;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
//# sourceMappingURL=JsonParser.js.map
|