// engine/frontmatter-parser.ts — Parse YAML frontmatter from spec.md files
// Zero-dependency: no external YAML parser needed for the simple key:value format.
const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/;
const KV_LINE_RE = /^(\w+):\s*(.+)$/;
/**
 * Parse YAML frontmatter from markdown content.
 * Supports simple key: value pairs, arrays `[a, b]`, null, integers, and quoted strings.
 * Returns the original content as body if no frontmatter is found.
 */
export function parseFrontmatter(content) {
    const match = FRONTMATTER_RE.exec(content);
    if (!match?.[1] || match[2] === undefined) {
        return { metadata: {}, body: content };
    }
    const metadata = {};
    for (const line of match[1].split('\n')) {
        const kv = KV_LINE_RE.exec(line.trim());
        if (!kv?.[1] || kv[2] === undefined) {
            continue;
        }
        const key = kv[1];
        const val = kv[2].trim();
        if (val.startsWith('[') && val.endsWith(']')) {
            metadata[key] = val
                .slice(1, -1)
                .split(',')
                .map((s) => s.trim().replace(/^["']|["']$/g, ''));
        }
        else if (val === 'null') {
            metadata[key] = null;
        }
        else if (/^\d+$/.test(val)) {
            metadata[key] = parseInt(val, 10);
        }
        else if (val === 'true') {
            metadata[key] = true;
        }
        else if (val === 'false') {
            metadata[key] = false;
        }
        else {
            metadata[key] = val.replace(/^["']|["']$/g, '');
        }
    }
    return { metadata, body: match[2] };
}
/**
 * Strip YAML frontmatter from markdown content, returning only the body.
 * If no frontmatter is present, returns the original content unchanged.
 */
export function stripFrontmatter(content) {
    return content.replace(/^---\n[\s\S]*?\n---\n/, '');
}
/**
 * Update a single field in YAML frontmatter of markdown content.
 * If the field exists, replaces its value. If not, appends before the closing ---.
 * Returns the updated content, or the original content if no frontmatter is found.
 *
 * SPEC-698: only top-level keys are matched. Indented (nested) keys with the same
 * name are NOT touched — e.g. `estimation:\n  model: sonnet` is preserved when
 * updating top-level `model`.
 *
 * SPEC-698 (security): `key` and `value` are rendered verbatim into the file. Newlines
 * or carriage returns in either would let a caller inject extra YAML keys or break
 * the frontmatter delimiters. Both are rejected.
 */
export function updateFrontmatterField(content, key, value) {
    if (/[\r\n]/.test(value)) {
        throw new Error(`updateFrontmatterField: value for key "${key}" contains newline or CR — refusing to write (YAML injection guard)`);
    }
    if (!/^[A-Za-z_][A-Za-z0-9_-]*$/.test(key)) {
        throw new Error(`updateFrontmatterField: key "${key}" is not a valid YAML identifier — refusing to write`);
    }
    const match = FRONTMATTER_RE.exec(content);
    if (!match?.[1] || match[2] === undefined) {
        return content;
    }
    const lines = match[1].split('\n');
    // Anchor to start of line — no .trim() — so only top-level (non-indented) keys match
    const fieldRe = new RegExp(`^${key}:\\s*`);
    const hasField = lines.some((line) => fieldRe.test(line));
    const updated = hasField
        ? lines.map((line) => (fieldRe.test(line) ? `${key}: ${value}` : line))
        : [...lines, `${key}: ${value}`];
    return `---\n${updated.join('\n')}\n---\n${match[2]}`;
}
//# sourceMappingURL=frontmatter-parser.js.map