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 ## not yet published, version 8.6.4
- Fix #921: `sortObjectKeys` emits `onChange` events. - Fix #921: `sortObjectKeys` emits `onChange` events.
- Implement support for repairing line separate JSON.
## 2020-03-18, version 8.6.3 ## 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 // escape all single and double quotes inside strings
const chars = [] const chars = []
let i = 0 let i = 0
let indent = 0
let isLineSeparatedJson = false
// If JSON starts with a function (characters/digits/"_-"), remove this function. // If JSON starts with a function (characters/digits/"_-"), remove this function.
// This is useful for "stripping" JSONP objects to become JSON // This is useful for "stripping" JSONP objects to become JSON
@ -109,19 +111,37 @@ export function repair (jsString) {
// skip a block comment '/* ... */' // skip a block comment '/* ... */'
function skipBlockComment () { function skipBlockComment () {
i += 2 if (curr() === '/' && next() === '*') {
while (i < jsString.length && (curr() !== '*' || next() !== '/')) { i += 2
i++ while (i < jsString.length && (curr() !== '*' || next() !== '/')) {
i++
}
i += 2
if (curr() === '\n') {
i++
}
} }
i += 2
} }
// skip a comment '// ...' // skip a comment '// ...'
function skipComment () { function skipComment () {
i += 2 if (curr() === '/' && next() === '/') {
while (i < jsString.length && (curr() !== '\n')) { i += 2
while (i < jsString.length && (curr() !== '\n')) {
i++
}
}
}
function parseWhiteSpace () {
let whitespace = ''
while (i < jsString.length && isWhiteSpace(curr())) {
whitespace += curr()
i++ i++
} }
return whitespace
} }
/** /**
@ -245,13 +265,19 @@ export function repair (jsString) {
} }
while (i < jsString.length) { while (i < jsString.length) {
skipBlockComment()
skipComment()
const c = curr() const c = curr()
if (c === '/' && next() === '*') { if (c === '{') {
skipBlockComment() indent++
} else if (c === '/' && next() === '/') { }
skipComment() if (c === '}') {
} else if (isSpecialWhiteSpace(c)) { indent--
}
if (isSpecialWhiteSpace(c)) {
// special white spaces (like non breaking space) // special white spaces (like non breaking space)
chars.push(' ') chars.push(' ')
i++ i++
@ -265,6 +291,21 @@ export function repair (jsString) {
chars.push(parseString(quoteRight)) chars.push(parseString(quoteRight))
} else if (c === quoteDblLeft) { } else if (c === quoteDblLeft) {
chars.push(parseString(quoteDblRight)) 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) { } else if (c === ',' && [']', '}'].indexOf(nextNonWhiteSpace()) !== -1) {
// skip trailing commas // skip trailing commas
i++ i++
@ -280,6 +321,11 @@ export function repair (jsString) {
} }
} }
if (isLineSeparatedJson) {
chars.unshift('[\n')
chars.push('\n]')
}
return chars.join('') return chars.join('')
} }

View File

@ -153,6 +153,28 @@ describe('util', () => {
assert.strictEqual(repair(pythonDocument), expectedJson) 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', () => { describe('jsonPath', () => {