"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseScalar = parseScalar;
exports.readTopLevelField = readTopLevelField;
exports.readUpstreamField = readUpstreamField;
exports.parseMarkdownFrontMatter = parseMarkdownFrontMatter;
exports.parseMarkdownListItems = parseMarkdownListItems;
exports.readDeclaredChildSlugs = readDeclaredChildSlugs;
exports.parseDeclaredChildSlugBullet = parseDeclaredChildSlugBullet;
exports.parseDeclaredChildSlugBullets = parseDeclaredChildSlugBullets;
exports.validateDeclaredChildSlugSection = validateDeclaredChildSlugSection;
exports.toRepositoryLikePath = toRepositoryLikePath;
exports.parseMarkdownSections = parseMarkdownSections;
exports.extractSectionText = extractSectionText;
function parseScalar(rawValue) {
    const value = rawValue.trim();
    if ((value.startsWith("\"") && value.endsWith("\"")) || (value.startsWith("'") && value.endsWith("'"))) {
        return value.slice(1, -1);
    }
    return value;
}
function readTopLevelField(lines, key) {
    for (const line of lines) {
        if (/^\s/.test(line)) {
            continue;
        }
        const match = line.match(/^([A-Za-z0-9_]+):\s*(.*)$/);
        if (match === null) {
            continue;
        }
        if (match[1] === key) {
            return parseScalar(match[2]);
        }
    }
    return undefined;
}
function readUpstreamField(lines, key) {
    let inUpstream = false;
    for (const line of lines) {
        if (/^upstream:\s*$/.test(line)) {
            inUpstream = true;
            continue;
        }
        if (!inUpstream) {
            continue;
        }
        if (/^[^\s]/.test(line)) {
            break;
        }
        const match = line.match(/^\s{2}([A-Za-z0-9_]+):\s*(.*)$/);
        if (match !== null && match[1] === key) {
            return parseScalar(match[2]);
        }
    }
    return undefined;
}
function parseMarkdownFrontMatter(markdownText) {
    const lines = markdownText.split(/\r?\n/);
    if (lines[0] !== "---") {
        return {
            frontMatterLines: [],
            bodyText: markdownText,
            hasFrontMatter: false
        };
    }
    const closingIndex = lines.findIndex((line, index) => index > 0 && line === "---");
    if (closingIndex < 0) {
        return {
            frontMatterLines: [],
            bodyText: markdownText,
            hasFrontMatter: false
        };
    }
    return {
        frontMatterLines: lines.slice(1, closingIndex),
        bodyText: lines.slice(closingIndex + 1).join("\n"),
        hasFrontMatter: true
    };
}
/**
 * Reads top-level Markdown list items as semantic values while retaining
 * indented soft-wrapped continuation lines. A sibling list marker or heading
 * closes the active item. The returned values are whitespace-normalized so
 * authored wrapping does not change scaffold projection identity.
 */
