From b071ce6f61727f47e193ff2aed4a22f8419211af Mon Sep 17 00:00:00 2001 From: Mike Bland Date: Tue, 2 Jan 2024 10:42:45 -0500 Subject: [PATCH] Bump to 1.0.4, fix escaped whitespace before " bug Before this change, an escaped whitespace before the closing double quote character of a string would cause stripJsonComments() to see the double quote as escaped. This would throw off the comment removal algorithm since the string would still appear open. Escaped whitespace inside a string will cause a JSON parse error, but that shouldn't prevent stripJsonComments() from removing comments from otherwise legitimate JSON. The new test reproduced the error and verified the fix, which was to check the `inString` case before the whitespace-preserving cases. --- README.md | 6 +++--- lib/index.js | 10 +++++----- package.json | 2 +- test/stripJsonComments.test.js | 29 +++++++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index b2e728d..60c25b0 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Running the wrapper will generate the local `file://` URL to the generated `index.html` file, e.g.: ```text -file:///path/to/jsdoc/output/jsdoc-cli-wrapper/1.0.3/index.html +file:///path/to/jsdoc/output/jsdoc-cli-wrapper/1.0.4/index.html ``` You can click on or copy this link to open it in your browser. You can also open @@ -99,10 +99,10 @@ This wrapper resolves both of these minor annoyances. ```sh $ pnpm jsdoc -> jsdoc-cli-wrapper@1.0.3 jsdoc /path/to/jsdoc-cli-wrapper +> jsdoc-cli-wrapper@1.0.4 jsdoc /path/to/jsdoc-cli-wrapper > node index.js -c jsdoc.json . -file:///path/to/jsdoc-cli-wrapper/jsdoc/jsdoc-cli-wrapper/1.0.3/index.html +file:///path/to/jsdoc-cli-wrapper/jsdoc/jsdoc-cli-wrapper/1.0.4/index.html ``` Of course, your own project would use `jsdoc-cli-wrapper` instead of `node diff --git a/lib/index.js b/lib/index.js index d5fc262..edc520b 100644 --- a/lib/index.js +++ b/lib/index.js @@ -183,19 +183,19 @@ export function stripJsonComments(str) { for (let i = 0; i !== str.length; ++i) { let c = str[i] - if (c === '\n') { - if (comment === 'line') comment = null - } else if (c.trimStart() === '') { // preserve other existing whitespace - } else if (inString) { + if (inString) { // check first so illegally escaped whitespace won't hide " inString = c !== '"' || escaped escaped = c === '\\' && !escaped + } else if (c === '\n') { + if (comment === 'line') comment = null + } else if (c.trimStart() === '') { // preserve all other existing whitespace } else if (comment) { if (c === '/' && comment === 'block' && str[i-1] === '*') comment = null c = ' ' } else if (c === '/' || c === '*') { // maybe a comment, don't update comma if (str[i-1] === '/') { // definitely a comment, or else a syntax error comment = (c === '/') ? 'line' : 'block' - c = result[i-1] = ' ' + result[i-1] = c = ' ' } } else if (c === ',') { comma = i diff --git a/package.json b/package.json index 4cc7d1a..c17fe9a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jsdoc-cli-wrapper", - "version": "1.0.3", + "version": "1.0.4", "description": "JSDoc command line interface wrapper", "main": "index.js", "bin": "./index.js", diff --git a/test/stripJsonComments.test.js b/test/stripJsonComments.test.js index d7bb798..9df959a 100644 --- a/test/stripJsonComments.test.js +++ b/test/stripJsonComments.test.js @@ -286,5 +286,34 @@ describe('stripJsonComments', () => { ` JSON at position ${src.indexOf(', // ...but this last comma')}` ) }) + + test('a string contains an escaped space before the closing quote', () => { + const src = [ + '{', + ' "opts": {', + ' // This comment should disappear regardless.', + ' "fubar": "If not handled, the comments below will remain.\\ "', + ' /* Escaped space is illegal JSON, but it shouldn\'t hide a', + ' * closing quote and prevent comment removal. */', + ' }', + '}'].join('\n') + + const result = stripJsonComments(src) + + expect(result).toBe([ + '{', + ' "opts": {', + ' ', + ' "fubar": "If not handled, the comments below will remain.\\ "', + ' ', + ' ', + ' }', + '}'].join('\n')) + expect(() => JSON.parse(result)).toThrowError( + // It will choke on the space, not the escape slash. + errPrefix(' ', 'Bad escaped character in') + + ` JSON at position ${src.indexOf('\\ "') + 1}` + ) + }) }) })