import { trimTrailingBlank } from './types.js';
const KEY = /^(\s*)([^\s#][^:]*?)\s*:(\s|$)/;
const LIST_ITEM = /^(\s*)-\s+(.*)$/;
const DOCUMENT_MARKER = /^(---|\.\.\.)\s*$/;
/**
 * YAML keys at every depth, as dot paths.
 *
 * Deeper than a top-level-only scan: `jobs.build.steps` is where a CI config
 * actually changes, and an extractor that only sees `jobs` reports every such
 * edit as one undifferentiated change to the whole file.
 *
 * Indentation-driven rather than parsed. A real YAML parser would resolve
 * anchors and merge keys, which is exactly wrong here — the entity must
 * correspond to the text a developer edits, not to its expansion.
 */
export function extractYamlEntities(content) {
    const lines = content.split(/\r?\n/);
    const entities = [];
    const open = [];
    const listOrdinals = new Map();
    let inBlockScalar;
    const close = (indent, endLine) => {
        while (open.length > 0 && open[open.length - 1].indent >= indent) {
            const key = open.pop();
            if (key)
                key.entity.endLine = trimTrailingBlank(lines, endLine, key.entity.startLine);
        }
    };
    for (const [position, line] of lines.entries()) {
        const lineNumber = position + 1;
        const indent = line.length - line.trimStart().length;
        // A block scalar's body is opaque text, not structure; scanning it would
        // turn any `key: value` line inside a shell script into a YAML key.
        if (inBlockScalar !== undefined) {
            if (line.trim() === '' || indent > inBlockScalar)
                continue;
            inBlockScalar = undefined;
        }
        const trimmed = line.trim();
        if (trimmed === '' || trimmed.startsWith('#') || DOCUMENT_MARKER.test(trimmed))
            continue;
        const listMatch = LIST_ITEM.exec(line);
        if (listMatch) {
            close(indent, lineNumber - 1);
            const parent = open[open.length - 1];
            const parentName = parent?.entity.qualifiedName ?? '';
            const ordinal = listOrdinals.get(parentName) ?? 0;
            listOrdinals.set(parentName, ordinal + 1);
            const qualifiedName = parentName ? `${parentName}[${ordinal}]` : `[${ordinal}]`;
            const inline = listMatch[2].trim();
            const inlineMatch = KEY.exec(`${' '.repeat(indent + 2)}${inline}`);
            const inlineKey = inlineMatch?.[2].trim().replace(/^['"]|['"]$/g, '');
            const inlineRest = inlineMatch ? `${' '.repeat(indent + 2)}${inline}`.slice(inlineMatch[0].length).trim() : '';
            const item = {
                kind: 'array-item',
                name: inlineKey === 'name' && inlineRest
                    ? inlineRest.replace(/\s+#.*$/u, '').replace(/^['"]|['"]$/g, '')
                    : `[${ordinal}]`,
                qualifiedName,
                containerName: parent?.entity.qualifiedName,
                startLine: lineNumber,
                endLine: lineNumber,
            };
            entities.push(item);
            open.push({ indent, entity: item });
            if (inlineKey) {
                const property = {
                    kind: inlineRest === '' || inlineRest.startsWith('#') ? 'section' : 'property',
                    name: inlineKey,
                    qualifiedName: `${qualifiedName}.${inlineKey}`,
                    containerName: qualifiedName,
                    startLine: lineNumber,
                    endLine: lineNumber,
                };
                entities.push(property);
                open.push({ indent: indent + 2, entity: property });
                if (/[|>][-+]?\d*\s*$/u.test(inlineRest))
                    inBlockScalar = indent + 2;
            }
            continue;
        }
        const match = KEY.exec(line);
        if (!match)
            continue;
        const key = match[2].trim().replace(/^['"]|['"]$/g, '');
        if (!key)
            continue;
        close(indent, lineNumber - 1);
        const parent = open[open.length - 1];
        const qualifiedName = parent ? `${parent.entity.qualifiedName}.${key}` : key;
        const rest = line.slice(match[0].length).trim();
        const entity = {
            // A key with an inline value is a leaf; one with children is a section.
            kind: rest === '' || rest.startsWith('#') ? 'section' : 'property',
            name: key,
            qualifiedName,
            containerName: parent?.entity.qualifiedName,
            startLine: lineNumber,
            endLine: lineNumber,
        };
        entities.push(entity);
        open.push({ indent, entity });
        if (/[|>][-+]?\d*\s*$/.test(rest))
            inBlockScalar = indent;
    }
    close(-1, lines.length);
    return entities;
}
//# sourceMappingURL=yaml.js.map