yaml: extract `parse_block_indented` helper; fix anchor/tag on empty node (6KGN/FH7J/H7J7/PW8X) (#31308)
## What
Anchor/tag properties standing alone (with no content of their own)
attach to e-scalar per [161], but Bun's parser was greedily consuming
the next sibling/parent token as content instead. `a: &x\nb: *x` gave
`{a:{b:null}}` (attached `b` to `&x`) rather than `{a:null, b:null}`.
## Why this shape
`-`, `?`, and `:` all reach content via the same spec production [185]
`s-l+block-indented(n,c)`. Each call site already had the right indent
dispatch — but it ran **once** on the post-indicator token. If that
token was an anchor/tag, control passed into `parse_node`, which
consumed the property and treated whatever followed as content; the call
site's indent rules never re-ran.
This PR extracts that dispatch into one `parse_block_indented(n,
indicator_line, indicator_start, kind)` helper that **owns the property
loop**: it records anchor/tag tokens and re-runs the same indent check
on what follows. When the next token belongs to the parent, the
collected properties resolve to e-scalar via `props_to_e_node` (tag →
`resolve_null`, anchor → registered).
Four call sites collapse onto it:
- `parse_block_mapping` first-value (`:`) — [191]/[194] BLOCK-OUT
- `parse_block_mapping` subsequent-value — same
- `parse_node` `MappingKey` arm (`?` key) — [190] BLOCK-OUT
- `parse_block_sequence` item (`-`) — [186] BLOCK-IN (replaces a 76-line
inline loop)
`BlockIndentedKind::{SeqEntry, MapExplicitKey,
MapValue{flow_pair_allowed}}` selects the [201] seq-space comparison
(BLOCK-IN: `≤ n` is sibling; BLOCK-OUT: `< n`) and threads the
explicit-key / flow-pair flags.
Net diff: **−14 lines** in `yaml.rs` (4 dispatches → 1 helper).
## Fixes
| Input | Before | After | Refs |
|---|---|---|---|
| `a: &x\nb: *x` | `{a:{b:null}}` | `{a:null,b:null}` | 4/4 |
| `a: !!str\nb: y` | `{a:"b: y"}` | `{a:"",b:"y"}` | 4/4 |
| `- &a\n- *a` | error | `[null,null]` | 4/4 |
| `? &k\n: v` | `{[obj]:null}` | `{null:"v"}` | 4/4 |
| `x:\n ? a\n : b\ny: z` | garbled | `{x:{a:b},y:z}` | 4/4 |
| `-\na` / `- &a\nk: v` | `["a"]` / `[{k:v}]` | error | 4/4 |
| `- &outer\n &inner b: 1` | error | [200] anchor split | 3/4 |
| `-\ta: b` | `[{a:b}]` | error | 4/4 |
## yaml-test-suite
`6KGN`, `FH7J`, `H7J7`, `PW8X` activated. **7 → 3 todos remaining**
(tab-as-indentation cluster: `Y79Y/005`, `Y79Y/008`, `DK95/06`).
## Validation
- 1862 pass / 0 fail / 15 todo
- 1015/1015 4-parser consensus harness (eemeli/yaml, js-yaml, PyYAML,
ruamel)
- 2 adversarial-review rounds: round 1 = 481+205+648 inputs, 0
regressions, 9 positive verifications; round 2 = 0 confirmed
- 19 new unit tests (13 fail on system Bun, 6 lock in existing-correct
behavior)
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> D
Dylan Conway committed
79a4029d2058a8787d381f942ba71e36438d876f
Parent: 510b517
Committed by GitHub <noreply@github.com>
on 5/28/2026, 6:04:04 PM