@reliverse/relifso 1.4.0 → 1.4.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/LICENSES +16 -0
- package/README.md +48 -17
- package/bin/impl/bun.d.ts +5 -28
- package/bin/impl/bun.js +2 -126
- package/bin/impl/copy.js +8 -7
- package/bin/impl/create.d.ts +34 -0
- package/bin/impl/create.js +54 -0
- package/bin/impl/dive.d.ts +10 -0
- package/bin/impl/dive.js +89 -0
- package/bin/impl/empty.d.ts +28 -0
- package/bin/impl/empty.js +75 -0
- package/bin/impl/extras.d.ts +22 -2
- package/bin/impl/extras.js +68 -3
- package/bin/impl/json-utils.d.ts +30 -0
- package/bin/impl/json-utils.js +46 -0
- package/bin/impl/output-file.d.ts +3 -2
- package/bin/impl/output-json.d.ts +7 -2
- package/bin/impl/output-json.js +73 -11
- package/bin/impl/read-file.d.ts +11 -0
- package/bin/impl/read-file.js +82 -4
- package/bin/impl/read-json.d.ts +6 -0
- package/bin/impl/read-json.js +133 -21
- package/bin/impl/stats.d.ts +31 -0
- package/bin/impl/stats.js +141 -0
- package/bin/impl/write-file.d.ts +19 -8
- package/bin/impl/write-file.js +218 -9
- package/bin/impl/write-json.d.ts +13 -2
- package/bin/impl/write-json.js +46 -7
- package/bin/mod.d.ts +84 -36
- package/bin/mod.js +108 -39
- package/bin/utils/json/helpers/JSONRepairError.d.ts +4 -0
- package/bin/utils/json/helpers/JSONRepairError.js +7 -0
- package/bin/utils/json/helpers/JsonSchemaError.d.ts +6 -0
- package/bin/utils/json/helpers/JsonSchemaError.js +6 -0
- package/bin/utils/json/helpers/stringUtils.d.ts +64 -0
- package/bin/utils/json/helpers/stringUtils.js +87 -0
- package/bin/utils/json/regular/jsonc.d.ts +45 -0
- package/bin/utils/json/regular/jsonc.js +88 -0
- package/bin/utils/json/regular/jsonrepair.d.ts +17 -0
- package/bin/utils/json/regular/jsonrepair.js +576 -0
- package/bin/utils/json/regular/validate.d.ts +22 -0
- package/bin/utils/json/regular/validate.js +52 -0
- package/bin/utils/json/stream/JsonStreamError.d.ts +6 -0
- package/bin/utils/json/stream/JsonStreamError.js +6 -0
- package/bin/utils/json/stream/buffer/InputBuffer.d.ts +13 -0
- package/bin/utils/json/stream/buffer/InputBuffer.js +68 -0
- package/bin/utils/json/stream/buffer/OutputBuffer.d.ts +17 -0
- package/bin/utils/json/stream/buffer/OutputBuffer.js +101 -0
- package/bin/utils/json/stream/core.d.ts +10 -0
- package/bin/utils/json/stream/core.js +695 -0
- package/bin/utils/json/stream/jsonl.d.ts +21 -0
- package/bin/utils/json/stream/jsonl.js +55 -0
- package/bin/utils/json/stream/parser.d.ts +14 -0
- package/bin/utils/json/stream/parser.js +81 -0
- package/bin/utils/json/stream/stack.d.ts +19 -0
- package/bin/utils/json/stream/stack.js +43 -0
- package/bin/utils/json/stream/stream.d.ts +6 -0
- package/bin/utils/json/stream/stream.js +30 -0
- package/bin/utils/json/stream/writer.d.ts +14 -0
- package/bin/utils/json/stream/writer.js +44 -0
- package/package.json +3 -2
- package/bin/impl/create-file.d.ts +0 -2
- package/bin/impl/create-file.js +0 -21
- package/bin/impl/dive-async.d.ts +0 -11
- package/bin/impl/dive-async.js +0 -88
- package/bin/impl/empty-dir.d.ts +0 -2
- package/bin/impl/empty-dir.js +0 -24
- package/bin/impl/file-utils.d.ts +0 -20
- package/bin/impl/file-utils.js +0 -63
- /package/bin/{impl/logger.d.ts → utils/log.d.ts} +0 -0
- /package/bin/{impl/logger.js → utils/log.js} +0 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { JSONRepairError } from "../helpers/JSONRepairError.js";
|
|
2
|
+
import { jsonrepair } from "./jsonrepair.js";
|
|
3
|
+
export function parseJsonc(text, options = {}) {
|
|
4
|
+
const { throws = true } = options;
|
|
5
|
+
try {
|
|
6
|
+
return JSON.parse(text);
|
|
7
|
+
} catch (_error) {
|
|
8
|
+
try {
|
|
9
|
+
const repaired = jsonrepair(text);
|
|
10
|
+
return JSON.parse(repaired);
|
|
11
|
+
} catch (_error2) {
|
|
12
|
+
if (throws) {
|
|
13
|
+
throw new JSONRepairError("Failed to parse JSONC", -1);
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function stringifyJsonc(value, options = {}) {
|
|
20
|
+
const { spaces = 2 } = options;
|
|
21
|
+
return JSON.stringify(value, null, spaces);
|
|
22
|
+
}
|
|
23
|
+
export function isValidJsonc(text) {
|
|
24
|
+
try {
|
|
25
|
+
parseJsonc(text, { throws: true });
|
|
26
|
+
return true;
|
|
27
|
+
} catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function extractComments(text) {
|
|
32
|
+
const comments = [];
|
|
33
|
+
let line = 1;
|
|
34
|
+
let column = 0;
|
|
35
|
+
let i = 0;
|
|
36
|
+
while (i < text.length) {
|
|
37
|
+
const char = text[i];
|
|
38
|
+
if (char === "/" && text[i + 1] === "/") {
|
|
39
|
+
const startColumn = column;
|
|
40
|
+
const startLine = line;
|
|
41
|
+
let commentText = "";
|
|
42
|
+
i += 2;
|
|
43
|
+
while (i < text.length && text[i] !== "\n") {
|
|
44
|
+
commentText += text[i];
|
|
45
|
+
i++;
|
|
46
|
+
}
|
|
47
|
+
comments.push({
|
|
48
|
+
line: startLine,
|
|
49
|
+
column: startColumn,
|
|
50
|
+
text: commentText.trim(),
|
|
51
|
+
type: "line"
|
|
52
|
+
});
|
|
53
|
+
} else if (char === "/" && text[i + 1] === "*") {
|
|
54
|
+
const startColumn = column;
|
|
55
|
+
const startLine = line;
|
|
56
|
+
let commentText = "";
|
|
57
|
+
i += 2;
|
|
58
|
+
while (i < text.length - 1 && !(text[i] === "*" && text[i + 1] === "/")) {
|
|
59
|
+
if (text[i] === "\n") {
|
|
60
|
+
line++;
|
|
61
|
+
column = 0;
|
|
62
|
+
} else {
|
|
63
|
+
column++;
|
|
64
|
+
}
|
|
65
|
+
commentText += text[i];
|
|
66
|
+
i++;
|
|
67
|
+
}
|
|
68
|
+
if (i < text.length - 1) {
|
|
69
|
+
i += 2;
|
|
70
|
+
}
|
|
71
|
+
comments.push({
|
|
72
|
+
line: startLine,
|
|
73
|
+
column: startColumn,
|
|
74
|
+
text: commentText.trim(),
|
|
75
|
+
type: "block"
|
|
76
|
+
});
|
|
77
|
+
} else {
|
|
78
|
+
if (char === "\n") {
|
|
79
|
+
line++;
|
|
80
|
+
column = 0;
|
|
81
|
+
} else {
|
|
82
|
+
column++;
|
|
83
|
+
}
|
|
84
|
+
i++;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return comments;
|
|
88
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repair a string containing an invalid JSON document.
|
|
3
|
+
* For example changes JavaScript notation into JSON notation.
|
|
4
|
+
*
|
|
5
|
+
* Example:
|
|
6
|
+
*
|
|
7
|
+
* try {
|
|
8
|
+
* const json = "{name: 'John'}"
|
|
9
|
+
* const repaired = jsonrepair(json)
|
|
10
|
+
* console.log(repaired)
|
|
11
|
+
* // '{"name": "John"}'
|
|
12
|
+
* } catch (err) {
|
|
13
|
+
* console.error(err)
|
|
14
|
+
* }
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
17
|
+
export declare function jsonrepair(text: string): string;
|
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
import { JSONRepairError } from "../helpers/JSONRepairError.js";
|
|
2
|
+
import {
|
|
3
|
+
endsWithCommaOrNewline,
|
|
4
|
+
insertBeforeLastWhitespace,
|
|
5
|
+
isControlCharacter,
|
|
6
|
+
isDelimiter,
|
|
7
|
+
isDigit,
|
|
8
|
+
isDoubleQuote,
|
|
9
|
+
isDoubleQuoteLike,
|
|
10
|
+
isFunctionNameChar,
|
|
11
|
+
isFunctionNameCharStart,
|
|
12
|
+
isHex,
|
|
13
|
+
isQuote,
|
|
14
|
+
isSingleQuote,
|
|
15
|
+
isSingleQuoteLike,
|
|
16
|
+
isSpecialWhitespace,
|
|
17
|
+
isStartOfValue,
|
|
18
|
+
isUnquotedStringDelimiter,
|
|
19
|
+
isValidStringCharacter,
|
|
20
|
+
isWhitespace,
|
|
21
|
+
isWhitespaceExceptNewline,
|
|
22
|
+
regexUrlChar,
|
|
23
|
+
regexUrlStart,
|
|
24
|
+
removeAtIndex,
|
|
25
|
+
stripLastOccurrence
|
|
26
|
+
} from "../helpers/stringUtils.js";
|
|
27
|
+
const controlCharacters = {
|
|
28
|
+
"\b": "\\b",
|
|
29
|
+
"\f": "\\f",
|
|
30
|
+
"\n": "\\n",
|
|
31
|
+
"\r": "\\r",
|
|
32
|
+
" ": "\\t"
|
|
33
|
+
};
|
|
34
|
+
const escapeCharacters = {
|
|
35
|
+
'"': '"',
|
|
36
|
+
"\\": "\\",
|
|
37
|
+
"/": "/",
|
|
38
|
+
b: "\b",
|
|
39
|
+
f: "\f",
|
|
40
|
+
n: "\n",
|
|
41
|
+
r: "\r",
|
|
42
|
+
t: " "
|
|
43
|
+
// note that \u is handled separately in parseString()
|
|
44
|
+
};
|
|
45
|
+
export function jsonrepair(text) {
|
|
46
|
+
let i = 0;
|
|
47
|
+
let output = "";
|
|
48
|
+
function charAt(index) {
|
|
49
|
+
return index < text.length ? text[index] : "";
|
|
50
|
+
}
|
|
51
|
+
parseMarkdownCodeBlock();
|
|
52
|
+
const processed = parseValue();
|
|
53
|
+
if (!processed) {
|
|
54
|
+
throwUnexpectedEnd();
|
|
55
|
+
}
|
|
56
|
+
parseMarkdownCodeBlock();
|
|
57
|
+
const processedComma = parseCharacter(",");
|
|
58
|
+
if (processedComma) {
|
|
59
|
+
parseWhitespaceAndSkipComments();
|
|
60
|
+
}
|
|
61
|
+
if (isStartOfValue(charAt(i)) && endsWithCommaOrNewline(output)) {
|
|
62
|
+
if (!processedComma) {
|
|
63
|
+
output = insertBeforeLastWhitespace(output, ",");
|
|
64
|
+
}
|
|
65
|
+
parseNewlineDelimitedJSON();
|
|
66
|
+
} else if (processedComma) {
|
|
67
|
+
output = stripLastOccurrence(output, ",");
|
|
68
|
+
}
|
|
69
|
+
while (charAt(i) === "}" || charAt(i) === "]") {
|
|
70
|
+
i++;
|
|
71
|
+
parseWhitespaceAndSkipComments();
|
|
72
|
+
}
|
|
73
|
+
if (i >= text.length) {
|
|
74
|
+
return output;
|
|
75
|
+
}
|
|
76
|
+
throwUnexpectedCharacter();
|
|
77
|
+
function parseValue() {
|
|
78
|
+
parseWhitespaceAndSkipComments();
|
|
79
|
+
const processed2 = parseObject() || parseArray() || parseString() || parseNumber() || parseKeywords() || parseUnquotedString(false) || parseRegex() || false;
|
|
80
|
+
parseWhitespaceAndSkipComments();
|
|
81
|
+
return processed2;
|
|
82
|
+
}
|
|
83
|
+
function parseWhitespaceAndSkipComments(skipNewline = true) {
|
|
84
|
+
const start = i;
|
|
85
|
+
let changed = parseWhitespace(skipNewline);
|
|
86
|
+
do {
|
|
87
|
+
changed = parseComment();
|
|
88
|
+
if (changed) {
|
|
89
|
+
changed = parseWhitespace(skipNewline);
|
|
90
|
+
}
|
|
91
|
+
} while (changed);
|
|
92
|
+
return i > start;
|
|
93
|
+
}
|
|
94
|
+
function parseWhitespace(skipNewline) {
|
|
95
|
+
const _isWhiteSpace = skipNewline ? isWhitespace : isWhitespaceExceptNewline;
|
|
96
|
+
let whitespace = "";
|
|
97
|
+
while (true) {
|
|
98
|
+
if (_isWhiteSpace(text, i)) {
|
|
99
|
+
whitespace += charAt(i);
|
|
100
|
+
i++;
|
|
101
|
+
} else if (isSpecialWhitespace(text, i)) {
|
|
102
|
+
whitespace += " ";
|
|
103
|
+
i++;
|
|
104
|
+
} else {
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (whitespace.length > 0) {
|
|
109
|
+
output += whitespace;
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
function parseComment() {
|
|
115
|
+
if (charAt(i) === "/" && charAt(i + 1) === "*") {
|
|
116
|
+
while (i < text.length && !atEndOfBlockComment(text, i)) {
|
|
117
|
+
i++;
|
|
118
|
+
}
|
|
119
|
+
i += 2;
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
if (charAt(i) === "/" && charAt(i + 1) === "/") {
|
|
123
|
+
while (i < text.length && charAt(i) !== "\n") {
|
|
124
|
+
i++;
|
|
125
|
+
}
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
function parseMarkdownCodeBlock() {
|
|
131
|
+
if (text.slice(i, i + 3) === "```") {
|
|
132
|
+
i += 3;
|
|
133
|
+
if (isFunctionNameCharStart(charAt(i))) {
|
|
134
|
+
while (i < text.length && isFunctionNameChar(charAt(i))) {
|
|
135
|
+
i++;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
parseWhitespaceAndSkipComments();
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
function parseCharacter(char) {
|
|
144
|
+
if (charAt(i) === char) {
|
|
145
|
+
output += charAt(i);
|
|
146
|
+
i++;
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
function skipCharacter(char) {
|
|
152
|
+
if (charAt(i) === char) {
|
|
153
|
+
i++;
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
function skipEscapeCharacter() {
|
|
159
|
+
return skipCharacter("\\");
|
|
160
|
+
}
|
|
161
|
+
function skipEllipsis() {
|
|
162
|
+
parseWhitespaceAndSkipComments();
|
|
163
|
+
if (charAt(i) === "." && charAt(i + 1) === "." && charAt(i + 2) === ".") {
|
|
164
|
+
i += 3;
|
|
165
|
+
parseWhitespaceAndSkipComments();
|
|
166
|
+
skipCharacter(",");
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
function parseObject() {
|
|
172
|
+
if (charAt(i) === "{") {
|
|
173
|
+
output += "{";
|
|
174
|
+
i++;
|
|
175
|
+
parseWhitespaceAndSkipComments();
|
|
176
|
+
if (skipCharacter(",")) {
|
|
177
|
+
parseWhitespaceAndSkipComments();
|
|
178
|
+
}
|
|
179
|
+
let initial = true;
|
|
180
|
+
while (i < text.length && charAt(i) !== "}") {
|
|
181
|
+
let processedComma2;
|
|
182
|
+
if (!initial) {
|
|
183
|
+
processedComma2 = parseCharacter(",");
|
|
184
|
+
if (!processedComma2) {
|
|
185
|
+
output = insertBeforeLastWhitespace(output, ",");
|
|
186
|
+
}
|
|
187
|
+
parseWhitespaceAndSkipComments();
|
|
188
|
+
} else {
|
|
189
|
+
processedComma2 = true;
|
|
190
|
+
initial = false;
|
|
191
|
+
}
|
|
192
|
+
skipEllipsis();
|
|
193
|
+
const processedKey = parseString() || parseUnquotedString(true);
|
|
194
|
+
if (!processedKey) {
|
|
195
|
+
if (charAt(i) === "}" || charAt(i) === "{" || charAt(i) === "]" || charAt(i) === "[" || charAt(i) === void 0) {
|
|
196
|
+
output = stripLastOccurrence(output, ",");
|
|
197
|
+
} else {
|
|
198
|
+
throwObjectKeyExpected();
|
|
199
|
+
}
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
parseWhitespaceAndSkipComments();
|
|
203
|
+
const processedColon = parseCharacter(":");
|
|
204
|
+
const truncatedText = i >= text.length;
|
|
205
|
+
if (!processedColon) {
|
|
206
|
+
if (isStartOfValue(charAt(i)) || truncatedText) {
|
|
207
|
+
output = insertBeforeLastWhitespace(output, ":");
|
|
208
|
+
} else {
|
|
209
|
+
throwColonExpected();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const processedValue = parseValue();
|
|
213
|
+
if (!processedValue) {
|
|
214
|
+
if (processedColon || truncatedText) {
|
|
215
|
+
output += "null";
|
|
216
|
+
} else {
|
|
217
|
+
throwColonExpected();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (charAt(i) === "}") {
|
|
222
|
+
output += "}";
|
|
223
|
+
i++;
|
|
224
|
+
} else {
|
|
225
|
+
output = insertBeforeLastWhitespace(output, "}");
|
|
226
|
+
}
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
function parseArray() {
|
|
232
|
+
if (charAt(i) === "[") {
|
|
233
|
+
output += "[";
|
|
234
|
+
i++;
|
|
235
|
+
parseWhitespaceAndSkipComments();
|
|
236
|
+
if (skipCharacter(",")) {
|
|
237
|
+
parseWhitespaceAndSkipComments();
|
|
238
|
+
}
|
|
239
|
+
let initial = true;
|
|
240
|
+
while (i < text.length && charAt(i) !== "]") {
|
|
241
|
+
if (!initial) {
|
|
242
|
+
const processedComma2 = parseCharacter(",");
|
|
243
|
+
if (!processedComma2) {
|
|
244
|
+
output = insertBeforeLastWhitespace(output, ",");
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
initial = false;
|
|
248
|
+
}
|
|
249
|
+
skipEllipsis();
|
|
250
|
+
const processedValue = parseValue();
|
|
251
|
+
if (!processedValue) {
|
|
252
|
+
output = stripLastOccurrence(output, ",");
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (charAt(i) === "]") {
|
|
257
|
+
output += "]";
|
|
258
|
+
i++;
|
|
259
|
+
} else {
|
|
260
|
+
output = insertBeforeLastWhitespace(output, "]");
|
|
261
|
+
}
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
function parseNewlineDelimitedJSON() {
|
|
267
|
+
let initial = true;
|
|
268
|
+
let processedValue = true;
|
|
269
|
+
while (processedValue) {
|
|
270
|
+
if (!initial) {
|
|
271
|
+
const processedComma2 = parseCharacter(",");
|
|
272
|
+
if (!processedComma2) {
|
|
273
|
+
output = insertBeforeLastWhitespace(output, ",");
|
|
274
|
+
}
|
|
275
|
+
} else {
|
|
276
|
+
initial = false;
|
|
277
|
+
}
|
|
278
|
+
processedValue = parseValue();
|
|
279
|
+
}
|
|
280
|
+
if (!processedValue) {
|
|
281
|
+
output = stripLastOccurrence(output, ",");
|
|
282
|
+
}
|
|
283
|
+
output = `[
|
|
284
|
+
${output}
|
|
285
|
+
]`;
|
|
286
|
+
}
|
|
287
|
+
function parseString(stopAtDelimiter = false, stopAtIndex = -1) {
|
|
288
|
+
let skipEscapeChars = charAt(i) === "\\";
|
|
289
|
+
if (skipEscapeChars) {
|
|
290
|
+
i++;
|
|
291
|
+
skipEscapeChars = true;
|
|
292
|
+
}
|
|
293
|
+
if (isQuote(charAt(i))) {
|
|
294
|
+
const isEndQuote = isDoubleQuote(charAt(i)) ? isDoubleQuote : isSingleQuote(charAt(i)) ? isSingleQuote : isSingleQuoteLike(charAt(i)) ? isSingleQuoteLike : isDoubleQuoteLike;
|
|
295
|
+
const iBefore = i;
|
|
296
|
+
const oBefore = output.length;
|
|
297
|
+
let str = '"';
|
|
298
|
+
i++;
|
|
299
|
+
while (true) {
|
|
300
|
+
if (i >= text.length) {
|
|
301
|
+
const iPrev = prevNonWhitespaceIndex(i - 1);
|
|
302
|
+
if (!stopAtDelimiter && isDelimiter(charAt(iPrev))) {
|
|
303
|
+
i = iBefore;
|
|
304
|
+
output = output.substring(0, oBefore);
|
|
305
|
+
return parseString(true);
|
|
306
|
+
}
|
|
307
|
+
str = insertBeforeLastWhitespace(str, '"');
|
|
308
|
+
output += str;
|
|
309
|
+
return true;
|
|
310
|
+
} else if (i === stopAtIndex) {
|
|
311
|
+
str = insertBeforeLastWhitespace(str, '"');
|
|
312
|
+
output += str;
|
|
313
|
+
return true;
|
|
314
|
+
} else if (isEndQuote(charAt(i))) {
|
|
315
|
+
const iQuote = i;
|
|
316
|
+
const oQuote = str.length;
|
|
317
|
+
str += '"';
|
|
318
|
+
i++;
|
|
319
|
+
output += str;
|
|
320
|
+
parseWhitespaceAndSkipComments(false);
|
|
321
|
+
if (stopAtDelimiter || i >= text.length || isDelimiter(charAt(i)) || isQuote(charAt(i)) || isDigit(charAt(i))) {
|
|
322
|
+
parseConcatenatedString();
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
const iPrevChar = prevNonWhitespaceIndex(iQuote - 1);
|
|
326
|
+
const prevChar = charAt(iPrevChar);
|
|
327
|
+
if (prevChar === ",") {
|
|
328
|
+
i = iBefore;
|
|
329
|
+
output = output.substring(0, oBefore);
|
|
330
|
+
return parseString(false, iPrevChar);
|
|
331
|
+
}
|
|
332
|
+
if (isDelimiter(prevChar)) {
|
|
333
|
+
i = iBefore;
|
|
334
|
+
output = output.substring(0, oBefore);
|
|
335
|
+
return parseString(true);
|
|
336
|
+
}
|
|
337
|
+
output = output.substring(0, oBefore);
|
|
338
|
+
i = iQuote + 1;
|
|
339
|
+
str = `${str.substring(0, oQuote)}\\${str.substring(oQuote)}`;
|
|
340
|
+
} else if (stopAtDelimiter && isUnquotedStringDelimiter(charAt(i))) {
|
|
341
|
+
if (charAt(i - 1) === ":" && regexUrlStart.test(text.substring(iBefore + 1, i + 2))) {
|
|
342
|
+
while (i < text.length && regexUrlChar.test(charAt(i))) {
|
|
343
|
+
str += charAt(i);
|
|
344
|
+
i++;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
str = insertBeforeLastWhitespace(str, '"');
|
|
348
|
+
output += str;
|
|
349
|
+
parseConcatenatedString();
|
|
350
|
+
return true;
|
|
351
|
+
} else if (charAt(i) === "\\") {
|
|
352
|
+
const char = charAt(i + 1);
|
|
353
|
+
const escapeChar = escapeCharacters[char];
|
|
354
|
+
if (escapeChar !== void 0) {
|
|
355
|
+
str += charAt(i) + char;
|
|
356
|
+
i += 2;
|
|
357
|
+
} else if (char === "u") {
|
|
358
|
+
let j = 2;
|
|
359
|
+
while (j < 6 && isHex(charAt(i + j))) {
|
|
360
|
+
j++;
|
|
361
|
+
}
|
|
362
|
+
if (j === 6) {
|
|
363
|
+
str += charAt(i) + charAt(i + 1) + charAt(i + 2) + charAt(i + 3) + charAt(i + 4) + charAt(i + 5);
|
|
364
|
+
i += 6;
|
|
365
|
+
} else if (i + j >= text.length) {
|
|
366
|
+
i = text.length;
|
|
367
|
+
} else {
|
|
368
|
+
throwInvalidUnicodeCharacter();
|
|
369
|
+
}
|
|
370
|
+
} else {
|
|
371
|
+
str += charAt(i) + char;
|
|
372
|
+
i += 2;
|
|
373
|
+
}
|
|
374
|
+
} else {
|
|
375
|
+
const char = charAt(i);
|
|
376
|
+
if (char === '"' && charAt(i - 1) !== "\\") {
|
|
377
|
+
str += `\\${char}`;
|
|
378
|
+
i++;
|
|
379
|
+
} else if (isControlCharacter(char)) {
|
|
380
|
+
str += controlCharacters[char];
|
|
381
|
+
i++;
|
|
382
|
+
} else {
|
|
383
|
+
if (!isValidStringCharacter(char)) {
|
|
384
|
+
throwInvalidCharacter(char);
|
|
385
|
+
}
|
|
386
|
+
str += char;
|
|
387
|
+
i++;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
if (skipEscapeChars) {
|
|
391
|
+
skipEscapeCharacter();
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
function parseConcatenatedString() {
|
|
398
|
+
let processed2 = false;
|
|
399
|
+
parseWhitespaceAndSkipComments();
|
|
400
|
+
while (charAt(i) === "+") {
|
|
401
|
+
processed2 = true;
|
|
402
|
+
i++;
|
|
403
|
+
parseWhitespaceAndSkipComments();
|
|
404
|
+
output = stripLastOccurrence(output, '"', true);
|
|
405
|
+
const start = output.length;
|
|
406
|
+
const parsedStr = parseString();
|
|
407
|
+
if (parsedStr) {
|
|
408
|
+
output = removeAtIndex(output, start, 1);
|
|
409
|
+
} else {
|
|
410
|
+
output = insertBeforeLastWhitespace(output, '"');
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return processed2;
|
|
414
|
+
}
|
|
415
|
+
function parseNumber() {
|
|
416
|
+
const start = i;
|
|
417
|
+
if (charAt(i) === "-") {
|
|
418
|
+
i++;
|
|
419
|
+
if (atEndOfNumber()) {
|
|
420
|
+
repairNumberEndingWithNumericSymbol(start);
|
|
421
|
+
return true;
|
|
422
|
+
}
|
|
423
|
+
if (!isDigit(charAt(i))) {
|
|
424
|
+
i = start;
|
|
425
|
+
return false;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
while (isDigit(charAt(i))) {
|
|
429
|
+
i++;
|
|
430
|
+
}
|
|
431
|
+
if (charAt(i) === ".") {
|
|
432
|
+
i++;
|
|
433
|
+
if (atEndOfNumber()) {
|
|
434
|
+
repairNumberEndingWithNumericSymbol(start);
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
if (!isDigit(charAt(i))) {
|
|
438
|
+
i = start;
|
|
439
|
+
return false;
|
|
440
|
+
}
|
|
441
|
+
while (isDigit(charAt(i))) {
|
|
442
|
+
i++;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (charAt(i) === "e" || charAt(i) === "E") {
|
|
446
|
+
i++;
|
|
447
|
+
if (charAt(i) === "-" || charAt(i) === "+") {
|
|
448
|
+
i++;
|
|
449
|
+
}
|
|
450
|
+
if (atEndOfNumber()) {
|
|
451
|
+
repairNumberEndingWithNumericSymbol(start);
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
if (!isDigit(charAt(i))) {
|
|
455
|
+
i = start;
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
while (isDigit(charAt(i))) {
|
|
459
|
+
i++;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
if (!atEndOfNumber()) {
|
|
463
|
+
i = start;
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
if (i > start) {
|
|
467
|
+
const num = text.slice(start, i);
|
|
468
|
+
const hasInvalidLeadingZero = /^0\d/.test(num);
|
|
469
|
+
output += hasInvalidLeadingZero ? `"${num}"` : num;
|
|
470
|
+
return true;
|
|
471
|
+
}
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
function parseKeywords() {
|
|
475
|
+
return parseKeyword("true", "true") || parseKeyword("false", "false") || parseKeyword("null", "null") || // repair Python keywords True, False, None
|
|
476
|
+
parseKeyword("True", "true") || parseKeyword("False", "false") || parseKeyword("None", "null");
|
|
477
|
+
}
|
|
478
|
+
function parseKeyword(name, value) {
|
|
479
|
+
if (text.slice(i, i + name.length) === name) {
|
|
480
|
+
output += value;
|
|
481
|
+
i += name.length;
|
|
482
|
+
return true;
|
|
483
|
+
}
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
function parseUnquotedString(isKey) {
|
|
487
|
+
const start = i;
|
|
488
|
+
if (isFunctionNameCharStart(charAt(i))) {
|
|
489
|
+
while (i < text.length && isFunctionNameChar(charAt(i))) {
|
|
490
|
+
i++;
|
|
491
|
+
}
|
|
492
|
+
let j = i;
|
|
493
|
+
while (isWhitespace(text, j)) {
|
|
494
|
+
j++;
|
|
495
|
+
}
|
|
496
|
+
if (charAt(j) === "(") {
|
|
497
|
+
i = j + 1;
|
|
498
|
+
parseValue();
|
|
499
|
+
if (charAt(i) === ")") {
|
|
500
|
+
i++;
|
|
501
|
+
if (charAt(i) === ";") {
|
|
502
|
+
i++;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return true;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
while (i < text.length && !isUnquotedStringDelimiter(charAt(i)) && !isQuote(charAt(i)) && (!isKey || charAt(i) !== ":")) {
|
|
509
|
+
i++;
|
|
510
|
+
}
|
|
511
|
+
if (charAt(i - 1) === ":" && regexUrlStart.test(text.substring(i, i + 2))) {
|
|
512
|
+
while (i < text.length && regexUrlChar.test(charAt(i))) {
|
|
513
|
+
i++;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
if (i > start) {
|
|
517
|
+
while (isWhitespace(text, i - 1) && i > 0) {
|
|
518
|
+
i--;
|
|
519
|
+
}
|
|
520
|
+
const symbol = text.slice(start, i);
|
|
521
|
+
output += symbol === "undefined" ? "null" : JSON.stringify(symbol);
|
|
522
|
+
if (charAt(i) === '"') {
|
|
523
|
+
i++;
|
|
524
|
+
}
|
|
525
|
+
return true;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
function parseRegex() {
|
|
529
|
+
if (charAt(i) === "/") {
|
|
530
|
+
const start = i;
|
|
531
|
+
i++;
|
|
532
|
+
while (i < text.length && (charAt(i) !== "/" || charAt(i - 1) === "\\")) {
|
|
533
|
+
i++;
|
|
534
|
+
}
|
|
535
|
+
i++;
|
|
536
|
+
output += `"${text.substring(start, i)}"`;
|
|
537
|
+
return true;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
function prevNonWhitespaceIndex(start) {
|
|
541
|
+
let prev = start;
|
|
542
|
+
while (prev > 0 && isWhitespace(text, prev)) {
|
|
543
|
+
prev--;
|
|
544
|
+
}
|
|
545
|
+
return prev;
|
|
546
|
+
}
|
|
547
|
+
function atEndOfNumber() {
|
|
548
|
+
return i >= text.length || isDelimiter(charAt(i)) || isWhitespace(text, i);
|
|
549
|
+
}
|
|
550
|
+
function repairNumberEndingWithNumericSymbol(start) {
|
|
551
|
+
output += `${text.slice(start, i)}0`;
|
|
552
|
+
}
|
|
553
|
+
function throwInvalidCharacter(char) {
|
|
554
|
+
throw new JSONRepairError(`Invalid character ${JSON.stringify(char)}`, i);
|
|
555
|
+
}
|
|
556
|
+
function throwUnexpectedCharacter() {
|
|
557
|
+
throw new JSONRepairError(`Unexpected character ${JSON.stringify(charAt(i))}`, i);
|
|
558
|
+
}
|
|
559
|
+
function throwUnexpectedEnd() {
|
|
560
|
+
throw new JSONRepairError("Unexpected end of json string", text.length);
|
|
561
|
+
}
|
|
562
|
+
function throwObjectKeyExpected() {
|
|
563
|
+
throw new JSONRepairError("Object key expected", i);
|
|
564
|
+
}
|
|
565
|
+
function throwColonExpected() {
|
|
566
|
+
throw new JSONRepairError("Colon expected", i);
|
|
567
|
+
}
|
|
568
|
+
function throwInvalidUnicodeCharacter() {
|
|
569
|
+
const chars = text.slice(i, i + 6);
|
|
570
|
+
throw new JSONRepairError(`Invalid unicode character "${chars}"`, i);
|
|
571
|
+
}
|
|
572
|
+
return output;
|
|
573
|
+
}
|
|
574
|
+
function atEndOfBlockComment(text, i) {
|
|
575
|
+
return text[i] === "*" && text[i + 1] === "/";
|
|
576
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Schema type definition
|
|
3
|
+
*/
|
|
4
|
+
export interface JSONSchema {
|
|
5
|
+
type?: "string" | "number" | "boolean" | "object" | "array" | "null";
|
|
6
|
+
properties?: Record<string, JSONSchema>;
|
|
7
|
+
items?: JSONSchema;
|
|
8
|
+
required?: string[];
|
|
9
|
+
minItems?: number;
|
|
10
|
+
maxItems?: number;
|
|
11
|
+
minProperties?: number;
|
|
12
|
+
maxProperties?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Validates a JSON value against a JSON Schema.
|
|
16
|
+
*
|
|
17
|
+
* @param value - The value to validate
|
|
18
|
+
* @param schema - The JSON Schema to validate against
|
|
19
|
+
* @returns true if valid, throws JsonSchemaError if invalid
|
|
20
|
+
* @throws {JsonSchemaError} If validation fails
|
|
21
|
+
*/
|
|
22
|
+
export declare function validateJson(value: unknown, schema: JSONSchema): boolean;
|