fix(#4725): write normalization preserves tight paragraph-list shape (#4842)

* test(#4725): write normalization must not reflow untouched prose (failing first)

* fix(#4725): stop write normalization injecting a blank before a list after prose

* test(#4725): repair ordered-list fixture and list-spacing snapshot

* test(#4725): assert whole-file prose stability, fix heading-list comment

* chore(#4725): backfill changeset PR number (4842)

---------

Co-authored-by: sim <sim@local>
This commit is contained in:
Tom Boucher
2026-09-18 01:38:14 -04:00
committed by GitHub
parent c9a5cc3e12
commit 8d0b6868ae
6 changed files with 222 additions and 18 deletions

View File

@@ -1156,11 +1156,15 @@ function _normalizeMd(content: string): string {
if (isFenceLine && i > 0 && prevTrimmed !== '' && !insideFence[i] && (i === 0 || !insideFence[i - 1] || isFenceLine)) {
if (i === 0 || !insideFence[i - 1]) result.push('');
}
// #3854: the `!/^\s/.test(prev)` guard mirrors the after-a-bullet rule below —
// an indented non-bullet line is a CONTINUATION of the previous list item, not a
// preceding paragraph, so no separating blank may be injected before this bullet
// (that injection converted every tight multi-line list to a loose one on write).
if (/^(\s*[-*+]\s|\s*\d+\.\s)/.test(line) && i > 0 && prevTrimmed !== '' && !/^(\s*[-*+]\s|\s*\d+\.\s)/.test(prev) && !/^\s/.test(prev) && prevTrimmed !== '---') result.push('');
// No "separate a list from a preceding paragraph" rule (#3854, #4725).
// This pass re-normalizes the ENTIRE document on every .md write, so an
// inserted blank before a bullet whose previous line is ordinary prose
// reflowed text the command never touched (converting tight lists to
// loose ones); #3854 first guarded the indented-continuation predecessor,
// #4725 removed the rule outright. A paragraph→list transition stays
// exactly as the author wrote it; a heading→list separation still comes
// from the after-heading rule below. The after-a-bullet rule at the end
// of this loop is a different transition (list→prose) and is unaffected.
result.push(line);
if (/^#{1,6}\s/.test(trimmed) && i < lines.length - 1 && (lines[i + 1] ?? '').trimEnd() !== '') result.push('');
if (/^```\s*$/.test(trimmed) && i > 0 && insideFence[i - 1] && i < lines.length - 1 && (lines[i + 1] ?? '').trimEnd() !== '') result.push('');