Simplify named rule extraction

AI-assisted by OpenAI Codex under maintainer pbakaus's scheduled-refactor authorization.
This commit is contained in:
Paul Bakaus
2026-08-31 12:59:53 -07:00
parent b0594c72d1
commit f1e8d4e70e
2 changed files with 45 additions and 30 deletions
+18 -30
View File
@@ -329,47 +329,37 @@ function stripBold(s) {
function extractNamedRules(lines) {
const rules = [];
const seen = new Set();
const addRule = (name, body, { allowDuplicate = false } = {}) => {
const key = name.toLowerCase();
if (!allowDuplicate && seen.has(key)) return;
seen.add(key);
rules.push({ name, body });
};
// Style A (Impeccable): "**The X Rule.** body body body" — can span lines.
const joined = lines.join('\n');
const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g;
const inlineMatches = [];
let m;
while ((m = inlineStart.exec(joined)) !== null) {
inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex });
}
const inlineMatches = [...joined.matchAll(/\*\*(The [^*]+?Rule)\.\*\*/g)];
for (let i = 0; i < inlineMatches.length; i++) {
const mm = inlineMatches[i];
const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length;
const match = inlineMatches[i];
const bodyEnd = inlineMatches[i + 1]?.index ?? joined.length;
const body = joined
.slice(mm.end, bodyEnd)
.slice(match.index + match[0].length, bodyEnd)
.replace(/\n##[^\n]*$/s, '')
.replace(/\n###[^\n]*$/s, '')
.trim();
const name = stripBold(mm.name).trim();
seen.add(name.toLowerCase());
rules.push({ name, body: stripBold(body) });
// Preserve the inline format's historical behavior: repeated inline rules
// remain visible, while the later heading and bullet formats dedupe.
addRule(stripBold(match[1]).trim(), stripBold(body), { allowDuplicate: true });
}
// Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the
// bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle.
for (let i = 0; i < lines.length; i++) {
const h3 = lines[i].match(/^###\s+(.+?)\s*$/);
if (!h3) continue;
const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim();
for (const subsection of splitSubsections(lines).slice(1)) {
const headerName = stripBold(subsection.name).replace(/["“”]/g, '').trim();
if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue;
if (seen.has(headerName.toLowerCase())) continue;
const bodyLines = [];
for (let j = i + 1; j < lines.length; j++) {
if (/^##\s|^###\s/.test(lines[j])) break;
bodyLines.push(lines[j]);
}
const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim();
if (body) {
seen.add(headerName.toLowerCase());
rules.push({ name: headerName, body });
}
const body = stripBold(subsection.lines.join('\n').replace(/\n+/g, ' ')).trim();
if (body) addRule(headerName, body);
}
// Style C (Stitch bullet form): "* **The Layering Principle:** body"
@@ -379,9 +369,7 @@ function extractNamedRules(lines) {
if (!mm) continue;
const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim();
if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue;
if (seen.has(nameRaw.toLowerCase())) continue;
seen.add(nameRaw.toLowerCase());
rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() });
addRule(nameRaw, stripBold(mm[2]).trim());
}
return rules;
+27
View File
@@ -228,6 +228,33 @@ describe('parseDesignMd overview branch', () => {
});
});
describe('parseDesignMd named rules', () => {
it('preserves format precedence while deduplicating later definitions', () => {
const md = `# Design System: Rules
## Layout
### The "Rhythm" Rule
Ignore this duplicate heading definition.
### The Fallback Principle
Use the heading definition.
### Named Rules
- **The Fallback Principle:** Ignore this duplicate bullet definition.
- **The Layering Principle:** Use the bullet definition.
**The Rhythm Rule.** Keep the first definition.
`;
assert.deepEqual(parseDesignMd(md).layout.rules, [
{ name: 'The Rhythm Rule', body: 'Keep the first definition.' },
{ name: 'The Fallback Principle', body: 'Use the heading definition.' },
{ name: 'The Layering Principle', body: 'Use the bullet definition.' },
]);
});
});
describe('parseDesignMd canonical sections', () => {
it('preserves content and named rules from all eight canonical sections', () => {
const md = `# Design System: Complete