{"version":3,"file":"index.mjs","names":["codes"],"sources":["../src/catalog.ts","../src/utils/identify.ts","../src/utils/env.ts","../src/catalog/normalize.ts","../src/utils/formatters.ts","../src/utils/language/data.json","../src/utils/language/module.ts","../src/utils/translations-record.ts","../src/utils/locale.ts","../src/utils/negotiate.ts","../src/utils/template.ts","../src/module.ts","../src/store/loader.ts","../src/store/memory.ts","../src/store/types.ts"],"sourcesContent":["/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type {\n    CatalogNode,\n    LocaleNode,\n    NamespaceChild,\n    NamespaceNode,\n    PluralForms,\n    PluralNode,\n    Translations,\n    TranslationsNode,\n} from './types';\n\n/**\n * A terminal group of translations for the surrounding namespace. The data\n * is a flat or key-nested map of `string | PluralNode` leaves — a nested\n * object extends the dotted *key* path (`{ nav: { home } }` → `nav.home`).\n *\n * @example\n *     defineTranslations({\n *         greeting: 'Hi {{name}}',\n *         nav: { home: 'Home', settings: 'Settings' }, // → nav.home, nav.settings\n *     });\n */\nexport function defineTranslations(data: Translations): TranslationsNode {\n    return { type: 'translations', data };\n}\n\n/**\n * A namespace. Its children are sub-namespaces and/or translations groups — a\n * nested `defineNamespace` extends the dotted *namespace* path\n * (`app` ▸ `nav` → namespace `app.nav`), while translations inside it populate the\n * namespace's keys.\n *\n * @example\n *     defineNamespace('app', [\n *         defineTranslations({ greeting: 'Hi {{name}}' }),\n *         defineNamespace('nav', [ defineTranslations({ home: 'Home' }) ]), // → app.nav\n *     ]);\n */\nexport function defineNamespace(name: string, data: NamespaceChild[]): NamespaceNode {\n    return {\n        type: 'namespace', \n        name, \n        data, \n    };\n}\n\n/**\n * One locale's content — a list of namespaces (and, reserved for the future\n * default-namespace feature, bare translations groups). Compose locales into a\n * catalog with `defineCatalog`.\n *\n * @example\n *     // locales/en.ts\n *     import { defineLocale, defineNamespace, defineTranslations, definePlural } from 'ilingo';\n *\n *     export default defineLocale('en', [\n *         defineNamespace('app', [ defineTranslations({ greeting: 'Hi {{name}}' }) ]),\n *         defineNamespace('cart', [\n *             defineTranslations({ items: definePlural({ one: '1 item', other: '{{count}} items' }) }),\n *         ]),\n *     ]);\n */\nexport function defineLocale(name: string, data: NamespaceChild[]): LocaleNode {\n    return {\n        type: 'locale', \n        name, \n        data, \n    };\n}\n\n/**\n * Root of a catalog tree — a list of locales. The result is the canonical\n * ingestion format consumed by `MemoryStore({ data })` (and reduced to the\n * internal lookup shape by `normalizeCatalog`).\n *\n * @example\n *     import { defineCatalog } from 'ilingo';\n *     import en from './locales/en';\n *     import de from './locales/de';\n *\n *     export const catalog = defineCatalog([en, de]);\n *     const ilingo = new Ilingo({ store: new MemoryStore({ data: catalog }) });\n */\nexport function defineCatalog(data: LocaleNode[]): CatalogNode {\n    return { type: 'catalog', data };\n}\n\n/**\n * A plural leaf. Wraps the CLDR-categorised forms into the tagged\n * `{ type: 'plural', data }` node — the only recognised plural form. The\n * `PluralForms` parameter requires `other` and restricts the keys to CLDR\n * categories, so a missing `other` or a misspelled category is a compile\n * error and the categories autocomplete.\n *\n * JSON files cannot call functions, so they write the literal\n * `{ \"type\": \"plural\", \"data\": { \"one\": \"...\", \"other\": \"...\" } }` instead.\n *\n * @example\n *     defineTranslations({\n *         items: definePlural({ one: '{{count}} item', other: '{{count}} items' }),\n *     });\n */\nexport function definePlural(data: PluralForms): PluralNode {\n    return { type: 'plural', data };\n}\n","/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { isObject } from 'smob';\nimport type {\n    CatalogNode,\n    LocaleNode,\n    NamespaceNode,\n    PluralCategory,\n    PluralForms,\n    PluralNode,\n    TranslationsNode,\n} from '../types';\n\nconst PLURAL_CATEGORIES = new Set<PluralCategory>([\n    'zero',\n    'one',\n    'two',\n    'few',\n    'many',\n    'other',\n]);\n\n/**\n * Validates the inner CLDR-categorised options carried by a plural node\n * — a `{ one, other, ... }` object whose keys are CLDR categories and\n * whose values are strings, with `other` always present. Used by\n * `isPluralNode` to check the `data` of a `{ type: 'plural' }` node.\n */\nexport function isPluralForms(value: unknown): value is PluralForms {\n    if (!isObject(value)) {\n        return false;\n    }\n    const obj = value as Record<string, unknown>;\n    const keys = Object.keys(obj);\n    if (keys.length === 0 || typeof obj.other !== 'string') {\n        return false;\n    }\n    for (const key of keys) {\n        if (!PLURAL_CATEGORIES.has(key as PluralCategory)) {\n            return false;\n        }\n        if (typeof obj[key] !== 'string') {\n            return false;\n        }\n    }\n    return true;\n}\n\n/**\n * Detects a plural leaf — the tagged `{ type: 'plural', data: PluralForms }`\n * node. The `type` discriminator disambiguates a plural from a regular\n * nested translations object whose keys happen to be CLDR-category names.\n */\nexport function isPluralNode(value: unknown): value is PluralNode {\n    return isObject(value) &&\n        (value as { type?: unknown }).type === 'plural' &&\n        isPluralForms((value as { data?: unknown }).data);\n}\n\n/** Detects a `{ type: 'translations', data }` node. */\nexport function isTranslationsNode(value: unknown): value is TranslationsNode {\n    return isObject(value) &&\n        (value as { type?: unknown }).type === 'translations' &&\n        isObject((value as { data?: unknown }).data);\n}\n\n/** Detects a `{ type: 'namespace', name, data }` node. */\nexport function isNamespaceNode(value: unknown): value is NamespaceNode {\n    return isObject(value) &&\n        (value as { type?: unknown }).type === 'namespace' &&\n        typeof (value as { name?: unknown }).name === 'string' &&\n        Array.isArray((value as { data?: unknown }).data);\n}\n\n/** Detects a `{ type: 'locale', name, data }` node. */\nexport function isLocaleNode(value: unknown): value is LocaleNode {\n    return isObject(value) &&\n        (value as { type?: unknown }).type === 'locale' &&\n        typeof (value as { name?: unknown }).name === 'string' &&\n        Array.isArray((value as { data?: unknown }).data);\n}\n\n/** Detects a `{ type: 'catalog', data }` root node. */\nexport function isCatalogNode(value: unknown): value is CatalogNode {\n    return isObject(value) &&\n        (value as { type?: unknown }).type === 'catalog' &&\n        Array.isArray((value as { data?: unknown }).data);\n}\n","/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\n/**\n * `true` when running under a production bundle.\n *\n * Webpack's DefinePlugin and Vite's `define` replace the literal expression\n * `process.env.NODE_ENV` at build time. We reference it directly (rather\n * than via `globalThis`) so that replacement actually fires. The\n * `typeof process !== 'undefined'` guard makes raw-browser execution\n * (no polyfill, no bundler) safe.\n */\nexport function isProductionEnv(): boolean {\n    try {\n        return typeof process !== 'undefined' &&\n            process.env != null &&\n            process.env.NODE_ENV === 'production';\n    } catch {\n        return false;\n    }\n}\n","/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type {\n    CatalogInput,\n    LocaleNode,\n    Locales,\n    NamespaceBodyInput,\n    NamespaceChild,\n    Translations,\n} from '../types';\nimport {\n    isCatalogNode,\n    isLocaleNode,\n    isNamespaceNode,\n    isPluralNode,\n    isTranslationsNode,\n} from '../utils/identify';\nimport { isProductionEnv } from '../utils/env';\n\n/**\n * Namespace key for translations placed directly under a locale (no enclosing\n * namespace node). Reserved for the future optional-namespace feature —\n * the normalizer already routes such translations here so the seam exists.\n */\nconst DEFAULT_NAMESPACE = '';\n\n/**\n * Dev-only, one-shot diagnostics keyed by call-site. The normalizer accepts\n * only descriptor nodes; a non-node value is the tell-tale of a catalog that\n * hasn't been migrated to the tree format (a loader/file that forgot the\n * `defineTranslations(...)` wrapper, or a plain locale object passed where a tree is\n * expected). Without this it degrades silently to \"every key missing\".\n */\nconst warnedNodeShapes = new Set<string>();\n\nfunction warnUnexpectedNode(context: string, received: unknown): void {\n    /* istanbul ignore next */\n    if (isProductionEnv()) {\n        return;\n    }\n    if (warnedNodeShapes.has(context)) {\n        return;\n    }\n    warnedNodeShapes.add(context);\n    const kind = received === null ? 'null' : typeof received;\n    // eslint-disable-next-line no-console\n    console.warn(\n        `[ilingo] ${context}: expected a catalog descriptor node but received ${kind}. ` +\n        'Catalog input is tree-only — build it with defineCatalog / defineLocale / ' +\n        'defineNamespace / defineTranslations (see the catalog-design guide).',\n    );\n}\n\n/**\n * Deep-merge `source` translations into `target`. Strings and plural nodes are\n * terminal (last write wins); plain nested objects merge recursively. The\n * source tree is never mutated — only leaf values are shared by reference.\n */\nfunction mergeLines(target: Translations, source: Translations): Translations {\n    for (const key of Object.keys(source)) {\n        const value = source[key];\n        if (typeof value === 'string' || isPluralNode(value)) {\n            target[key] = value;\n            continue;\n        }\n        const existing = target[key];\n        const base: Translations = (existing && typeof existing !== 'string' && !isPluralNode(existing)) ?\n            existing as Translations :\n            {};\n        target[key] = mergeLines(base, value as Translations);\n    }\n    return target;\n}\n\n/**\n * Fold a namespace body into `namespaces` under `fullName`. Translations nodes\n * populate `namespaces[fullName]`; nested namespace nodes recurse with a\n * dotted-suffixed name. A namespace with only sub-namespaces creates no\n * entry of its own.\n */\nfunction namespaceInto(\n    namespaces: Record<string, Translations>,\n    fullName: string,\n    body: NamespaceChild[],\n): void {\n    for (const child of body) {\n        if (isTranslationsNode(child)) {\n            namespaces[fullName] = mergeLines(namespaces[fullName] || {}, child.data);\n        } else if (isNamespaceNode(child)) {\n            const nested = fullName ? `${fullName}.${child.name}` : child.name;\n            namespaceInto(namespaces, nested, child.data);\n        } else {\n            warnUnexpectedNode('namespace child', child);\n        }\n    }\n}\n\nfunction toLocaleNodes(input: CatalogInput): LocaleNode[] {\n    if (isCatalogNode(input)) {\n        return input.data;\n    }\n    if (Array.isArray(input)) {\n        return input;\n    }\n    return [input];\n}\n\n/**\n * Reduce a catalog tree to the internal `Locales` lookup shape. A nested\n * namespace node extends the dotted **namespace**; a nested object inside a\n * translations node extends the dotted **key**. Translations placed directly under a\n * locale (no namespace) land in the default namespace.\n *\n * Accepts a `CatalogNode`, a bare `LocaleNode[]`, or a single `LocaleNode`.\n */\nexport function normalizeCatalog(input: CatalogInput): Locales {\n    const result: Locales = {};\n    for (const locale of toLocaleNodes(input)) {\n        if (!isLocaleNode(locale)) {\n            warnUnexpectedNode('catalog locale', locale);\n            continue;\n        }\n        const namespaces = result[locale.name] || (result[locale.name] = {});\n        for (const child of locale.data) {\n            if (isNamespaceNode(child)) {\n                namespaceInto(namespaces, child.name, child.data);\n            } else if (isTranslationsNode(child)) {\n                namespaces[DEFAULT_NAMESPACE] = mergeLines(\n                    namespaces[DEFAULT_NAMESPACE] || {},\n                    child.data,\n                );\n            } else {\n                warnUnexpectedNode('locale child', child);\n            }\n        }\n    }\n    return result;\n}\n\n/**\n * Reduce a single namespace body (from a `LoaderStore` loader or an\n * `@ilingo/fs` file, where `(locale, namespace)` is already known) to the\n * internal `Translations` shape. Returns an empty record for a non-translations body.\n */\nexport function normalizeNamespaceBody(body: NamespaceBodyInput): Translations {\n    if (isTranslationsNode(body)) {\n        return mergeLines({}, body.data);\n    }\n    warnUnexpectedNode('namespace body', body);\n    return {};\n}\n","/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\n/**\n * A formatter receives the raw `data` value, parsed options from the\n * placeholder, and the resolved locale, and returns the substituted string.\n * Register one via `Ilingo.registerFormatter(name, fn)` or the\n * `Options.formatters` constructor option; the built-ins are `number`,\n * `date`, and `list`.\n */\nexport type Formatter = (\n    value: unknown,\n    options: Record<string, unknown>,\n    locale: string,\n) => string;\n\nexport type FormatterOptions = Record<string, unknown>;\n\n/**\n * Parse the options-string segment of a template modifier.\n *\n * `currency=EUR, style=currency, minimumFractionDigits=2`\n *   → `{ currency: 'EUR', style: 'currency', minimumFractionDigits: 2 }`\n *\n * Numbers and booleans are auto-coerced; everything else stays a string.\n */\nexport function parseFormatterOptions(input: string | undefined): FormatterOptions {\n    if (!input) return {};\n    const result: FormatterOptions = {};\n    for (const segment of input.split(',')) {\n        const eq = segment.indexOf('=');\n        if (eq === -1) continue;\n        const key = segment.slice(0, eq).trim();\n        const rawValue = segment.slice(eq + 1).trim();\n        if (!key || !rawValue) continue;\n        if (rawValue === 'true') {\n            result[key] = true;\n        } else if (rawValue === 'false') {\n            result[key] = false;\n        } else if (/^-?\\d+(\\.\\d+)?$/.test(rawValue)) {\n            result[key] = Number(rawValue);\n        } else {\n            result[key] = rawValue;\n        }\n    }\n    return result;\n}\n\n/**\n * Split a modifier expression into `{ name, options }`.\n * `number(currency=EUR)` → `{ name: 'number', options: 'currency=EUR' }`.\n * `date`                  → `{ name: 'date', options: undefined }`.\n *\n * Returns `undefined` for malformed input (e.g. unbalanced parens).\n */\nconst NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nexport function parseModifier(input: string): { name: string, options: string | undefined } | undefined {\n    const trimmed = input.trim();\n    if (!trimmed) return undefined;\n    const open = trimmed.indexOf('(');\n    if (open === -1) {\n        // Bare name. Must be a valid identifier — guards against malformed\n        // input like 'number)' that has no opening paren but a stray closing one.\n        return NAME_RE.test(trimmed) ? { name: trimmed, options: undefined } : undefined;\n    }\n    // The first `)` after the opening paren must be the very last character.\n    // Catches stray closes like `number(currency=EUR))` and nested parens\n    // (which the option grammar doesn't support).\n    const close = trimmed.indexOf(')', open);\n    if (close !== trimmed.length - 1) return undefined;\n    const name = trimmed.slice(0, open).trim();\n    if (!NAME_RE.test(name)) return undefined;\n    const options = trimmed.slice(open + 1, close).trim();\n    return { name, options };\n}\n\n/**\n * Per-instance formatter registry. Caches `Intl.*Format` instances keyed by\n * `(formatter, locale, JSON-encoded options)` so repeated template renders\n * don't reallocate.\n */\nexport class FormatterRegistry {\n    protected entries = new Map<string, Formatter>();\n\n    protected cache = new Map<string, Intl.NumberFormat | Intl.DateTimeFormat | Intl.ListFormat>();\n\n    constructor() {\n        this.register('number', (value, options, locale) => {\n            const numeric = typeof value === 'number' ? value : Number(value);\n            if (Number.isNaN(numeric)) return String(value);\n            const fmt = this.intl<Intl.NumberFormat>(\n                'number', \n                locale, \n                options,\n                () => new Intl.NumberFormat(locale, options as Intl.NumberFormatOptions),\n            );\n            if (!fmt) return String(value);\n            return fmt.format(numeric);\n        });\n\n        this.register('date', (value, options, locale) => {\n            let d: Date;\n            if (value instanceof Date) {\n                d = value;\n            } else if (typeof value === 'number' || typeof value === 'string') {\n                d = new Date(value);\n            } else {\n                return String(value);\n            }\n            if (Number.isNaN(d.getTime())) return String(value);\n            const fmt = this.intl<Intl.DateTimeFormat>(\n                'date', \n                locale, \n                options,\n                () => new Intl.DateTimeFormat(locale, options as Intl.DateTimeFormatOptions),\n            );\n            if (!fmt) return String(value);\n            return fmt.format(d);\n        });\n\n        this.register('list', (value, options, locale) => {\n            if (!Array.isArray(value)) return String(value);\n            const fmt = this.intl<Intl.ListFormat>(\n                'list', \n                locale, \n                options,\n                () => new Intl.ListFormat(locale, options as Intl.ListFormatOptions),\n            );\n            if (!fmt) return value.map(String).join(', ');\n            return fmt.format(value.map(String));\n        });\n    }\n\n    register(name: string, formatter: Formatter): void {\n        this.entries.set(name, formatter);\n    }\n\n    get(name: string): Formatter | undefined {\n        return this.entries.get(name);\n    }\n\n    has(name: string): boolean {\n        return this.entries.has(name);\n    }\n\n    /**\n     * Look up or construct the `Intl.*Format` instance for `(kind, locale,\n     * options)`. Returns `undefined` if either the cache-key generation or\n     * the constructor throws — built-in formatters then fall back to a plain\n     * `String(value)` rendering rather than letting a typo in a translator's\n     * options crash the entire render.\n     *\n     * Options are stringified with sorted keys so callers that happen to pass\n     * the same logical options in a different order share a cache entry.\n     */\n    protected intl<T extends Intl.NumberFormat | Intl.DateTimeFormat | Intl.ListFormat>(\n        kind: string,\n        locale: string,\n        options: FormatterOptions,\n        create: () => T,\n    ): T | undefined {\n        let key: string;\n        try {\n            const sortedKeys = Object.keys(options).sort();\n            key = `${kind}|${locale}|${JSON.stringify(options, sortedKeys)}`;\n        } catch {\n            return undefined;\n        }\n        let fmt = this.cache.get(key) as T | undefined;\n        if (!fmt) {\n            try {\n                fmt = create();\n            } catch {\n                return undefined;\n            }\n            this.cache.set(key, fmt);\n        }\n        return fmt;\n    }\n}\n","","/*\n * Copyright (c) 2023.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { hasOwnProperty } from 'smob';\nimport codes from './data.json';\n\nexport function isISO639LanguageCode(input: string) {\n    return hasOwnProperty(codes, input);\n}\n\nexport function isBCP47LanguageCode(input: string) {\n    const hyphenIndex = input.indexOf('-');\n    if (hyphenIndex !== -1) {\n        input = input.substring(0, hyphenIndex);\n    }\n\n    return isISO639LanguageCode(input);\n}\n","/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { PluralNode, Translations } from '../types';\nimport { isPluralNode } from './identify';\n\nexport type TranslationsRecordParsed = {\n    key: string,\n    value: string | PluralNode\n};\nexport function parseTranslationsRecord(record: Translations, parent?: string): TranslationsRecordParsed[] {\n    const output : TranslationsRecordParsed[] = [];\n    const keys = Object.keys(record);\n    for (const key of keys) {\n        const value = record[key];\n        const nextKey = parent ?\n            `${parent}.${  key}` :\n            key;\n\n        if (typeof value === 'string' || isPluralNode(value)) {\n            output.push({\n                value,\n                key: nextKey,\n            });\n        } else {\n            output.push(...parseTranslationsRecord(value, nextKey));\n        }\n    }\n\n    return output;\n}\n","/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { Fallback } from '../types';\n\n/**\n * Derive the BCP-47 parent tags of a locale, from most-specific to most-generic.\n *\n * `pt-BR-Latn` → `['pt-BR', 'pt']`\n * `pt-BR`      → `['pt']`\n * `pt`         → `[]`\n */\nexport function bcp47Parents(locale: string): string[] {\n    const parts = locale.split('-');\n    const chain: string[] = [];\n    for (let i = parts.length - 1; i > 0; i--) {\n        chain.push(parts.slice(0, i).join('-'));\n    }\n    return chain;\n}\n\n/**\n * Resolve the ordered chain of locales to try for a single lookup.\n *\n * The returned array always starts with `locale` and ends with the default\n * locale, deduplicated. The middle is the explicit `fallback` if given,\n * otherwise the BCP-47 parent chain.\n */\nexport function resolveLocaleChain(\n    locale: string,\n    fallback: Fallback | undefined,\n    defaultLocale: string,\n): string[] {\n    // Opt out of fallback entirely — chain is just the requested locale.\n    if (fallback === false) {\n        return [locale];\n    }\n\n    const explicit: string[] = [];\n    // Did the caller hand us an *explicit* fallback shape (array or function)?\n    // If yes and that shape evaluates to empty, the caller is asking for no\n    // fallback at all — don't fall back to the default locale either.\n    let explicitlyProvided = false;\n\n    if (typeof fallback === 'function') {\n        explicitlyProvided = true;\n        explicit.push(...fallback(locale));\n    } else if (Array.isArray(fallback)) {\n        explicitlyProvided = true;\n        explicit.push(...fallback);\n    } else if (typeof fallback === 'string') {\n        explicit.push(fallback);\n    } else {\n        explicit.push(...bcp47Parents(locale));\n    }\n\n    if (explicitlyProvided && explicit.length === 0) {\n        return [locale];\n    }\n\n    // Order-preserving de-dupe that guarantees defaultLocale stays at the end.\n    // A plain `new Set([...locale, ...explicit, defaultLocale])` would move\n    // defaultLocale earlier in the chain if it appears in `explicit`.\n    const seen = new Set<string>();\n    const chain: string[] = [];\n    for (const candidate of [locale, ...explicit]) {\n        if (candidate !== defaultLocale && !seen.has(candidate)) {\n            seen.add(candidate);\n            chain.push(candidate);\n        }\n    }\n    chain.push(defaultLocale);\n    return chain;\n}\n","/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { bcp47Parents } from './locale';\n\n/**\n * Pick the best match between a list of supported locales and a list of\n * requested locales, using BCP-47 best-match semantics:\n *\n *   1. Exact match — if any `requested` entry equals a `supported` entry\n *      after canonicalisation.\n *   2. Prefix match — if a `requested` tag is a parent of a `supported` tag\n *      (e.g. requested `pt` matches supported `pt-BR`).\n *   3. Parent match — if a `requested` tag's BCP-47 parents include a\n *      `supported` tag (e.g. requested `pt-PT` matches supported `pt`).\n *\n * **Casing:** comparison is case-insensitive — both `supported` and\n * `requested` tags are canonicalised internally (language lowercase, region\n * uppercase, script titlecase, per the convention browsers and `Intl.*`\n * emit). The **returned** locale preserves the original casing of the\n * matching `supported` entry — so `negotiateLocale(['PT-br'], ['pt-BR'])`\n * returns `'PT-br'`, not the canonical form.\n *\n * Returns the matching `supported` entry, or `undefined` if nothing matches.\n *\n * Pure utility — does not mutate `Ilingo` state. Compose with\n * `ilingo.setLocale(negotiateLocale(supported, requested) ?? defaultLocale)`.\n *\n * @example\n *   negotiateLocale(['en', 'pt-BR'], ['pt-PT', 'pt', 'en']);\n *   // → 'pt-BR'  (requested 'pt' is a parent of supported 'pt-BR')\n *\n *   negotiateLocale(['en', 'de'], ['fr', 'es']);\n *   // → undefined\n */\nexport function negotiateLocale(\n    supported: string[],\n    requested: string[],\n): string | undefined {\n    if (supported.length === 0 || requested.length === 0) return undefined;\n\n    const supportedSet = new Map<string, string>();\n    for (const s of supported) {\n        const key = canonicalize(s);\n        if (!supportedSet.has(key)) supportedSet.set(key, s);\n    }\n\n    for (const r of requested) {\n        const key = canonicalize(r);\n\n        // 1. Exact.\n        if (supportedSet.has(key)) return supportedSet.get(key)!;\n\n        // 2. Prefix — requested 'pt' should match supported 'pt-BR'.\n        for (const [supKey, supRaw] of supportedSet) {\n            if (supKey === key || supKey.startsWith(`${key}-`)) {\n                return supRaw;\n            }\n        }\n\n        // 3. Parent walk — requested 'pt-PT' should match supported 'pt'.\n        for (const parent of bcp47Parents(key)) {\n            if (supportedSet.has(parent)) return supportedSet.get(parent)!;\n        }\n    }\n    return undefined;\n}\n\n/**\n * Parse an HTTP `Accept-Language` header into an ordered list of locale tags,\n * sorted by quality (`q=`) descending. Tags lacking a `q=` parameter default\n * to `q=1.0` (RFC 9110).\n *\n * Tags with `q=0` are dropped per RFC 9110 § 12.5.4 — `q=0` means\n * \"not acceptable\", so a client that says `de;q=0` is explicitly rejecting\n * German and we must not negotiate to it. Invalid q-values (NaN or outside\n * `0..1`) cause the tag to be dropped as well.\n *\n * The `*` wildcard is dropped — callers that want a fallback should pass it\n * separately to `negotiateLocale`'s `requested` argument.\n *\n * @example\n *   parseAcceptLanguage('en-US,en;q=0.9,de;q=0.8');\n *   // → ['en-US', 'en', 'de']\n *\n *   parseAcceptLanguage('pt-PT;q=0.7, pt;q=0.5, *;q=0.1');\n *   // → ['pt-PT', 'pt']\n *\n *   parseAcceptLanguage('en, fr;q=0, de;q=0.8');\n *   // → ['en', 'de']    (French explicitly rejected)\n */\nexport function parseAcceptLanguage(header: string): string[] {\n    if (!header) return [];\n\n    const entries: { tag: string, q: number }[] = [];\n    for (const raw of header.split(',')) {\n        const item = raw.trim();\n        if (!item) continue;\n        const [tagRaw, ...params] = item.split(';');\n        const tag = tagRaw.trim();\n        if (!tag || tag === '*') continue;\n\n        let q = 1;\n        let qValid = true;\n        for (const param of params) {\n            const [k, v] = param.split('=').map((s) => s.trim());\n            // Header parameter names are case-insensitive (RFC 9110 § 5.6.2).\n            if (k.toLowerCase() === 'q' && v !== undefined) {\n                const parsed = Number(v);\n                if (Number.isNaN(parsed) || parsed < 0 || parsed > 1) {\n                    qValid = false;\n                } else {\n                    q = parsed;\n                }\n            }\n        }\n        // q=0 ⇒ \"not acceptable\" — drop. Invalid q ⇒ drop (defensive).\n        if (!qValid || q <= 0) continue;\n        entries.push({ tag, q });\n    }\n\n    // Stable sort by q descending; entries with the same q keep their\n    // declared order (Array.prototype.sort in V8 / SpiderMonkey is stable\n    // since ES2019).\n    entries.sort((a, b) => b.q - a.q);\n    return entries.map((e) => e.tag);\n}\n\n/**\n * Canonicalise a BCP-47 tag for comparison: language sub-tag lowercase,\n * region sub-tag uppercase, script sub-tag titlecase. Matches the casing\n * convention browsers and `Intl.*` use when emitting tags.\n */\nfunction canonicalize(tag: string): string {\n    const parts = tag.split('-');\n    if (parts.length === 0 || !parts[0]) return tag;\n\n    return parts\n        .map((part, i) => {\n            if (i === 0) return part.toLowerCase();\n            if (part.length === 2) return part.toUpperCase(); // region\n            if (part.length === 4) {\n                // script: titlecase\n                return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();\n            }\n            return part.toLowerCase();\n        })\n        .join('-');\n}\n","/*\n * Copyright (c) 2023.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { FormatterRegistry } from './formatters';\nimport { parseFormatterOptions, parseModifier } from './formatters';\n\nexport type TemplateContext = {\n    locale: string;\n    formatters: FormatterRegistry;\n    onUnknownFormatter?: (name: string) => void;\n};\n\nconst DEFAULT_REGEX = /\\{\\{\\s*([^,}]+?)(?:\\s*,\\s*([^}]+?))?\\s*\\}\\}/g;\n\n/**\n * Tokens emitted by `tokenize()` for slot-aware rendering (e.g. Vue's\n * `<ITranslateT>` component).\n *\n * - `text`: literal substring between placeholders.\n * - `var`:  `{{name}}` or `{{name, modifier(opts)}}`. The orchestrator\n *           replaces these with `data[name]` (optionally piped through\n *           a formatter); slot renderers do the same.\n * - `slot`: `{slot-name}` (single curly braces). Slot renderers fill\n *           these from a named scoped slot; plain `template()` leaves\n *           them as literal text (no slot-aware substitution).\n */\nexport type TextToken = { kind: 'text', value: string };\nexport type VarToken = {\n    kind: 'var',\n    name: string,\n    modifierExpression?: string,\n};\nexport type SlotToken = { kind: 'slot', name: string };\nexport type TemplateToken = TextToken | VarToken | SlotToken;\n\n// `{{...}}` for vars (with optional modifier) OR `{ident}` for slots.\n// Slot identifier is restricted to a JS-ish identifier so an inline JSON\n// snippet or hand-written `{` in prose doesn't get hijacked.\nconst TOKEN_REGEX =    /\\{\\{\\s*([^,}]+?)(?:\\s*,\\s*([^}]+?))?\\s*\\}\\}|\\{\\s*([A-Za-z_][A-Za-z0-9_-]*)\\s*\\}/g;\n\n/**\n * Parse `str` into an interleaved sequence of text / var / slot tokens.\n *\n * Designed for renderers that produce VNodes (or other non-string\n * structures): the plain `template()` function still returns a string\n * for the common case.\n */\nexport function tokenize(str: string): TemplateToken[] {\n    const tokens: TemplateToken[] = [];\n    let lastIndex = 0;\n    // `replace()` exposes match index via the named-callback signature.\n    // `matchAll` is cleaner here.\n    for (const match of str.matchAll(TOKEN_REGEX)) {\n        const start = match.index ?? 0;\n        if (start > lastIndex) {\n            tokens.push({ kind: 'text', value: str.slice(lastIndex, start) });\n        }\n\n        const [, varName, modifierExpression, slotName] = match;\n        if (typeof slotName === 'string') {\n            tokens.push({ kind: 'slot', name: slotName });\n        } else if (typeof varName === 'string') {\n            const token: TemplateToken = { kind: 'var', name: varName.trim() };\n            if (typeof modifierExpression === 'string') {\n                token.modifierExpression = modifierExpression.trim();\n            }\n            tokens.push(token);\n        }\n\n        lastIndex = start + match[0].length;\n    }\n    if (lastIndex < str.length) {\n        tokens.push({ kind: 'text', value: str.slice(lastIndex) });\n    }\n    return tokens;\n}\n\n/**\n * Substitute `{{var}}` placeholders. With a `TemplateContext`, also supports\n * modifier syntax: `{{var, modifier}}` and `{{var, modifier(opts)}}`.\n *\n * - Unknown data key → placeholder left in place (unchanged from prior behaviour).\n * - Unknown modifier → raw value substituted, `onUnknownFormatter` invoked.\n * - Malformed modifier expression (e.g. unbalanced parens) → raw value substituted.\n *\n * The third parameter accepts either a `TemplateContext` (modern, with\n * formatter support) or a `RegExp` (legacy escape-hatch for custom\n * placeholder delimiters). Passing a `RegExp` disables modifier dispatch,\n * matching the pre-formatter behaviour for callers that supplied their own\n * delimiter.\n */\nexport function template(\n    str: string,\n    data: Record<string, any>,\n    ctxOrRegex?: TemplateContext | RegExp,\n): string {\n    let regex: RegExp;\n    let ctx: TemplateContext | undefined;\n    if (ctxOrRegex instanceof RegExp) {\n        regex = ctxOrRegex;\n        ctx = undefined;\n    } else {\n        regex = DEFAULT_REGEX;\n        ctx = ctxOrRegex;\n    }\n\n    return str.replace(regex, (match, rawKey: string, modExpr: string | undefined) => {\n        const key = rawKey.trim();\n        if (typeof data[key] === 'undefined') return match;\n\n        const value = data[key];\n\n        if (!modExpr || !ctx) {\n            return String(value);\n        }\n\n        const modifier = parseModifier(modExpr);\n        if (!modifier) return String(value);\n\n        const formatter = ctx.formatters.get(modifier.name);\n        if (!formatter) {\n            ctx.onUnknownFormatter?.(modifier.name);\n            return String(value);\n        }\n\n        const options = parseFormatterOptions(modifier.options);\n        return formatter(value, options, ctx.locale);\n    });\n}\n","/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { IlingoOptions } from './options';\nimport { LOCALE_DEFAULT } from './constants';\nimport type { IStore } from './store';\nimport type {\n    Data,\n    Fallback,\n    GetContext,\n    IIlingo,\n    Leaf,\n    MissingKeyHandler,\n} from './types';\nimport type { Formatter } from './utils';\nimport {\n    FormatterRegistry,\n    isProductionEnv,\n    resolveLocaleChain,\n    template,\n} from './utils';\n\nexport class Ilingo implements IIlingo {\n    /**\n     * Registered stores, keyed by a `symbol` identity. Insertion order is\n     * preserved (it drives the serial intra-locale store walk — earlier\n     * registrations are consulted first) and the symbol key is how\n     * registration deduplicates (see {@link registerStore}).\n     *\n     * Use `Symbol.for('@scope/pkg')` as the key for library catalogs so a\n     * duplicate package copy (pnpm / peer-dep mismatch) resolves to the\n     * same identity and re-registration stays a no-op.\n     */\n    public readonly stores: Map<symbol | string, IStore>;\n\n    protected locale: string;\n\n    protected fallback: Fallback | undefined;\n\n    protected onMissingKey: MissingKeyHandler | undefined;\n\n    protected pluralRulesCache: Map<string, Intl.PluralRules>;\n\n    /**\n     * Per-instance registry for `{{value, formatter(opts)}}` template\n     * modifiers. Built-in entries: `number`, `date`, `list` (each backed\n     * by the matching `Intl.*Format`, memoised by `(locale, options)`).\n     */\n    public formatters: FormatterRegistry;\n\n    /**\n     * Per-instance set of `(locale, namespace, key)` triples that have already\n     * triggered a missing-key warning. Kept on the instance — not module\n     * scope — so multiple `Ilingo` instances do not dedupe each other's\n     * warnings.\n     */\n    protected warnedKeys: Set<string>;\n\n    /**\n     * Mirror of `warnedKeys` for unknown-formatter diagnostics.\n     */\n    protected warnedFormatters: Set<string>;\n\n    // ----------------------------------------------------\n\n    constructor(input: IlingoOptions = {}) {\n        this.locale = input.locale || LOCALE_DEFAULT;\n        this.fallback = input.fallback;\n        this.onMissingKey = input.onMissingKey;\n        this.pluralRulesCache = new Map();\n        this.warnedKeys = new Set();\n        this.warnedFormatters = new Set();\n        this.formatters = new FormatterRegistry();\n        if (input.formatters) {\n            for (const [name, fn] of Object.entries(input.formatters)) {\n                this.formatters.register(name, fn);\n            }\n        }\n\n        this.stores = new Map<symbol, IStore>();\n        if (input.store) {\n            const stores = Array.isArray(input.store) ? input.store : [input.store];\n            for (const store of stores) {\n                this.registerStore(store);\n            }\n        }\n    }\n\n    /**\n     * Register a store, keyed by its own `store.id` identity.\n     *\n     * Idempotent: if a store is already registered under `store.id`, this\n     * is a no-op and the existing store is kept. Library catalogs set\n     * `id` to a `Symbol.for('@scope/pkg')` (e.g. `createMemoryStore()` /\n     * `createLoaderStore()` from `@ilingo/validup`), so re-registering —\n     * even from a duplicate package copy — never stacks duplicates.\n     * Anonymous stores default to a fresh `Symbol(...)`, so each is always\n     * added.\n     *\n     * Insertion order drives the serial intra-locale store walk, so a\n     * store registered earlier is consulted first and wins per key. To\n     * override individual keys of a library catalog, register your own\n     * store before registering the library's.\n     */\n    registerStore(store: IStore): void {\n        if (this.stores.has(store.id)) {\n            return;\n        }\n\n        this.stores.set(store.id, store);\n    }\n\n    /**\n     * Register a custom formatter for use inside `{{value, name(opts)}}`\n     * placeholders. Equivalent to `this.formatters.register(name, fn)` —\n     * exposed as an instance method for discoverability and parity with\n     * `setLocale` / `merge` / `clone`.\n     *\n     * @example\n     *     ilingo.registerFormatter('upper', (value, _opts, locale) =>\n     *         String(value).toLocaleUpperCase(locale));\n     *     await ilingo.get({\n     *         namespace: 'app', key: 'shout',\n     *         data: { name: 'peter' },\n     *     });\n     *     // \"{{name, upper}}\" → \"PETER\"\n     */\n    registerFormatter(name: string, formatter: Formatter): void {\n        this.formatters.register(name, formatter);\n    }\n\n    // ----------------------------------------------------\n\n    /**\n     * Build a new `Ilingo` that inherits this instance's configuration\n     * (locale, fallback, missing-key handler), shares its formatter\n     * registry, and includes its stores in order. The new instance is\n     * independent — mutating its `stores` does not affect the parent —\n     * but the shared `formatters` registry means custom formatters\n     * registered on either side are visible to both.\n     *\n     * `overrides.store`, when provided, becomes the **first** store(s) in\n     * the new instance (resolved before any inherited store; an array is\n     * registered in order). Other overrides replace the corresponding\n     * inherited config field.\n     *\n     * `overrides.formatters`, when provided, is registered on the shared\n     * registry — visible to both the parent and the child (consistent with\n     * the registry-sharing design). Callers that need formatter isolation\n     * should construct manually instead of cloning.\n     *\n     * Designed for consumers that need a scoped variant of an existing\n     * orchestrator — e.g. `@ilingo/vue`'s `useScopedCatalog`.\n     */\n    clone(overrides: IlingoOptions = {}): IIlingo {\n        const child = new Ilingo({\n            store: overrides.store,\n            locale: overrides.locale ?? this.locale,\n            // Use `in`-check (not ??) so explicit `undefined` clears the\n            // inherited value. Matches the `fallback` handling above —\n            // both nullable config fields treat \"field present in overrides\"\n            // as intent to replace, even when the new value is undefined.\n            fallback: 'fallback' in overrides ? overrides.fallback : this.fallback,\n            onMissingKey: 'onMissingKey' in overrides ? overrides.onMissingKey : this.onMissingKey,\n        });\n        // Inherit stores in order, preserving each store's symbol identity\n        // (overrides.store, if any, was already added first by the\n        // constructor under a minted symbol — appending parent's keeps the\n        // precedence, and reusing the parent keys means a later merge()\n        // dedupes correctly).\n        for (const [id, store] of this.stores) {\n            child.stores.set(id, store);\n        }\n        // Share the formatter registry so custom registrations on the parent\n        // are honoured. Trade-off: mutations on either side are visible to\n        // both. Callers that need isolation should construct manually.\n        child.formatters = this.formatters;\n        // Apply any new formatters from the overrides AFTER pointing at the\n        // shared registry, so they land on the shared map and are visible to\n        // the parent too. (Type contract: overrides.formatters is honoured.)\n        if (overrides.formatters) {\n            for (const [name, fn] of Object.entries(overrides.formatters)) {\n                child.formatters.register(name, fn);\n            }\n        }\n        return child;\n    }\n\n    /**\n     * Fold another instance's stores into this one, deduping by symbol\n     * identity. A foreign store whose key is already present is skipped\n     * (the existing store wins); foreign keys not present here are appended\n     * in order. Library catalogs keyed by `Symbol.for('@scope/pkg')` thus\n     * never stack across a merge, while anonymously-keyed stores (minted\n     * `Symbol()`) are always distinct and so always carried over.\n     */\n    merge(instance: IIlingo) {\n        for (const [id, store] of instance.stores) {\n            if (!this.stores.has(id)) {\n                this.stores.set(id, store);\n            }\n        }\n    }\n\n    // ----------------------------------------------------\n\n    setLocale(key: string) {\n        this.locale = key;\n    }\n\n    resetLocale() {\n        this.locale = LOCALE_DEFAULT;\n    }\n\n    getLocale(): string {\n        return this.locale;\n    }\n\n    // ----------------------------------------------------\n\n    async getLocales(): Promise<string[]> {\n        const locales: string[] = [];\n        for (const store of this.stores.values()) {\n            locales.push(...await store.getLocales());\n        }\n        return Array.from(new Set(locales));\n    }\n\n    /**\n     * Locale chain that would be tried for the given context, in order.\n     */\n    getResolvedLocaleChain(ctx: Pick<GetContext, 'locale'>): string[] {\n        return resolveLocaleChain(\n            ctx.locale || this.getLocale(),\n            this.fallback,\n            LOCALE_DEFAULT,\n        );\n    }\n\n    /**\n     * Which locale in the chain actually yielded a value for the given\n     * `(namespace, key)`, or `undefined` if the key is missing in every locale.\n     */\n    async getResolvedLocale(ctx: GetContext): Promise<string | undefined> {\n        const chain = this.getResolvedLocaleChain(ctx);\n        const hit = await this.lookup(chain, ctx);\n        return hit?.locale;\n    }\n\n    // ----------------------------------------------------\n\n    async get(ctx: GetContext): Promise<string | undefined> {\n        const requestedLocale = ctx.locale ?? this.getLocale();\n        const chain = this.getResolvedLocaleChain({ locale: requestedLocale });\n\n        const hit = await this.lookup(chain, ctx);\n        return hit ?\n            this.render(hit.leaf, hit.locale, ctx) :\n            this.handleMissingKey(ctx, requestedLocale, chain);\n    }\n\n    /**\n     * The post-lookup half of `get()`: pick the plural form for `ctx.count`,\n     * auto-merge `count` into the interpolation data (so `{{count}}` works\n     * without restating it), and substitute `{{var}}` placeholders against\n     * the *resolved* locale.\n     */\n    protected render(leaf: Leaf, locale: string, ctx: GetContext): string {\n        const message = this.selectPluralForm(leaf, locale, ctx.count);\n        const data: Data = { ...(ctx.data || {}) };\n        if (typeof ctx.count === 'number' && typeof data.count === 'undefined') {\n            data.count = ctx.count;\n        }\n        return this.format(message, data, locale);\n    }\n\n    // ----------------------------------------------------\n\n    /**\n     * Walk the locale chain in order. Within each locale, query stores\n     * serially in insertion order and stop at the first hit.\n     *\n     * Locale-first composition: the closer locale always beats the farther\n     * one, regardless of which store would have answered. Within a single\n     * locale, a store is only consulted when every earlier store has\n     * missed — so a network-backed adapter registered after a Memory\n     * adapter is never called when the Memory adapter hits.\n     */\n    protected async lookup(\n        chain: string[],\n        ctx: Pick<GetContext, 'namespace' | 'key'>,\n    ): Promise<{ locale: string, leaf: Leaf } | undefined> {\n        if (this.stores.size === 0) {\n            return undefined;\n        }\n\n        for (const locale of chain) {\n            for (const store of this.stores.values()) {\n                const candidate = await store.get({\n                    locale,\n                    namespace: ctx.namespace,\n                    key: ctx.key,\n                });\n                if (typeof candidate !== 'undefined') {\n                    return { locale, leaf: candidate };\n                }\n            }\n        }\n        return undefined;\n    }\n\n    /**\n     * Run the configured `onMissingKey` (or the built-in warn-once default)\n     * and return whatever it produces.\n     */\n    protected handleMissingKey(\n        ctx: GetContext,\n        requestedLocale: string,\n        chain: string[],\n    ): string | undefined {\n        if (this.onMissingKey) {\n            const result = this.onMissingKey({\n                ...ctx,\n                locale: requestedLocale,\n                resolvedLocale: chain[chain.length - 1],\n            });\n            return typeof result === 'string' ? result : undefined;\n        }\n\n        /* istanbul ignore next */\n        if (isProductionEnv()) {\n            return undefined;\n        }\n\n        const id = `${requestedLocale}|${ctx.namespace}|${ctx.key}`;\n        if (!this.warnedKeys.has(id)) {\n            this.warnedKeys.add(id);\n            // eslint-disable-next-line no-console\n            console.warn(\n                `[ilingo] missing translation for \"${ctx.namespace}.${ctx.key}\" ` +\n                `(locale=${requestedLocale})`,\n            );\n        }\n        return undefined;\n    }\n\n    /**\n     * Pick the matching plural form for `count`. Pass-through when the leaf\n     * is already a string. Falls back to `other` if the selected category\n     * isn't present.\n     */\n    protected selectPluralForm(leaf: Leaf, locale: string, count: number | undefined): string {\n        if (typeof leaf === 'string') {\n            return leaf;\n        }\n        if (typeof count !== 'number') {\n            return leaf.other;\n        }\n        const category = this.getPluralRules(locale).select(count);\n        const candidate = leaf[category];\n        return typeof candidate === 'string' ? candidate : leaf.other;\n    }\n\n    protected getPluralRules(locale: string): Intl.PluralRules {\n        let rules = this.pluralRulesCache.get(locale);\n        if (!rules) {\n            rules = new Intl.PluralRules(locale);\n            this.pluralRulesCache.set(locale, rules);\n        }\n        return rules;\n    }\n\n    // ----------------------------------------------------\n\n    /**\n     * Substitute `{{var}}` placeholders. Modifier syntax\n     * (`{{var, number(currency=EUR)}}`) is dispatched through\n     * `this.formatters`. The optional `locale` argument controls which\n     * locale `Intl.*Format` instances are constructed for; if omitted, the\n     * instance's current locale is used.\n     */\n    format(input: string, data: Record<string, any>, locale?: string): string {\n        return template(input, data || {}, {\n            locale: locale ?? this.getLocale(),\n            formatters: this.formatters,\n            onUnknownFormatter: (name) => this.handleUnknownFormatter(name),\n        });\n    }\n\n    protected handleUnknownFormatter(name: string): void {\n        /* istanbul ignore next */\n        if (isProductionEnv()) return;\n        if (this.warnedFormatters.has(name)) return;\n        this.warnedFormatters.add(name);\n        // eslint-disable-next-line no-console\n        console.warn(`[ilingo] unknown formatter \"${name}\" — falling back to raw value`);\n    }\n}\n","/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { getPathValue, setPathValue } from 'pathtrace';\nimport { normalizeNamespaceBody } from '../catalog/normalize';\nimport type { Leaf, NamespaceBodyInput, Translations } from '../types';\nimport { isPluralNode } from '../utils/identify';\nimport type {\n    IInvalidatingStore,\n    IMutableStore,\n    InvalidateListener,\n    StoreGetContext,\n    StoreSetContext,\n} from './types';\n\n/**\n * User-supplied loader. Resolves a `(locale, namespace)` pair to a\n * `TranslationsNode` (`defineTranslations({ ... })`) — the namespace body whose\n * `(locale, namespace)` is fixed by the call arguments.\n *\n * Return `undefined` to signal \"no data for this pair\" — the store caches\n * the absence so the loader isn't called again for the same pair.\n */\nexport type LoaderFn = (\n    locale: string,\n    namespace: string,\n) => Promise<NamespaceBodyInput | undefined> | NamespaceBodyInput | undefined;\n\nexport type LoaderStoreOptions = {\n    /**\n     * Function that loads a `Translations` on demand for a given\n     * `(locale, namespace)` pair. Typically wraps a dynamic `import()`:\n     *\n     * ```typescript\n     * new LoaderStore({\n     *     // each module's default export is a translations node — a `.json` file\n     *     // shaped `{ \"type\": \"translations\", \"data\": { ... } }`, or a `.ts` file\n     *     // `export default defineTranslations({ ... })`.\n     *     loader: (locale, namespace) =>\n     *         import(`./locales/${locale}/${namespace}.json`).then((m) => m.default),\n     * });\n     * ```\n     */\n    loader: LoaderFn,\n    /**\n     * Optional list of locales the loader knows about. Returned verbatim\n     * from `getLocales()` so `Ilingo.getLocales()` can answer without\n     * touching the loader (which would otherwise mean probing every\n     * (locale, namespace) combination). If omitted, `getLocales()` returns\n     * whatever has been cached so far.\n     */\n    locales?: string[],\n\n    id?: string | symbol,\n};\n\ntype CacheEntry = {\n    /** `undefined` when the loader explicitly returned no data — cached as a miss. */\n    record: Translations | undefined,\n};\n\n/**\n * Separator used to join `(locale, namespace)` into a cache key. The NUL byte\n * is forbidden in both BCP-47 tags and any sensible filename/namespace name,\n * so the resulting key is unambiguous even when a namespace string contains\n * characters that would collide with a printable separator.\n */\nconst KEY_SEP = '\\u0000';\n\n/**\n * Lazy-loaded store backed by a user-supplied `loader(locale, namespace)`.\n * Caches the loaded `Translations` per `(locale, namespace)` so the loader is\n * called at most once per pair until `invalidate()` is called.\n *\n * Designed for SPA / browser code-splitting:\n *\n * ```typescript\n * const store = new LoaderStore({\n *     loader: (locale, namespace) => import(`./locales/${locale}/${namespace}.json`)\n *         .then((m) => m.default),\n *     locales: ['en', 'de'],\n * });\n * ```\n *\n * Implements `IInvalidatingStore` — calling `invalidate(locale?, namespace?)`\n * drops the matching cached entries and fires the `invalidate` event so\n * subscribers (e.g. a Vue composable in dev mode) can re-fetch.\n */\nexport class LoaderStore implements IInvalidatingStore, IMutableStore {\n    readonly id: string | symbol;\n\n    protected loaderFn: LoaderFn;\n\n    protected locales: string[];\n\n    /** Map of `${locale}\\0${namespace} (NUL-joined)` → cache entry (including miss markers). */\n    protected cache = new Map<string, CacheEntry>();\n\n    /** In-flight loads, keyed identically, so concurrent get()s share a promise. */\n    protected inflight = new Map<string, Promise<Translations | undefined>>();\n\n    protected listeners = new Set<InvalidateListener>();\n\n    /**\n     * Monotonically increasing generation counter. Bumped by `invalidate()`.\n     * `loadNamespace` captures the generation at the start of a load and only\n     * writes the resolved value into the cache if the generation hasn't\n     * changed in the meantime — protects against an in-flight load\n     * clobbering a fresh cache state after an invalidation race.\n     */\n    protected generation = 0;\n\n    constructor(options: LoaderStoreOptions) {\n        this.loaderFn = options.loader;\n        this.id = options.id || Symbol('LoaderStore');\n        this.locales = options.locales ? [...options.locales] : [];\n    }\n\n    async get(context: StoreGetContext): Promise<Leaf | undefined> {\n        const record = await this.loadNamespace(context.locale, context.namespace);\n        if (!record) return undefined;\n\n        const output = getPathValue(record, context.key);\n        if (typeof output === 'string') return output;\n        if (isPluralNode(output)) return output.data;\n        return undefined;\n    }\n\n    async set(context: StoreSetContext): Promise<void> {\n        // Set mutates the cached record for the (locale, namespace). If the\n        // namespace hasn't been loaded yet, load it first so we don't overwrite\n        // the loader's data on a subsequent get().\n        const record = (await this.loadNamespace(context.locale, context.namespace)) ?? {};\n        setPathValue(record, context.key, context.value);\n        this.cache.set(this.cacheKey(context.locale, context.namespace), { record });\n        // Notify subscribers — `IInvalidatingStore` consumers (Vue's\n        // useTranslation, custom watchers) treat any mutation as a reason\n        // to refetch. Keeps the contract of the interface internally\n        // consistent: changes are observable.\n        this.emit(context.locale, context.namespace);\n    }\n\n    async getLocales(): Promise<string[]> {\n        if (this.locales.length > 0) {\n            return [...this.locales];\n        }\n        // No declared locale list — return the set of locales we've seen\n        // loads for. Best-effort; consumers that want a complete list\n        // should pass `locales` to the constructor.\n        const seen = new Set<string>();\n        for (const key of this.cache.keys()) {\n            const sep = key.indexOf(KEY_SEP);\n            if (sep >= 0) seen.add(key.slice(0, sep));\n        }\n        return Array.from(seen);\n    }\n\n    invalidate(locale?: string, namespace?: string): void {\n        // Bump the generation so in-flight loads can detect they were\n        // invalidated mid-flight and skip writing their (now stale) result\n        // into the cache.\n        this.generation += 1;\n\n        if (typeof locale === 'undefined') {\n            this.cache.clear();\n        } else if (typeof namespace === 'undefined') {\n            const prefix = `${locale}${KEY_SEP}`;\n            for (const key of this.cache.keys()) {\n                if (key.startsWith(prefix)) this.cache.delete(key);\n            }\n        } else {\n            this.cache.delete(this.cacheKey(locale, namespace));\n        }\n        // Fire after cache is dropped so subscribers see the post-invalidate\n        // state if they probe the store.\n        this.emit(locale, namespace);\n    }\n\n    on(event: 'invalidate', listener: InvalidateListener): () => void {\n        // Event name reserved for future expansion (only 'invalidate' today).\n        if (event !== 'invalidate') {\n            return () => {};\n        }\n        this.listeners.add(listener);\n        return () => {\n            this.listeners.delete(listener);\n        };\n    }\n\n    protected cacheKey(locale: string, namespace: string): string {\n        return `${locale}${KEY_SEP}${namespace}`;\n    }\n\n    protected emit(locale: string | undefined, namespace: string | undefined): void {\n        for (const listener of this.listeners) {\n            listener(locale, namespace);\n        }\n    }\n\n    protected async loadNamespace(locale: string, namespace: string): Promise<Translations | undefined> {\n        const key = this.cacheKey(locale, namespace);\n        const cached = this.cache.get(key);\n        if (cached) return cached.record;\n\n        // De-duplicate concurrent loads — multiple `get()` calls for the\n        // same (locale, namespace) share one loader invocation.\n        const existing = this.inflight.get(key);\n        if (existing) return existing;\n\n        // Capture the generation at load start. If invalidate() bumps it\n        // before we resolve, our result is stale by definition — drop it on\n        // the floor so the next get() re-runs the loader against the\n        // post-invalidate state.\n        const startGeneration = this.generation;\n\n        const promise = Promise.resolve(this.loaderFn(locale, namespace))\n            .then((body) => {\n                this.inflight.delete(key);\n                // Reduce the loaded namespace body to the internal `Translations`\n                // shape before caching — every store holds the normalized\n                // form. A nullish body is cached as a miss.\n                const record = typeof body === 'undefined' ?\n                    undefined :\n                    normalizeNamespaceBody(body);\n                if (this.generation === startGeneration) {\n                    this.cache.set(key, { record });\n                }\n                return record;\n            })\n            .catch((err) => {\n                // Don't poison the cache with a failed load; the next get()\n                // will try again. Propagate so the orchestrator's existing\n                // missing-key path can handle it.\n                this.inflight.delete(key);\n                throw err;\n            });\n        this.inflight.set(key, promise);\n        return promise;\n    }\n}\n","/*\n * Copyright (c) 2023.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { getPathValue, setPathValue } from 'pathtrace';\nimport { normalizeCatalog } from '../catalog/normalize';\nimport type { Leaf, Locales } from '../types';\nimport { isPluralNode } from '../utils/identify';\nimport type {\n    IMutableStore,\n    MemoryStoreOptions,\n    StoreGetContext,\n    StoreSetContext,\n} from './types';\n\nexport class MemoryStore implements IMutableStore {\n    readonly id: string | symbol;\n\n    protected data: Locales;\n\n    constructor(options: MemoryStoreOptions) {\n        this.id = options.id || Symbol('MemoryStore');\n\n        this.data = normalizeCatalog(options.data);\n    }\n\n    async get(context: StoreGetContext): Promise<Leaf | undefined> {\n        return this.getSync(context);\n    }\n\n    getSync(context: StoreGetContext): Leaf | undefined {\n        if (\n            !this.data[context.locale] ||\n            !this.data[context.locale][context.namespace]\n        ) {\n            return undefined;\n        }\n\n        const output = getPathValue(\n            this.data[context.locale][context.namespace],\n            context.key,\n        );\n\n        if (typeof output === 'string') {\n            return output;\n        }\n\n        // Plural leaves are the tagged `{ type: 'plural', data }` node.\n        // A bare nested object is an ordinary key group, never a plural —\n        // the `type` discriminator is the only signal of a plural leaf.\n        if (isPluralNode(output)) {\n            return output.data;\n        }\n\n        return undefined;\n    }\n\n    setSync(context: StoreSetContext): void {\n        this.initLines(context.namespace, context.locale);\n\n        setPathValue(\n            this.data[context.locale][context.namespace],\n            context.key,\n            context.value,\n        );\n    }\n\n    async set(context: StoreSetContext): Promise<void> {\n        this.setSync(context);\n    }\n\n    protected initLines(namespace: string, locale: string) {\n        if (typeof this.data[locale] === 'undefined') {\n            this.data[locale] = {};\n        }\n\n        if (typeof this.data[locale][namespace] === 'undefined') {\n            this.data[locale][namespace] = {};\n        }\n    }\n\n    getLocalesSync(): string[] {\n        return Object.keys(this.data);\n    }\n\n    async getLocales(): Promise<string[]> {\n        return this.getLocalesSync();\n    }\n}\n","/*\n * Copyright (c) 2023.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { CatalogInput, Leaf, PluralNode } from '../types';\n\nexport type StoreGetContext = {\n    locale: string,\n    namespace: string,\n    key: string,\n};\n\nexport type StoreSetContext = StoreGetContext & {\n    /**\n     * Value to persist at the `(locale, namespace, key)` position. Plain\n     * translations are strings; plural translations use the tagged\n     * `{ type: 'plural', data }` node (build it with `definePlural()`) so\n     * they round-trip with `get()`, which unwraps that node when reading.\n     */\n    value: string | PluralNode,\n};\n\n/**\n * **Read** port for translation backends — the contract `Ilingo` relies on.\n * ilingo's job is to *read* a datasource: the orchestrator only ever calls\n * `get` (and `getLocales`), never `set`. So the required surface is just\n * `id` + `get` + `getLocales`, and it is **frozen** at those — external\n * adapters can rely on this being the complete required contract.\n *\n * Writing is an *optional* capability layered as a separate interface\n * detected via a type guard — see {@link IMutableStore} / {@link isMutableStore}\n * (only stores that hold mutable state, like `MemoryStore` / `FSStore`,\n * implement it). This mirrors {@link IInvalidatingStore} for caches.\n *\n * Other capabilities (`has`, `delete`, `getKeys`, batch `getAll`) follow\n * the same opt-in pattern rather than expanding this interface — each was\n * considered for inclusion and deferred:\n *\n * - `has(ctx)` — `get(ctx)` already returns `undefined` for misses; a\n *   separate `has` doubles the round-trip count for network-backed stores\n *   without buying meaningful API ergonomics.\n * - `delete(ctx)` / `getKeys(namespace)` — no in-tree consumer; speculative.\n * - `getAll(locale, namespace)` — bulk loading is the job of `LoaderStore`,\n *   which pre-warms a whole namespace on first access.\n *\n * Re-evaluate each only when a concrete consumer surfaces.\n */\nexport interface IStore {\n    readonly id: string | symbol;\n\n    /**\n     * Resolve a `(locale, namespace, key)` to a leaf value.\n     *\n     * The returned value is `Leaf` — `string | PluralForms` — which is\n     * the *post-unwrap* shape: stores that hold the catalog-side\n     * `PluralNode` (`{ type: 'plural', data }`) are expected to return its\n     * `data` before returning, matching `MemoryStore` and `LoaderStore`.\n     * Stores that don't support plurals can return just `string | undefined`.\n     */\n    get(context: StoreGetContext): Promise<Leaf | undefined>;\n\n    /**\n     * Enumerate the locales the store can currently resolve. Used by\n     * `Ilingo.getLocales()` to aggregate across every registered store\n     * and by `negotiateLocale()` callers that want the supported list.\n     */\n    getLocales(): Promise<string[]>;\n}\n\n/**\n * Optional **write** capability for stores that hold mutable state. ilingo\n * is read-first — the orchestrator never writes — so `set` is *not* part of\n * the required {@link IStore} port; a read-only adapter (a remote/HTTP\n * datasource, a {@link LoaderStore} you don't mutate) need not implement it.\n *\n * Implemented by `MemoryStore` (in-memory mutation) and `FSStore` (writes\n * through to disk). `extendStore(...)` and any caller that seeds a store at\n * runtime should type the argument as `IMutableStore`. Detect at runtime\n * with {@link isMutableStore}.\n *\n * The port stays **async** so it can cover async backends uniformly. A\n * store that *also* supports synchronous writes (e.g. `MemoryStore`) may\n * expose a concrete `setSync(...)` for seeding data after construction\n * without an `await` — that is store-specific, not part of this contract.\n */\nexport interface IMutableStore extends IStore {\n    /**\n     * Persist a `(locale, namespace, key)` → leaf mapping.\n     */\n    set(context: StoreSetContext): Promise<void>;\n}\n\n/**\n * Type guard for {@link IMutableStore} — true when the store exposes a\n * `set` method.\n */\nexport function isMutableStore(store: IStore): store is IMutableStore {\n    return typeof (store as Partial<IMutableStore>).set === 'function';\n}\n\nexport type MemoryStoreOptions = {\n    id?: string | symbol,\n    data: CatalogInput,\n};\n\n/**\n * Listener for a store's `invalidate` event. Receives the scope of the\n * invalidation: a `locale` (drop entries for that locale), a\n * `(locale, namespace)` tuple (drop only that namespace), or `undefined` for both\n * (drop everything).\n */\nexport type InvalidateListener = (locale?: string, namespace?: string) => void;\n\n/**\n * Stores that cache lookups and can drop those caches expose this surface\n * so consumers (e.g. the Vue composable in dev mode, the file-watching\n * `FSStore`, future loader-based stores) can both *trigger* an invalidation\n * and *react* to one.\n *\n * Optional — not every `IStore` caches. Detect with `isInvalidatingStore`.\n */\nexport interface IInvalidatingStore extends IStore {\n    /**\n     * Drop cached entries.\n     *\n     * - `invalidate()` — drop everything.\n     * - `invalidate(locale)` — drop all namespaces for `locale`.\n     * - `invalidate(locale, namespace)` — drop just one namespace.\n     *\n     * After invalidation the next `get()` for the affected key re-runs the\n     * underlying load (a fresh file read, a re-import, etc.).\n     */\n    invalidate(locale?: string, namespace?: string): void;\n\n    /**\n     * Subscribe to invalidation events. Listeners are fired *after* the\n     * cache has been dropped. Returns an unsubscribe function.\n     *\n     * Fires for every invalidation — both explicit `invalidate()` calls and\n     * source-driven ones (e.g. file change under `FSStore({ watch: true })`).\n     */\n    on(event: 'invalidate', listener: InvalidateListener): () => void;\n}\n\nexport function isInvalidatingStore(store: IStore): store is IInvalidatingStore {\n    return typeof (store as Partial<IInvalidatingStore>).invalidate === 'function' &&\n        typeof (store as Partial<IInvalidatingStore>).on === 'function';\n}\n"],"mappings":"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"}