/** * Shared block scanning utilities — safe for both CLI and browser. * * Parses fenced code blocks with attributes: * ```lang id=xxx role=xxx as=xxx * * - `role` dispatches to content scanners (declare, spark-table) * - `as` controls rendering (none, codeblock, md-table, md-card, md-dice) * - `id` is used for cross-references (file paths) */ // --------------------------------------------------------------------------- // Types // --------------------------------------------------------------------------- export interface BlockAttrs { lang: string; id?: string; role?: string; as?: string; /** Any other attributes not in the standard set */ extra: Record; } // --------------------------------------------------------------------------- // Regex // --------------------------------------------------------------------------- /** Matches fenced code blocks with an info string (at least one attr). */ export const FENCED_BLOCK_RE = /^```(\w*)\s+(\S.*?)\s*\n([\s\S]*?)```\s*$/gm; // --------------------------------------------------------------------------- // Attribute parsing // --------------------------------------------------------------------------- /** Parse key="value" and key=value pairs from an attribute string. */ export function parseBlockAttrs(info: string): BlockAttrs { const attrs: Record = {}; const re = /(\w+)\s*=\s*("[^"]*"|\S+)/g; let m: RegExpExecArray | null; while ((m = re.exec(info)) !== null) { attrs[m[1]] = m[2].replace(/^"|"$/g, ""); } const { lang, id, role, as, ...extra } = attrs; return { lang: lang || "", id, role, as, extra }; } // --------------------------------------------------------------------------- // as resolution // --------------------------------------------------------------------------- /** * Determine the effective `as` value. * * Defaults: * - role is set, no explicit as → "none" (strip — it's metadata) * - role=spark-table → "md-table" (render as md-table directive) * - role=tag → "codeblock" (kept for the marked yaml-tag extension) * - no role, no as → "codeblock" (keep as visible code block) */ export function resolveBlockAs(role: string | undefined, as: string | undefined): string { if (as) return as; // spark-table blocks render as md-table by default if (role === "spark-table") return "md-table"; // yaml-defined tag blocks must survive stripping so the // code-block-yaml-tag marked extension can render them if (role === "tag") return "codeblock"; if (role) return "none"; return "codeblock"; }