{"version":3,"file":"rewriteUtils.cjs","names":[],"sources":["../../../src/localization/rewriteUtils.ts"],"sourcesContent":["// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\n/**\n * True when rewrite rules are explicitly disabled at build time\n * (INTLAYER_ROUTING_REWRITE_RULES === 'false').\n */\nconst TREE_SHAKE_REWRITE =\n  process.env['INTLAYER_ROUTING_REWRITE_RULES'] === 'false';\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type {\n  RewriteObject,\n  RewriteRules,\n  RoutingConfig,\n} from '@intlayer/types/config';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\n\nexport type LocalizedPathResult = {\n  path: string;\n  isRewritten: boolean;\n};\n\n/**\n * Normalizes legacy Record format or extracts specialized rules from RewriteObject.\n */\nexport const getRewriteRules = (\n  rewrite: RoutingConfig['rewrite'],\n  context: keyof RewriteObject = 'url'\n): RewriteRules | undefined => {\n  if (!rewrite || TREE_SHAKE_REWRITE) return undefined;\n\n  if ('url' in rewrite) {\n    return (rewrite as RewriteObject)[context];\n  }\n\n  // Normalize legacy format\n  return {\n    rules: Object.entries(rewrite).map(([canonical, localized]) => ({\n      // Normalize canonical path\n      canonical: canonical.startsWith('/')\n        ? canonical.replace(/\\[([^\\]]+)\\]/g, ':$1')\n        : `/${canonical.replace(/\\[([^\\]]+)\\]/g, ':$1')}`,\n\n      // Normalize localized path\n      localized: Object.fromEntries(\n        Object.entries(localized).map(([locale, pattern]) => {\n          const normalizedPattern = pattern?.startsWith('/')\n            ? pattern.replace(/\\[([^\\]]+)\\]/g, ':$1')\n            : `/${(pattern || '').replace(/\\[([^\\]]+)\\]/g, ':$1')}`;\n          return [locale, normalizedPattern];\n        })\n      ),\n    })),\n  };\n};\n\n/**\n * Converts normalized pattern to Regex.\n * Internal syntax supports:\n * - :param -> ([^/]+) (one segment)\n * - :param* -> (.*) (zero or more segments)\n * - :param+ -> (.+) (one or more segments)\n * - :param? -> ([^/]*) (zero or one segment)\n */\nconst patternToRegex = (pattern: string) => {\n  const regexString = pattern\n    .replace(/\\//g, '\\\\/') // Escape slashes\n    .replace(/\\\\\\/:(?:[^/\\\\*+?]+)\\*/g, '(?:\\\\/(.*))?') // /:param*\n    .replace(/\\\\\\/:(?:[^/\\\\*+?]+)\\?/g, '(?:\\\\/([^\\\\/]+))?') // /:param?\n    .replace(/:([^/\\\\*+?]+)\\*/g, '(.*)') // :param* (if no leading slash)\n    .replace(/:([^/\\\\*+?]+)\\?/g, '([^\\\\/]*)') // :param? (if no leading slash)\n    .replace(/:([^/\\\\*+?]+)\\+/g, '(.+)') // :param+\n    .replace(/:([^/\\\\*+?]+)/g, '([^\\\\/]+)'); // :param\n\n  return new RegExp(`^${regexString}$`);\n};\n\n/**\n * Replaces route parameters in a path with provided values.\n */\nconst fillPath = (pattern: string, params: string[]) => {\n  let index = 0;\n  return (\n    pattern\n      .replace(/:([^/\\\\*+?]+)[*+?]?/g, () => params[index++] ?? '')\n      .replace(/\\/+/g, '/')\n      .replace(/\\/$/, '') || '/'\n  );\n};\n\n/**\n * Extract values from a URL based on a pattern.\n */\nconst extractParams = (url: string, pattern: string): string[] | null => {\n  const regex = patternToRegex(pattern);\n  const match = url.match(regex);\n  return match ? match.slice(1) : null;\n};\n\n/**\n * Given a localized URL (e.g., \"/produits/123\"), finds the canonical internal path (e.g., \"/products/123\").\n * If locale is provided, only check for that locale. Otherwise, check for all locales.\n */\nexport const getCanonicalPath = (\n  localizedPath: string,\n  locale?: Locale,\n  rewriteRules?: RewriteRules\n): string => {\n  if (!rewriteRules || TREE_SHAKE_REWRITE) return localizedPath;\n\n  for (const rule of rewriteRules.rules) {\n    const { canonical, localized } = rule;\n    const localesToCheck = locale ? [locale] : Object.keys(localized);\n\n    for (const loc of localesToCheck) {\n      const localizedPattern = localized[loc as keyof typeof localized];\n\n      if (!localizedPattern) continue;\n\n      const params = extractParams(localizedPath, localizedPattern);\n\n      if (params) {\n        return fillPath(canonical, params);\n      }\n    }\n  }\n\n  return localizedPath;\n};\n\n/**\n * Given a canonical path (e.g., \"/products/123\"), finds the localized URL pattern (e.g., \"/produits/123\").\n */\nexport const getLocalizedPath = (\n  canonicalPath: string,\n  locale: LocalesValues,\n  rewriteRules?: RewriteRules\n): LocalizedPathResult => {\n  if (!rewriteRules || TREE_SHAKE_REWRITE)\n    return { path: canonicalPath, isRewritten: false };\n\n  for (const rule of rewriteRules.rules) {\n    const { canonical, localized } = rule;\n\n    // Check if the input path matches a configured canonical pattern\n    const params = extractParams(canonicalPath, canonical);\n\n    if (params) {\n      const targetPattern = localized[locale as keyof typeof localized];\n\n      if (targetPattern) {\n        return {\n          path: fillPath(targetPattern, params),\n          isRewritten: true,\n        };\n      }\n    }\n  }\n\n  return { path: canonicalPath, isRewritten: false };\n};\n\n/**\n * Returns the internal path for a given canonical path and locale.\n * Ensures the locale prefix is present exactly once.\n */\nexport const getInternalPath = (\n  canonicalPath: string,\n  locale: Locale\n): string => {\n  const pathWithLeadingSlash = canonicalPath.startsWith('/')\n    ? canonicalPath\n    : `/${canonicalPath}`;\n\n  if (\n    pathWithLeadingSlash.startsWith(`/${locale}/`) ||\n    pathWithLeadingSlash === `/${locale}`\n  ) {\n    return pathWithLeadingSlash;\n  }\n\n  return `/${locale}${pathWithLeadingSlash === '/' ? '' : pathWithLeadingSlash}`;\n};\n\n/**\n * Given a current pathname and locale, returns the pretty localized path if a rewrite rule exists and the path is not already localized.\n */\nexport const getRewritePath = (\n  pathname: string,\n  locale: Locale,\n  rewrite?: RoutingConfig['rewrite']\n): string | undefined => {\n  if (TREE_SHAKE_REWRITE) return undefined;\n  const rules = getRewriteRules(rewrite, 'url');\n  if (!rules) return undefined;\n\n  // Identify canonical path (relative to root, no locale prefix expected in 'url' context)\n  const canonicalPath = getCanonicalPath(pathname, undefined, rules);\n\n  // Get the localized path for the current locale\n  const { path: localizedPath, isRewritten } = getLocalizedPath(\n    canonicalPath,\n    locale,\n    rules\n  );\n\n  if (isRewritten && localizedPath !== pathname) {\n    return localizedPath;\n  }\n\n  return undefined;\n};\n"],"mappings":"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"}