From cba5659e78173c34521863834e9a09da980effd0 Mon Sep 17 00:00:00 2001 From: jos Date: Tue, 14 Nov 2017 21:18:49 +0100 Subject: [PATCH] Implemented repairing JSON objects containing left and right single and double quotes --- HISTORY.md | 2 ++ src/js/util.js | 31 ++++++++++++++++++++++++++----- test/util.test.js | 8 ++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 765d3bf..5108846 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -8,6 +8,8 @@ https://github.com/josdejong/jsoneditor - Implemented a navigation bar showing the path. Thanks @meirotstein. - Implemented a status bar showing cursor location. Thanks @meirotstein. +- Implemented repairing JSON objects containing left and right single + and double quotes (which you get when typing a JSON object in Word). ## 2017-09-16, version 5.9.6 diff --git a/src/js/util.js b/src/js/util.js index b67ae71..0694b09 100644 --- a/src/js/util.js +++ b/src/js/util.js @@ -50,6 +50,15 @@ exports.sanitize = function (jsString) { '\t': '\\t' }; + var quote = '\''; + var quoteDbl = '"'; + var quoteLeft = '\u2018'; + var quoteRight = '\u2019'; + var quoteDblLeft = '\u201C'; + var quoteDblRight = '\u201D'; + var graveAccent = '\u0060'; + var acuteAccent = '\u00B4'; + // helper functions to get the current/prev/next character function curr () { return jsString.charAt(i); } function next() { return jsString.charAt(i + 1); } @@ -88,11 +97,11 @@ exports.sanitize = function (jsString) { } // parse single or double quoted string - function parseString(quote) { + function parseString(endQuote) { chars.push('"'); i++; var c = curr(); - while (i < jsString.length && c !== quote) { + while (i < jsString.length && c !== endQuote) { if (c === '"' && prev() !== '\\') { // unescaped double quote, escape it chars.push('\\"'); @@ -118,7 +127,7 @@ exports.sanitize = function (jsString) { i++; c = curr(); } - if (c === quote) { + if (c === endQuote) { chars.push('"'); i++; } @@ -154,8 +163,20 @@ exports.sanitize = function (jsString) { else if (c === '/' && next() === '/') { skipComment(); } - else if (c === '\'' || c === '"') { - parseString(c); + else if (c === quote) { + parseString(quote); + } + else if (c === quoteDbl) { + parseString(quoteDbl); + } + else if (c === graveAccent) { + parseString(acuteAccent); + } + else if (c === quoteLeft) { + parseString(quoteRight); + } + else if (c === quoteDblLeft) { + parseString(quoteDblRight); } else if (/[a-zA-Z_$]/.test(c) && ['{', ','].indexOf(lastNonWhitespace()) !== -1) { // an unquoted object key (like a in '{a:2}') diff --git a/test/util.test.js b/test/util.test.js index 24272bc..8abbf6b 100644 --- a/test/util.test.js +++ b/test/util.test.js @@ -14,6 +14,8 @@ describe('util', function () { it('should replace JavaScript with JSON', function () { assert.equal(util.sanitize('{a:2}'), '{"a":2}'); + assert.equal(util.sanitize('{a: 2}'), '{"a": 2}'); + assert.equal(util.sanitize('{\n a: 2\n}'), '{\n "a": 2\n}'); assert.equal(util.sanitize('{\'a\':2}'), '{"a":2}'); assert.equal(util.sanitize('{a:\'foo\'}'), '{"a":"foo"}'); assert.equal(util.sanitize('{a:\'foo\',b:\'bar\'}'), '{"a":"foo","b":"bar"}'); @@ -39,6 +41,12 @@ describe('util', function () { assert.equal(util.sanitize('{"value\n": "dc=hcm,dc=com"}'), '{"value\\n": "dc=hcm,dc=com"}') }) + it.only('should replace left/right quotes', function () { + assert.equal(util.sanitize('\u2018foo\u2019'), '"foo"') + assert.equal(util.sanitize('\u201Cfoo\u201D'), '"foo"') + assert.equal(util.sanitize('\u0060foo\u00B4'), '"foo"') + }) + it('remove comments', function () { assert.equal(util.sanitize('/* foo */ {}'), ' {}'); assert.equal(util.sanitize('/* foo */ {}'), ' {}');