Skip to content

Commit

Permalink
fix: improve resolving unquoted strings and missing colon
Browse files Browse the repository at this point in the history
  • Loading branch information
josdejong committed Dec 19, 2022
1 parent ca97fef commit 45cd4e4
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 16 deletions.
4 changes: 2 additions & 2 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ <h1>jsonrepair</h1>
<div class="column">
<label for="input-text">Input (invalid JSON)</label>
<textarea id="input-text" autocomplete="off" autocapitalize="off" spellcheck="false">{
'firstName' 'John'
'firstName': 'John'

lastName: “Smith”
lastName “Smith”

fullName: John Smith,

Expand Down
12 changes: 12 additions & 0 deletions src/jsonrepair.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ describe('jsonRepair', () => {
strictEqual(jsonrepair("{a:'foo',b:'bar'}"), '{"a":"foo","b":"bar"}')
})

it('should replace special quotes with double quotes', () => {
strictEqual(jsonrepair('{“a”:“b”}'), '{"a":"b"}')
strictEqual(jsonrepair('{‘a’:‘b’}'), '{"a":"b"}')
strictEqual(jsonrepair('{`a´:`b´}'), '{"a":"b"}')
})

it('should leave string content untouched', () => {
strictEqual(jsonrepair('"{a:b}"'), '"{a:b}"')
})
Expand Down Expand Up @@ -341,7 +347,13 @@ describe('jsonRepair', () => {

it('should repair missing colon between object key and value', () => {
strictEqual(jsonrepair('{"a" "b"}'), '{"a": "b"}')
strictEqual(jsonrepair('{"a" 2}'), '{"a": 2}')
strictEqual(jsonrepair('{\n"a" "b"\n}'), '{\n"a": "b"\n}')
strictEqual(jsonrepair('{"a" \'b\'}'), '{"a": "b"}')
strictEqual(jsonrepair("{'a' 'b'}"), '{"a": "b"}')
strictEqual(jsonrepair('{“a” “b”}'), '{"a": "b"}')
strictEqual(jsonrepair("{a 'b'}"), '{"a": "b"}')
strictEqual(jsonrepair('{a “b”}'), '{"a": "b"}')
})

it('should repair missing a combination of comma, quotes and brackets', () => {
Expand Down
9 changes: 7 additions & 2 deletions src/jsonrepair.ts
Original file line number Diff line number Diff line change
Expand Up @@ -561,8 +561,6 @@ export function jsonrepair(text: string): string {
}

if (i > start) {
const symbol = text.slice(start, i)

if (text.charCodeAt(i) === codeOpenParenthesis) {
// repair a MongoDB function call like NumberLong("2")
// repair a JSONP function call like callback({...});
Expand All @@ -582,6 +580,13 @@ export function jsonrepair(text: string): string {
return true
} else {
// repair unquoted string

// first, go back to prevent getting trailing whitespaces in the string
while (isWhitespace(text.charCodeAt(i - 1)) && i > 0) {
i--
}

const symbol = text.slice(start, i)
output += JSON.stringify(symbol)

return true
Expand Down
25 changes: 13 additions & 12 deletions src/stringUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ const codeHairSpace = 0x200a
const codeNarrowNoBreakSpace = 0x202f
const codeMediumMathematicalSpace = 0x205f
const codeIdeographicSpace = 0x3000
const codeDoubleQuoteLeft = 0x201c
const codeDoubleQuoteRight = 0x201d
const codeQuoteLeft = 0x2018
const codeQuoteRight = 0x2019
const codeGraveAccent = 0x0060
const codeAcuteAccent = 0x00b4
const codeDoubleQuoteLeft = 0x201c // “
const codeDoubleQuoteRight = 0x201d // ”
const codeQuoteLeft = 0x2018 // ‘
const codeQuoteRight = 0x2019 // ’
const codeGraveAccent = 0x0060 // `
const codeAcuteAccent = 0x00b4 // ´

export function isHex(code: number): boolean {
return (
Expand All @@ -65,16 +65,17 @@ export function isValidStringCharacter(code: number): boolean {
}

export function isDelimiter(char: string): boolean {
return regexDelimiter.test(char)
return regexDelimiter.test(char) || (char && isQuote(char.charCodeAt(0)))
}

const regexDelimiter = /^[,:[\]{}()\n"]$/
const regexDelimiter = /^[,:[\]{}()\n]$/

export function isStartOfValue(char: string): boolean {
return regexStartOfValue.test(char)
return regexStartOfValue.test(char) || (char && isQuote(char.charCodeAt(0)))
}

const regexStartOfValue = /^[[{\w"-_]$/
// alpha, number, minus, or opening bracket or brace
const regexStartOfValue = /^[[{\w-]$/

export function isControlCharacter(code: number) {
return (
Expand Down Expand Up @@ -146,11 +147,11 @@ export function isSingleQuote(code: number): boolean {
export function stripLastOccurrence(
text: string,
textToStrip: string,
stripWhitespace = false
stripRemainingText = false
): string {
const index = text.lastIndexOf(textToStrip)
return index !== -1
? text.substring(0, index) + (stripWhitespace ? '' : text.substring(index + 1))
? text.substring(0, index) + (stripRemainingText ? '' : text.substring(index + 1))
: text
}

Expand Down

0 comments on commit 45cd4e4

Please sign in to comment.