function parseMarkdownListItems(lines) {
    const items = [];
    let activeIndex = null;
    let activeIndent = 0;
    for (const line of lines ?? []) {
        const heading = line.match(/^\s*#{1,6}\s+/u);
        if (heading !== null) {
            activeIndex = null;
            continue;
        }
        const marker = line.match(/^(\s*)[-*+]\s+(.+?)\s*$/u);
        if (marker !== null) {
            const indent = markdownIndentWidth(marker[1]);
            if (activeIndex === null || indent <= activeIndent) {
                const value = normalizeMarkdownListItemFragment(marker[2]);
                if (value !== "") {
                    items.push(value);
                    activeIndex = items.length - 1;
                    activeIndent = indent;
                }
                continue;
            }
        }
        if (activeIndex === null || line.trim() === "") {
            activeIndex = null;
            continue;
        }
        const indentation = line.match(/^(\s*)/u)?.[1] ?? "";
        if (markdownIndentWidth(indentation) <= activeIndent) {
            activeIndex = null;
            continue;
        }
        const continuation = normalizeMarkdownListItemFragment(line.trim());
        if (continuation === "")
            continue;
        items[activeIndex] = joinMarkdownListItemFragments(items[activeIndex], continuation);
    }
    return items;
}
function markdownIndentWidth(value) {
    return [...value].reduce((width, character) => width + (character === "\t" ? 4 : 1), 0);
}
function normalizeMarkdownListItemFragment(value) {
    return value.replace(/[ \t]+/gu, " ").trim();
}
function joinMarkdownListItemFragments(left, right) {
    const joinsWithoutSpace = /-$/u.test(left) && /^\p{L}/u.test(right)
        || /[([{\u2018\u201c]$/u.test(left)
        || /^[,.;:!?%\])}]/u.test(right);
    return `${left}${joinsWithoutSpace ? "" : " "}${right}`;
}
function readDeclaredChildSlugs(markdownOrSectionText, sectionName) {
    const sectionText = sectionName === undefined
        ? markdownOrSectionText
        : extractSectionText(markdownOrSectionText, sectionName);
    if (sectionText.trim() === "") {
        return [];
    }
    const slugs = [];
    const seen = new Set();
    for (const declaration of parseDeclaredChildSlugBullets(sectionText.split(/\r?\n/))) {
        const slug = declaration.slug;
        if (slug === "" || seen.has(slug)) {
            continue;
        }
        seen.add(slug);
        slugs.push(slug);
    }
    return slugs;
}
const ORDERED_DECLARED_CHILD_SLUG_PATTERN = /^\d{2}-[a-z0-9]+(?:-[a-z0-9]+)*$/;
const DECLARED_CHILD_PLACEHOLDER_PATTERN = /^(to be planned\.?|tbd\.?|todo\.?|pending\.?)$/i;
function parseDeclaredChildSlugBullet(line) {
    const trimmed = line.trim();
    const backtickedMatch = trimmed.match(/^-\s+`([^`]+)`:\s+(.+)$/);
    if (backtickedMatch !== null) {
        return {
            slug: backtickedMatch[1].trim(),
            description: backtickedMatch[2].trim(),
            format: "backticked"
        };
    }
    const linkedMatch = trimmed.match(/^-\s+\[([^\]\n]+)\]\(([^)\n]+)\):\s+(.+)$/);
    if (linkedMatch !== null) {
        return {
            slug: linkedMatch[1].trim(),
            href: linkedMatch[2].trim(),
            description: linkedMatch[3].trim(),
            format: "markdown-link"
        };
    }
    return null;
}
function parseDeclaredChildSlugBullets(lines) {
    const declarations = [];
    let activeDeclarationIndex = null;
    for (const line of lines) {
        const declaration = parseDeclaredChildSlugBullet(line);
        if (declaration !== null) {
            declarations.push(declaration);
            activeDeclarationIndex = declarations.length - 1;
            continue;
        }
        if (activeDeclarationIndex !== null
            && isDeclaredChildDescriptionContinuation(line)) {
            const activeDeclaration = declarations[activeDeclarationIndex];
            declarations[activeDeclarationIndex] = {
                ...activeDeclaration,
                description: `${activeDeclaration.description} ${line.trim()}`
            };
            continue;
        }
        activeDeclarationIndex = null;
    }
    return declarations;
}
function isDeclaredChildDescriptionContinuation(line) {
    const trimmed = line.trim();
    return /^(?: {2,}|\t)\S/u.test(line)
        && trimmed !== ""
        && !/^[-*+]\s+/u.test(trimmed)
        && !/^\d+[.)]\s+/u.test(trimmed)
        && !/^#{1,6}\s+/u.test(trimmed);
}
function validateDeclaredChildSlugSection(markdownOrSectionText, sectionName) {
    const sectionText = sectionName === undefined
        ? markdownOrSectionText
        : extractSectionText(markdownOrSectionText, sectionName);
    const issues = [];
    const slugs = [];
    const seen = new Set();
    let previousValidUniqueSlug = null;
    let declarationCanContinue = false;
    for (const rawLine of sectionText.split(/\r?\n/)) {
        const line = rawLine.trim();
        if (line === "") {
            declarationCanContinue = false;
            continue;
        }
        const declaration = parseDeclaredChildSlugBullet(line);
        if (declaration === null) {
            if (declarationCanContinue && isDeclaredChildDescriptionContinuation(rawLine)) {
                continue;
            }
            declarationCanContinue = false;
            issues.push({
                code: "invalid-line",
                line,
                message: "Declared child entries must use '- `01-some-ordered-slug`: short description.' or '- [01-some-ordered-slug](relative/path.md): short description.'."
            });
            continue;
        }
        declarationCanContinue = true;
        const slug = declaration.slug;
        const description = declaration.description;
        const slugIsValid = ORDERED_DECLARED_CHILD_SLUG_PATTERN.test(slug);
        const slugIsDuplicate = seen.has(slug);
        if (!slugIsValid) {
            issues.push({
                code: "invalid-slug",
                line,
                slug,
                message: `Declared child slug '${slug}' must match /^\\d{2}-[a-z0-9]+(?:-[a-z0-9]+)*$/.`
            });
        }
        if (slugIsDuplicate) {
            issues.push({
                code: "duplicate-slug",
                line,
                slug,
                message: `Declared child slug '${slug}' must be unique within the section.`
            });
        }
        else {
            seen.add(slug);
        }
        if (slugIsValid &&
            !slugIsDuplicate &&
            previousValidUniqueSlug !== null &&
            slug.localeCompare(previousValidUniqueSlug) <= 0) {
            issues.push({
                code: "out-of-order-slug",
                line,
                slug,
                message: `Declared child slug '${slug}' must appear after '${previousValidUniqueSlug}' in ascending order.`
            });
        }
        if (slugIsValid && !slugIsDuplicate) {
            previousValidUniqueSlug = slug;
        }
        if (DECLARED_CHILD_PLACEHOLDER_PATTERN.test(description)) {
            issues.push({
                code: "placeholder-description",
                line,
                slug,
                message: `Declared child slug '${slug}' must include a non-placeholder description.`
            });
        }
        if (slugIsValid && !slugs.includes(slug)) {
            slugs.push(slug);
        }
    }
    if (slugs.length === 0) {
        issues.push({
            code: "missing-declarations",
            line: null,
            message: "Section must contain at least one declared child slug bullet."
        });
    }
    return { slugs, issues };
}
function toRepositoryLikePath(filePath) {
    return filePath.replace(/\\/g, "/");
}
function parseMarkdownSections(markdownText) {
    const sections = new Map();
    let currentHeading = null;
    let sectionBuffer = [];
    for (const line of markdownText.split(/\r?\n/)) {
        const headingMatch = line.match(/^##\s+(.+)$/);
        if (headingMatch !== null) {
            if (currentHeading !== null) {
                sections.set(currentHeading, sectionBuffer.join("\n").trim());
            }
            currentHeading = headingMatch[1].trim();
            sectionBuffer = [];
            continue;
        }
        if (currentHeading !== null) {
            sectionBuffer.push(line);
        }
    }
    if (currentHeading !== null) {
        sections.set(currentHeading, sectionBuffer.join("\n").trim());
    }
    return sections;
}
function extractSectionText(markdownText, sectionName) {
    const lines = markdownText.split(/\r?\n/);
    const sectionHeader = `## ${sectionName}`;
    const sectionIndex = lines.findIndex((line) => line.trim() === sectionHeader);
    if (sectionIndex < 0) {
        return "";
    }
    const sectionLines = [];
    for (let index = sectionIndex + 1; index < lines.length; index += 1) {
        const trimmed = lines[index].trim();
        if (trimmed.startsWith("## ")) {
            break;
        }
        sectionLines.push(lines[index]);
    }
    return sectionLines.join("\n");
}
