{"version":3,"file":"getPrefix.cjs","names":["internationalization","DEFAULT_LOCALE","routing","ROUTING_MODE","LOCALES"],"sources":["../../../src/localization/getPrefix.ts"],"sourcesContent":["import { internationalization, routing } from '@intlayer/config/built';\nimport {\n  DEFAULT_LOCALE,\n  LOCALES,\n  ROUTING_MODE,\n} from '@intlayer/config/defaultValues';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { RoutingConfig } from '@intlayer/types/config';\nimport type {\n  DeclaredLocales,\n  LocalesValues,\n  ResolvedDefaultLocale,\n  ResolvedRoutingMode,\n} from '@intlayer/types/module_augmentation';\n\n/**\n * Shared routing options used across all URL localization functions.\n */\nexport type RoutingOptions = {\n  locales?: LocalesValues[];\n  defaultLocale?: LocalesValues;\n  mode?: RoutingConfig['mode'];\n  rewrite?: RoutingConfig['rewrite'];\n  domains?: RoutingConfig['domains'];\n  /**\n   * The hostname of the page currently being rendered (e.g. `'intlayer.org'`).\n   * When provided, `getLocalizedUrl` returns a relative URL for locales whose\n   * configured domain matches `currentDomain`, and an absolute URL only when\n   * the target locale lives on a different domain.\n   *\n   * When omitted the function tries to infer it from:\n   *   1. The domain of an absolute input URL.\n   *   2. `window.location.hostname` in browser environments.\n   * Falls back to always generating absolute URLs when neither is available.\n   */\n  currentDomain?: string;\n};\n\n/**\n * Resolves routing configuration by merging provided options with configuration defaults.\n * Single source of truth for default routing config resolution across all localization functions.\n */\nexport const resolveRoutingConfig = (options: RoutingOptions = {}) => ({\n  defaultLocale: internationalization?.defaultLocale ?? DEFAULT_LOCALE,\n  mode: routing?.mode ?? ROUTING_MODE,\n  locales: internationalization?.locales ?? LOCALES,\n  rewrite: routing?.rewrite,\n  domains: routing?.domains,\n  ...options,\n});\n\nexport type GetPrefixOptions = {\n  defaultLocale?: LocalesValues;\n  mode?: RoutingConfig['mode'];\n};\n\nexport type GetPrefixResult = {\n  /**\n   * The locale path segment appended to `/`, with a trailing slash (e.g. `'fr/'`).\n   * Empty string when no prefix is needed.\n   */\n  prefix: string;\n  /**\n   * The bare locale identifier (e.g. `'fr'`), or `undefined` when no prefix is applied.\n   */\n  localePrefix: Locale | undefined;\n};\n\n/**\n * Narrowed return type for {@link getPrefix} that carries the locale literal through.\n *\n * Distributes over union locales — calling `getPrefix('fr')` in `prefix-no-default`\n * mode with `defaultLocale = 'en'` resolves to `{ prefix: 'fr/'; localePrefix: 'fr' }`.\n *\n * Note: domain-based routing and \"locale not in locales\" edge cases may return an\n * empty result at runtime regardless of what this type reports.\n */\nexport type GetPrefixResultNarrowed<\n  L extends LocalesValues | undefined,\n  Mode extends string = ResolvedRoutingMode,\n  Default extends LocalesValues = ResolvedDefaultLocale,\n> = L extends string\n  ? [string] extends [L] // L is wide (string / LocalesValues) → distribute over declared locales\n    ? GetPrefixResultNarrowed<DeclaredLocales, Mode, Default>\n    : [string] extends [Mode]\n      ? GetPrefixResult // mode is wide → fall back to generic result\n      : Mode extends 'prefix-all'\n        ? { prefix: `${L}/`; localePrefix: L }\n        : Mode extends 'prefix-no-default'\n          ? L extends Default\n            ? { prefix: ''; localePrefix: undefined }\n            : { prefix: `${L}/`; localePrefix: L }\n          : { prefix: ''; localePrefix: undefined } // no-prefix / search-params\n  : { prefix: ''; localePrefix: undefined }; // locale is undefined\n\n/**\n * Determines the URL prefix for a given locale based on the routing mode configuration.\n *\n * Example:\n *\n * ```ts\n *  // prefix-no-default mode with default locale\n *  getPrefix('en', { defaultLocale: 'en', mode: 'prefix-no-default' })\n *     // Returns { prefix: '', localePrefix: undefined }\n *\n *  // prefix-no-default mode with non-default locale\n *  getPrefix('fr', { defaultLocale: 'en', mode: 'prefix-no-default' })\n *     // Returns { prefix: '/fr', localePrefix: 'fr' }\n *\n *  // prefix-all mode\n *  getPrefix('en', { defaultLocale: 'en', mode: 'prefix-all' })\n *     // Returns { prefix: '/en', localePrefix: locale }\n *\n *  // search-params mode\n *  getPrefix('en', { defaultLocale: 'en', mode: 'search-params' })\n *     // Returns { prefix: '', localePrefix: undefined }\n *\n *  // no-prefix mode\n *  getPrefix('en', { defaultLocale: 'en', mode: 'no-prefix' })\n *     // Returns { prefix: '', localePrefix: undefined }\n * ```\n *\n * @param locale - The locale to check for prefix. If not provided, uses configured default locale.\n * @param options - Configuration options\n * @param options.defaultLocale - The default locale. Defaults to configured default locale.\n * @param options.mode - URL routing mode for locale handling. Defaults to configured mode.\n * @returns An object containing pathPrefix, prefix, and localePrefix for the given locale.\n */\nexport const getPrefix = <const L extends LocalesValues | undefined>(\n  locale: L,\n  options: RoutingOptions = {}\n): GetPrefixResultNarrowed<L> => {\n  const { defaultLocale, mode, locales, domains } =\n    resolveRoutingConfig(options);\n\n  if (\n    (process.env['INTLAYER_ROUTING_MODE'] &&\n      process.env['INTLAYER_ROUTING_MODE'] !== 'prefix-all' &&\n      process.env['INTLAYER_ROUTING_MODE'] !== 'prefix-no-default') ||\n    !locale ||\n    !locales.includes(locale)\n  ) {\n    return {\n      prefix: '',\n      localePrefix: undefined,\n    } as GetPrefixResultNarrowed<L>;\n  }\n\n  // If this locale is the only one assigned to its domain, no URL prefix is needed\n  // (the domain itself identifies the locale). Shared domains use normal prefix logic.\n  if (process.env['INTLAYER_ROUTING_DOMAINS'] !== 'false' && domains) {\n    const localeDomain = domains[locale as LocalesValues];\n\n    if (localeDomain) {\n      const localesOnSameDomain = Object.values(domains).filter(\n        (domain) => domain === localeDomain\n      ).length;\n\n      if (localesOnSameDomain === 1) {\n        return {\n          prefix: '',\n          localePrefix: undefined,\n        } as GetPrefixResultNarrowed<L>;\n      }\n    }\n  }\n\n  // Handle prefix-based modes (prefix-all or prefix-no-default)\n  const shouldPrefix =\n    mode === 'prefix-all' ||\n    (mode === 'prefix-no-default' && defaultLocale !== locale);\n\n  if (shouldPrefix) {\n    return {\n      prefix: `${locale}/`,\n      localePrefix: locale as Locale,\n    } as GetPrefixResultNarrowed<L>;\n  }\n\n  return {\n    prefix: '',\n    localePrefix: undefined,\n  } as GetPrefixResultNarrowed<L>;\n};\n"],"mappings":";;;;;;;;;;AA+CA,MAAa,wBAAwB,UAA0B,EAAE,MAAM;CACrE,eAAeA,6CAAsB,iBAAiBC;CACtD,MAAMC,gCAAS,QAAQC;CACvB,SAASH,6CAAsB,WAAWI;CAC1C,SAASF,gCAAS;CAClB,SAASA,gCAAS;CAClB,GAAG;CACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+ED,MAAa,aACX,QACA,UAA0B,EAAE,KACG;CAC/B,MAAM,EAAE,eAAe,MAAM,SAAS,YACpC,qBAAqB,QAAQ;AAE/B,KACG,QAAQ,IAAI,4BACX,QAAQ,IAAI,6BAA6B,gBACzC,QAAQ,IAAI,6BAA6B,uBAC3C,CAAC,UACD,CAAC,QAAQ,SAAS,OAAO,CAEzB,QAAO;EACL,QAAQ;EACR,cAAc;EACf;AAKH,KAAI,QAAQ,IAAI,gCAAgC,WAAW,SAAS;EAClE,MAAM,eAAe,QAAQ;AAE7B,MAAI,cAKF;OAJ4B,OAAO,OAAO,QAAQ,CAAC,QAChD,WAAW,WAAW,aACxB,CAAC,WAE0B,EAC1B,QAAO;IACL,QAAQ;IACR,cAAc;IACf;;;AAUP,KAHE,SAAS,gBACR,SAAS,uBAAuB,kBAAkB,OAGnD,QAAO;EACL,QAAQ,GAAG,OAAO;EAClB,cAAc;EACf;AAGH,QAAO;EACL,QAAQ;EACR,cAAc;EACf"}