/**
 * Canonical slug rules shared by the whole system.
 *
 * Historically each surface had its own slugify regex (the admin `SlugField`
 * allowed underscores via `\w`; the page/post modals used `[a-z0-9]` only) and
 * the server stored whatever it was handed — no format check, no reserved-word
 * guard. That let a slug like `My Page!` or `admin` reach the database and break
 * URLs or shadow admin routes. This module is the single source of truth.
 */
/**
 * A valid slug is one or more lowercase alphanumeric segments joined by single
 * hyphens: no uppercase, no spaces, no leading/trailing/double hyphens, no other
 * punctuation. Matches the strict form the public URL builder expects.
 */
export const SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
/**
 * Slugs that would shadow framework/admin routes or collide with reserved
 * site-root handling. `home`/`index`/`""` intentionally resolve to the site root
 * (see `resolveDocumentUrl`) so they are allowed and handled there — these are
 * the ones that must never become a document slug.
 */
export const RESERVED_SLUGS = [
    'admin',
    'api',
    '_next',
    'sitemap',
    'sitemap.xml',
    'robots',
    'robots.txt',
    'feed',
    'feed.xml',
    'feed.json',
    'llms.txt',
];
/**
 * Normalize arbitrary input into a valid slug: lowercase, collapse any run of
 * non-alphanumeric characters to a single hyphen, and trim leading/trailing
 * hyphens. Returns `''` when nothing usable remains.
 */
export function normalizeSlug(input) {
    if (!input)
        return '';
    return input
        .toLowerCase()
        .normalize('NFKD')
        .replace(/[\u0300-\u036f]/g, '')
        .replace(/[^a-z0-9]+/g, '-')
        .replace(/^-+|-+$/g, '');
}
/** True when `slug` is already in canonical form. */
export function isValidSlug(slug) {
    return SLUG_PATTERN.test(slug);
}
/** True when `slug` (case-insensitively) is reserved. */
export function isReservedSlug(slug) {
    return RESERVED_SLUGS.includes(slug.toLowerCase());
}
/**
 * Validate a document slug. Returns a human-readable error message, or `null`
 * when the slug is acceptable. An empty/absent slug is allowed here (URL
 * presence is enforced separately by the publish gate, which also accepts a
 * `path`).
 */
export function validateSlug(slug) {
    if (slug === null || slug === undefined)
        return null;
    const trimmed = slug.trim();
    if (trimmed.length === 0)
        return null;
    if (!isValidSlug(trimmed)) {
        return `Invalid slug "${trimmed}" — use lowercase letters, numbers, and single hyphens (e.g. "my-page").`;
    }
    if (isReservedSlug(trimmed)) {
        return `The slug "${trimmed}" is reserved and cannot be used.`;
    }
    return null;
}
//# sourceMappingURL=slug.js.map