@bhsd/common 1.2.0 → 1.3.1
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/dist/index.d.ts +5 -0
- package/dist/index.js +21 -10
- package/dist/index.mjs +81 -56
- package/dist/json_parse.js +61 -45
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,11 @@ declare interface JsonError {
|
|
|
3
3
|
message: string;
|
|
4
4
|
line: number;
|
|
5
5
|
column: number;
|
|
6
|
+
endLine?: number;
|
|
7
|
+
endColumn?: number;
|
|
8
|
+
from: number;
|
|
9
|
+
to?: number;
|
|
10
|
+
/** @deprecated */
|
|
6
11
|
position: number;
|
|
7
12
|
}
|
|
8
13
|
export type RegexGetter<T = string> = (s: T) => RegExp;
|
package/dist/index.js
CHANGED
|
@@ -51,7 +51,8 @@ exports.splitColors = splitColors;
|
|
|
51
51
|
* 清理内联样式中的`{`和`}`
|
|
52
52
|
* @param style 内联样式
|
|
53
53
|
*/
|
|
54
|
-
const sanitizeInlineStyle = (style) => style.replace(/[{}]/gu, p => p === '{' ? '{' : '}')
|
|
54
|
+
const sanitizeInlineStyle = (style) => style.replace(/[{}]/gu, p => p === '{' ? '{' : '}')
|
|
55
|
+
.replace(/^[\s;]+/u, p => p.replace(/;/gu, ' '));
|
|
55
56
|
exports.sanitizeInlineStyle = sanitizeInlineStyle;
|
|
56
57
|
function getRegex(f) {
|
|
57
58
|
const map = new Map(), weakMap = new WeakMap();
|
|
@@ -91,25 +92,35 @@ exports.splitLines = splitLines;
|
|
|
91
92
|
const mt2num = (mt) => mt && Number(mt[1]);
|
|
92
93
|
const formatJsonError = (str, errors) => {
|
|
93
94
|
let lines;
|
|
95
|
+
const offsetToPosition = (offset) => {
|
|
96
|
+
lines ??= (0, exports.splitLines)(str);
|
|
97
|
+
const line = lines.findIndex(([, , end]) => offset <= end) + 1;
|
|
98
|
+
return {
|
|
99
|
+
line,
|
|
100
|
+
column: offset - lines[line - 1][1] + 1,
|
|
101
|
+
};
|
|
102
|
+
};
|
|
94
103
|
for (const error of errors) {
|
|
95
|
-
const { line, column,
|
|
96
|
-
if (
|
|
104
|
+
const { line, column, from, to } = error;
|
|
105
|
+
if (from === null || from === undefined) {
|
|
97
106
|
if (line) {
|
|
98
107
|
lines ??= (0, exports.splitLines)(str);
|
|
99
108
|
error.column ??= 1;
|
|
100
|
-
error.
|
|
109
|
+
error.from = lines[line - 1][1] + (error.column - 1);
|
|
101
110
|
}
|
|
102
111
|
else {
|
|
103
|
-
error.
|
|
112
|
+
error.from = 0;
|
|
104
113
|
error.line = 1;
|
|
105
114
|
error.column = 1;
|
|
106
115
|
}
|
|
107
116
|
}
|
|
108
117
|
else if (!line || !column) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
118
|
+
Object.assign(error, offsetToPosition(from));
|
|
119
|
+
}
|
|
120
|
+
if (to !== undefined) {
|
|
121
|
+
({ line: error.endLine, column: error.endColumn } = offsetToPosition(to));
|
|
112
122
|
}
|
|
123
|
+
error.position = error.from;
|
|
113
124
|
}
|
|
114
125
|
return errors;
|
|
115
126
|
};
|
|
@@ -124,8 +135,8 @@ const lintJSONNative = (str, force) => {
|
|
|
124
135
|
JSON.parse(str);
|
|
125
136
|
}
|
|
126
137
|
catch (e) {
|
|
127
|
-
const { message } = e, line = mt2num(/\bline (\d+)/u.exec(message)), column = mt2num(/\bcolumn (\d+)/u.exec(message)),
|
|
128
|
-
return formatJsonError(str, [{ message, line, column,
|
|
138
|
+
const { message } = e, line = mt2num(/\bline (\d+)/u.exec(message)), column = mt2num(/\bcolumn (\d+)/u.exec(message)), from = mt2num(/\bposition (\d+)/u.exec(message));
|
|
139
|
+
return formatJsonError(str, [{ message, line, column, from, severity: 'error' }]);
|
|
129
140
|
}
|
|
130
141
|
}
|
|
131
142
|
return [];
|
package/dist/index.mjs
CHANGED
|
@@ -1,52 +1,62 @@
|
|
|
1
1
|
// src/json_parse.ts
|
|
2
|
+
var escapee = {
|
|
3
|
+
'"': '"',
|
|
4
|
+
"\\": "\\",
|
|
5
|
+
"/": "/",
|
|
6
|
+
b: "\b",
|
|
7
|
+
f: "\f",
|
|
8
|
+
n: "\n",
|
|
9
|
+
r: "\r",
|
|
10
|
+
t: " "
|
|
11
|
+
};
|
|
12
|
+
var spaces = /* @__PURE__ */ new Set([" ", " ", "\n", "\r"]);
|
|
13
|
+
var stringify = (c) => {
|
|
14
|
+
if (c === "") {
|
|
15
|
+
return "end of input";
|
|
16
|
+
}
|
|
17
|
+
return c === '"' ? `'"'` : JSON.stringify(c);
|
|
18
|
+
};
|
|
2
19
|
var json_parse = /* @__PURE__ */ (() => {
|
|
3
20
|
let at;
|
|
4
21
|
let ch;
|
|
5
|
-
const escapee = {
|
|
6
|
-
'"': '"',
|
|
7
|
-
"\\": "\\",
|
|
8
|
-
"/": "/",
|
|
9
|
-
b: "\b",
|
|
10
|
-
f: "\f",
|
|
11
|
-
n: "\n",
|
|
12
|
-
r: "\r",
|
|
13
|
-
t: " "
|
|
14
|
-
};
|
|
15
|
-
const spaces = /* @__PURE__ */ new Set([" ", " ", "\n", "\r"]);
|
|
16
22
|
let text;
|
|
17
23
|
let warnings;
|
|
18
|
-
const
|
|
19
|
-
if (
|
|
20
|
-
|
|
24
|
+
const prepareError = (e, from, to) => {
|
|
25
|
+
if (from === void 0) {
|
|
26
|
+
e.from = at - 1;
|
|
27
|
+
} else {
|
|
28
|
+
e.from = from;
|
|
29
|
+
e.to = to ?? at - 1;
|
|
21
30
|
}
|
|
22
|
-
return c === '"' ? `'"'` : JSON.stringify(c);
|
|
23
31
|
};
|
|
24
|
-
const warn = (
|
|
25
|
-
|
|
26
|
-
message
|
|
27
|
-
position: at - 1,
|
|
32
|
+
const warn = (message, from, to) => {
|
|
33
|
+
const warning = {
|
|
34
|
+
message,
|
|
28
35
|
severity: "warning"
|
|
29
|
-
}
|
|
36
|
+
};
|
|
37
|
+
prepareError(warning, from, to);
|
|
38
|
+
warnings.push(warning);
|
|
30
39
|
};
|
|
31
|
-
const error = (
|
|
32
|
-
|
|
40
|
+
const error = (message, from, to) => {
|
|
41
|
+
const e = {
|
|
33
42
|
warnings,
|
|
34
|
-
message
|
|
35
|
-
position: at - 1,
|
|
43
|
+
message,
|
|
36
44
|
severity: "error"
|
|
37
45
|
};
|
|
46
|
+
prepareError(e, from, to);
|
|
47
|
+
throw e;
|
|
38
48
|
};
|
|
39
49
|
const next = (c) => {
|
|
40
50
|
if (c && c !== ch) {
|
|
41
51
|
error(`Expected ${stringify(c)} instead of ${stringify(ch)}`);
|
|
42
52
|
}
|
|
43
53
|
ch = text.charAt(at);
|
|
44
|
-
at
|
|
54
|
+
at++;
|
|
45
55
|
return ch;
|
|
46
56
|
};
|
|
47
57
|
const number = () => {
|
|
48
|
-
let value2;
|
|
49
58
|
let string2 = "";
|
|
59
|
+
const from = at - 1;
|
|
50
60
|
if (ch === "-") {
|
|
51
61
|
string2 = "-";
|
|
52
62
|
next();
|
|
@@ -66,10 +76,11 @@ var json_parse = /* @__PURE__ */ (() => {
|
|
|
66
76
|
error("No number after minus sign");
|
|
67
77
|
}
|
|
68
78
|
if (ch !== "." && ch !== "e" && ch !== "E") {
|
|
69
|
-
|
|
70
|
-
if (!Number.isSafeInteger(
|
|
71
|
-
warn("Not a safe integer");
|
|
79
|
+
const value3 = Number(string2);
|
|
80
|
+
if (!Number.isSafeInteger(value3)) {
|
|
81
|
+
warn("Not a safe integer", from);
|
|
72
82
|
}
|
|
83
|
+
return;
|
|
73
84
|
}
|
|
74
85
|
if (ch === ".") {
|
|
75
86
|
string2 += ".";
|
|
@@ -94,44 +105,43 @@ var json_parse = /* @__PURE__ */ (() => {
|
|
|
94
105
|
next();
|
|
95
106
|
}
|
|
96
107
|
}
|
|
97
|
-
value2
|
|
108
|
+
const value2 = Number(string2);
|
|
98
109
|
if (!Number.isFinite(value2)) {
|
|
99
110
|
error("Bad number");
|
|
100
111
|
}
|
|
101
112
|
};
|
|
102
113
|
const string = () => {
|
|
103
|
-
let hex;
|
|
104
|
-
let i;
|
|
105
114
|
let value2 = "";
|
|
106
|
-
let uffff;
|
|
107
115
|
if (ch === '"') {
|
|
108
116
|
while (next()) {
|
|
109
117
|
if (ch === '"') {
|
|
110
118
|
next();
|
|
111
119
|
return value2;
|
|
112
120
|
}
|
|
121
|
+
const from = at - 1;
|
|
113
122
|
if (ch === "\\") {
|
|
114
123
|
next();
|
|
115
124
|
if (ch === "u") {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
125
|
+
let i = 0;
|
|
126
|
+
let uffff = 0;
|
|
127
|
+
for (; i < 4; i++) {
|
|
128
|
+
const hex = parseInt(next(), 16);
|
|
119
129
|
if (!isFinite(hex)) {
|
|
120
130
|
break;
|
|
121
131
|
}
|
|
122
132
|
uffff = uffff * 16 + hex;
|
|
123
133
|
}
|
|
124
134
|
if (i < 4) {
|
|
125
|
-
error("Bad unicode escape");
|
|
135
|
+
error("Bad unicode escape", from);
|
|
126
136
|
}
|
|
127
137
|
value2 += String.fromCharCode(uffff);
|
|
128
138
|
} else if (typeof escapee[ch] === "string") {
|
|
129
139
|
value2 += escapee[ch];
|
|
130
140
|
} else {
|
|
131
|
-
error("Bad escaped character");
|
|
141
|
+
error("Bad escaped character", from, at);
|
|
132
142
|
}
|
|
133
143
|
} else if (ch < " ") {
|
|
134
|
-
error("Bad control character");
|
|
144
|
+
error("Bad control character", from, at);
|
|
135
145
|
} else {
|
|
136
146
|
value2 += ch;
|
|
137
147
|
}
|
|
@@ -172,15 +182,16 @@ var json_parse = /* @__PURE__ */ (() => {
|
|
|
172
182
|
}
|
|
173
183
|
};
|
|
174
184
|
const array = () => {
|
|
175
|
-
next(
|
|
185
|
+
next();
|
|
176
186
|
white();
|
|
177
187
|
if (ch === "]") {
|
|
178
188
|
next();
|
|
179
189
|
return;
|
|
180
190
|
}
|
|
191
|
+
let from;
|
|
181
192
|
while (ch) {
|
|
182
193
|
if (ch === "]") {
|
|
183
|
-
error("Trailing comma in array");
|
|
194
|
+
error("Trailing comma in array", from, from + 1);
|
|
184
195
|
}
|
|
185
196
|
value();
|
|
186
197
|
white();
|
|
@@ -188,6 +199,7 @@ var json_parse = /* @__PURE__ */ (() => {
|
|
|
188
199
|
next();
|
|
189
200
|
return;
|
|
190
201
|
} else if (ch === ",") {
|
|
202
|
+
from = at - 1;
|
|
191
203
|
next();
|
|
192
204
|
white();
|
|
193
205
|
} else {
|
|
@@ -197,23 +209,25 @@ var json_parse = /* @__PURE__ */ (() => {
|
|
|
197
209
|
error("Unterminated array");
|
|
198
210
|
};
|
|
199
211
|
const object = () => {
|
|
200
|
-
let key;
|
|
201
212
|
const keys = /* @__PURE__ */ new Set();
|
|
202
|
-
next(
|
|
213
|
+
next();
|
|
203
214
|
white();
|
|
204
215
|
if (ch === "}") {
|
|
205
216
|
next();
|
|
206
217
|
return;
|
|
207
218
|
}
|
|
219
|
+
let from;
|
|
208
220
|
while (ch) {
|
|
209
221
|
if (ch === "}") {
|
|
210
|
-
error("Trailing comma in object");
|
|
222
|
+
error("Trailing comma in object", from, from + 1);
|
|
211
223
|
}
|
|
212
|
-
|
|
224
|
+
from = at;
|
|
225
|
+
const key = string();
|
|
226
|
+
const to = at - 2;
|
|
213
227
|
white();
|
|
214
228
|
next(":");
|
|
215
229
|
if (keys.has(key)) {
|
|
216
|
-
warn(`Duplicate key ${stringify(key)}
|
|
230
|
+
warn(`Duplicate key ${stringify(key)}`, from, to);
|
|
217
231
|
} else {
|
|
218
232
|
keys.add(key);
|
|
219
233
|
}
|
|
@@ -223,6 +237,7 @@ var json_parse = /* @__PURE__ */ (() => {
|
|
|
223
237
|
next();
|
|
224
238
|
return;
|
|
225
239
|
} else if (ch === ",") {
|
|
240
|
+
from = at - 1;
|
|
226
241
|
next();
|
|
227
242
|
white();
|
|
228
243
|
} else {
|
|
@@ -290,7 +305,7 @@ var splitColors = (str, hsl = true) => {
|
|
|
290
305
|
}
|
|
291
306
|
return pieces;
|
|
292
307
|
};
|
|
293
|
-
var sanitizeInlineStyle = (style) => style.replace(/[{}]/gu, (p) => p === "{" ? "{" : "}");
|
|
308
|
+
var sanitizeInlineStyle = (style) => style.replace(/[{}]/gu, (p) => p === "{" ? "{" : "}").replace(/^[\s;]+/u, (p) => p.replace(/;/gu, " "));
|
|
294
309
|
function getRegex(f) {
|
|
295
310
|
const map = /* @__PURE__ */ new Map(), weakMap = /* @__PURE__ */ new WeakMap();
|
|
296
311
|
return (s) => {
|
|
@@ -319,23 +334,33 @@ var splitLines = (str) => {
|
|
|
319
334
|
var mt2num = (mt) => mt && Number(mt[1]);
|
|
320
335
|
var formatJsonError = (str, errors) => {
|
|
321
336
|
let lines;
|
|
337
|
+
const offsetToPosition = (offset) => {
|
|
338
|
+
lines ??= splitLines(str);
|
|
339
|
+
const line = lines.findIndex(([, , end]) => offset <= end) + 1;
|
|
340
|
+
return {
|
|
341
|
+
line,
|
|
342
|
+
column: offset - lines[line - 1][1] + 1
|
|
343
|
+
};
|
|
344
|
+
};
|
|
322
345
|
for (const error of errors) {
|
|
323
|
-
const { line, column,
|
|
324
|
-
if (
|
|
346
|
+
const { line, column, from, to } = error;
|
|
347
|
+
if (from === null || from === void 0) {
|
|
325
348
|
if (line) {
|
|
326
349
|
lines ??= splitLines(str);
|
|
327
350
|
error.column ??= 1;
|
|
328
|
-
error.
|
|
351
|
+
error.from = lines[line - 1][1] + (error.column - 1);
|
|
329
352
|
} else {
|
|
330
|
-
error.
|
|
353
|
+
error.from = 0;
|
|
331
354
|
error.line = 1;
|
|
332
355
|
error.column = 1;
|
|
333
356
|
}
|
|
334
357
|
} else if (!line || !column) {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
358
|
+
Object.assign(error, offsetToPosition(from));
|
|
359
|
+
}
|
|
360
|
+
if (to !== void 0) {
|
|
361
|
+
({ line: error.endLine, column: error.endColumn } = offsetToPosition(to));
|
|
338
362
|
}
|
|
363
|
+
error.position = error.from;
|
|
339
364
|
}
|
|
340
365
|
return errors;
|
|
341
366
|
};
|
|
@@ -344,8 +369,8 @@ var lintJSONNative = (str, force) => {
|
|
|
344
369
|
try {
|
|
345
370
|
JSON.parse(str);
|
|
346
371
|
} catch (e) {
|
|
347
|
-
const { message } = e, line = mt2num(/\bline (\d+)/u.exec(message)), column = mt2num(/\bcolumn (\d+)/u.exec(message)),
|
|
348
|
-
return formatJsonError(str, [{ message, line, column,
|
|
372
|
+
const { message } = e, line = mt2num(/\bline (\d+)/u.exec(message)), column = mt2num(/\bcolumn (\d+)/u.exec(message)), from = mt2num(/\bposition (\d+)/u.exec(message));
|
|
373
|
+
return formatJsonError(str, [{ message, line, column, from, severity: "error" }]);
|
|
349
374
|
}
|
|
350
375
|
}
|
|
351
376
|
return [];
|
package/dist/json_parse.js
CHANGED
|
@@ -29,6 +29,23 @@
|
|
|
29
29
|
*/
|
|
30
30
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
31
|
exports.json_parse = void 0;
|
|
32
|
+
const escapee = {
|
|
33
|
+
'"': '"',
|
|
34
|
+
"\\": "\\",
|
|
35
|
+
"/": "/",
|
|
36
|
+
b: "\b",
|
|
37
|
+
f: "\f",
|
|
38
|
+
n: "\n",
|
|
39
|
+
r: "\r",
|
|
40
|
+
t: "\t",
|
|
41
|
+
};
|
|
42
|
+
const spaces = new Set([" ", "\t", "\n", "\r"]);
|
|
43
|
+
const stringify = (c) => {
|
|
44
|
+
if (c === "") {
|
|
45
|
+
return "end of input";
|
|
46
|
+
}
|
|
47
|
+
return c === '"' ? `'"'` : JSON.stringify(c);
|
|
48
|
+
};
|
|
32
49
|
exports.json_parse = (() => {
|
|
33
50
|
// This is a function that can parse a JSON text.
|
|
34
51
|
// It is a simple, recursive descent parser.
|
|
@@ -37,41 +54,35 @@ exports.json_parse = (() => {
|
|
|
37
54
|
// We are defining the function inside of another function to avoid creating global variables.
|
|
38
55
|
let at; // The index of the current character
|
|
39
56
|
let ch; // The current character
|
|
40
|
-
const escapee = {
|
|
41
|
-
'"': '"',
|
|
42
|
-
"\\": "\\",
|
|
43
|
-
"/": "/",
|
|
44
|
-
b: "\b",
|
|
45
|
-
f: "\f",
|
|
46
|
-
n: "\n",
|
|
47
|
-
r: "\r",
|
|
48
|
-
t: "\t",
|
|
49
|
-
};
|
|
50
|
-
const spaces = new Set([" ", "\t", "\n", "\r"]);
|
|
51
57
|
let text;
|
|
52
58
|
let warnings;
|
|
53
|
-
const
|
|
54
|
-
if (
|
|
55
|
-
|
|
59
|
+
const prepareError = (e, from, to) => {
|
|
60
|
+
if (from === undefined) {
|
|
61
|
+
e.from = at - 1;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
e.from = from;
|
|
65
|
+
e.to = to ?? at - 1;
|
|
56
66
|
}
|
|
57
|
-
return c === '"' ? `'"'` : JSON.stringify(c);
|
|
58
67
|
};
|
|
59
|
-
const warn = (
|
|
68
|
+
const warn = (message, from, to) => {
|
|
60
69
|
// Log warning when something is wrong.
|
|
61
|
-
|
|
62
|
-
message
|
|
63
|
-
position: at - 1,
|
|
70
|
+
const warning = {
|
|
71
|
+
message,
|
|
64
72
|
severity: "warning",
|
|
65
|
-
}
|
|
73
|
+
};
|
|
74
|
+
prepareError(warning, from, to);
|
|
75
|
+
warnings.push(warning);
|
|
66
76
|
};
|
|
67
|
-
const error = (
|
|
77
|
+
const error = (message, from, to) => {
|
|
68
78
|
// Call error when something is wrong.
|
|
69
|
-
|
|
79
|
+
const e = {
|
|
70
80
|
warnings,
|
|
71
|
-
message
|
|
72
|
-
position: at - 1,
|
|
81
|
+
message,
|
|
73
82
|
severity: "error",
|
|
74
83
|
};
|
|
84
|
+
prepareError(e, from, to);
|
|
85
|
+
throw e;
|
|
75
86
|
};
|
|
76
87
|
const next = (c) => {
|
|
77
88
|
// If a c parameter is provided, verify that it matches the current character.
|
|
@@ -80,13 +91,13 @@ exports.json_parse = (() => {
|
|
|
80
91
|
}
|
|
81
92
|
// Get the next character. When there are no more characters, return the empty string.
|
|
82
93
|
ch = text.charAt(at);
|
|
83
|
-
at
|
|
94
|
+
at++;
|
|
84
95
|
return ch;
|
|
85
96
|
};
|
|
86
97
|
const number = () => {
|
|
87
98
|
// Parse a number value.
|
|
88
|
-
let value;
|
|
89
99
|
let string = "";
|
|
100
|
+
const from = at - 1;
|
|
90
101
|
if (ch === "-") {
|
|
91
102
|
string = "-";
|
|
92
103
|
next();
|
|
@@ -108,10 +119,11 @@ exports.json_parse = (() => {
|
|
|
108
119
|
error("No number after minus sign");
|
|
109
120
|
}
|
|
110
121
|
if (ch !== "." && ch !== "e" && ch !== "E") {
|
|
111
|
-
value = Number(string);
|
|
122
|
+
const value = Number(string);
|
|
112
123
|
if (!Number.isSafeInteger(value)) {
|
|
113
|
-
warn("Not a safe integer");
|
|
124
|
+
warn("Not a safe integer", from);
|
|
114
125
|
}
|
|
126
|
+
return;
|
|
115
127
|
}
|
|
116
128
|
if (ch === ".") {
|
|
117
129
|
string += ".";
|
|
@@ -137,17 +149,14 @@ exports.json_parse = (() => {
|
|
|
137
149
|
next();
|
|
138
150
|
}
|
|
139
151
|
}
|
|
140
|
-
value
|
|
152
|
+
const value = Number(string);
|
|
141
153
|
if (!Number.isFinite(value)) {
|
|
142
154
|
error("Bad number");
|
|
143
155
|
}
|
|
144
156
|
};
|
|
145
157
|
const string = () => {
|
|
146
158
|
// Parse a string value.
|
|
147
|
-
let hex;
|
|
148
|
-
let i;
|
|
149
159
|
let value = "";
|
|
150
|
-
let uffff;
|
|
151
160
|
// When parsing for string values, we must look for " and \ characters.
|
|
152
161
|
if (ch === '"') {
|
|
153
162
|
while (next()) {
|
|
@@ -155,19 +164,21 @@ exports.json_parse = (() => {
|
|
|
155
164
|
next();
|
|
156
165
|
return value;
|
|
157
166
|
}
|
|
167
|
+
const from = at - 1;
|
|
158
168
|
if (ch === "\\") {
|
|
159
169
|
next();
|
|
160
170
|
if (ch === "u") {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
171
|
+
let i = 0;
|
|
172
|
+
let uffff = 0;
|
|
173
|
+
for (; i < 4; i++) {
|
|
174
|
+
const hex = parseInt(next(), 16);
|
|
164
175
|
if (!isFinite(hex)) {
|
|
165
176
|
break;
|
|
166
177
|
}
|
|
167
178
|
uffff = uffff * 16 + hex;
|
|
168
179
|
}
|
|
169
180
|
if (i < 4) {
|
|
170
|
-
error("Bad unicode escape");
|
|
181
|
+
error("Bad unicode escape", from);
|
|
171
182
|
}
|
|
172
183
|
value += String.fromCharCode(uffff);
|
|
173
184
|
}
|
|
@@ -175,11 +186,11 @@ exports.json_parse = (() => {
|
|
|
175
186
|
value += escapee[ch];
|
|
176
187
|
}
|
|
177
188
|
else {
|
|
178
|
-
error("Bad escaped character");
|
|
189
|
+
error("Bad escaped character", from, at);
|
|
179
190
|
}
|
|
180
191
|
}
|
|
181
192
|
else if (ch < " ") {
|
|
182
|
-
error("Bad control character");
|
|
193
|
+
error("Bad control character", from, at);
|
|
183
194
|
}
|
|
184
195
|
else {
|
|
185
196
|
value += ch;
|
|
@@ -225,15 +236,16 @@ exports.json_parse = (() => {
|
|
|
225
236
|
};
|
|
226
237
|
const array = () => {
|
|
227
238
|
// Parse an array value.
|
|
228
|
-
next(
|
|
239
|
+
next();
|
|
229
240
|
white();
|
|
230
241
|
if (ch === "]") {
|
|
231
242
|
next();
|
|
232
243
|
return; // empty array
|
|
233
244
|
}
|
|
245
|
+
let from;
|
|
234
246
|
while (ch) {
|
|
235
247
|
if (ch === "]") {
|
|
236
|
-
error("Trailing comma in array");
|
|
248
|
+
error("Trailing comma in array", from, from + 1);
|
|
237
249
|
}
|
|
238
250
|
value();
|
|
239
251
|
white();
|
|
@@ -242,6 +254,7 @@ exports.json_parse = (() => {
|
|
|
242
254
|
return;
|
|
243
255
|
}
|
|
244
256
|
else if (ch === ",") {
|
|
257
|
+
from = at - 1;
|
|
245
258
|
next();
|
|
246
259
|
white();
|
|
247
260
|
}
|
|
@@ -253,23 +266,25 @@ exports.json_parse = (() => {
|
|
|
253
266
|
};
|
|
254
267
|
const object = () => {
|
|
255
268
|
// Parse an object value.
|
|
256
|
-
let key;
|
|
257
269
|
const keys = new Set();
|
|
258
|
-
next(
|
|
270
|
+
next();
|
|
259
271
|
white();
|
|
260
272
|
if (ch === "}") {
|
|
261
273
|
next();
|
|
262
274
|
return; // empty object
|
|
263
275
|
}
|
|
276
|
+
let from;
|
|
264
277
|
while (ch) {
|
|
265
278
|
if (ch === "}") {
|
|
266
|
-
error("Trailing comma in object");
|
|
279
|
+
error("Trailing comma in object", from, from + 1);
|
|
267
280
|
}
|
|
268
|
-
|
|
281
|
+
from = at;
|
|
282
|
+
const key = string();
|
|
283
|
+
const to = at - 2;
|
|
269
284
|
white();
|
|
270
285
|
next(":");
|
|
271
286
|
if (keys.has(key)) {
|
|
272
|
-
warn(`Duplicate key ${stringify(key)}
|
|
287
|
+
warn(`Duplicate key ${stringify(key)}`, from, to);
|
|
273
288
|
}
|
|
274
289
|
else {
|
|
275
290
|
keys.add(key);
|
|
@@ -281,6 +296,7 @@ exports.json_parse = (() => {
|
|
|
281
296
|
return;
|
|
282
297
|
}
|
|
283
298
|
else if (ch === ",") {
|
|
299
|
+
from = at - 1;
|
|
284
300
|
next();
|
|
285
301
|
white();
|
|
286
302
|
}
|