* test(#3657): fence-width tolerance regression rows * test(#3657): fix pure-row fixtures to use appendWindow result shape * fix(#3657): tolerate commonmark fence widths in ledger readers * fix(#3657): restore throw-block indentation in parseJsonBlock * chore(#3657): backfill changeset pr number --------- Co-authored-by: sim <sim@local>
This commit is contained in:
@@ -874,6 +874,29 @@ export function reanchorBaseline(
|
||||
const PROPOSAL_JSON_FENCE_OPEN = '````json';
|
||||
const PROPOSAL_JSON_FENCE_CLOSE = '````';
|
||||
|
||||
// Reader-side fence tolerance (#3657 — same defect class as the WINDOWS.md
|
||||
// ledger): CommonMark formatters (Prettier et al.) narrow the written
|
||||
// 4-backtick fence to the shortest legal width (3) whenever the body holds no
|
||||
// backtick run, and a canonical-JSON candidates array never does. Locate the
|
||||
// block by a line-anchored 3+ fence and close on a run at least as wide
|
||||
// (CommonMark: a shorter run does not close). The writer above is unchanged.
|
||||
// This module is a leaf (CONTEXT.md — imports only node:fs/node:path), so the
|
||||
// span logic is local rather than imported from broken-windows.
|
||||
const PROPOSAL_FENCE_OPEN_RE = /^(`{3,})json[ \t]*\r?$/m;
|
||||
|
||||
function locateProposalJsonBlock(text: string): { jsonText: string } | null {
|
||||
const open = text.match(PROPOSAL_FENCE_OPEN_RE);
|
||||
if (!open || open.index === undefined) return null;
|
||||
const width = open[1].length;
|
||||
const bodyStart = open.index + open[0].length;
|
||||
for (const close of text.slice(bodyStart).matchAll(/^(`{3,})[ \t]*\r?$/gm)) {
|
||||
if (close[1].length < width) continue;
|
||||
const bodyEnd = close.index ?? 0;
|
||||
return { jsonText: text.slice(bodyStart, bodyStart + bodyEnd).trim() };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function renderProposal(p: Proposal): string {
|
||||
const fm = [
|
||||
'---',
|
||||
@@ -931,11 +954,9 @@ export function parseProposal(text: string): Proposal | null {
|
||||
fm[m[1]] = m[2].trim();
|
||||
}
|
||||
|
||||
const jsonStart = text.indexOf(PROPOSAL_JSON_FENCE_OPEN);
|
||||
if (jsonStart === -1) return null;
|
||||
const jsonEnd = text.indexOf(PROPOSAL_JSON_FENCE_CLOSE, jsonStart + PROPOSAL_JSON_FENCE_OPEN.length);
|
||||
if (jsonEnd === -1) return null;
|
||||
const jsonText = text.slice(jsonStart + PROPOSAL_JSON_FENCE_OPEN.length, jsonEnd).trim();
|
||||
const span = locateProposalJsonBlock(text);
|
||||
if (span === null) return null;
|
||||
const jsonText = span.jsonText;
|
||||
let candidates: unknown;
|
||||
try {
|
||||
candidates = JSON.parse(jsonText);
|
||||
|
||||
Reference in New Issue
Block a user