diff --git a/HISTORY.md b/HISTORY.md index aa7df3c..8738821 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -3,6 +3,12 @@ https://github.com/josdejong/jsoneditor +## not yet published, version 8.6.0 + +- Fixed #906: Implemented turning Python objects containing `True`, `False` + and `None` into valid JSON using repair. + + ## 2020-02-06, version 8.5.3 - Fix #892: the undo/redo buttons in mode `code` being broken when custom diff --git a/src/js/util.js b/src/js/util.js index 573657e..ffb7349 100644 --- a/src/js/util.js +++ b/src/js/util.js @@ -67,6 +67,12 @@ export function repair (jsString) { const graveAccent = '\u0060' const acuteAccent = '\u00B4' + const pythonConstants = { + None: 'null', + True: 'true', + False: 'false' + } + // helper functions to get the current/prev/next character function curr () { return jsString.charAt(i) } function next () { return jsString.charAt(i + 1) } @@ -180,29 +186,29 @@ export function repair (jsString) { } } - function parseMongoDataType () { + function parseValue () { let c = curr() - let value - let dataType = '' - while (/[a-zA-Z_$]/.test(c)) { - dataType += c + let value = '' + while (/\w/.test(c)) { + value += c i++ c = curr() } - if (dataType.length > 0 && c === '(') { - // This is an MongoDB data type like {"_id": ObjectId("123")} + if (value.length > 0 && c === '(') { + // This is an MongoDB data type like in {"_id": ObjectId("123")} + let innerValue i++ c = curr() if (c === '"') { // a data type containing a string, like ISODate("2012-12-19T06:01:17.171Z") - value = parseString(c) + innerValue = parseString(c) c = curr() } else { // a data type containing a value, like 'NumberLong(2)' - value = '' + innerValue = '' while (c !== ')' && c !== '') { - value += c + innerValue += c i++ c = curr() } @@ -213,14 +219,17 @@ export function repair (jsString) { i++ // return the value (strip the data type object) - return value + return innerValue } else { // huh? that's unexpected. don't touch it - return dataType + '(' + value + c + return value + '(' + innerValue + c } + } else if (typeof pythonConstants[value] === 'string') { + // it's a python constant like None + return pythonConstants[value] } else { - // hm, no Mongo data type after all - return dataType + // just leave as is + return value } } @@ -260,13 +269,11 @@ export function repair (jsString) { } else if (/[a-zA-Z_$]/.test(c) && ['{', ','].indexOf(lastNonWhitespace()) !== -1) { // an unquoted object key (like a in '{a:2}') chars.push(parseKey()) + } else if (/\w/.test(c)) { + chars.push(parseValue()) } else { - if (/[a-zA-Z_$]/.test(c)) { - chars.push(parseMongoDataType()) - } else { - chars.push(c) - i++ - } + chars.push(c) + i++ } } diff --git a/test/util.test.js b/test/util.test.js index 0d00adb..715be60 100644 --- a/test/util.test.js +++ b/test/util.test.js @@ -135,6 +135,22 @@ describe('util', () => { assert.strictEqual(repair(mongoDocument), expectedJson) }) + + it('should replace Python constants None, True, False', () => { + const pythonDocument = '{\n' + + ' "null": None,\n' + + ' "true": True,\n' + + ' "false": False\n' + + '}' + + const expectedJson = '{\n' + + ' "null": null,\n' + + ' "true": true,\n' + + ' "false": false\n' + + '}' + + assert.strictEqual(repair(pythonDocument), expectedJson) + }) }) describe('jsonPath', () => {