🐛 Fix DESIGN.md Layout and Shapes parsing (#481)

* 🐛 Fix DESIGN.md Layout and Shapes parsing

Prepared with AI assistance.

* ♻️ Refine canonical design parser coverage

Prepared with AI assistance.
This commit is contained in:
CypherPoet
2026-08-03 14:59:00 -07:00
committed by GitHub
parent 1a3f588c71
commit 85f84bf620
5 changed files with 138 additions and 11 deletions
+32 -9
View File
@@ -2,15 +2,20 @@
// the live-mode design-system panel can render. Deterministic, dependency-free.
//
// Two-layer: YAML frontmatter (machine-readable tokens) + markdown body
// (prose with six canonical H2 sections). When frontmatter is present, it's
// (prose with eight canonical H2 sections). When frontmatter is present, it's
// exposed on `model.frontmatter` alongside the prose-scraped sections;
// consumers can prefer frontmatter values and fall back to prose.
// Array order is also match precedence: matchCanonicalSection's keyword-contained
// pass returns the first entry a heading contains, so reordering this changes
// which section an ambiguous heading resolves to.
const CANONICAL_SECTIONS = [
'Overview',
'Colors',
'Typography',
'Layout',
'Elevation',
'Shapes',
'Components',
"Do's and Don'ts",
];
@@ -662,11 +667,19 @@ function parseTypeBullet(bullet) {
};
}
function extractElevation(section) {
function extractGuidance(section) {
if (!section) return null;
const subs = splitSubsections(section.lines);
return {
subtitle: section.subtitle,
description: collectParagraphs(subs[0].lines).join(' ') || null,
rules: extractNamedRules(section.lines),
};
}
const description = collectParagraphs(subs[0].lines).join(' ') || null;
function extractElevation(section) {
const guidance = extractGuidance(section);
if (!guidance) return null;
const shadows = [];
const seen = new Set();
@@ -691,12 +704,7 @@ function extractElevation(section) {
for (const inline of extractInlineShadows(b)) dedupe(inline);
}
return {
subtitle: section.subtitle,
description,
shadows,
rules: extractNamedRules(section.lines),
};
return { ...guidance, shadows };
}
function extractInlineShadows(text) {
@@ -828,6 +836,15 @@ function extractDosDonts(section) {
// ---------- Coverage assessment ----------
// Sections whose model is description-plus-rules only (see extractGuidance).
const guidanceCoverage = (guidance) =>
guidance
? {
description: Boolean(guidance.description),
rules: guidance.rules.length,
}
: 'missing';
function assessCoverage(model) {
const report = {};
@@ -856,6 +873,8 @@ function assessCoverage(model) {
}
: 'missing';
report.layout = guidanceCoverage(model.layout);
report.elevation = model.elevation
? {
shadows: model.elevation.shadows.length,
@@ -864,6 +883,8 @@ function assessCoverage(model) {
}
: 'missing';
report.shapes = guidanceCoverage(model.shapes);
report.components = model.components
? {
count: model.components.components.length,
@@ -893,7 +914,9 @@ export function parseDesignMd(md) {
overview: extractOverview(sections['Overview']),
colors: extractColors(sections['Colors']),
typography: extractTypography(sections['Typography']),
layout: extractGuidance(sections['Layout']),
elevation: extractElevation(sections['Elevation']),
shapes: extractGuidance(sections['Shapes']),
components: extractComponents(sections['Components']),
dosDonts: extractDosDonts(sections["Do's and Don'ts"]),
};
+2
View File
@@ -11975,7 +11975,9 @@ void main() {
rules: [
...(md.colors?.rules || []).map((r) => ({ ...r, section: 'colors' })),
...(md.typography?.rules || []).map((r) => ({ ...r, section: 'typography' })),
...(md.layout?.rules || []).map((r) => ({ ...r, section: 'layout' })),
...(md.elevation?.rules || []).map((r) => ({ ...r, section: 'elevation' })),
...(md.shapes?.rules || []).map((r) => ({ ...r, section: 'shapes' })),
],
dos: md.dosDonts?.dos || [],
donts: md.dosDonts?.donts || [],
+1 -1
View File
@@ -873,7 +873,7 @@ function createRequestHandler({ detectScript, liveScriptParts }) {
// { present, parsed, sidecar, hasMd, hasSidecar,
// mdNewerThanJson, parseError?, sidecarError? }
// - parsed: output of parseDesignMd (frontmatter
// + six canonical sections) when DESIGN.md exists.
// + the canonical sections) when DESIGN.md exists.
// - sidecar: .impeccable/design.json contents when present.
// Expected shape: schemaVersion 2, carrying
// extensions + components + narrative.