PluginProbe ʕ •ᴥ•ʔ
GPTranslate – Multilingual AI Translation for WordPress: Automatically Translate Websites / 2.28
GPTranslate – Multilingual AI Translation for WordPress: Automatically Translate Websites v2.28
2.33.7 2.33.6 2.33.5 2.33.2 2.32.10 2.33 2.33.1 2.32.6 2.32.7 2.32.8 trunk 2.10.3 2.10.4 2.10.5 2.10.6 2.11 2.12 2.13 2.14 2.14.1 2.15 2.15.1 2.16.1 2.16.2 2.17 2.18 2.18.1 2.18.2 2.19 2.20 2.21 2.22 2.23 2.24 2.25 2.25.1 2.25.2 2.26 2.27 2.27.10 2.27.5 2.28 2.28.1 2.29 2.30 2.31 2.32 2.32.5
gptranslate / assets / js / jsonrepair / streaming / core.js
gptranslate / assets / js / jsonrepair / streaming Last commit date
buffer 3 months ago core.js 3 months ago core.js.map 3 months ago stack.js 3 months ago stack.js.map 3 months ago stream.js 3 months ago stream.js.map 3 months ago
core.js
730 lines
1 import { JSONRepairError } from '../utils/JSONRepairError.js';
2 import { codeAsterisk, codeBackslash, codeCloseParenthesis, codeClosingBrace, codeClosingBracket, codeColon, codeComma, codeDot, codeDoubleQuote, codeLowercaseE, codeMinus, codeNewline, codeOpeningBrace, codeOpeningBracket, codeOpenParenthesis, codePlus, codeSemicolon, codeSlash, codeUppercaseE, isControlCharacter, isDelimiter, isDelimiterExceptSlash, isDigit, isDoubleQuote, isDoubleQuoteLike, isFunctionName, isHex, isQuote, isSingleQuote, isSingleQuoteLike, isSpecialWhitespace, isStartOfValue, isValidStringCharacter, isWhitespace } from '../utils/stringUtils.js';
3 import { createInputBuffer } from './buffer/InputBuffer.js';
4 import { createOutputBuffer } from './buffer/OutputBuffer.js';
5 import { Caret, createStack, StackType } from './stack.js';
6 const controlCharacters = {
7 '\b': '\\b',
8 '\f': '\\f',
9 '\n': '\\n',
10 '\r': '\\r',
11 '\t': '\\t'
12 };
13
14 // map with all escape characters
15 const escapeCharacters = {
16 '"': '"',
17 '\\': '\\',
18 '/': '/',
19 b: '\b',
20 f: '\f',
21 n: '\n',
22 r: '\r',
23 t: '\t'
24 // note that \u is handled separately in parseString()
25 };
26 export function jsonrepairCore(_ref) {
27 let {
28 onData,
29 bufferSize = 65536,
30 chunkSize = 65536
31 } = _ref;
32 const input = createInputBuffer();
33 const output = createOutputBuffer({
34 write: onData,
35 bufferSize,
36 chunkSize
37 });
38 let i = 0;
39 let iFlushed = 0;
40 const stack = createStack();
41 function flushInputBuffer() {
42 while (iFlushed < i - bufferSize - chunkSize) {
43 iFlushed += chunkSize;
44 input.flush(iFlushed);
45 }
46 }
47 function transform(chunk) {
48 input.push(chunk);
49 while (i < input.currentLength() - bufferSize && parse()) {
50 // loop until there is nothing more to process
51 }
52 flushInputBuffer();
53 }
54 function flush() {
55 input.close();
56 while (parse()) {
57 // loop until there is nothing more to process
58 }
59 output.flush();
60 }
61 function parse() {
62 parseWhitespaceAndSkipComments();
63 switch (stack.type) {
64 case StackType.object:
65 {
66 switch (stack.caret) {
67 case Caret.beforeKey:
68 return skipEllipsis() || parseObjectKey() || parseUnexpectedColon() || parseRepairTrailingComma() || parseRepairObjectEndOrComma();
69 case Caret.beforeValue:
70 return parseValue() || parseRepairMissingObjectValue();
71 case Caret.afterValue:
72 return parseObjectComma() || parseObjectEnd() || parseRepairObjectEndOrComma();
73 default:
74 return false;
75 }
76 }
77 case StackType.array:
78 {
79 switch (stack.caret) {
80 case Caret.beforeValue:
81 return skipEllipsis() || parseValue() || parseRepairTrailingComma() || parseRepairArrayEnd();
82 case Caret.afterValue:
83 return parseArrayComma() || parseArrayEnd() || parseRepairMissingComma() || parseRepairArrayEnd();
84 default:
85 return false;
86 }
87 }
88 case StackType.ndJson:
89 {
90 switch (stack.caret) {
91 case Caret.beforeValue:
92 return parseValue() || parseRepairTrailingComma();
93 case Caret.afterValue:
94 return parseArrayComma() || parseRepairMissingComma() || parseRepairNdJsonEnd();
95 default:
96 return false;
97 }
98 }
99 case StackType.functionCall:
100 {
101 switch (stack.caret) {
102 case Caret.beforeValue:
103 return parseValue();
104 case Caret.afterValue:
105 return parseFunctionCallEnd();
106 default:
107 return false;
108 }
109 }
110 case StackType.root:
111 {
112 switch (stack.caret) {
113 case Caret.beforeValue:
114 return parseValue() || parseUnexpectedEnd();
115 case Caret.afterValue:
116 return parseRootEnd();
117 default:
118 return false;
119 }
120 }
121 default:
122 return false;
123 }
124 }
125 function parseValue() {
126 return parseObjectStart() || parseArrayStart() || parseString() || parseNumber() || parseKeywords() || parseRepairUnquotedString();
127 }
128 function parseObjectStart() {
129 if (parseCharacter(codeOpeningBrace)) {
130 parseWhitespaceAndSkipComments();
131 skipEllipsis();
132 if (skipCharacter(codeComma)) {
133 parseWhitespaceAndSkipComments();
134 }
135 if (parseCharacter(codeClosingBrace)) {
136 return stack.update(Caret.afterValue);
137 }
138 return stack.push(StackType.object, Caret.beforeKey);
139 }
140 return false;
141 }
142 function parseArrayStart() {
143 if (parseCharacter(codeOpeningBracket)) {
144 parseWhitespaceAndSkipComments();
145 skipEllipsis();
146 if (skipCharacter(codeComma)) {
147 parseWhitespaceAndSkipComments();
148 }
149 if (parseCharacter(codeClosingBracket)) {
150 return stack.update(Caret.afterValue);
151 }
152 return stack.push(StackType.array, Caret.beforeValue);
153 }
154 return false;
155 }
156 function parseRepairUnquotedString() {
157 const unquotedStringEnd = findNextDelimiter();
158 if (unquotedStringEnd !== null) {
159 const symbol = input.substring(i, unquotedStringEnd);
160 i = unquotedStringEnd;
161 if (skipCharacter(codeOpenParenthesis) && isFunctionName(symbol.trim())) {
162 // A MongoDB function call like NumberLong("2")
163 // Or a JSONP function call like callback({...});
164 // we strip the function call
165
166 return stack.push(StackType.functionCall, Caret.beforeValue);
167 }
168 output.push(symbol === 'undefined' ? 'null' : JSON.stringify(symbol));
169 if (input.charCodeAt(i) === codeDoubleQuote) {
170 // we had a missing start quote, but now we encountered the end quote, so we can skip that one
171 i++;
172 }
173 return stack.update(Caret.afterValue);
174 }
175 return false;
176 }
177 function parseRepairMissingObjectValue() {
178 // repair missing object value
179 output.push('null');
180 return stack.update(Caret.afterValue);
181 }
182 function parseRepairTrailingComma() {
183 // repair trailing comma
184 if (output.endsWithIgnoringWhitespace(',')) {
185 output.stripLastOccurrence(',');
186 return stack.update(Caret.afterValue);
187 }
188 return false;
189 }
190 function parseUnexpectedColon() {
191 if (input.charCodeAt(i) === codeColon) {
192 throwObjectKeyExpected();
193 }
194 return false;
195 }
196 function parseUnexpectedEnd() {
197 if (input.isEnd(i)) {
198 throwUnexpectedEnd();
199 } else {
200 throwUnexpectedCharacter();
201 }
202 return false;
203 }
204 function parseObjectKey() {
205 const parsedKey = parseString() || parseUnquotedKey();
206 if (parsedKey) {
207 parseWhitespaceAndSkipComments();
208 if (parseCharacter(codeColon)) {
209 // expect a value after the :
210 return stack.update(Caret.beforeValue);
211 }
212 const truncatedText = input.isEnd(i);
213 if (isStartOfValue(input.charAt(i)) || truncatedText) {
214 // repair missing colon
215 output.insertBeforeLastWhitespace(':');
216 return stack.update(Caret.beforeValue);
217 }
218 throwColonExpected();
219 }
220 return false;
221 }
222 function parseObjectComma() {
223 if (parseCharacter(codeComma)) {
224 return stack.update(Caret.beforeKey);
225 }
226 return false;
227 }
228 function parseObjectEnd() {
229 if (parseCharacter(codeClosingBrace)) {
230 return stack.pop();
231 }
232 return false;
233 }
234 function parseRepairObjectEndOrComma() {
235 // repair missing object end and trailing comma
236 if (input.charAt(i) === '{') {
237 output.stripLastOccurrence(',');
238 output.insertBeforeLastWhitespace('}');
239 return stack.pop();
240 }
241
242 // repair missing comma
243 if (!input.isEnd(i) && isStartOfValue(input.charAt(i))) {
244 output.insertBeforeLastWhitespace(',');
245 return stack.update(Caret.beforeKey);
246 }
247
248 // repair missing closing brace
249 output.insertBeforeLastWhitespace('}');
250 return stack.pop();
251 }
252 function parseArrayComma() {
253 if (parseCharacter(codeComma)) {
254 return stack.update(Caret.beforeValue);
255 }
256 return false;
257 }
258 function parseArrayEnd() {
259 if (parseCharacter(codeClosingBracket)) {
260 return stack.pop();
261 }
262 return false;
263 }
264 function parseRepairMissingComma() {
265 // repair missing comma
266 if (!input.isEnd(i) && isStartOfValue(input.charAt(i))) {
267 output.insertBeforeLastWhitespace(',');
268 return stack.update(Caret.beforeValue);
269 }
270 return false;
271 }
272 function parseRepairArrayEnd() {
273 // repair missing closing bracket
274 output.insertBeforeLastWhitespace(']');
275 return stack.pop();
276 }
277 function parseRepairNdJsonEnd() {
278 if (input.isEnd(i)) {
279 output.push('\n]');
280 return stack.pop();
281 } else {
282 throwUnexpectedEnd();
283 return false; // just to make TS happy
284 }
285 }
286 function parseFunctionCallEnd() {
287 if (skipCharacter(codeCloseParenthesis)) {
288 skipCharacter(codeSemicolon);
289 }
290 return stack.pop();
291 }
292 function parseRootEnd() {
293 const parsedComma = parseCharacter(codeComma);
294 parseWhitespaceAndSkipComments();
295 if (isStartOfValue(input.charAt(i)) && (output.endsWithIgnoringWhitespace(',') || output.endsWithIgnoringWhitespace('\n'))) {
296 // start of a new value after end of the root level object: looks like
297 // newline delimited JSON -> turn into a root level array
298 if (!parsedComma) {
299 // repair missing comma
300 output.insertBeforeLastWhitespace(',');
301 }
302 output.unshift('[\n');
303 return stack.push(StackType.ndJson, Caret.beforeValue);
304 }
305 if (parsedComma) {
306 // repair: remove trailing comma
307 output.stripLastOccurrence(',');
308 return stack.update(Caret.afterValue);
309 }
310
311 // repair redundant end braces and brackets
312 while (input.charCodeAt(i) === codeClosingBrace || input.charCodeAt(i) === codeClosingBracket) {
313 i++;
314 parseWhitespaceAndSkipComments();
315 }
316 if (!input.isEnd(i)) {
317 throwUnexpectedCharacter();
318 }
319 return false;
320 }
321 function parseWhitespaceAndSkipComments() {
322 const start = i;
323 let changed = parseWhitespace();
324 do {
325 changed = parseComment();
326 if (changed) {
327 changed = parseWhitespace();
328 }
329 } while (changed);
330 return i > start;
331 }
332 function parseWhitespace() {
333 let whitespace = '';
334 let normal;
335 while ((normal = isWhitespace(input.charCodeAt(i))) || isSpecialWhitespace(input.charCodeAt(i))) {
336 if (normal) {
337 whitespace += input.charAt(i);
338 } else {
339 // repair special whitespace
340 whitespace += ' ';
341 }
342 i++;
343 }
344 if (whitespace.length > 0) {
345 output.push(whitespace);
346 return true;
347 }
348 return false;
349 }
350 function parseComment() {
351 // find a block comment '/* ... */'
352 if (input.charCodeAt(i) === codeSlash && input.charCodeAt(i + 1) === codeAsterisk) {
353 // repair block comment by skipping it
354 while (!input.isEnd(i) && !atEndOfBlockComment(i)) {
355 i++;
356 }
357 i += 2;
358 return true;
359 }
360
361 // find a line comment '// ...'
362 if (input.charCodeAt(i) === codeSlash && input.charCodeAt(i + 1) === codeSlash) {
363 // repair line comment by skipping it
364 while (!input.isEnd(i) && input.charCodeAt(i) !== codeNewline) {
365 i++;
366 }
367 return true;
368 }
369 return false;
370 }
371 function parseCharacter(code) {
372 if (input.charCodeAt(i) === code) {
373 output.push(input.charAt(i));
374 i++;
375 return true;
376 }
377 return false;
378 }
379 function skipCharacter(code) {
380 if (input.charCodeAt(i) === code) {
381 i++;
382 return true;
383 }
384 return false;
385 }
386 function skipEscapeCharacter() {
387 return skipCharacter(codeBackslash);
388 }
389
390 /**
391 * Skip ellipsis like "[1,2,3,...]" or "[1,2,3,...,9]" or "[...,7,8,9]"
392 * or a similar construct in objects.
393 */
394 function skipEllipsis() {
395 parseWhitespaceAndSkipComments();
396 if (input.charCodeAt(i) === codeDot && input.charCodeAt(i + 1) === codeDot && input.charCodeAt(i + 2) === codeDot) {
397 // repair: remove the ellipsis (three dots) and optionally a comma
398 i += 3;
399 parseWhitespaceAndSkipComments();
400 skipCharacter(codeComma);
401 return true;
402 }
403 return false;
404 }
405
406 /**
407 * Parse a string enclosed by double quotes "...". Can contain escaped quotes
408 * Repair strings enclosed in single quotes or special quotes
409 * Repair an escaped string
410 *
411 * The function can run in two stages:
412 * - First, it assumes the string has a valid end quote
413 * - If it turns out that the string does not have a valid end quote followed
414 * by a delimiter (which should be the case), the function runs again in a
415 * more conservative way, stopping the string at the first next delimiter
416 * and fixing the string by inserting a quote there.
417 */
418 function parseString() {
419 let stopAtDelimiter = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
420 let skipEscapeChars = input.charCodeAt(i) === codeBackslash;
421 if (skipEscapeChars) {
422 // repair: remove the first escape character
423 i++;
424 skipEscapeChars = true;
425 }
426 if (isQuote(input.charCodeAt(i))) {
427 // double quotes are correct JSON,
428 // single quotes come from JavaScript for example, we assume it will have a correct single end quote too
429 // otherwise, we will match any double-quote-like start with a double-quote-like end,
430 // or any single-quote-like start with a single-quote-like end
431 const isEndQuote = isDoubleQuote(input.charCodeAt(i)) ? isDoubleQuote : isSingleQuote(input.charCodeAt(i)) ? isSingleQuote : isSingleQuoteLike(input.charCodeAt(i)) ? isSingleQuoteLike : isDoubleQuoteLike;
432 const iBefore = i;
433 const oBefore = output.length();
434 output.push('"');
435 i++;
436 while (true) {
437 if (input.isEnd(i)) {
438 // end of text, we have a missing quote somewhere
439
440 const iPrev = prevNonWhitespaceIndex(i - 1);
441 if (!stopAtDelimiter && isDelimiter(input.charAt(iPrev))) {
442 // if the text ends with a delimiter, like ["hello],
443 // so the missing end quote should be inserted before this delimiter
444 // retry parsing the string, stopping at the first next delimiter
445 i = iBefore;
446 output.remove(oBefore);
447 return parseString(true);
448 }
449
450 // repair missing quote
451 output.insertBeforeLastWhitespace('"');
452 return stack.update(Caret.afterValue);
453 } else if (isEndQuote(input.charCodeAt(i))) {
454 // end quote
455 // let us check what is before and after the quote to verify whether this is a legit end quote
456 const iQuote = i;
457 const oQuote = output.length();
458 output.push('"');
459 i++;
460 parseWhitespaceAndSkipComments();
461 if (stopAtDelimiter || input.isEnd(i) || isDelimiter(input.charAt(i)) || isQuote(input.charCodeAt(i)) || isDigit(input.charCodeAt(i))) {
462 // The quote is followed by the end of the text, a delimiter, or a next value
463 // so the quote is indeed the end of the string
464 parseConcatenatedString();
465 return stack.update(Caret.afterValue);
466 }
467 if (isDelimiter(input.charAt(prevNonWhitespaceIndex(iQuote - 1)))) {
468 // This is not the right end quote: it is preceded by a delimiter,
469 // and NOT followed by a delimiter. So, there is an end quote missing
470 // parse the string again and then stop at the first next delimiter
471 i = iBefore;
472 output.remove(oBefore);
473 return parseString(true);
474 }
475
476 // revert to right after the quote but before any whitespace, and continue parsing the string
477 output.remove(oQuote + 1);
478 i = iQuote + 1;
479
480 // repair unescaped quote
481 output.insertAt(oQuote, '\\');
482 } else if (stopAtDelimiter && isDelimiter(input.charAt(i))) {
483 // we're in the mode to stop the string at the first delimiter
484 // because there is an end quote missing
485
486 // repair missing quote
487 output.insertBeforeLastWhitespace('"');
488 parseConcatenatedString();
489 return stack.update(Caret.afterValue);
490 } else if (input.charCodeAt(i) === codeBackslash) {
491 // handle escaped content like \n or \u2605
492 const char = input.charAt(i + 1);
493 const escapeChar = escapeCharacters[char];
494 if (escapeChar !== undefined) {
495 output.push(input.substring(i, i + 2));
496 i += 2;
497 } else if (char === 'u') {
498 let j = 2;
499 while (j < 6 && isHex(input.charCodeAt(i + j))) {
500 j++;
501 }
502 if (j === 6) {
503 output.push(input.substring(i, i + 6));
504 i += 6;
505 } else if (input.isEnd(i + j)) {
506 // repair invalid or truncated unicode char at the end of the text
507 // by removing the unicode char and ending the string here
508 i += j;
509 } else {
510 throwInvalidUnicodeCharacter();
511 }
512 } else {
513 // repair invalid escape character: remove it
514 output.push(char);
515 i += 2;
516 }
517 } else {
518 // handle regular characters
519 const char = input.charAt(i);
520 const code = char.charCodeAt(0);
521 if (code === codeDoubleQuote && input.charCodeAt(i - 1) !== codeBackslash) {
522 // repair unescaped double quote
523 output.push('\\' + char);
524 i++;
525 } else if (isControlCharacter(code)) {
526 // unescaped control character
527 output.push(controlCharacters[char]);
528 i++;
529 } else {
530 if (!isValidStringCharacter(code)) {
531 throwInvalidCharacter(char);
532 }
533 output.push(char);
534 i++;
535 }
536 }
537 if (skipEscapeChars) {
538 // repair: skipped escape character (nothing to do)
539 skipEscapeCharacter();
540 }
541 }
542 }
543 return false;
544 }
545
546 /**
547 * Repair concatenated strings like "hello" + "world", change this into "helloworld"
548 */
549 function parseConcatenatedString() {
550 let parsed = false;
551 parseWhitespaceAndSkipComments();
552 while (input.charCodeAt(i) === codePlus) {
553 parsed = true;
554 i++;
555 parseWhitespaceAndSkipComments();
556
557 // repair: remove the end quote of the first string
558 output.stripLastOccurrence('"', true);
559 const start = output.length();
560 const parsedStr = parseString();
561 if (parsedStr) {
562 // repair: remove the start quote of the second string
563 output.remove(start, start + 1);
564 } else {
565 // repair: remove the + because it is not followed by a string
566 output.insertBeforeLastWhitespace('"');
567 }
568 }
569 return parsed;
570 }
571
572 /**
573 * Parse a number like 2.4 or 2.4e6
574 */
575 function parseNumber() {
576 const start = i;
577 if (input.charCodeAt(i) === codeMinus) {
578 i++;
579 if (atEndOfNumber()) {
580 repairNumberEndingWithNumericSymbol(start);
581 return stack.update(Caret.afterValue);
582 }
583 if (!isDigit(input.charCodeAt(i))) {
584 i = start;
585 return false;
586 }
587 }
588
589 // Note that in JSON leading zeros like "00789" are not allowed.
590 // We will allow all leading zeros here though and at the end of parseNumber
591 // check against trailing zeros and repair that if needed.
592 // Leading zeros can have meaning, so we should not clear them.
593 while (isDigit(input.charCodeAt(i))) {
594 i++;
595 }
596 if (input.charCodeAt(i) === codeDot) {
597 i++;
598 if (atEndOfNumber()) {
599 repairNumberEndingWithNumericSymbol(start);
600 return stack.update(Caret.afterValue);
601 }
602 if (!isDigit(input.charCodeAt(i))) {
603 i = start;
604 return false;
605 }
606 while (isDigit(input.charCodeAt(i))) {
607 i++;
608 }
609 }
610 if (input.charCodeAt(i) === codeLowercaseE || input.charCodeAt(i) === codeUppercaseE) {
611 i++;
612 if (input.charCodeAt(i) === codeMinus || input.charCodeAt(i) === codePlus) {
613 i++;
614 }
615 if (atEndOfNumber()) {
616 repairNumberEndingWithNumericSymbol(start);
617 return stack.update(Caret.afterValue);
618 }
619 if (!isDigit(input.charCodeAt(i))) {
620 i = start;
621 return false;
622 }
623 while (isDigit(input.charCodeAt(i))) {
624 i++;
625 }
626 }
627
628 // if we're not at the end of the number by this point, allow this to be parsed as another type
629 if (!atEndOfNumber()) {
630 i = start;
631 return false;
632 }
633 if (i > start) {
634 // repair a number with leading zeros like "00789"
635 const num = input.substring(start, i);
636 const hasInvalidLeadingZero = /^0\d/.test(num);
637 output.push(hasInvalidLeadingZero ? "\"".concat(num, "\"") : num);
638 return stack.update(Caret.afterValue);
639 }
640 return false;
641 }
642
643 /**
644 * Parse keywords true, false, null
645 * Repair Python keywords True, False, None
646 */
647 function parseKeywords() {
648 return parseKeyword('true', 'true') || parseKeyword('false', 'false') || parseKeyword('null', 'null') ||
649 // repair Python keywords True, False, None
650 parseKeyword('True', 'true') || parseKeyword('False', 'false') || parseKeyword('None', 'null');
651 }
652 function parseKeyword(name, value) {
653 if (input.substring(i, i + name.length) === name) {
654 output.push(value);
655 i += name.length;
656 return stack.update(Caret.afterValue);
657 }
658 return false;
659 }
660 function parseUnquotedKey() {
661 let end = findNextDelimiter();
662 if (end !== null) {
663 // first, go back to prevent getting trailing whitespaces in the string
664 while (isWhitespace(input.charCodeAt(end - 1)) && end > i) {
665 end--;
666 }
667 const symbol = input.substring(i, end);
668 output.push(JSON.stringify(symbol));
669 i = end;
670 if (input.charCodeAt(i) === codeDoubleQuote) {
671 // we had a missing start quote, but now we encountered the end quote, so we can skip that one
672 i++;
673 }
674 return stack.update(Caret.afterValue); // we do not have a state Caret.afterKey, therefore we use afterValue here
675 }
676 return false;
677 }
678 function findNextDelimiter() {
679 // note that the symbol can end with whitespaces: we stop at the next delimiter
680 // also, note that we allow strings to contain a slash / in order to support repairing regular expressions
681 let j = i;
682 while (!input.isEnd(j) && !isDelimiterExceptSlash(input.charAt(j)) && !isQuote(input.charCodeAt(j))) {
683 j++;
684 }
685 return j > i ? j : null;
686 }
687 function prevNonWhitespaceIndex(start) {
688 let prev = start;
689 while (prev > 0 && isWhitespace(input.charCodeAt(prev))) {
690 prev--;
691 }
692 return prev;
693 }
694 function atEndOfNumber() {
695 return input.isEnd(i) || isDelimiter(input.charAt(i)) || isWhitespace(input.charCodeAt(i));
696 }
697 function repairNumberEndingWithNumericSymbol(start) {
698 // repair numbers cut off at the end
699 // this will only be called when we end after a '.', '-', or 'e' and does not
700 // change the number more than it needs to make it valid JSON
701 output.push(input.substring(start, i) + '0');
702 }
703 function throwInvalidCharacter(char) {
704 throw new JSONRepairError('Invalid character ' + JSON.stringify(char), i);
705 }
706 function throwUnexpectedCharacter() {
707 throw new JSONRepairError('Unexpected character ' + JSON.stringify(input.charAt(i)), i);
708 }
709 function throwUnexpectedEnd() {
710 throw new JSONRepairError('Unexpected end of json string', i);
711 }
712 function throwObjectKeyExpected() {
713 throw new JSONRepairError('Object key expected', i);
714 }
715 function throwColonExpected() {
716 throw new JSONRepairError('Colon expected', i);
717 }
718 function throwInvalidUnicodeCharacter() {
719 const chars = input.substring(i, i + 6);
720 throw new JSONRepairError("Invalid unicode character \"".concat(chars, "\""), i);
721 }
722 function atEndOfBlockComment(i) {
723 return input.charAt(i) === '*' && input.charAt(i + 1) === '/';
724 }
725 return {
726 transform,
727 flush
728 };
729 }
730 //# sourceMappingURL=core.js.map