diff --git a/HISTORY.md b/HISTORY.md index 1fa2dc4..5a110fb 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -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 diff --git a/src/js/util.js b/src/js/util.js index 5fc365b..a059cec 100644 --- a/src/js/util.js +++ b/src/js/util.js @@ -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,19 +111,37 @@ export function repair (jsString) { // skip a block comment '/* ... */' function skipBlockComment () { - i += 2 - while (i < jsString.length && (curr() !== '*' || next() !== '/')) { - i++ + if (curr() === '/' && next() === '*') { + i += 2 + while (i < jsString.length && (curr() !== '*' || next() !== '/')) { + i++ + } + i += 2 + + if (curr() === '\n') { + i++ + } } - i += 2 } // skip a comment '// ...' function skipComment () { - i += 2 - while (i < jsString.length && (curr() !== '\n')) { + 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 } /** @@ -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('') } diff --git a/test/util.test.js b/test/util.test.js index 6b03ac4..4ff8bdd 100644 --- a/test/util.test.js +++ b/test/util.test.js @@ -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', () => {