presenter: treat a tab-indented line in a folded scalar as more-indented - #780
Merged
Merged
Conversation
YAML 1.2.2 8.1.3 defines a more-indented ("spaced text") line by production
[175] s-nb-spaced-text, whose leading [33] s-white is a space *or a tab*; the
breaks around such a line are preserved verbatim ([177] b-l-spaced) rather than
folded. getBlockValue() in the parser already tests for both (0x20 or 0x09),
but the presenter tested only for a space, at four sites in foldBlockScalar()
and foldLine(). It therefore doubled breaks the parser keeps literally, adding
one \n per adjacency:
parseEvents/eventsToAst/present of
k: >
<TAB>
detected
emitted a blank line before "detected", so the value went from
"\t\ndetected\n" to "\t\n\ndetected\n". A tab line between two folded lines
cost two extra \n.
Extract the predicate as isMoreIndented() and use it for the prevMoreIndented
seed, the per-line test and the foldLine guard; the fold-point regexp becomes
/ [^ \t]/ so a break is never placed before a tab either (breaking at the space
in "aaa... \tzzz" moved the tab to the start of the next line).
Enumerating every two-line block-scalar body over a 7-line alphabet in both
block styles gave 84 parseable sources: 12 changed value through
present(), all folded style, all involving a tab; literal style was clean
(0/42). All 12 were confirmed against PyYAML 6.0.3 and ruamel.yaml 0.19.1
reading the emitted bytes, and all 12 round-trip after this change. The public
dump() API never enters this path (it quotes tab-containing strings), so it was
unaffected before and after.
puzrin
added a commit
that referenced
this pull request
Aug 1, 2026
chaiphet6669-afk
approved these changes
Aug 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Round-tripping
through
parseEvents→eventsToAst→presentemits a blank line beforedetected, so the value goes from"\t\ndetected\n"to"\t\n\ndetected\n"; with the tab line between two folded lines it costs two extra newlines. YAML 1.2.2 §8.1.3 defines a more-indented line by production [175]s-nb-spaced-text, whose leading [33]s-whiteis a space or a tab, and whose surrounding breaks are preserved ([177]b-l-spaced) rather than folded —getBlockValue()in the parser tests for both (0x20 || 0x09), but the presenter tested only for a space, at four sites infoldBlockScalar/foldLine, including the fold-point regexp/ [^ ]/which would break at the space inaaa… \tzzzand move the tab to the start of the next line. Enumerating every two-line block-scalar body over a 7-line alphabet in both block styles gave 84 parseable sources, of which 12 changed value throughpresent()— all folded style, all involving a tab, literal style clean at 0/42; all 12 were confirmed against PyYAML 6.0.3 and ruamel.yaml 0.19.1 reading the emitted bytes, and all 12 round-trip after this change.To be straight about the blast radius:
dump()is not affected, since it routes tab-containing strings to double-quoted or literal style and never enters the folded path (0 of 41 distinct values from the same family broke either way), so this only reaches code that presents a parsed AST — exported and typed, but not documented in the README. I leftdivergedFixturesalone: R4YG'sdumpcomparison still fails after the fix because the suite double-quotes that scalar while js-yaml faithfully keeps>, which is a genuine style divergence. (Its label there is "missing block scalar indent indicator", but a leading tab needs no indicator — indentation auto-detection only counts spaces — so R4YG was really this bug.)npm testgoes from 1613 tests / 1600 pass / 0 fail to 1614 / 1601 / 0 fail with the added case, and reverting each of the four predicates on its own makes that case fail.