"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseScalar = parseScalar;
exports.readTopLevelField = readTopLevelField;
exports.readUpstreamField = readUpstreamField;
exports.parseMarkdownFrontMatter = parseMarkdownFrontMatter;
exports.readDeclaredChildSlugs = readDeclaredChildSlugs;
exports.parseDeclaredChildSlugBullet = parseDeclaredChildSlugBullet;
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
    };
}
function readDeclaredChildSlugs(markdownOrSectionText, sectionName) {
    const sectionText = sectionName === undefined
        ? markdownOrSectionText
        : extractSectionText(markdownOrSectionText, sectionName);
    if (sectionText.trim() === "") {
        return [];
    }
    const slugs = [];
    const seen = new Set();
    for (const line of sectionText.split(/\r?\n/)) {
        const declaration = parseDeclaredChildSlugBullet(line);
        if (declaration === null) {
            continue;
        }
        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 validateDeclaredChildSlugSection(markdownOrSectionText, sectionName) {
    const sectionText = sectionName === undefined
        ? markdownOrSectionText
        : extractSectionText(markdownOrSectionText, sectionName);
    const issues = [];
    const slugs = [];
    const seen = new Set();
    let previousValidUniqueSlug = null;
    for (const rawLine of sectionText.split(/\r?\n/)) {
        const line = rawLine.trim();
        if (line === "") {
            continue;
        }
        const declaration = parseDeclaredChildSlugBullet(line);
        if (declaration === null) {
            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;
        }
        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");
}
