80 lines
2.4 KiB
JavaScript
80 lines
2.4 KiB
JavaScript
/**
|
|
* Shared frontmatter parsing utilities.
|
|
*
|
|
* Extracted so that validate-repo.mjs and validate-repo.test.mjs can both
|
|
* import parseFrontmatterBooks without the test file triggering the full
|
|
* validation run on import.
|
|
*/
|
|
|
|
/**
|
|
* Parse the `books:` list from a YAML frontmatter block at the top of a
|
|
* markdown file. Returns an array of book title strings, or null if the
|
|
* frontmatter or `books` key is absent.
|
|
*
|
|
* Expected frontmatter shape:
|
|
* ---
|
|
* books:
|
|
* - Title One
|
|
* - Title Two
|
|
* ---
|
|
*
|
|
* Tolerates any leading whitespace before the hyphen (2-space or 4-space
|
|
* indentation both work). Book titles may contain colons, asterisks, or
|
|
* other special characters — the only delimiter is the line break.
|
|
*/
|
|
export function parseFrontmatterBooks(text) {
|
|
const match = text.match(/^---\n([\s\S]*?)\n---/);
|
|
if (!match) return null;
|
|
const booksSection = match[1].match(/^books:\n((?:[ \t]+-[^\n]+\n?)+)/m);
|
|
if (!booksSection) return null;
|
|
return booksSection[1]
|
|
.split("\n")
|
|
.filter((line) => /^\s+-/.test(line))
|
|
.map((line) => line.replace(/^\s+-\s*/, "").trim());
|
|
}
|
|
|
|
/**
|
|
* Count book sections in source-coverage.md.
|
|
* Each book section uses the pattern: ## Author Name — *Book Title*
|
|
*/
|
|
export function countBookSections(text) {
|
|
return (text.match(/^## .+ — \*/gm) ?? []).length;
|
|
}
|
|
|
|
/**
|
|
* Count production decay risk sections in decay-risks.md.
|
|
* Each risk section uses the pattern: ## Risk N: Title
|
|
*/
|
|
export function countProductionRisks(text) {
|
|
return (text.match(/^## Risk \d+:/gm) ?? []).length;
|
|
}
|
|
|
|
/**
|
|
* Count test decay risk sections in test-decay-risks.md.
|
|
* Each risk section uses the pattern: ## Risk TN: Title
|
|
*/
|
|
export function countTestRisks(text) {
|
|
return (text.match(/^## Risk T\d+:/gm) ?? []).length;
|
|
}
|
|
|
|
/**
|
|
* Extract the latest version string from CHANGELOG.md.
|
|
* Returns null if no version header is found.
|
|
*/
|
|
export function extractChangelogVersion(text) {
|
|
return text.match(/^## \[(.+?)\] - /m)?.[1] ?? null;
|
|
}
|
|
|
|
/**
|
|
* Extract step labels from a guide file.
|
|
* Matches: ### Step 1, ### Step 2a, ### Step 6b, ### Step 0, etc.
|
|
* Returns: ["1", "2a", "6b", ...] — the label portion only.
|
|
*/
|
|
export function extractGuideStepLabels(text) {
|
|
return (text.match(/^### Step (\d+[a-z]?)/gm) ?? [])
|
|
.map(m => m.replace(/^### Step /, ""));
|
|
}
|
|
|
|
export const PRODUCTION_RISK_COUNT = 6;
|
|
export const TEST_RISK_COUNT = 6;
|