import { posix } from "path"; /** * Regex to match a fenced code block with a `file="..."` attribute, e.g.: * * ```csv file="card-data.csv" * name, cost, effect * Fireball, 1, Blast em * ``` * * ```yaml file="monsters.yaml" * goblin: * hp: 7 * ``` * * The language identifier is optional — only `file="..."` matters. * * Group 1: the info string after the opening fence (e.g. `csv file="card-data.csv"`) * Group 2: the code block body */ const INLINE_FILE_BLOCK_RE = /^```\w*\s+file="([^"]+)"(?:\s+\w+="[^"]*")*\s*\n([\s\S]*?)```\s*$/gm; /** * Process fenced code blocks that contain a `file="..."` attribute. * * For each block like: * ```lang file="card-data.csv" * content * ``` * * 1. Strips the block from the returned text (so it doesn't render) * 2. Injects a synthetic entry into `index` at the resolved file path * * @param content - Raw file content * @param fileRelativePath - Normalized path of the containing file (e.g. "/rules/combat.md") * @param index - The content index to inject synthetic entries into * @returns Content with inline blocks removed */ export function extractInlineBlocks( content: string, fileRelativePath: string, index: Record, ): string { const matches: { filename: string; body: string }[] = []; let match: RegExpExecArray | null; INLINE_FILE_BLOCK_RE.lastIndex = 0; while ((match = INLINE_FILE_BLOCK_RE.exec(content)) !== null) { matches.push({ filename: match[1], body: match[2] }); } if (matches.length === 0) return content; const stripped = content.replace(INLINE_FILE_BLOCK_RE, ""); for (const { filename, body } of matches) { const fileDir = posix.dirname(fileRelativePath); const resolvedPath = posix.join(fileDir, filename); index[resolvedPath] = body; console.log( `[inline] Extracted ${resolvedPath} from ${fileRelativePath}`, ); } return stripped; }