From 2556c4c89b879baf748523f7774e4a4fdbe22cd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=98=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2?= Date: Mon, 24 Aug 2026 21:39:42 +0300 Subject: [PATCH] fix(yaml): preserve trailing whitespace in block scalars (#19764) --- changelog_unreleased/yaml/19764.md | 14 ++++ src/language-yaml/massage-ast/index.js | 17 ----- src/language-yaml/print/block.js | 10 ++- src/language-yaml/printer-yaml.js | 44 ++++++++++--- src/language-yaml/utilities.js | 7 +- .../__snapshots__/format.test.js.snap | 4 ++ .../__snapshots__/format.test.js.snap | 64 +++++++++++++++++++ tests/format/yaml/block-value/format.test.js | 29 +++++++++ .../__snapshots__/format.test.js.snap | 4 +- 9 files changed, 163 insertions(+), 30 deletions(-) create mode 100644 changelog_unreleased/yaml/19764.md diff --git a/changelog_unreleased/yaml/19764.md b/changelog_unreleased/yaml/19764.md new file mode 100644 index 000000000..0f9c8e03e --- /dev/null +++ b/changelog_unreleased/yaml/19764.md @@ -0,0 +1,14 @@ +#### Preserve trailing whitespace in YAML block scalars (#19764 by @splincode) + +Prettier now preserves trailing spaces, tabs, and whitespace-only lines when formatting literal and folded YAML block scalars. + +```js +await prettier.format("foo: |-\n value \n", { parser: "yaml" }); + +/* Prettier stable */ +// -> "foo: |-\n value\n" + +/* Prettier main */ +// -> "foo: |-\n value \n" +// ^^ spaces preserved +``` diff --git a/src/language-yaml/massage-ast/index.js b/src/language-yaml/massage-ast/index.js index 9613aa10b..e86180505 100644 --- a/src/language-yaml/massage-ast/index.js +++ b/src/language-yaml/massage-ast/index.js @@ -21,23 +21,6 @@ function massageAstNode(original, cloned /* , parent */) { delete cloned.documentEndMarker; } break; - - case "blockLiteral": - case "blockFolded": - // The doc printer currently have bug when print trailing space/tab, they get wiped. - // But at least we can still make sure the new lines doesn't change in `value` property. - if (original.chomping === "keep") { - cloned.value = original.value - .split("\n") - .map((line) => line.replace(/[ \t]+$/, "")) - .join("\n"); - } - - // TODO: Fix this - else if (original.chomping === "clip" || original.chomping === "strip") { - cloned.value = original.value.trimEnd(); - } - break; } } massageAstNode.ignoredProperties = new Set(["position"]); diff --git a/src/language-yaml/print/block.js b/src/language-yaml/print/block.js index cddba7d33..d100a0ce7 100644 --- a/src/language-yaml/print/block.js +++ b/src/language-yaml/print/block.js @@ -13,6 +13,7 @@ import { import { getBlockValueLineContents, hasIndicatorComment, + hasTrailingContentWhitespace, isLastDescendantNode, } from "../utilities.js"; import { alignWithSpaces } from "./misc.js"; @@ -53,9 +54,14 @@ function printBlock(path, options, print) { contentsParts.push( lineWords.length === 0 ? hardline : markAsRoot(literalline), ); - } else if (node.chomping === "keep" && isLastDescendant) { + } else if ( + (isLastDescendant && node.chomping === "keep") || + hasTrailingContentWhitespace(node) + ) { contentsParts.push( - dedentToRoot(lineWords.length === 0 ? hardline : literalline), + isLastDescendant + ? dedentToRoot(lineWords.length === 0 ? hardline : literalline) + : dedent(lineWords.length === 0 ? hardline : literalline), ); } } diff --git a/src/language-yaml/printer-yaml.js b/src/language-yaml/printer-yaml.js index 0e0d69b1e..2176b92a6 100644 --- a/src/language-yaml/printer-yaml.js +++ b/src/language-yaml/printer-yaml.js @@ -37,6 +37,7 @@ import { hasMiddleComments, hasPrettierIgnore, hasTrailingComment, + hasTrailingContentWhitespace, isInlineNode, isLastDescendantNode, isNode, @@ -155,18 +156,31 @@ function printNode(path, options, print) { switch (node.type) { case "root": { const lastDescendantNode = getLastDescendantNode(node); - const shouldPrintHardline = !( + const lastBlockUsesKeepChomping = isNode(lastDescendantNode, ["blockLiteral", "blockFolded"]) && - lastDescendantNode.chomping === "keep" - ); + lastDescendantNode.chomping === "keep"; + const lastBlockPrintsTrailingLine = + lastBlockUsesKeepChomping || + (isNode(lastDescendantNode, ["blockLiteral", "blockFolded"]) && + hasTrailingContentWhitespace(lastDescendantNode)); + const shouldPrintHardline = !lastBlockPrintsTrailingLine; const parts = []; - path.each(({ node: document, isFirst }) => { - if (!isFirst) { + let lastDocumentEndMarkerPrinted = false; + let previousDocumentPrintsTrailingLine = false; + path.each(({ node: document, isFirst, isLast }) => { + if (!isFirst && !previousDocumentPrintsTrailingLine) { parts.push(hardline); } parts.push(print()); - if (shouldPrintDocumentEndMarker(path)) { - if (shouldPrintHardline) { + const documentLastDescendantNode = getLastDescendantNode(document); + const documentBlockPrintsTrailingLine = + isNode(documentLastDescendantNode, ["blockLiteral", "blockFolded"]) && + (hasTrailingContentWhitespace(documentLastDescendantNode) || + (isLast && documentLastDescendantNode.chomping === "keep")); + const documentEndMarkerPrinted = shouldPrintDocumentEndMarker(path); + lastDocumentEndMarkerPrinted = documentEndMarkerPrinted; + if (documentEndMarkerPrinted) { + if (!documentBlockPrintsTrailingLine) { parts.push(hardline); } @@ -175,9 +189,14 @@ function printNode(path, options, print) { parts.push(" ", print("trailingComment")); } } + previousDocumentPrintsTrailingLine = + documentBlockPrintsTrailingLine && !documentEndMarkerPrinted; }, "children"); - if (shouldPrintHardline) { + if ( + shouldPrintHardline || + (lastDocumentEndMarkerPrinted && !lastBlockUsesKeepChomping) + ) { parts.push(hardline); } @@ -325,7 +344,14 @@ function printNode(path, options, print) { case "mapping": case "sequence": - return join(hardline, path.map(print, "children")); + return path.map(({ node, isLast }) => { + const lastDescendantNode = getLastDescendantNode(node); + const childPrintsTrailingLine = + isNode(lastDescendantNode, ["blockLiteral", "blockFolded"]) && + hasTrailingContentWhitespace(lastDescendantNode); + + return [print(), !isLast && !childPrintsTrailingLine ? hardline : ""]; + }, "children"); case "sequenceItem": return ["- ", alignWithSpaces(2, node.content ? print("content") : "")]; case "mappingKey": diff --git a/src/language-yaml/utilities.js b/src/language-yaml/utilities.js index 9b75d3da3..8beb068ab 100644 --- a/src/language-yaml/utilities.js +++ b/src/language-yaml/utilities.js @@ -286,7 +286,7 @@ function getBlockValueLineContents( let trailingNewlineCount = 0; for (let i = lineContents.length - 1; i >= 0; i--) { - if (lineContents[i].every((line) => line.replace(/[ \t]+$/, "") === "")) { + if (lineContents[i].length === 0) { trailingNewlineCount++; } else { break; @@ -302,6 +302,10 @@ function getBlockValueLineContents( } } +function hasTrailingContentWhitespace(node) { + return /[ \t]+\n*$/.test(node.value); +} + function isInlineNode(node) { /* c8 ignore next 3 */ if (!node) { @@ -332,6 +336,7 @@ export { hasMiddleComments, hasPrettierIgnore, hasTrailingComment, + hasTrailingContentWhitespace, isEmptyNode, isInlineNode, isLastDescendantNode, diff --git a/tests/format/yaml/block-folded/__snapshots__/format.test.js.snap b/tests/format/yaml/block-folded/__snapshots__/format.test.js.snap index 01ffa02e6..238a98743 100644 --- a/tests/format/yaml/block-folded/__snapshots__/format.test.js.snap +++ b/tests/format/yaml/block-folded/__snapshots__/format.test.js.snap @@ -59,6 +59,8 @@ proseWrap: "always" --- >- ab + + ... ================================================================================ @@ -79,6 +81,8 @@ parsers: ["yaml"] --- >- ab + + ... ================================================================================ diff --git a/tests/format/yaml/block-value/__snapshots__/format.test.js.snap b/tests/format/yaml/block-value/__snapshots__/format.test.js.snap index 5ec500cae..68da4103c 100644 --- a/tests/format/yaml/block-value/__snapshots__/format.test.js.snap +++ b/tests/format/yaml/block-value/__snapshots__/format.test.js.snap @@ -1377,6 +1377,7 @@ foo: > =====================================output===================================== foo: > x + ================================================================================ `; @@ -1394,6 +1395,7 @@ foo: > =====================================output===================================== foo: > x + ================================================================================ `; @@ -1411,6 +1413,7 @@ foo: > =====================================output===================================== foo: > x + ... ================================================================================ @@ -1430,6 +1433,7 @@ foo: > =====================================output===================================== foo: > x + ================================================================================ `; @@ -1448,6 +1452,7 @@ foo: > =====================================output===================================== foo: > x + ... ================================================================================ @@ -1468,6 +1473,7 @@ foo: > =====================================output===================================== foo: > x + ================================================================================ `; @@ -1487,6 +1493,7 @@ foo: > =====================================output===================================== foo: > x + ... ================================================================================ @@ -1508,6 +1515,7 @@ foo: > =====================================output===================================== foo: > x + ... ================================================================================ @@ -1525,6 +1533,7 @@ foo: > =====================================output===================================== foo: > x + ================================================================================ `; @@ -1542,6 +1551,7 @@ foo: > =====================================output===================================== foo: > x + ================================================================================ `; @@ -1559,6 +1569,7 @@ foo: > =====================================output===================================== foo: > x + ... ================================================================================ @@ -1578,6 +1589,7 @@ foo: > =====================================output===================================== foo: > x + ================================================================================ `; @@ -1596,6 +1608,7 @@ foo: > =====================================output===================================== foo: > x + ... ================================================================================ @@ -1616,6 +1629,7 @@ foo: > =====================================output===================================== foo: > x + ================================================================================ `; @@ -1635,6 +1649,7 @@ foo: > =====================================output===================================== foo: > x + ... ================================================================================ @@ -1656,6 +1671,7 @@ foo: > =====================================output===================================== foo: > x + ... ================================================================================ @@ -2613,6 +2629,7 @@ foo: >- =====================================output===================================== foo: >- x + ================================================================================ `; @@ -2630,6 +2647,7 @@ foo: >- =====================================output===================================== foo: >- x + ================================================================================ `; @@ -2647,6 +2665,7 @@ foo: >- =====================================output===================================== foo: >- x + ... ================================================================================ @@ -2666,6 +2685,7 @@ foo: >- =====================================output===================================== foo: >- x + ================================================================================ `; @@ -2684,6 +2704,7 @@ foo: >- =====================================output===================================== foo: >- x + ... ================================================================================ @@ -2704,6 +2725,7 @@ foo: >- =====================================output===================================== foo: >- x + ================================================================================ `; @@ -2723,6 +2745,7 @@ foo: >- =====================================output===================================== foo: >- x + ... ================================================================================ @@ -2744,6 +2767,7 @@ foo: >- =====================================output===================================== foo: >- x + ... ================================================================================ @@ -2761,6 +2785,7 @@ foo: >- =====================================output===================================== foo: >- x + ================================================================================ `; @@ -2778,6 +2803,7 @@ foo: >- =====================================output===================================== foo: >- x + ================================================================================ `; @@ -2795,6 +2821,7 @@ foo: >- =====================================output===================================== foo: >- x + ... ================================================================================ @@ -2814,6 +2841,7 @@ foo: >- =====================================output===================================== foo: >- x + ================================================================================ `; @@ -2832,6 +2860,7 @@ foo: >- =====================================output===================================== foo: >- x + ... ================================================================================ @@ -2852,6 +2881,7 @@ foo: >- =====================================output===================================== foo: >- x + ================================================================================ `; @@ -2871,6 +2901,7 @@ foo: >- =====================================output===================================== foo: >- x + ... ================================================================================ @@ -2892,6 +2923,7 @@ foo: >- =====================================output===================================== foo: >- x + ... ================================================================================ @@ -5214,6 +5246,7 @@ foo: | =====================================output===================================== foo: | x + ================================================================================ `; @@ -5231,6 +5264,7 @@ foo: | =====================================output===================================== foo: | x + ================================================================================ `; @@ -5248,6 +5282,7 @@ foo: | =====================================output===================================== foo: | x + ... ================================================================================ @@ -5267,6 +5302,7 @@ foo: | =====================================output===================================== foo: | x + ================================================================================ `; @@ -5285,6 +5321,7 @@ foo: | =====================================output===================================== foo: | x + ... ================================================================================ @@ -5305,6 +5342,7 @@ foo: | =====================================output===================================== foo: | x + ================================================================================ `; @@ -5324,6 +5362,7 @@ foo: | =====================================output===================================== foo: | x + ... ================================================================================ @@ -5345,6 +5384,7 @@ foo: | =====================================output===================================== foo: | x + ... ================================================================================ @@ -5362,6 +5402,7 @@ foo: | =====================================output===================================== foo: | x + ================================================================================ `; @@ -5379,6 +5420,7 @@ foo: | =====================================output===================================== foo: | x + ================================================================================ `; @@ -5396,6 +5438,7 @@ foo: | =====================================output===================================== foo: | x + ... ================================================================================ @@ -5415,6 +5458,7 @@ foo: | =====================================output===================================== foo: | x + ================================================================================ `; @@ -5433,6 +5477,7 @@ foo: | =====================================output===================================== foo: | x + ... ================================================================================ @@ -5453,6 +5498,7 @@ foo: | =====================================output===================================== foo: | x + ================================================================================ `; @@ -5472,6 +5518,7 @@ foo: | =====================================output===================================== foo: | x + ... ================================================================================ @@ -5493,6 +5540,7 @@ foo: | =====================================output===================================== foo: | x + ... ================================================================================ @@ -6450,6 +6498,7 @@ foo: |- =====================================output===================================== foo: |- x + ================================================================================ `; @@ -6467,6 +6516,7 @@ foo: |- =====================================output===================================== foo: |- x + ================================================================================ `; @@ -6484,6 +6534,7 @@ foo: |- =====================================output===================================== foo: |- x + ... ================================================================================ @@ -6503,6 +6554,7 @@ foo: |- =====================================output===================================== foo: |- x + ================================================================================ `; @@ -6521,6 +6573,7 @@ foo: |- =====================================output===================================== foo: |- x + ... ================================================================================ @@ -6541,6 +6594,7 @@ foo: |- =====================================output===================================== foo: |- x + ================================================================================ `; @@ -6560,6 +6614,7 @@ foo: |- =====================================output===================================== foo: |- x + ... ================================================================================ @@ -6581,6 +6636,7 @@ foo: |- =====================================output===================================== foo: |- x + ... ================================================================================ @@ -6598,6 +6654,7 @@ foo: |- =====================================output===================================== foo: |- x + ================================================================================ `; @@ -6615,6 +6672,7 @@ foo: |- =====================================output===================================== foo: |- x + ================================================================================ `; @@ -6632,6 +6690,7 @@ foo: |- =====================================output===================================== foo: |- x + ... ================================================================================ @@ -6651,6 +6710,7 @@ foo: |- =====================================output===================================== foo: |- x + ================================================================================ `; @@ -6669,6 +6729,7 @@ foo: |- =====================================output===================================== foo: |- x + ... ================================================================================ @@ -6689,6 +6750,7 @@ foo: |- =====================================output===================================== foo: |- x + ================================================================================ `; @@ -6708,6 +6770,7 @@ foo: |- =====================================output===================================== foo: |- x + ... ================================================================================ @@ -6729,6 +6792,7 @@ foo: |- =====================================output===================================== foo: |- x + ... ================================================================================ diff --git a/tests/format/yaml/block-value/format.test.js b/tests/format/yaml/block-value/format.test.js index 2282ccafd..ac5567380 100644 --- a/tests/format/yaml/block-value/format.test.js +++ b/tests/format/yaml/block-value/format.test.js @@ -25,3 +25,32 @@ runFormatTest( }, ["yaml"], ); + +runFormatTest( + { + importMeta: import.meta, + snippets: [ + { + name: "preserves trailing spaces in a stripped block literal", + code: "foo: |-\n value \n", + output: "foo: |-\n value \n", + }, + { + name: "preserves trailing spaces before the next mapping item", + code: "foo: |-\n value \nbar: baz\n", + output: "foo: |-\n value \nbar: baz\n", + }, + { + name: "preserves a trailing tab before the next sequence item", + code: "- >-\n value\t\n- next\n", + output: "- >-\n value\t\n- next\n", + }, + { + name: "preserves trailing spaces before the next document", + code: "foo: |-\n value \n---\nbar: baz\n", + output: "foo: |-\n value \n---\nbar: baz\n", + }, + ], + }, + ["yaml"], +); diff --git a/tests/format/yaml/yaml-test-suite/__snapshots__/format.test.js.snap b/tests/format/yaml/yaml-test-suite/__snapshots__/format.test.js.snap index cdd573166..103f68f63 100644 --- a/tests/format/yaml/yaml-test-suite/__snapshots__/format.test.js.snap +++ b/tests/format/yaml/yaml-test-suite/__snapshots__/format.test.js.snap @@ -3958,6 +3958,7 @@ foo: | =====================================output===================================== foo: | x + ================================================================================ `; @@ -3973,6 +3974,7 @@ foo: | =====================================output===================================== foo: | x + ================================================================================ `; @@ -5893,7 +5895,7 @@ bar: 1 =====================================output===================================== foo: | - + bar: 1 ================================================================================