mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-15 09:25:28 +02:00
fix(design-md): text-level edits keep CRLF, one section-boundary rule, control characters quoted
- insertMarker and spliceSection normalized every line ending to LF, so a CRLF DESIGN.md came back rewritten beyond the one line they promised to touch. Both detect the file's dominant line ending and restore it. - parseDesignMd and spliceSection each walked headings with their own fence tracking; they now share headingLines (and upsertSection shares headingMatches). An unclosed ``` is treated as prose for that file: it used to swallow every later section on a splice. - A token value carrying a control character (an LLM-extracted font family with an embedded newline) was emitted as a bare multi-line scalar that Bun.YAML rejects, turning a freshly written DESIGN.md into frontmatter-unparsable; needsQuotes routes it through the quoted form. - The marker-line regex variants are built once beside YAML_MARKER_RE; the dead setMarker export and a no-op ternary are gone; LEGACY_HEADINGS derives from the identity list; the header diagram names the text-level editors as the write path for user-owned files; the bin validates and prints the mark choices from FORMAT_CHOICES. Tests: CRLF round-trips for both editors, a fenced ## inside a section and an unclosed fence, and a newline-bearing scalar parsing back. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
b2e67d0097
commit
ae5a5298e0
@@ -28,8 +28,7 @@ import { SENTINEL } from '../lib/design-detect-contract';
|
||||
import { atomicWriteSync } from '../lib/fs-atomic';
|
||||
import {
|
||||
parseDesignMd, detectFormat, convertLegacy, renderDesignMd, tokensFlat, insertMarker,
|
||||
type DesignMdDoc, type FormatChoice,
|
||||
} from '../lib/design-md';
|
||||
type DesignMdDoc, type FormatChoice, FORMAT_CHOICES } from '../lib/design-md';
|
||||
|
||||
function resolveFile(arg?: string): string {
|
||||
return path.resolve(arg ?? 'DESIGN.md');
|
||||
@@ -86,8 +85,8 @@ export function main(argv = process.argv.slice(2)): number {
|
||||
}
|
||||
case 'mark': {
|
||||
const choice = positional[0] as FormatChoice | undefined;
|
||||
if (choice !== 'spec' && choice !== 'legacy-keep') {
|
||||
process.stderr.write('usage: gstack-design-md.ts mark <spec|legacy-keep> [DESIGN.md]\n');
|
||||
if (!(FORMAT_CHOICES as readonly string[]).includes(choice)) {
|
||||
process.stderr.write(`usage: gstack-design-md.ts mark <${FORMAT_CHOICES.join('|')}> [DESIGN.md]\n`);
|
||||
return 2;
|
||||
}
|
||||
const file = resolveFile(positional[1]);
|
||||
@@ -103,7 +102,7 @@ export function main(argv = process.argv.slice(2)): number {
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
process.stderr.write('usage: gstack-design-md.ts check [file] | convert [file] [--write] | tokens [file] | mark <spec|legacy-keep> [file]\n');
|
||||
process.stderr.write(`usage: gstack-design-md.ts check [file] | convert [file] [--write] | tokens [file] | mark <${FORMAT_CHOICES.join('|')}> [file]\n`);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user