/*
Parses RFC-0073 content-discipline artifacts and exposes reusable normalization helpers for validators.
- Do not read files from disk.
- Do not resolve Astro content references here.
- RFC-0073: Add shared parsers and normalization helpers for content-discipline validators.
- RFC-0082: Delegate YAML reading to @warpgogol/werkstatt-shared/onboarding so single-doc and two-doc RFC-0076-headed files both parse correctly.
*/
import { parseOnboardingArtifactPayload } from "../onboarding/yaml.ts";
import {
contentAtomsFileSchema,
coverageLedgerEntrySchema,
voiceProfileSchema,
type ContentAtomsFile,
type CoverageLedgerEntry,
type VoiceProfile,
} from "./types.ts";
const COVERAGE_LEDGER_LINE = /^-\s+(atom-\d{4,})\s+·\s+reason:\s+([a-z-]+)\s+·\s+note:\s+(.+)$/;
export function parseContentAtomsFile(source: string): ContentAtomsFile {
return parseOnboardingArtifactPayload(source, contentAtomsFileSchema);
}
export function parseVoiceProfileFile(source: string): VoiceProfile {
return parseOnboardingArtifactPayload(source, voiceProfileSchema);
}
export function parseCoverageLedgerMarkdown(source: string): CoverageLedgerEntry[] {
const entries: CoverageLedgerEntry[] = [];
for (const rawLine of source.split(/\r?\n/)) {
const line = rawLine.trim();
const match = line.match(COVERAGE_LEDGER_LINE);
if (!match) {
continue;
}
const [, atomId, reason, note] = match;
entries.push(
coverageLedgerEntrySchema.parse({
atomId,
reason,
note: note.trim(),
}),
);
}
return entries;
}
export function normalizeComparableText(value: string): string {
return value
.normalize("NFKC")
.replace(/\{\{quote\}\}[\s\S]*?\{\{\/quote\}\}/g, " ")
.replace(/\s+/g, " ")
.trim()
.toLocaleLowerCase();
}
export function stripAllowedQuoteBlocks(value: string): string {
return value.replace(/\{\{quote\}\}[\s\S]*?\{\{\/quote\}\}/g, " ");
}