Implement support for repairing line separate JSON

This commit is contained in:
jos 2020-03-25 12:11:33 +01:00
parent 0ba8321eb3
commit fd0db5dc73
3 changed files with 80 additions and 11 deletions

View File

@ -5,6 +5,7 @@ https://github.com/josdejong/jsoneditor
## not yet published, version 8.6.4
- Fix #921: `sortObjectKeys` emits `onChange` events.
- Implement support for repairing line separate JSON.
## 2020-03-18, version 8.6.3

View File

@ -41,6 +41,8 @@ export function repair (jsString) {
// escape all single and double quotes inside strings
const chars = []
let i = 0
let indent = 0
let isLineSeparatedJson = false
// If JSON starts with a function (characters/digits/"_-"), remove this function.
// This is useful for "stripping" JSONP objects to become JSON
@ -109,20 +111,38 @@ export function repair (jsString) {
// skip a block comment '/* ... */'
function skipBlockComment () {
if (curr() === '/' && next() === '*') {
i += 2
while (i < jsString.length && (curr() !== '*' || next() !== '/')) {
i++
}
i += 2
if (curr() === '\n') {
i++
}
}
}
// skip a comment '// ...'
function skipComment () {
if (curr() === '/' && next() === '/') {
i += 2
while (i < jsString.length && (curr() !== '\n')) {
i++
}
}
}
function parseWhiteSpace () {
let whitespace = ''
while (i < jsString.length && isWhiteSpace(curr())) {
whitespace += curr()
i++
}
return whitespace
}
/**
* parse single or double quoted string. Returns the parsed string
@ -245,13 +265,19 @@ export function repair (jsString) {
}
while (i < jsString.length) {
skipBlockComment()
skipComment()
const c = curr()
if (c === '/' && next() === '*') {
skipBlockComment()
} else if (c === '/' && next() === '/') {
skipComment()
} else if (isSpecialWhiteSpace(c)) {
if (c === '{') {
indent++
}
if (c === '}') {
indent--
}
if (isSpecialWhiteSpace(c)) {
// special white spaces (like non breaking space)
chars.push(' ')
i++
@ -265,6 +291,21 @@ export function repair (jsString) {
chars.push(parseString(quoteRight))
} else if (c === quoteDblLeft) {
chars.push(parseString(quoteDblRight))
} else if (c === '}') {
// check for missing comma between objects
chars.push(c)
i++
const whitespaces = parseWhiteSpace()
skipBlockComment()
if (curr() === '{' || nextNonWhiteSpace() === '{') {
chars.push(',')
if (indent === 0) {
isLineSeparatedJson = true
}
}
chars.push(whitespaces)
} else if (c === ',' && [']', '}'].indexOf(nextNonWhiteSpace()) !== -1) {
// skip trailing commas
i++
@ -280,6 +321,11 @@ export function repair (jsString) {
}
}
if (isLineSeparatedJson) {
chars.unshift('[\n')
chars.push('\n]')
}
return chars.join('')
}

View File

@ -153,6 +153,28 @@ describe('util', () => {
assert.strictEqual(repair(pythonDocument), expectedJson)
})
it('should repair missing comma between objects', () => {
const text = '{"aray": [{}{}]}'
const expected = '{"aray": [{},{}]}'
assert.strictEqual(repair(text), expected)
})
it('should repair line separated json (for example from robo3t', () => {
const text = '' +
'/* 1 */\n' +
'{}\n' +
'\n' +
'/* 2 */\n' +
'{}\n' +
'\n' +
'/* 3 */\n' +
'{}\n'
const expected = '[\n{},\n\n{},\n\n{}\n\n]'
assert.strictEqual(repair(text), expected)
})
})
describe('jsonPath', () => {