From 303391a94a2fdb8c6756240f6622f5c664275c37 Mon Sep 17 00:00:00 2001 From: Seiya <20365512+seiyab@users.noreply.github.com> Date: Tue, 13 Jan 2026 01:14:18 +0900 Subject: [PATCH] Preserve trailing double spaces in JSDoc (#18594) Co-authored-by: fisker --- changelog_unreleased/javascript/18594.md | 13 ++ src/language-js/print/comment.js | 42 ++++-- .../__snapshots__/format.test.js.snap | 2 + tests/format/js/comments/jsdoc.js | 2 +- .../comments/trailing-spaces/format.test.js | 124 ++++++++++++++++++ .../format.test.js | 34 +++++ 6 files changed, 207 insertions(+), 10 deletions(-) create mode 100644 changelog_unreleased/javascript/18594.md create mode 100644 tests/format/js/comments/trailing-spaces/format.test.js create mode 100644 tests/format/vue/comments/trailing-spaces-in-js-comment/format.test.js diff --git a/changelog_unreleased/javascript/18594.md b/changelog_unreleased/javascript/18594.md new file mode 100644 index 000000000..268305beb --- /dev/null +++ b/changelog_unreleased/javascript/18594.md @@ -0,0 +1,13 @@ +#### Preserve trailing double spaces in JSDoc (#18594 by @seiyab) + +Some tools treat these spaces as meaningful. + +```bash +await require('prettier').format('/**\n * With 2 spaces \n */', {parser: 'babel'}); + +# Prettier stable +// -> '/**\n * With 2 spaces\n */\n' + +# Prettier main +// -> '/**\n * With 2 spaces \n */\n' +``` diff --git a/src/language-js/print/comment.js b/src/language-js/print/comment.js index f2e50f35e..673378f75 100644 --- a/src/language-js/print/comment.js +++ b/src/language-js/print/comment.js @@ -1,9 +1,19 @@ -import { hardline, join, replaceEndOfLine } from "../../document/index.js"; +import { + hardline, + literalline, + markAsRoot, + replaceEndOfLine, +} from "../../document/index.js"; import { locEnd, locStart } from "../loc.js"; import isBlockComment from "../utilities/is-block-comment.js"; import isIndentableBlockComment from "../utilities/is-indentable-block-comment.js"; import isLineComment from "../utilities/is-line-comment.js"; +/** +@import {Doc} from "../../document/index.js" +@import {Comment} from "../types/estree.js" +*/ + function printComment(path, options) { const comment = path.node; @@ -26,19 +36,33 @@ function printComment(path, options) { throw new Error("Not a comment: " + JSON.stringify(comment)); } +/** +@param {Comment} comment +@returns {Doc} +*/ function printIndentableBlockComment(comment) { const lines = comment.value.split("\n"); + const isJsdoc = comment.value[0] === "*" && comment.value[1] !== "*"; return [ "/*", - join( - hardline, - lines.map((line, index) => - index === 0 - ? line.trimEnd() - : " " + (index < lines.length - 1 ? line.trim() : line.trimStart()), - ), - ), + lines.map((line, index) => { + if (index === 0) { + return [line.trimEnd(), hardline]; + } + + if (index === lines.length - 1) { + return [" ", line.trimStart()]; + } + + const trimmed = line.trim(); + const content = [" ", trimmed]; + if (isJsdoc && trimmed !== "*" && line.endsWith(" ")) { + return [content, " ", markAsRoot(literalline)]; + } + + return [content, hardline]; + }), "*/", ]; } diff --git a/tests/format/js/comments/__snapshots__/format.test.js.snap b/tests/format/js/comments/__snapshots__/format.test.js.snap index 375e5a45f..69c5002ac 100644 --- a/tests/format/js/comments/__snapshots__/format.test.js.snap +++ b/tests/format/js/comments/__snapshots__/format.test.js.snap @@ -3374,6 +3374,7 @@ function HelloWorld() { ); } + =====================================output===================================== /** @type {any} */ const x = ( @@ -3437,6 +3438,7 @@ function HelloWorld() { ); } + =====================================output===================================== /** @type {any} */ const x = ( diff --git a/tests/format/js/comments/jsdoc.js b/tests/format/js/comments/jsdoc.js index 24800022a..0f39589fc 100644 --- a/tests/format/js/comments/jsdoc.js +++ b/tests/format/js/comments/jsdoc.js @@ -23,4 +23,4 @@ function HelloWorld() { Test ); -} \ No newline at end of file +} diff --git a/tests/format/js/comments/trailing-spaces/format.test.js b/tests/format/js/comments/trailing-spaces/format.test.js new file mode 100644 index 000000000..5a46aca3e --- /dev/null +++ b/tests/format/js/comments/trailing-spaces/format.test.js @@ -0,0 +1,124 @@ +import { outdent } from "outdent"; + +const fixtures = { + importMeta: import.meta, + snippets: [ + { + name: "Preserve trailing double spaces in JSDoc", + code: outdent` + /** + * 2 spaces.${" ".repeat(2)} + */ + `, + output: outdent` + /** + * 2 spaces.${" ".repeat(2)} + */\n + `, + }, + { + name: "Misaligned", + code: outdent` + /** + * 2 spaces.${" ".repeat(2)} + */ + `, + output: outdent` + /** + * 2 spaces.${" ".repeat(2)} + */\n + `, + }, + { + name: "Non-top-level", + code: outdent` + function foo() { + /** + * 2 spaces.${" ".repeat(2)} + */ + } + `, + output: outdent` + function foo() { + /** + * 2 spaces.${" ".repeat(2)} + */ + }\n + `, + }, + { + name: "Preserve trailing 2+ spaces in JSDoc", + code: outdent` + /** + * 3 spaces.${" ".repeat(3)} + */ + `, + output: outdent` + /** + * 3 spaces.${" ".repeat(2)} + */\n + `, + }, + { + name: "Spaces on start line", + code: outdent` + /**${" ".repeat(2)} + * 2 spaces.${" ".repeat(2)} + */ + `, + output: outdent` + /** + * 2 spaces.${" ".repeat(2)} + */\n + `, + }, + { + name: "Remove on blank line", + code: outdent` + /** + *${" ".repeat(2)} + */ + `, + output: outdent` + /** + * + */\n + `, + }, + { + name: "Remove trailing single space in JSDoc", + code: outdent` + /** + * 1 space.${" ".repeat(1)} + */ + `, + output: outdent` + /** + * 1 space. + */\n + `, + }, + /* + > Each comment must start with a `/**` sequence in order to be recognized by the JSDoc parser. + > Comments beginning with `/*`, `/***`, or more than 3 stars will be ignored. + > This is a feature to allow you to suppress parsing of comment blocks. + + https://jsdoc.app/about-getting-started + */ + { + name: "Remove trailing single space in non-JSDoc", + code: outdent` + /*** + * NOT JSDOC.${" ".repeat(2)} + */ + `, + output: outdent` + /*** + * NOT JSDOC. + */\n + `, + }, + ], +}; + +runFormatTest(fixtures, ["babel", "flow", "typescript"]); diff --git a/tests/format/vue/comments/trailing-spaces-in-js-comment/format.test.js b/tests/format/vue/comments/trailing-spaces-in-js-comment/format.test.js new file mode 100644 index 000000000..d57b2cd80 --- /dev/null +++ b/tests/format/vue/comments/trailing-spaces-in-js-comment/format.test.js @@ -0,0 +1,34 @@ +import { outdent } from "outdent"; + +const fixtures = { + importMeta: import.meta, + snippets: [ + { + name: "Preserve trailing double spaces in JSDoc", + code: outdent` + + `, + output: outdent` + \n + `, + }, + ], +}; + +runFormatTest(fixtures, ["vue"], { vueIndentScriptAndStyle: true });