Skip to content

fix: add explicit indent indicator to empty block scalar when followed by a document comment#689

Closed
naveentehrpariya wants to merge 2 commits into
eemeli:mainfrom
naveentehrpariya:fix-empty-block-scalar-comment
Closed

fix: add explicit indent indicator to empty block scalar when followed by a document comment#689
naveentehrpariya wants to merge 2 commits into
eemeli:mainfrom
naveentehrpariya:fix-empty-block-scalar-comment

Conversation

@naveentehrpariya

Copy link
Copy Markdown

Problem

An empty block scalar whose document has a trailing comment produces a toString() output that does not round-trip correctly.

Reproducer (issue #687):

import { parseDocument } from 'yaml'

const doc = parseDocument('|5\n#comment')
// |5 → literal block scalar, explicit indent 5
// #comment is at indent 0 (< 5) → YAML comment, not block content
console.log(doc.toJSON())       // ''  ✓

const str = doc.toString()
console.log(str)                // '|\n\n\n#comment\n'  ← bug

console.log(parseDocument(str).toJSON())  // '\n\n#comment\n'  ← should be ''

What goes wrong: stringifyDocument sets ctx.forceBlockIndent = true when a document comment exists (so that the comment can be placed after the block scalar). For non-empty block scalars, forceBlockIndent causes a two-space indent in the header, which correctly pushes the comment outside the scalar's content. But the early-return path for empty strings (if (!value) return literal ? '|\n' : '>\n') ignores indent, emitting a bare | with no explicit indent indicator.

After the document comment is appended, the output looks like:

|       ← no indent indicator → content determined by first non-empty line
        ← empty line
        ← empty line
#comment  ← indent 0, becomes the first content line → value is "\n\n#comment\n"

On re-parse, #comment is block-scalar content, not a YAML comment — corrupting the round-trip.

Fix

When indent is non-empty (i.e. forceBlockIndent or a document-marker-safe context requires it), emit |1 / >1 instead of | / > for an empty block scalar. The explicit indent indicator 1 means content must start at indent ≥ 1; the comment at indent 0 therefore falls outside the scalar and is correctly interpreted as a YAML comment on re-parse.

- if (!value) return literal ? '|\n' : '>\n'
+ if (!value) return literal ? (indent ? '|1\n' : '|\n') : (indent ? '>1\n' : '>\n')

Tests

When an untagged scalar like `61e9540` matches the float-EXP regex but
parseFloat() returns Infinity, the YAML 1.2 spec §2.4 says the tag may
only be applied if the value round-trips faithfully. Returning Infinity
for a value whose source text is a finite exponent violates that
guarantee and causes surprising results (e.g. git SHAs parsed as Inf).

Add a `matchDefault` predicate to `ScalarTag` that is checked only
during automatic tag detection (i.e. no explicit tag). The `floatExp`
tag in both the core and YAML 1.1 schemas sets `matchDefault` to reject
values that parseFloat() cannot represent as a finite number, allowing
them to fall through to the string tag instead.

Explicit `!!float` tags are unaffected: they still use the `test` regex
for format selection and resolve to Infinity when the value overflows,
which matches the behaviour of other YAML libraries (e.g. PyYAML).

Fixes eemeli#657
An empty block scalar (value '') with a document-level trailing comment
was producing a toString() output where the comment line was at indent 0,
which caused it to be re-absorbed as block-scalar content on round-trip.

Before: '|5\n#comment' → toString → '|\n\n\n#comment\n' → reparse → '\n\n#comment\n'
After:  '|5\n#comment' → toString → '|1\n\n\n#comment\n' → reparse → ''

The fix adds |1 (explicit indent indicator) when a non-empty indent context
is present (forceBlockIndent or containsDocumentMarker), matching the
behaviour of non-empty block scalars in the same context.

Fixes eemeli#687
@eemeli

eemeli commented Jun 21, 2026

Copy link
Copy Markdown
Owner

Closing due to undeclared LLM use.

@eemeli eemeli closed this Jun 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants