diff --git a/src/index.test.ts b/src/index.test.ts index 551c2e6..3628354 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -586,6 +586,17 @@ describe.each(implementations)('jsonrepair [$name]', ({ jsonrepair }) => { test('should repair missing comma between object properties', () => { expect(jsonrepair('{"a":2\n"b":3\n}')).toBe('{"a":2,\n"b":3\n}') expect(jsonrepair('{"a":2\n"b":3\nc:4}')).toBe('{"a":2,\n"b":3,\n"c":4}') + expect(jsonrepair('{\n "firstName": "John"\n lastName: Smith')).toBe( + '{\n "firstName": "John",\n "lastName": "Smith"}' + ) + expect(jsonrepair('{\n "firstName": "John" /* comment */ \n lastName: Smith')).toBe( + '{\n "firstName": "John", \n "lastName": "Smith"}' + ) + + // verify parsing a comma after a return (since in parseString we stop at a return) + expect(jsonrepair('{\n "firstName": "John"\n , lastName: Smith')).toBe( + '{\n "firstName": "John"\n , "lastName": "Smith"}' + ) }) test('should repair numbers at the end', () => { diff --git a/src/regular/jsonrepair.ts b/src/regular/jsonrepair.ts index 1d599fb..f6d4a08 100644 --- a/src/regular/jsonrepair.ts +++ b/src/regular/jsonrepair.ts @@ -34,6 +34,7 @@ import { isUnquotedStringDelimiter, isValidStringCharacter, isWhitespace, + isWhitespaceExceptNewline, regexFunctionNameChar, regexFunctionNameCharStart, regexUrlChar, @@ -135,25 +136,30 @@ export function jsonrepair(text: string): string { return processed } - function parseWhitespaceAndSkipComments(): boolean { + function parseWhitespaceAndSkipComments(skipNewline = true): boolean { const start = i - let changed = parseWhitespace() + let changed = parseWhitespace(skipNewline) do { changed = parseComment() if (changed) { - changed = parseWhitespace() + changed = parseWhitespace(skipNewline) } } while (changed) return i > start } - function parseWhitespace(): boolean { + function parseWhitespace(skipNewline: boolean): boolean { + const _isWhiteSpace = skipNewline ? isWhitespace : isWhitespaceExceptNewline let whitespace = '' let normal: boolean - // biome-ignore lint/suspicious/noAssignInExpressions: - while ((normal = isWhitespace(text.charCodeAt(i))) || isSpecialWhitespace(text.charCodeAt(i))) { + + while ( + // biome-ignore lint/suspicious/noAssignInExpressions: + (normal = _isWhiteSpace(text.charCodeAt(i))) || + isSpecialWhitespace(text.charCodeAt(i)) + ) { if (normal) { whitespace += text[i] } else { @@ -486,7 +492,7 @@ export function jsonrepair(text: string): string { i++ output += str - parseWhitespaceAndSkipComments() + parseWhitespaceAndSkipComments(false) if ( stopAtDelimiter || diff --git a/src/streaming/core.ts b/src/streaming/core.ts index fce9b8a..5f9dbd8 100644 --- a/src/streaming/core.ts +++ b/src/streaming/core.ts @@ -33,6 +33,7 @@ import { isUnquotedStringDelimiter, isValidStringCharacter, isWhitespace, + isWhitespaceExceptNewline, regexFunctionNameChar, regexFunctionNameCharStart, regexUrlChar, @@ -494,26 +495,28 @@ export function jsonrepairCore({ return false } - function parseWhitespaceAndSkipComments(): boolean { + function parseWhitespaceAndSkipComments(skipNewline = true): boolean { const start = i - let changed = parseWhitespace() + let changed = parseWhitespace(skipNewline) do { changed = parseComment() if (changed) { - changed = parseWhitespace() + changed = parseWhitespace(skipNewline) } } while (changed) return i > start } - function parseWhitespace(): boolean { + function parseWhitespace(skipNewline: boolean): boolean { + const _isWhiteSpace = skipNewline ? isWhitespace : isWhitespaceExceptNewline let whitespace = '' let normal: boolean + while ( // biome-ignore lint/suspicious/noAssignInExpressions: - (normal = isWhitespace(input.charCodeAt(i))) || + (normal = _isWhiteSpace(input.charCodeAt(i))) || isSpecialWhitespace(input.charCodeAt(i)) ) { if (normal) { @@ -679,7 +682,7 @@ export function jsonrepairCore({ output.push('"') i++ - parseWhitespaceAndSkipComments() + parseWhitespaceAndSkipComments(false) if ( stopAtDelimiter || diff --git a/src/utils/stringUtils.ts b/src/utils/stringUtils.ts index 313d2b5..691545b 100644 --- a/src/utils/stringUtils.ts +++ b/src/utils/stringUtils.ts @@ -102,6 +102,14 @@ export function isWhitespace(code: number): boolean { return code === codeSpace || code === codeNewline || code === codeTab || code === codeReturn } +/** + * Check if the given character is a whitespace character like space or tab, + * but NOT a newline + */ +export function isWhitespaceExceptNewline(code: number): boolean { + return code === codeSpace || code === codeTab || code === codeReturn +} + /** * Check if the given character is a special whitespace character, some * unicode variant