@i18n-micro/path-strategy 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -29
- package/dist/base-strategy-BHkH418r.cjs +2 -0
- package/dist/base-strategy-BHkH418r.cjs.map +1 -0
- package/dist/base-strategy-CSEFam3u.js +585 -0
- package/dist/base-strategy-CSEFam3u.js.map +1 -0
- package/dist/common-BaGdobUC.js +114 -0
- package/dist/common-BaGdobUC.js.map +1 -0
- package/dist/common-sNHyO9pg.cjs +2 -0
- package/dist/common-sNHyO9pg.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +63 -352
- package/dist/index.mjs +21 -34
- package/dist/index.mjs.map +1 -1
- package/dist/no-prefix-strategy.cjs +1 -1
- package/dist/no-prefix-strategy.cjs.map +1 -1
- package/dist/no-prefix-strategy.d.ts +38 -262
- package/dist/no-prefix-strategy.mjs +17 -32
- package/dist/no-prefix-strategy.mjs.map +1 -1
- package/dist/prefix-and-default-strategy.cjs +1 -1
- package/dist/prefix-and-default-strategy.cjs.map +1 -1
- package/dist/prefix-and-default-strategy.d.ts +36 -259
- package/dist/prefix-and-default-strategy.mjs +75 -125
- package/dist/prefix-and-default-strategy.mjs.map +1 -1
- package/dist/prefix-except-default-strategy.cjs +1 -1
- package/dist/prefix-except-default-strategy.cjs.map +1 -1
- package/dist/prefix-except-default-strategy.d.ts +41 -269
- package/dist/prefix-except-default-strategy.mjs +228 -251
- package/dist/prefix-except-default-strategy.mjs.map +1 -1
- package/dist/prefix-strategy.cjs +1 -1
- package/dist/prefix-strategy.cjs.map +1 -1
- package/dist/prefix-strategy.d.ts +36 -257
- package/dist/prefix-strategy.mjs +16 -53
- package/dist/prefix-strategy.mjs.map +1 -1
- package/dist/types.d.ts +23 -78
- package/package.json +5 -3
- package/dist/base-strategy-DDkINDnZ.js +0 -922
- package/dist/base-strategy-DDkINDnZ.js.map +0 -1
- package/dist/base-strategy-iCda2UF-.cjs +0 -2
- package/dist/base-strategy-iCda2UF-.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,24 +1,28 @@
|
|
|
1
1
|
# @i18n-micro/path-strategy
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Runtime path and route strategies for **Nuxt I18n Micro**: locale resolution from URL, link generation, redirects, and SEO helpers. Use this package when you need a single routing strategy at build time so only the chosen implementation is bundled.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## Overview
|
|
8
8
|
|
|
9
9
|
- **Strategies**: `no_prefix`, `prefix`, `prefix_except_default`, `prefix_and_default`
|
|
10
|
-
- **API**: `resolveLocaleFromPath`, `getLocaleFromPath`, `localeRoute`, `switchLocaleRoute`, `getRedirect`, `
|
|
10
|
+
- **API**: `resolveLocaleFromPath`, `getLocaleFromPath`, `localeRoute`, `switchLocaleRoute`, `getRedirect`, `getClientRedirect`, `shouldReturn404`, `getCanonicalPath`, `getRouteBaseName`, `getCurrentLocale`, `getPluginRouteName`, `formatPathForResolve`
|
|
11
11
|
- **Framework-agnostic**: Works with any router that implements the `RouterAdapter` interface (`hasRoute`, `resolve`); compatible with Vue Router and custom adapters.
|
|
12
|
+
- **Tree-shakeable**: Subpath exports (`/prefix`, `/no-prefix`, etc.) let the bundler include only the selected strategy.
|
|
12
13
|
|
|
13
14
|
---
|
|
14
15
|
|
|
15
16
|
## Package structure
|
|
16
17
|
|
|
17
|
-
|
|
|
18
|
-
|
|
19
|
-
| `src/
|
|
20
|
-
| `src/
|
|
21
|
-
| `src/
|
|
18
|
+
| Path | Contents |
|
|
19
|
+
|------|----------|
|
|
20
|
+
| `src/types.ts` | All type definitions (`PathStrategyContext`, `RouteLike`, `ResolvedRouteLike`, `RouterAdapter`, `PathStrategy`, etc.) |
|
|
21
|
+
| `src/path.ts` | Path utilities (`normalizePath`, `joinUrl`, `buildUrl`, `getPathWithoutLocale`, `getLocaleFromPath`, `hasKeys`, etc.) |
|
|
22
|
+
| `src/resolver.ts` | Route analysis and resolution (`analyzeRoute`, `getRouteBaseName`, `buildLocalizedName`, `isIndexRouteName`, `resolveCustomPath`, etc.) |
|
|
23
|
+
| `src/helpers.ts` | Strategy-agnostic helpers (`shouldReturn404`, `preserveQueryAndHash`, `tryResolveByLocalizedName`, etc.) |
|
|
24
|
+
| `src/strategies/` | `BasePathStrategy`, `createPathStrategy` factory, and strategy implementations: `no-prefix`, `prefix`, `prefix-except-default`, `prefix-and-default` |
|
|
25
|
+
| `src/strategies/common.ts` | Shared strategy logic (`defaultResolveLocaleRoute`) |
|
|
22
26
|
|
|
23
27
|
---
|
|
24
28
|
|
|
@@ -38,7 +42,7 @@ To ship only the selected strategy (no factory, no other implementations), wire
|
|
|
38
42
|
|
|
39
43
|
### 1. Configure the Nuxt module
|
|
40
44
|
|
|
41
|
-
In your Nuxt module
|
|
45
|
+
In your Nuxt module's `setup()` (or in `nuxt.config`), set the alias to the strategy entry you want:
|
|
42
46
|
|
|
43
47
|
```ts
|
|
44
48
|
// src/module.ts (or nuxt.config.ts)
|
|
@@ -109,12 +113,12 @@ Only the selected strategy and the base class are included in the bundle; the ot
|
|
|
109
113
|
|
|
110
114
|
| Entry | Contents |
|
|
111
115
|
|-------|----------|
|
|
112
|
-
| `@i18n-micro/path-strategy` | Main entry: types, factory, all strategies, utils (`getRouteBaseName`, `buildLocalizedName`, `isIndexRouteName`) |
|
|
116
|
+
| `@i18n-micro/path-strategy` | Main entry: types, factory, all strategies, resolver utils (`getRouteBaseName`, `buildLocalizedName`, `isIndexRouteName`, `analyzeRoute`) |
|
|
113
117
|
| `@i18n-micro/path-strategy/prefix` | `PrefixPathStrategy` and `Strategy` alias |
|
|
114
118
|
| `@i18n-micro/path-strategy/no-prefix` | `NoPrefixPathStrategy` and `Strategy` |
|
|
115
119
|
| `@i18n-micro/path-strategy/prefix-except-default` | `PrefixExceptDefaultPathStrategy` and `Strategy` |
|
|
116
120
|
| `@i18n-micro/path-strategy/prefix-and-default` | `PrefixAndDefaultPathStrategy` and `Strategy` |
|
|
117
|
-
| `@i18n-micro/path-strategy/types` | Types only (`PathStrategyContext`, `RouteLike`, `ResolvedRouteLike`, `RouterAdapter`,
|
|
121
|
+
| `@i18n-micro/path-strategy/types` | Types only (`PathStrategyContext`, `RouteLike`, `ResolvedRouteLike`, `RouterAdapter`, etc.) |
|
|
118
122
|
|
|
119
123
|
---
|
|
120
124
|
|
|
@@ -122,13 +126,14 @@ Only the selected strategy and the base class are included in the bundle; the ot
|
|
|
122
126
|
|
|
123
127
|
### Factory
|
|
124
128
|
|
|
125
|
-
- **`createPathStrategy(ctx: PathStrategyContext)`** — Returns the strategy instance for `ctx.strategy`. Use for tests or server-side when you don
|
|
129
|
+
- **`createPathStrategy(ctx: PathStrategyContext)`** — Returns the strategy instance for `ctx.strategy`. Use for tests or server-side when you don't use the alias.
|
|
126
130
|
|
|
127
|
-
###
|
|
131
|
+
### Resolver utilities (from main entry)
|
|
128
132
|
|
|
129
|
-
- **`getRouteBaseName(route, options?)`** — Returns the base route name (without localized prefix/suffix).
|
|
130
|
-
- **`buildLocalizedName(baseName, localeCode, prefix?)`** — Builds a localized route name (e.g. `about` + `de` + `localized-`
|
|
131
|
-
- **`isIndexRouteName(name, options?)`** — Returns whether the route name is the index route (e.g. `index`, `localized-index-en`).
|
|
133
|
+
- **`getRouteBaseName(route, options?)`** — Returns the base route name (without localized prefix/suffix).
|
|
134
|
+
- **`buildLocalizedName(baseName, localeCode, prefix?)`** — Builds a localized route name (e.g. `about` + `de` + `localized-` -> `localized-about-de`).
|
|
135
|
+
- **`isIndexRouteName(name, options?)`** — Returns whether the route name is the index route (e.g. `index`, `localized-index-en`).
|
|
136
|
+
- **`analyzeRoute(route, ctx)`** — Returns a `RouteAnalysis` object with `baseName`, `pathWithoutLocale`, `localeFromPath`, and `isIndex` for a given route and context.
|
|
132
137
|
|
|
133
138
|
### Strategy interface
|
|
134
139
|
|
|
@@ -136,14 +141,23 @@ Each strategy implements:
|
|
|
136
141
|
|
|
137
142
|
| Method | Description |
|
|
138
143
|
|--------|-------------|
|
|
139
|
-
| `
|
|
140
|
-
| `
|
|
144
|
+
| `localeRoute(targetLocale, routeOrPath, currentRoute?)` | Localized route for the target locale. Returns `RouteLike` with `path` and `fullPath` set. |
|
|
145
|
+
| `switchLocaleRoute(fromLocale, toLocale, route, options)` | Route to navigate to when switching locale. Returns `RouteLike` or `string`. |
|
|
146
|
+
| `getRedirect(currentPath, targetLocale)` | Path to redirect to on server, or `null`. |
|
|
147
|
+
| `getClientRedirect(currentPath, preferredLocale)` | Path to redirect to on client (after hydration), or `null`. |
|
|
148
|
+
| `shouldReturn404(currentPath)` | Returns a 404 redirect path if the current path is invalid, or `null`. |
|
|
141
149
|
| `getCanonicalPath(route, targetLocale)` | Custom path for the route in that locale (from `globalLocaleRoutes`), or `null`. |
|
|
142
150
|
| `resolveLocaleFromPath(path)` | Locale code from path (strategy-specific; e.g. `no_prefix` returns `null`). |
|
|
143
|
-
| `getLocaleFromPath(path)` | Parses path and returns first segment if it is a locale code
|
|
144
|
-
| `
|
|
145
|
-
| `
|
|
146
|
-
| `
|
|
151
|
+
| `getLocaleFromPath(path)` | Parses path and returns first segment if it is a locale code. |
|
|
152
|
+
| `getRouteBaseName(route)` | Base name for the route (delegates to resolver with context). |
|
|
153
|
+
| `getCurrentLocale(route, defaultLocaleOverride?)` | Determines current locale from route (considers strategy, hashMode, params, path). |
|
|
154
|
+
| `getPluginRouteName(route, locale)` | Returns the base route name for translation loading. |
|
|
155
|
+
| `getCurrentLocaleName(route, defaultLocaleOverride?)` | Returns `displayName` of the current locale, or `null`. |
|
|
156
|
+
| `setRouter(router)` | Replaces the router adapter at runtime. |
|
|
157
|
+
| `formatPathForResolve(path, fromLocale, toLocale)` | Transforms a path for cross-locale resolution. |
|
|
158
|
+
| `getDefaultLocale()` | Returns the default locale code. |
|
|
159
|
+
| `getLocales()` | Returns the configured locales array. |
|
|
160
|
+
| `getStrategy()` | Returns the strategy name. |
|
|
147
161
|
|
|
148
162
|
### Context (`PathStrategyContext`)
|
|
149
163
|
|
|
@@ -152,18 +166,21 @@ Import from `@i18n-micro/path-strategy/types`.
|
|
|
152
166
|
| Property | Description |
|
|
153
167
|
|----------|-------------|
|
|
154
168
|
| `strategy`, `defaultLocale`, `locales`, `localizedRouteNamePrefix`, `router` | Required. |
|
|
169
|
+
| `localeCodes` | Pre-computed locale code strings. Set automatically in constructor from `locales`. |
|
|
155
170
|
| `globalLocaleRoutes` | `Record<string, Record<string, string> \| false>`: custom path per route/locale; `false` = unlocalized. |
|
|
156
|
-
| `routeLocales` | `Record<string, string[]>`: route path or base name
|
|
157
|
-
| `routesLocaleLinks` | `Record<string, string>`: base name
|
|
158
|
-
| `noPrefixRedirect` | When `true` (default), `NoPrefixPathStrategy.getRedirect` strips a leading locale segment (e.g. `/en/about`
|
|
171
|
+
| `routeLocales` | `Record<string, string[]>`: route path or base name -> list of locale codes; limits hreflang entries. |
|
|
172
|
+
| `routesLocaleLinks` | `Record<string, string>`: base name -> key for `routeLocales` lookup (e.g. `'products-id'` -> `'products'`). |
|
|
173
|
+
| `noPrefixRedirect` | When `true` (default), `NoPrefixPathStrategy.getRedirect` strips a leading locale segment (e.g. `/en/about` -> `/about`). Set to `false` to disable. |
|
|
174
|
+
| `hashMode` | Locale stored in hash, no prefix in path. |
|
|
175
|
+
| `disablePageLocales` | When `true`, all pages use only global translations (no page-specific loading). |
|
|
159
176
|
| `debug` | Enable debug logging. |
|
|
160
177
|
|
|
161
178
|
### Redirect behavior per strategy
|
|
162
179
|
|
|
163
|
-
- **prefix**: root `/`
|
|
164
|
-
- **prefix_except_default**: default locale with prefix (e.g. `/en/about`)
|
|
180
|
+
- **prefix**: root `/` -> `/{locale}`; paths without prefix get prefix; wrong prefix is replaced.
|
|
181
|
+
- **prefix_except_default**: default locale with prefix (e.g. `/en/about`) -> path without prefix (`/about`); non-default without prefix -> add prefix; root with non-default -> `/{locale}`.
|
|
165
182
|
- **prefix_and_default**: same as prefix (all locales have prefix in URL).
|
|
166
|
-
- **no_prefix**: paths that start with a locale segment (e.g. `/en/about`)
|
|
183
|
+
- **no_prefix**: paths that start with a locale segment (e.g. `/en/about`) -> path without segment (`/about`), unless `noPrefixRedirect` is `false`.
|
|
167
184
|
|
|
168
185
|
### Using getRedirect in middleware
|
|
169
186
|
|
|
@@ -176,18 +193,47 @@ if (redirectPath) return navigateTo(redirectPath)
|
|
|
176
193
|
|
|
177
194
|
## Integration with Nuxt I18n Micro
|
|
178
195
|
|
|
179
|
-
The main Nuxt module (**nuxt-i18n-micro**) integrates path-strategy by default: it generates the strategy from the chosen `strategy` option, creates the instance with runtime config and router, and provides it as `nuxtApp.$i18nStrategy`. The
|
|
196
|
+
The main Nuxt module (**nuxt-i18n-micro**) integrates path-strategy by default: it generates the strategy from the chosen `strategy` option, creates the instance with runtime config and router, and provides it as `nuxtApp.$i18nStrategy`. The redirect plugin calls `strategy.getRedirect()` (server) and `strategy.getClientRedirect()` (client) and redirects when a path is returned.
|
|
180
197
|
|
|
181
198
|
---
|
|
182
199
|
|
|
183
200
|
## Testing
|
|
184
201
|
|
|
185
|
-
The package is tested with **Jest**. Tests include unit tests for each strategy,
|
|
202
|
+
The package is tested with **Jest**. Tests include unit tests for each strategy, snapshot tests, a memory-leak test suite, and performance benchmarks.
|
|
186
203
|
|
|
187
204
|
```bash
|
|
205
|
+
# Unit tests
|
|
188
206
|
pnpm test
|
|
207
|
+
|
|
208
|
+
# Performance benchmarks (Node.js)
|
|
209
|
+
pnpm test:perf
|
|
210
|
+
|
|
211
|
+
# Performance benchmarks (real browsers — Chromium, Firefox, WebKit)
|
|
212
|
+
pnpm bench:browser:ci
|
|
213
|
+
|
|
214
|
+
# Single browser
|
|
215
|
+
pnpm bench:browser:ci -- --browser=firefox
|
|
216
|
+
|
|
217
|
+
# Interactive browser benchmark (opens dev server)
|
|
218
|
+
pnpm bench:browser
|
|
189
219
|
```
|
|
190
220
|
|
|
221
|
+
### Browser benchmarks
|
|
222
|
+
|
|
223
|
+
The `bench/` directory contains a browser-based performance benchmark that runs the same suite as the Node.js tests but in a real browser engine via Playwright. This measures actual client-side performance across V8 (Chromium), SpiderMonkey (Firefox), and JavaScriptCore (WebKit).
|
|
224
|
+
|
|
225
|
+
Results are saved as baselines per browser engine in `tests/__perf__/baseline-browser-{engine}.json`.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Performance optimizations
|
|
230
|
+
|
|
231
|
+
- **Pure functions over classes** — Route resolution (`analyzeRoute`, `resolveCustomPath`, etc.) uses pure functions instead of a class-based `RouteResolver`, enabling better tree-shaking and V8 inlining.
|
|
232
|
+
- **Pre-computed context flags** — `localeCodes`, `_hasGR` (has global locale routes), and `_hasRL` (has route locales) are computed once in the constructor, avoiding `Object.keys()` allocations on hot paths.
|
|
233
|
+
- **Minimal object allocation** — Route objects are constructed via direct property assignment instead of `{ ...spread }` to reduce GC pressure.
|
|
234
|
+
- **Fast path utilities** — `normalizePath`, `joinUrl`, and `cleanDoubleSlashes` use character-code checks and fast paths for common cases (e.g. simple paths without double slashes).
|
|
235
|
+
- **`hasKeys()` utility** — O(1) check for whether an object has own keys, without `Object.keys()` array allocation.
|
|
236
|
+
|
|
191
237
|
---
|
|
192
238
|
|
|
193
239
|
## License
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const W=/[^A-Za-z0-9_.\-~]/;function w(t){return t.charCodeAt(0)===47?t:`/${t}`}function z(t){return t.charCodeAt(0)===47?t.slice(1):t}function R(t){return t.length>1&&t.charCodeAt(t.length-1)===47?t.slice(0,-1):t}function Z(t){return t.charCodeAt(0)===47}function g(t){const e=t.indexOf("://");return e===-1?U(t):t.slice(0,e+3)+U(t.slice(e+3))}function U(t){if(t.indexOf("//")===-1)return t;let e="",n=!1;for(let r=0;r<t.length;r++){const l=t.charCodeAt(r)===47;l&&n||(e+=t[r],n=l)}return e}function x(t){const e=t.indexOf("://");if(e<1)return!1;for(let n=0;n<e;n++){const r=t.charCodeAt(n);if(!(r>=97&&r<=122||r>=65&&r<=90||r>=48&&r<=57||r===43||r===45||r===46))return!1}return!0}function m(t){if(!t)return!1;for(const e in t)return!0;return!1}function J(t){let e=t,n="",r="";const l=t.indexOf("#");l>=0&&(r=t.slice(l),e=t.slice(0,l));const o=e.indexOf("?");return o>=0&&(n=e.slice(o),e=e.slice(0,o)),{pathname:e,search:n,hash:r}}function X(t){const e=t.lastIndexOf("/");return e===-1?t:t.slice(e+1)}function B(t,e){return p(t)===p(e)}function Y(t,...e){let n=t||"";for(const r of e)if(!(!r||r==="/"))if(n){const l=r.charCodeAt(0)===46&&r.charCodeAt(1)===47?r.slice(2):r.charCodeAt(0)===47?r.slice(1):r;n=(n.charCodeAt(n.length-1)===47?n:`${n}/`)+l}else n=r;return n}function h(...t){if(t.length===2){const o=t[0],a=t[1];return o&&a?ee(o,a):o?q(o):a?q(a):"/"}const e=t.filter(o=>typeof o=="string"&&o!=="");if(e.length===0)return"/";const[n,...r]=e,l=Y(n,...r)||"/";return x(l)?R(l)||l:w(R(l))||"/"}function ee(t,e){const n=t.charCodeAt(t.length-1)===47,r=e.charCodeAt(0)===47;let l;return n&&r?l=t+e.slice(1):!n&&!r?l=`${t}/${e}`:l=t+e,l.indexOf("://")!==-1?(l.length>1&&l.charCodeAt(l.length-1)===47&&(l=l.slice(0,-1)),l):(l.charCodeAt(0)!==47&&(l=`/${l}`),l.length>1&&l.charCodeAt(l.length-1)===47&&(l=l.slice(0,-1)),l)}function q(t){return t.charCodeAt(0)!==47&&(t=`/${t}`),t.length>1&&t.charCodeAt(t.length-1)===47&&(t=t.slice(0,-1)),t||"/"}function F(t,e,n){const r=n&&n!=="#";if(!e&&!r)return t;let l=t;if(e){let o="",i=l.indexOf("?")!==-1?"&":"?";for(const s in e){const c=e[s];if(c!=null)if(Array.isArray(c)){const u=`${s}=`;for(let f=0,P=c.length;f<P;f++){const y=c[f];if(y==null)continue;let A;const v=typeof y;if(v==="number"||v==="boolean")A=y;else{const N=`${y}`;A=W.test(N)?encodeURIComponent(N):N}o===""?(o=i,i="&"):o="&",l+=o+u+A}}else{let u;const f=typeof c;if(f==="number"||f==="boolean")u=c;else{const P=`${c}`;u=W.test(P)?encodeURIComponent(P):P}o===""?(o=i,i="&"):o="&",l+=`${o+s}=${u}`}}}return r&&(l+=n.charCodeAt(0)===35?n:`#${n}`),l}function I(t){const e=t.charCodeAt(0)===47?t:`/${t}`,{pathname:n}=J(e);return n.split("/").filter(Boolean)}const d=t=>!t||t==="/"?"/":t.charCodeAt(0)===47&&t.indexOf("//")===-1?t.length>1&&t.charCodeAt(t.length-1)===47?t.slice(0,-1):t:w(R(g(t)))||"/";function p(t){return R(g(t||"/"))||"/"}function L(t){if(!t)return"";const e=t.indexOf("#"),n=e>=0?t.slice(0,e):t,r=n.indexOf("?");return r>=0?n.slice(0,r):n}function S(t){if(!t)return"";let e="";for(let n=0;n<t.length;n++)e+=t.charCodeAt(n)===45?"/":t[n];return e}function O(t){if(!t)return"";const e=t.indexOf("-");return e===-1?t:`${t.slice(0,e)}/${t.slice(e+1)}`}function j(t){if(!t)return"";const e=t.lastIndexOf("-");return e===-1?t:`${t.slice(0,e)}/${t.slice(e+1)}`}function te(t){const e=I(t);return e.length>1?e.slice(0,-1).join("-"):""}function ne(t){return X(t||"/")}function T(t,e){if(!t||t==="/")return{pathWithoutLocale:"/",localeFromPath:null};const n=L(t),r=d(n);if(r==="/"||r.charCodeAt(0)!==47)return{pathWithoutLocale:r||"/",localeFromPath:null};const l=r.indexOf("/",1),o=l===-1?r.slice(1):r.slice(1,l);if(o&&e.includes(o)){const a=1+o.length,i=r.slice(a);return{pathWithoutLocale:!i||i==="/"?"/":i.charCodeAt(0)===47?i:`/${i}`,localeFromPath:o}}return{pathWithoutLocale:r,localeFromPath:null}}function re(t,e){const n=L(t);if(n==="/"||n===""||!Z(n))return null;const r=n.indexOf("/",1),l=r===-1?n.slice(1):n.slice(1,r);return l&&e.includes(l)?l:null}const le=/:(\w+)\(\)|:(\w+)(?!\w)|\[\.\.\.(\w+)\]/g;function H(t,e={}){return!e||!m(e)?t:t.replace(le,(n,r,l,o)=>{const a=r||l||o;if(!a)return n;const i=e[a];return i==null||i===""?n:Array.isArray(i)?i.join("/"):String(i)})}function $(t,e){const n=t.name?.toString();if(!n)return null;const r=e.localizedRouteNamePrefix||"localized-",l=n.startsWith(r)?n.slice(r.length):n;let o=0,a=-1;for(let i=0;i<e.locales.length;i++){const s=e.locales[i].code;if(s.length<=o)continue;const c=l.length-s.length-1;c<0||l[c]!=="-"||l.endsWith(s)&&(o=s.length,a=c)}return a>=0?l.slice(0,a):l}function E(t,e,n="localized-"){return`${n}${t}-${e}`}function G(t,e){if(t==null)return!1;const n=String(t).trim();if(n===""||n==="index")return!0;const r=e?.localizedRouteNamePrefix??"localized-",l=e?.localeCodes??[],o=`${r}index-`;if(!n.startsWith(o))return!1;const a=n.slice(o.length);return l.length===0?a.length>=2:l.includes(a)}function b(t,e){const n=t.localeCodes??t.locales.map(o=>o.code),{pathWithoutLocale:r}=T(e.path||"/",n);let l=null;return e.name&&(l=$(e,{locales:t.locales,localizedRouteNamePrefix:t.localizedRouteNamePrefix||"localized-"})),{pathWithoutLocale:r,baseRouteName:l}}function M(t,e){const n=[];n.push(t);const r=z(t);if(r&&r!==t&&n.push(r),(t==="/"||r==="")&&n.push(""),e){n.push(`/${e}`),n.push(e);const l=S(e);l&&l!==e&&n.push(l);const o=O(e);o&&n.push(o);const a=j(e);a&&n.push(a)}return n}function _(t,e,n,r){const l=t.globalLocaleRoutes;if(!l||!(t._hasGR??m(l)))return null;const{pathWithoutLocale:o,baseRouteName:a}=r??b(t,e),i=M(o,a);for(const s of i){const c=l[s];if(c&&typeof c=="object"&&!Array.isArray(c)){const u=c[n];if(typeof u=="string")return H(u,e.params??{})}}return null}function oe(t,e,n){const r=t.globalLocaleRoutes;if(!r)return null;const{pathWithoutLocale:l,baseRouteName:o}=n??b(t,e),a=M(l,o);for(const i of a)if(r[i]===!1){if(o&&(i===o||i===`/${o}`)){const s=S(o);return s?h("/",s):`/${o}`}return l}return null}function ae(t,e){const n=t.globalLocaleRoutes;if(!n)return null;const r=[e,`/${e}`,z(e)];for(const l of r)if(n[l]===!1){const o=S(l.startsWith("/")?l.slice(1):l);return o?h("/",o):l.startsWith("/")?l:`/${l}`}return null}function ie(t,e,n){const l=_(t,{path:e,name:null,params:{}},n);return d(l||e)}function k(t,e,n,r){const l=`${e}${n}-${r}`;if(t.hasRoute(l))return{name:l,needsLocaleParam:!1};const o=`${e}${n}`;return t.hasRoute(o)?{name:o,needsLocaleParam:!0}:null}function Q(t,e,n,r,l,o,a){const i={...l};n&&(i.locale=r);let s;try{s=t.resolve({name:e,params:i,query:o?.query,hash:o?.hash})}catch{return null}return!s?.path||a&&s.path==="/"?null:{name:e,path:s.path,fullPath:s.fullPath,params:s.params,query:s.query??o?.query,hash:s.hash??o?.hash}}function se(t,e,n,r,l){const o=k(t,e,n,r);return o?Q(t,o.name,o.needsLocaleParam,r,{...l?.params},l,!1):null}function ce(t,e,n,r,l,o){const a=k(t,e,n,r);return a?Q(t,a.name,a.needsLocaleParam,r,l,o,!0):null}function ue(t,e){if(!e||!e.query&&!e.hash)return t;let n;typeof t=="string"?n={path:t}:n=t,e.query&&(n.query=n.query?Object.assign({},e.query,n.query):e.query),!n.hash&&e.hash&&(n.hash=e.hash);const r=n.path??"";return n.fullPath=F(r,n.query,n.hash),n}function fe(t,e){if(!t)return null;const n=L(t);if(!n||n==="/")return null;const r=n.charCodeAt(0)===47?1:0,l=n.indexOf("/",r),o=l===-1?n.slice(r):n.slice(r,l);if(!o)return null;for(let a=0;a<e.length;a++)if(e[a].code===o)return o;return null}function D(t,e,n){if(t.hashMode||t.strategy==="no_prefix")return n||t.defaultLocale;const r=e.path||e.fullPath||"";if(t.strategy==="prefix_and_default"&&(r==="/"||r==="")&&n)return n;if(e.params?.locale)return String(e.params.locale);const l=fe(r,t.locales);return l||(t.strategy==="prefix_except_default"?t.defaultLocale:n||t.defaultLocale)}function he(t,e,n,r){if(t.disablePageLocales)return"index";const l=r||t.localizedRouteNamePrefix||"localized-",o=$(e,{locales:t.locales,localizedRouteNamePrefix:l});if(o)return o;const a=(e.name??"").toString();let i=a.startsWith(l)?a.slice(l.length):a;const s=`-${n}`;return i.endsWith(s)&&(i=i.slice(0,-s.length)),i}function de(t,e,n){const r=D(t,e,n);for(let l=0;l<t.locales.length;l++)if(t.locales[l].code===r)return t.locales[l].displayName??null;return null}function me(t,e){if(!t)return null;for(let n=0;n<e.length;n++)if(t.endsWith(`-${e[n].code}`))return e[n].code;return null}function C(t,e){if(!e)return!1;if(e[t]===!1)return!0;const n=t==="/"?"/":z(t);return e[n]===!1}function K(t,e,n){const r=t.resolvePathForLocale(e,n);if(r==="/"||r==="")return`/${n}`;const l=r.charCodeAt(0)===47?r:`/${r}`;return g(`/${n}${l}`)}function ge(t,e){if(t==="/"||t==="")return`/${e}`;const n=t.charCodeAt(0)===47?t:`/${t}`;return g(`/${e}${n}`)}function V(t,e){if(!t)return null;const n=t.charCodeAt(0)===47?t:`/${t}`;return e?g(`/${e}${n}`):n}function Pe(t,e,n){const r=t.ctx.globalLocaleRoutes,{pathWithoutLocale:l,localeFromPath:o}=t.getPathWithoutLocale(e);if(o!==null&&C(l,r))return p(l);if(o===null&&C(l,r))return null;const a=K(t,l,n),i=L(e);return o===n&&B(i,a)?null:a}function ye(t,e){const{pathWithoutLocale:n,localeFromPath:r}=e;if(r===null)return null;if(C(n,t.globalLocaleRoutes))return"Unlocalized route cannot have locale prefix";const l=t.routeLocales;if(l&&(t._hasRL??m(l))){const o=t.localeCodes??t.locales.map(s=>s.code),a=n==="/"?"/":z(n),i=l[n]??l[a];if(Array.isArray(i)&&i.length>0){const s=i.filter(c=>o.includes(c));if(s.length>0&&!s.includes(r))return"Locale not allowed for this route"}}return null}class Re{constructor(e){e.localeCodes||(e.localeCodes=e.locales.map(n=>n.code)),e._hasGR===void 0&&(e._hasGR=m(e.globalLocaleRoutes)),e._hasRL===void 0&&(e._hasRL=m(e.routeLocales)),this.ctx=e}setRouter(e){this.ctx.router=e}getDefaultLocale(){return this.ctx.defaultLocale}getLocales(){return this.ctx.locales}getStrategy(){return this.ctx.strategy}getLocalizedRouteNamePrefix(){return this.ctx.localizedRouteNamePrefix||"localized-"}getGlobalLocaleRoutes(){return this.ctx.globalLocaleRoutes}getRouteLocales(){return this.ctx.routeLocales}getRoutesLocaleLinks(){return this.ctx.routesLocaleLinks}getNoPrefixRedirect(){return this.ctx.noPrefixRedirect}getRouteBaseName(e,n){const r=n?[{code:n}]:this.ctx.locales;return $(e,{locales:r,localizedRouteNamePrefix:this.getLocalizedRouteNamePrefix()})}getBaseRouteName(e,n){return this.getRouteBaseName(e,n)}buildLocalizedName(e,n){return E(e,n,this.getLocalizedRouteNamePrefix())}buildLocalizedRouteName(e,n){return this.buildLocalizedName(e,n)}resolveLocaleFromPath(e){const{localeFromPath:n}=this.getPathWithoutLocale(e);return n}detectLocaleFromName(e){return me(e,this.ctx.locales)}buildLocalizedPath(e,n,r){return h(n,d(e))}formatPathForResolve(e,n,r){return`/${n}${e}`}resolvePathForLocale(e,n){return ie(this.ctx,e,n)}getPathWithoutLocale(e){return T(e,this.ctx.localeCodes)}getLocaleFromPath(e){return re(e,this.ctx.localeCodes)}getCanonicalPath(e,n){return V(_(this.ctx,e,n)??"",n)}applyBaseUrl(e,n){if(typeof n=="string"){if(x(n))return n}else if(n.path&&x(n.path))return n;const r=this.ctx.locales.find(a=>a.code===e);if(!r?.baseUrl)return n;const l=R(r.baseUrl);if(typeof n=="string")return h(l,d(n.charCodeAt(0)===47?n:`/${n}`));const o=h(l,d(n.path||""));return x(o)?o:{...n,path:o,fullPath:o}}getSwitchLocaleFallbackWhenNoRoute(e,n){return{...e,name:n}}localeRoute(e,n,r){const l=this._normalizeRouteInput(n,r),o=this.resolveLocaleRoute(e,l,r);return this._ensureRouteLike(o,l.kind==="route"?l.sourceRoute:void 0)}_ensureRouteLike(e,n){if(typeof e=="string"){const o=e,a=n?.query||n?.hash?F(o,n?.query,n?.hash):o,i={path:o,fullPath:a};return n?.query&&(i.query=n.query),n?.hash&&(i.hash=n.hash),i}if(e.path&&e.fullPath)return e;let r=e.fullPath??e.path??"",l=e.path??(r.indexOf("?")!==-1?r.slice(0,r.indexOf("?")):r.indexOf("#")!==-1?r.slice(0,r.indexOf("#")):r);if(!l&&!r){const o=e.name?.toString()??n?.name?.toString()??"";G(o,{localizedRouteNamePrefix:this.getLocalizedRouteNamePrefix(),localeCodes:this.ctx.localeCodes})&&(l="/",r="/")}return e.path=l,e.fullPath=r,e}_normalizeRouteInput(e,n){if(typeof e=="string")return{kind:"path",path:e};const r=e,l=r.name?.toString()??null;let o;try{o=this.ctx.router.resolve(e)}catch{o={name:l,path:r.path??"/",fullPath:r.fullPath??r.path??"/",params:r.params??{},query:r.query??{},hash:r.hash??""}}return{kind:"route",inputName:l,sourceRoute:r,resolved:o}}getCurrentLocale(e,n){return D(this.ctx,e,n)}getPluginRouteName(e,n){return he(this.ctx,e,n,this.getLocalizedRouteNamePrefix())}getCurrentLocaleName(e,n){return de(this.ctx,e,n)}shouldReturn404(e){return ye(this.ctx,this.getPathWithoutLocale(e))}}exports.BasePathStrategy=Re;exports.analyzeRoute=b;exports.buildCanonicalFromSegment=V;exports.buildLocalizedName=E;exports.buildPrefixedPath=K;exports.buildUrl=F;exports.cleanDoubleSlashes=g;exports.findLocalizedRouteName=k;exports.getCleanPath=L;exports.getPathForUnlocalizedRoute=oe;exports.getPathForUnlocalizedRouteByName=ae;exports.getPathSegments=I;exports.getRouteBaseName=$;exports.hasKeys=m;exports.isIndexRouteName=G;exports.isSamePath=B;exports.isUnlocalizedRoute=C;exports.joinUrl=h;exports.joinWithLocalePrefix=ge;exports.lastPathSegment=ne;exports.nameKeyFirstSlash=O;exports.nameKeyLastSlash=j;exports.normalizePath=d;exports.normalizePathForCompare=p;exports.parentKeyFromSlashKey=te;exports.prefixRedirect=Pe;exports.preserveQueryAndHash=ue;exports.resolveCustomPath=_;exports.resolvePathWithParams=H;exports.transformNameKeyToPath=S;exports.tryResolveByLocalizedName=se;exports.tryResolveByLocalizedNameWithParams=ce;
|
|
2
|
+
//# sourceMappingURL=base-strategy-BHkH418r.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-strategy-BHkH418r.cjs","sources":["../src/path.ts","../src/resolver.ts","../src/helpers.ts","../src/strategies/base-strategy.ts"],"sourcesContent":["/**\n * Path utilities — zero external dependencies, zero regexes at runtime.\n * Lightweight replacements for ufo, tailored to i18n routing.\n * Also includes normalizer functions (getPathWithoutLocale, getLocaleFromPath).\n */\n\n// ---------------------------------------------------------------------------\n// Primitive helpers\n// ---------------------------------------------------------------------------\n\nconst UNSAFE_CHARS_RE = /[^A-Za-z0-9_.\\-~]/\n\nexport function withLeadingSlash(p: string): string {\n return p.charCodeAt(0) === 47 /* / */ ? p : `/${p}`\n}\n\nexport function withoutLeadingSlash(p: string): string {\n return p.charCodeAt(0) === 47 /* / */ ? p.slice(1) : p\n}\n\nexport function withoutTrailingSlash(p: string): string {\n return p.length > 1 && p.charCodeAt(p.length - 1) === 47 /* / */ ? p.slice(0, -1) : p\n}\n\nexport function hasLeadingSlash(p: string): boolean {\n return p.charCodeAt(0) === 47 /* / */\n}\n\n/** Collapse consecutive slashes to single, preserving :// in protocols. */\nexport function cleanDoubleSlashes(p: string): string {\n const protoIdx = p.indexOf('://')\n if (protoIdx === -1) return _dedupSlashes(p)\n return p.slice(0, protoIdx + 3) + _dedupSlashes(p.slice(protoIdx + 3))\n}\n\nfunction _dedupSlashes(s: string): string {\n if (s.indexOf('//') === -1) return s\n let out = ''\n let prevSlash = false\n for (let i = 0; i < s.length; i++) {\n const isSlash = s.charCodeAt(i) === 47\n if (isSlash && prevSlash) continue\n out += s[i]\n prevSlash = isSlash\n }\n return out\n}\n\nexport function hasProtocol(p: string): boolean {\n const idx = p.indexOf('://')\n if (idx < 1) return false\n for (let i = 0; i < idx; i++) {\n const c = p.charCodeAt(i)\n // a-z A-Z 0-9 + - .\n if ((c >= 97 && c <= 122) || (c >= 65 && c <= 90) || (c >= 48 && c <= 57) || c === 43 || c === 45 || c === 46) continue\n return false\n }\n return true\n}\n\n/** O(1) check whether object has at least one own enumerable key. No array allocation. */\nexport function hasKeys(obj: Record<string, unknown> | null | undefined): boolean {\n if (!obj) return false\n for (const _ in obj) return true\n return false\n}\n\n// ---------------------------------------------------------------------------\n// Parse helpers\n// ---------------------------------------------------------------------------\n\nexport function parsePath(p: string): { pathname: string; search: string; hash: string } {\n let pathname = p\n let search = ''\n let hash = ''\n const hashIdx = p.indexOf('#')\n if (hashIdx >= 0) {\n hash = p.slice(hashIdx)\n pathname = p.slice(0, hashIdx)\n }\n const searchIdx = pathname.indexOf('?')\n if (searchIdx >= 0) {\n search = pathname.slice(searchIdx)\n pathname = pathname.slice(0, searchIdx)\n }\n return { pathname, search, hash }\n}\n\nexport function parseFilename(p: string): string {\n const idx = p.lastIndexOf('/')\n return idx === -1 ? p : p.slice(idx + 1)\n}\n\n// ---------------------------------------------------------------------------\n// isSamePath\n// ---------------------------------------------------------------------------\n\nexport function isSamePath(p1: string, p2: string): boolean {\n return normalizePathForCompare(p1) === normalizePathForCompare(p2)\n}\n\n// ---------------------------------------------------------------------------\n// Join\n// ---------------------------------------------------------------------------\n\nexport function joinURL(base: string, ...input: string[]): string {\n let url = base || ''\n for (const segment of input) {\n if (!segment || segment === '/') continue\n if (url) {\n const clean =\n segment.charCodeAt(0) === 46 && segment.charCodeAt(1) === 47 /* ./ */\n ? segment.slice(2)\n : segment.charCodeAt(0) === 47 /* / */\n ? segment.slice(1)\n : segment\n url = (url.charCodeAt(url.length - 1) === 47 ? url : `${url}/`) + clean\n } else {\n url = segment\n }\n }\n return url\n}\n\nexport function joinUrl(...segments: (string | undefined | null)[]): string {\n if (segments.length === 2) {\n const a = segments[0]\n const b = segments[1]\n if (a && b) return _joinTwo(a, b)\n if (a) return _normSimple(a)\n if (b) return _normSimple(b)\n return '/'\n }\n const valid = segments.filter((s): s is string => typeof s === 'string' && s !== '')\n if (valid.length === 0) return '/'\n const [base, ...rest] = valid\n const joined = joinURL(base!, ...rest) || '/'\n if (hasProtocol(joined)) return withoutTrailingSlash(joined) || joined\n return withLeadingSlash(withoutTrailingSlash(joined)) || '/'\n}\n\nfunction _joinTwo(a: string, b: string): string {\n const aEnd = a.charCodeAt(a.length - 1) === 47\n const bStart = b.charCodeAt(0) === 47\n let result: string\n if (aEnd && bStart) result = a + b.slice(1)\n else if (!aEnd && !bStart) result = `${a}/${b}`\n else result = a + b\n if (result.indexOf('://') !== -1) {\n if (result.length > 1 && result.charCodeAt(result.length - 1) === 47) result = result.slice(0, -1)\n return result\n }\n if (result.charCodeAt(0) !== 47) result = `/${result}`\n if (result.length > 1 && result.charCodeAt(result.length - 1) === 47) result = result.slice(0, -1)\n return result\n}\n\nfunction _normSimple(s: string): string {\n if (s.charCodeAt(0) !== 47) s = `/${s}`\n if (s.length > 1 && s.charCodeAt(s.length - 1) === 47) s = s.slice(0, -1)\n return s || '/'\n}\n\n// ---------------------------------------------------------------------------\n// Query / URL building\n// ---------------------------------------------------------------------------\n\nexport function buildUrl(path: string, query?: Record<string, any>, hash?: string): string {\n const hasHash = hash && hash !== '#'\n if (!query && !hasHash) return path\n\n let url = path\n\n if (query) {\n let separator = ''\n const hasQuestionMark = url.indexOf('?') !== -1\n let sepChar = hasQuestionMark ? '&' : '?'\n\n for (const key in query) {\n const value = query[key]\n\n if (value === undefined || value === null) continue\n\n if (Array.isArray(value)) {\n const keyPrefix = `${key}=`\n for (let i = 0, len = value.length; i < len; i++) {\n const val = value[i]\n if (val === undefined || val === null) continue\n\n let encodedVal\n const type = typeof val\n\n if (type === 'number' || type === 'boolean') {\n encodedVal = val\n } else {\n const str = `${val}`\n encodedVal = UNSAFE_CHARS_RE.test(str) ? encodeURIComponent(str) : str\n }\n // ---------------------------\n\n if (separator === '') {\n separator = sepChar\n sepChar = '&'\n } else {\n separator = '&'\n }\n\n url += separator + keyPrefix + encodedVal\n }\n } else {\n let encodedVal\n const type = typeof value\n\n if (type === 'number' || type === 'boolean') {\n encodedVal = value\n } else {\n const str = `${value}`\n encodedVal = UNSAFE_CHARS_RE.test(str) ? encodeURIComponent(str) : str\n }\n\n if (separator === '') {\n separator = sepChar\n sepChar = '&'\n } else {\n separator = '&'\n }\n\n url += `${separator + key}=${encodedVal}`\n }\n }\n }\n\n if (hasHash) {\n url += hash!.charCodeAt(0) === 35 ? hash : `#${hash}`\n }\n\n return url\n}\n\n// ---------------------------------------------------------------------------\n// High-level path helpers\n// ---------------------------------------------------------------------------\n\nexport function getPathSegments(pathOrSlashKey: string): string[] {\n const p = pathOrSlashKey.charCodeAt(0) === 47 ? pathOrSlashKey : `/${pathOrSlashKey}`\n const { pathname } = parsePath(p)\n return pathname.split('/').filter(Boolean)\n}\n\nexport const normalizePath = (p: string): string => {\n if (!p || p === '/') return '/'\n if (p.charCodeAt(0) === 47 && p.indexOf('//') === -1) {\n return p.length > 1 && p.charCodeAt(p.length - 1) === 47 ? p.slice(0, -1) : p\n }\n return withLeadingSlash(withoutTrailingSlash(cleanDoubleSlashes(p))) || '/'\n}\n\nexport function normalizePathForCompare(p: string): string {\n return withoutTrailingSlash(cleanDoubleSlashes(p || '/')) || '/'\n}\n\nexport function getCleanPath(path: string | null | undefined): string {\n if (!path) return ''\n const hashIdx = path.indexOf('#')\n const noHash = hashIdx >= 0 ? path.slice(0, hashIdx) : path\n const searchIdx = noHash.indexOf('?')\n return searchIdx >= 0 ? noHash.slice(0, searchIdx) : noHash\n}\n\nexport function getParentPath(routePath: string): string | null {\n const segments = getPathSegments(routePath)\n if (segments.length === 0) return null\n if (segments.length <= 1) return '/'\n return joinUrl('/', ...segments.slice(0, -1))\n}\n\n// ---------------------------------------------------------------------------\n// Route-name helpers (string transforms)\n// ---------------------------------------------------------------------------\n\nexport function transformNameKeyToPath(nameKey: string): string {\n if (!nameKey) return ''\n let out = ''\n for (let i = 0; i < nameKey.length; i++) {\n out += nameKey.charCodeAt(i) === 45 /* - */ ? '/' : nameKey[i]\n }\n return out\n}\n\nexport function nameKeyFirstSlash(nameKey: string): string {\n if (!nameKey) return ''\n const idx = nameKey.indexOf('-')\n return idx === -1 ? nameKey : `${nameKey.slice(0, idx)}/${nameKey.slice(idx + 1)}`\n}\n\nexport function nameKeyLastSlash(nameKey: string): string {\n if (!nameKey) return ''\n const idx = nameKey.lastIndexOf('-')\n return idx === -1 ? nameKey : `${nameKey.slice(0, idx)}/${nameKey.slice(idx + 1)}`\n}\n\nexport function parentKeyFromSlashKey(keyWithSlash: string): string {\n const segments = getPathSegments(keyWithSlash)\n return segments.length > 1 ? segments.slice(0, -1).join('-') : ''\n}\n\nexport function lastPathSegment(path: string): string {\n return parseFilename(path || '/')\n}\n\n// ---------------------------------------------------------------------------\n// Normalizer — locale extraction from path (was core/normalizer.ts)\n// ---------------------------------------------------------------------------\n\n/**\n * Parses path: if first segment is a known locale, returns path without it and locale code.\n */\nexport function getPathWithoutLocale(path: string, localeCodes: readonly string[]): { pathWithoutLocale: string; localeFromPath: string | null } {\n if (!path || path === '/') return { pathWithoutLocale: '/', localeFromPath: null }\n\n const clean = getCleanPath(path)\n const normalized = normalizePath(clean)\n\n if (normalized === '/' || normalized.charCodeAt(0) !== 47) {\n return { pathWithoutLocale: normalized || '/', localeFromPath: null }\n }\n\n const nextSlash = normalized.indexOf('/', 1)\n const firstSegment = nextSlash === -1 ? normalized.slice(1) : normalized.slice(1, nextSlash)\n\n if (firstSegment && localeCodes.includes(firstSegment)) {\n const lengthToCut = 1 + firstSegment.length\n const remaining = normalized.slice(lengthToCut)\n const result = !remaining || remaining === '/' ? '/' : remaining.charCodeAt(0) === 47 ? remaining : `/${remaining}`\n return { pathWithoutLocale: result, localeFromPath: firstSegment }\n }\n\n return { pathWithoutLocale: normalized, localeFromPath: null }\n}\n\n/**\n * Determines locale from first path segment.\n */\nexport function getLocaleFromPath(path: string, localeCodes: readonly string[]): string | null {\n const clean = getCleanPath(path)\n\n if (clean === '/' || clean === '') return null\n\n if (!hasLeadingSlash(clean)) return null\n\n const nextSlash = clean.indexOf('/', 1)\n const segment = nextSlash === -1 ? clean.slice(1) : clean.slice(1, nextSlash)\n if (segment && localeCodes.includes(segment)) {\n return segment\n }\n\n return null\n}\n","/**\n * Route resolver — pure functions for resolving custom paths from globalLocaleRoutes.\n * No class, no stored state. Takes context as first argument.\n */\n\nimport {\n getPathWithoutLocale,\n hasKeys,\n joinUrl,\n nameKeyFirstSlash,\n nameKeyLastSlash,\n normalizePath,\n transformNameKeyToPath,\n withoutLeadingSlash,\n} from './path'\nimport type { PathStrategyContext, ResolvedRouteLike } from './types'\n\n/**\n * Single pre-compiled regex that matches all Nuxt route param patterns in one pass:\n * :key() — optional param (group 1)\n * :key — required param (group 2, not followed by word char)\n * [...key] — catch-all param (group 3)\n */\nconst PARAM_PATTERN = /:(\\w+)\\(\\)|:(\\w+)(?!\\w)|\\[\\.\\.\\.(\\w+)\\]/g\n\n/**\n * Substitutes params into path template (:key, :key(), [...key]).\n * Uses a single pre-compiled regex for all keys in one pass.\n */\nexport function resolvePathWithParams(path: string, params: Record<string, unknown> = {}): string {\n if (!params || !hasKeys(params)) return path\n\n return path.replace(PARAM_PATTERN, (match, optKey?: string, reqKey?: string, catchAllKey?: string) => {\n const key = optKey || reqKey || catchAllKey\n if (!key) return match\n\n const value = params[key]\n if (value === undefined || value === null || value === '') return match\n\n return Array.isArray(value) ? (value as unknown[]).join('/') : String(value)\n })\n}\n\n// ---------------------------------------------------------------------------\n// Route name helpers (used internally by resolver)\n// ---------------------------------------------------------------------------\n\nexport interface GetRouteBaseNameOptions {\n locales: { code: string }[]\n localizedRouteNamePrefix?: string\n}\n\n/**\n * Base route name without prefix (localized-) and suffix (-{locale}).\n */\nexport function getRouteBaseName(route: { name?: string | null } & Record<string, any>, options: GetRouteBaseNameOptions): string | null {\n const name = route.name?.toString()\n if (!name) return null\n\n const prefix = options.localizedRouteNamePrefix || 'localized-'\n const base = name.startsWith(prefix) ? name.slice(prefix.length) : name\n\n let bestLen = 0\n let bestSlice = -1\n for (let i = 0; i < options.locales.length; i++) {\n const code = options.locales[i]!.code\n if (code.length <= bestLen) continue\n const dashPos = base.length - code.length - 1\n if (dashPos < 0 || base[dashPos] !== '-') continue\n if (base.endsWith(code)) {\n bestLen = code.length\n bestSlice = dashPos\n }\n }\n return bestSlice >= 0 ? base.slice(0, bestSlice) : base\n}\n\n/** Builds localized name: localized-{baseName}-{locale}. */\nexport function buildLocalizedName(baseName: string, locale: string, prefix = 'localized-'): string {\n return `${prefix}${baseName}-${locale}`\n}\n\nexport interface IsIndexRouteNameOptions {\n localizedRouteNamePrefix?: string\n localeCodes?: readonly string[]\n}\n\n/**\n * Returns true if the given route name refers to the index (root) route.\n */\nexport function isIndexRouteName(name: string | null | undefined, options?: IsIndexRouteNameOptions): boolean {\n if (name == null) return false\n const s = String(name).trim()\n if (s === '' || s === 'index') return true\n const prefix = options?.localizedRouteNamePrefix ?? 'localized-'\n const localeCodes = options?.localeCodes ?? []\n const localizedIndexPrefix = `${prefix}index-`\n if (!s.startsWith(localizedIndexPrefix)) return false\n const localePart = s.slice(localizedIndexPrefix.length)\n return localeCodes.length === 0 ? localePart.length >= 2 : localeCodes.includes(localePart)\n}\n\n// ---------------------------------------------------------------------------\n// Lookup keys — shared by resolveCustomPath, getPathForUnlocalizedRoute, getAllowedLocalesForRoute\n// ---------------------------------------------------------------------------\n\nexport interface RouteAnalysis {\n pathWithoutLocale: string\n baseRouteName: string | null\n}\n\nexport function analyzeRoute(ctx: PathStrategyContext, route: ResolvedRouteLike): RouteAnalysis {\n const codes = ctx.localeCodes ?? ctx.locales.map((l) => l.code)\n const { pathWithoutLocale } = getPathWithoutLocale(route.path || '/', codes)\n\n let baseRouteName: string | null = null\n if (route.name) {\n baseRouteName = getRouteBaseName(route, {\n locales: ctx.locales,\n localizedRouteNamePrefix: ctx.localizedRouteNamePrefix || 'localized-',\n })\n }\n\n return { pathWithoutLocale, baseRouteName }\n}\n\nfunction getLookupKeys(pathWithoutLocale: string, baseRouteName: string | null): string[] {\n const keys: string[] = []\n\n keys.push(pathWithoutLocale)\n\n const pathKey = withoutLeadingSlash(pathWithoutLocale)\n if (pathKey && pathKey !== pathWithoutLocale) keys.push(pathKey)\n if (pathWithoutLocale === '/' || pathKey === '') keys.push('')\n\n if (baseRouteName) {\n keys.push(`/${baseRouteName}`)\n keys.push(baseRouteName)\n\n const asPath = transformNameKeyToPath(baseRouteName)\n if (asPath && asPath !== baseRouteName) keys.push(asPath)\n\n const firstSlash = nameKeyFirstSlash(baseRouteName)\n if (firstSlash) keys.push(firstSlash)\n\n const lastSlash = nameKeyLastSlash(baseRouteName)\n if (lastSlash) keys.push(lastSlash)\n }\n\n return keys\n}\n\n/**\n * Resolves custom path for targetLocale from globalLocaleRoutes.\n */\nexport function resolveCustomPath(\n ctx: PathStrategyContext,\n route: ResolvedRouteLike,\n targetLocale: string,\n precomputed?: RouteAnalysis,\n): string | null {\n const gr = ctx.globalLocaleRoutes\n if (!gr || !(ctx._hasGR ?? hasKeys(gr as Record<string, unknown>))) return null\n\n const { pathWithoutLocale, baseRouteName } = precomputed ?? analyzeRoute(ctx, route)\n const keys = getLookupKeys(pathWithoutLocale, baseRouteName)\n\n for (const key of keys) {\n const rule = gr[key]\n if (rule && typeof rule === 'object' && !Array.isArray(rule)) {\n const customPath = (rule as Record<string, string>)[targetLocale]\n if (typeof customPath === 'string') {\n return resolvePathWithParams(customPath, route.params ?? {})\n }\n }\n }\n\n return null\n}\n\n/**\n * Unlocalized route (globalLocaleRoutes[key] === false) — returns path without locale.\n */\nexport function getPathForUnlocalizedRoute(ctx: PathStrategyContext, route: ResolvedRouteLike, precomputed?: RouteAnalysis): string | null {\n const gr = ctx.globalLocaleRoutes\n if (!gr) return null\n\n const { pathWithoutLocale, baseRouteName } = precomputed ?? analyzeRoute(ctx, route)\n const keys = getLookupKeys(pathWithoutLocale, baseRouteName)\n\n for (const key of keys) {\n if (gr[key] === false) {\n if (baseRouteName && (key === baseRouteName || key === `/${baseRouteName}`)) {\n const pathForm = transformNameKeyToPath(baseRouteName)\n return pathForm ? joinUrl('/', pathForm) : `/${baseRouteName}`\n }\n return pathWithoutLocale\n }\n }\n\n return null\n}\n\n/**\n * Unlocalized by name (when no route object available).\n */\nexport function getPathForUnlocalizedRouteByName(ctx: PathStrategyContext, routeName: string): string | null {\n const gr = ctx.globalLocaleRoutes\n if (!gr) return null\n\n const keys = [routeName, `/${routeName}`, withoutLeadingSlash(routeName)]\n\n for (const key of keys) {\n if (gr[key] === false) {\n const pathForm = transformNameKeyToPath(key.startsWith('/') ? key.slice(1) : key)\n return pathForm ? joinUrl('/', pathForm) : key.startsWith('/') ? key : `/${key}`\n }\n }\n return null\n}\n\n/**\n * Allowed locales for route (routeLocales).\n */\nexport function getAllowedLocalesForRoute(ctx: PathStrategyContext, route: ResolvedRouteLike, precomputed?: RouteAnalysis): string[] {\n const codes = ctx.localeCodes ?? ctx.locales.map((l) => l.code)\n const rl = ctx.routeLocales\n if (!rl || !(ctx._hasRL ?? hasKeys(rl as Record<string, unknown>))) {\n return codes as string[]\n }\n\n const { pathWithoutLocale, baseRouteName } = precomputed ?? analyzeRoute(ctx, route)\n let keys = getLookupKeys(pathWithoutLocale, baseRouteName)\n\n if (baseRouteName && ctx.routesLocaleLinks?.[baseRouteName]) {\n const linkedName = ctx.routesLocaleLinks[baseRouteName]\n keys = [linkedName, ...keys]\n }\n\n for (const key of keys) {\n const allowed = rl[key]\n if (Array.isArray(allowed) && allowed.length > 0) {\n return allowed.filter((code) => codes.includes(code))\n }\n }\n\n return codes as string[]\n}\n\n/**\n * Parent path for nested route (parent key -> targetLocale path).\n */\nexport function getParentPathForNested(ctx: PathStrategyContext, nameSegments: string[], targetLocale: string): string {\n if (nameSegments.length <= 1) return '/'\n\n const parentKey = nameSegments.length > 1 ? nameSegments.slice(0, -1).join('-') : ''\n const gr = ctx.globalLocaleRoutes\n\n if (parentKey && gr?.[parentKey] && typeof gr[parentKey] === 'object') {\n const parentRules = gr[parentKey] as Record<string, string>\n if (parentRules[targetLocale]) {\n return normalizePath(parentRules[targetLocale])\n }\n }\n\n return joinUrl('/', ...nameSegments.slice(0, -1))\n}\n\n// ---------------------------------------------------------------------------\n// Resolve path for locale (used by strategies)\n// ---------------------------------------------------------------------------\n\n/**\n * Resolves a path for a target locale using custom routes.\n * Returns normalized path (custom or original).\n */\nexport function resolvePathForLocale(ctx: PathStrategyContext, path: string, targetLocale: string): string {\n const mockRoute: ResolvedRouteLike = { path, name: null, fullPath: path, params: {} }\n const customSegment = resolveCustomPath(ctx, mockRoute, targetLocale)\n return normalizePath(customSegment || path)\n}\n","/**\n * Standalone strategy helper functions.\n * Merged: route-resolve + strategy-helpers.\n * No class dependencies — pure functions of context + route.\n */\nimport type { Locale } from '@i18n-micro/types'\nimport { buildUrl, cleanDoubleSlashes, getCleanPath, hasKeys, isSamePath, normalizePathForCompare, withoutLeadingSlash } from './path'\nimport { getRouteBaseName } from './resolver'\nimport type { GlobalLocaleRoutes, PathStrategyContext, ResolvedRouteLike, RouteLike, RouterAdapter } from './types'\n\n// ---------------------------------------------------------------------------\n// Route resolution helpers (was route-resolve.ts)\n// ---------------------------------------------------------------------------\n\n/**\n * Finds the localized route name that the router recognises.\n * Tries \"{prefix}{routeName}-{locale}\" first, then \"{prefix}{routeName}\".\n */\nexport function findLocalizedRouteName(\n router: RouterAdapter,\n prefix: string,\n routeName: string,\n targetLocale: string,\n): { name: string; needsLocaleParam: boolean } | null {\n const withSuffix = `${prefix}${routeName}-${targetLocale}`\n if (router.hasRoute(withSuffix)) return { name: withSuffix, needsLocaleParam: false }\n const withoutSuffix = `${prefix}${routeName}`\n if (router.hasRoute(withoutSuffix)) return { name: withoutSuffix, needsLocaleParam: true }\n return null\n}\n\n/**\n * Core resolver: resolves a localized route given name, params, locale.\n */\nfunction resolveLocalizedRoute(\n router: RouterAdapter,\n localizedName: string,\n needsLocaleParam: boolean,\n targetLocale: string,\n params: Record<string, unknown>,\n sourceRoute: RouteLike | undefined,\n rejectRoot: boolean,\n): RouteLike | null {\n const resolveParams = { ...params }\n if (needsLocaleParam) resolveParams.locale = targetLocale\n\n let resolved: ReturnType<RouterAdapter['resolve']>\n try {\n resolved = router.resolve({\n name: localizedName,\n params: resolveParams,\n query: sourceRoute?.query,\n hash: sourceRoute?.hash,\n })\n } catch {\n return null\n }\n if (!resolved?.path) return null\n if (rejectRoot && resolved.path === '/') return null\n return {\n name: localizedName,\n path: resolved.path,\n fullPath: resolved.fullPath,\n params: resolved.params,\n query: resolved.query ?? sourceRoute?.query,\n hash: resolved.hash ?? sourceRoute?.hash,\n }\n}\n\n/**\n * Try to resolve route by localized name (uses sourceRoute.params).\n */\nexport function tryResolveByLocalizedName(\n router: RouterAdapter,\n prefix: string,\n routeName: string,\n targetLocale: string,\n sourceRoute?: RouteLike,\n): RouteLike | null {\n const found = findLocalizedRouteName(router, prefix, routeName, targetLocale)\n if (!found) return null\n return resolveLocalizedRoute(router, found.name, found.needsLocaleParam, targetLocale, { ...sourceRoute?.params }, sourceRoute, false)\n}\n\n/**\n * Try to resolve route by localized name with explicit params.\n * Returns null if resolved path is \"/\" (root).\n */\nexport function tryResolveByLocalizedNameWithParams(\n router: RouterAdapter,\n prefix: string,\n routeName: string,\n targetLocale: string,\n params: Record<string, unknown>,\n sourceRoute?: RouteLike,\n): RouteLike | null {\n const found = findLocalizedRouteName(router, prefix, routeName, targetLocale)\n if (!found) return null\n return resolveLocalizedRoute(router, found.name, found.needsLocaleParam, targetLocale, params, sourceRoute, true)\n}\n\n/**\n * Merges target route with query and hash from source route.\n */\nexport function preserveQueryAndHash(target: RouteLike | string, source?: RouteLike | null): RouteLike | string {\n if (!source || (!source.query && !source.hash)) {\n return target\n }\n\n let result: RouteLike\n if (typeof target === 'string') {\n result = { path: target }\n } else {\n result = target\n }\n\n if (source.query) {\n result.query = result.query ? Object.assign({}, source.query, result.query) : source.query\n }\n if (!result.hash && source.hash) {\n result.hash = source.hash\n }\n\n const basePath = result.path ?? ''\n result.fullPath = buildUrl(basePath, result.query, result.hash)\n\n return result\n}\n\n// ---------------------------------------------------------------------------\n// Strategy helpers (was strategy-helpers.ts)\n// ---------------------------------------------------------------------------\n\n/**\n * Extracts locale from the first path segment.\n */\nexport function extractLocaleFromPath(path: string, locales: Locale[]): string | null {\n if (!path) return null\n const clean = getCleanPath(path)\n if (!clean || clean === '/') return null\n const start = clean.charCodeAt(0) === 47 ? 1 : 0\n const nextSlash = clean.indexOf('/', start)\n const first = nextSlash === -1 ? clean.slice(start) : clean.slice(start, nextSlash)\n if (!first) return null\n for (let i = 0; i < locales.length; i++) {\n if (locales[i]!.code === first) return first\n }\n return null\n}\n\n/**\n * Determines current locale from route.\n * @param defaultLocaleOverride — optional locale value (e.g. from cookie/state); replaces the old callback.\n */\nexport function getCurrentLocale(ctx: PathStrategyContext, route: ResolvedRouteLike, defaultLocaleOverride?: string | null): string {\n if (ctx.hashMode || ctx.strategy === 'no_prefix') {\n return defaultLocaleOverride || ctx.defaultLocale\n }\n\n const path = route.path || route.fullPath || ''\n\n if (ctx.strategy === 'prefix_and_default' && (path === '/' || path === '')) {\n if (defaultLocaleOverride) return defaultLocaleOverride\n }\n\n if (route.params?.locale) return String(route.params.locale)\n\n const localeFromPath = extractLocaleFromPath(path, ctx.locales)\n if (localeFromPath) return localeFromPath\n\n if (ctx.strategy === 'prefix_except_default') return ctx.defaultLocale\n\n return defaultLocaleOverride || ctx.defaultLocale\n}\n\n/**\n * Returns the route name for plugin translation loading.\n */\nexport function getPluginRouteName(ctx: PathStrategyContext, route: ResolvedRouteLike, locale: string, localizedRouteNamePrefix?: string): string {\n if (ctx.disablePageLocales) return 'index'\n const prefix = localizedRouteNamePrefix || ctx.localizedRouteNamePrefix || 'localized-'\n const baseName = getRouteBaseName(route, { locales: ctx.locales, localizedRouteNamePrefix: prefix })\n if (baseName) return baseName\n const name = (route.name ?? '').toString()\n let stripped = name.startsWith(prefix) ? name.slice(prefix.length) : name\n const suffix = `-${locale}`\n if (stripped.endsWith(suffix)) {\n stripped = stripped.slice(0, -suffix.length)\n }\n return stripped\n}\n\n/**\n * Returns displayName of the current locale, or null.\n */\nexport function getCurrentLocaleName(ctx: PathStrategyContext, route: ResolvedRouteLike, defaultLocaleOverride?: string | null): string | null {\n const code = getCurrentLocale(ctx, route, defaultLocaleOverride)\n for (let i = 0; i < ctx.locales.length; i++) {\n if (ctx.locales[i]!.code === code) return ctx.locales[i]!.displayName ?? null\n }\n return null\n}\n\n/**\n * Detects locale code from a localized route name suffix (e.g. \"localized-about-de\" → \"de\").\n */\nexport function detectLocaleFromName(name: string | null, locales: Locale[]): string | null {\n if (!name) return null\n for (let i = 0; i < locales.length; i++) {\n if (name.endsWith(`-${locales[i]!.code}`)) return locales[i]!.code\n }\n return null\n}\n\n/**\n * Checks whether a path corresponds to an unlocalized route (globalLocaleRoutes[key] === false).\n */\nexport function isUnlocalizedRoute(pathWithoutLocale: string, gr: GlobalLocaleRoutes | undefined): boolean {\n if (!gr) return false\n if (gr[pathWithoutLocale] === false) return true\n const pathKey = pathWithoutLocale === '/' ? '/' : withoutLeadingSlash(pathWithoutLocale)\n return gr[pathKey] === false\n}\n\n/**\n * Minimal interface for strategies that use prefix redirect / buildPrefixedPath helpers.\n */\nexport interface PrefixRedirectHost {\n readonly ctx: { globalLocaleRoutes?: GlobalLocaleRoutes }\n getPathWithoutLocale(path: string): { pathWithoutLocale: string; localeFromPath: string | null }\n resolvePathForLocale(path: string, locale: string): string\n}\n\n/**\n * Builds a path with locale prefix: `/{locale}{resolved}`.\n */\nexport function buildPrefixedPath(host: PrefixRedirectHost, pathWithoutLocale: string, locale: string): string {\n const resolved = host.resolvePathForLocale(pathWithoutLocale, locale)\n if (resolved === '/' || resolved === '') return `/${locale}`\n const withSlash = resolved.charCodeAt(0) === 47 ? resolved : `/${resolved}`\n return cleanDoubleSlashes(`/${locale}${withSlash}`)\n}\n\n/**\n * Joins a path with a locale prefix: `/{locale}{path}`.\n */\nexport function joinWithLocalePrefix(pathWithoutLocale: string, locale: string): string {\n if (pathWithoutLocale === '/' || pathWithoutLocale === '') return `/${locale}`\n const withSlash = pathWithoutLocale.charCodeAt(0) === 47 ? pathWithoutLocale : `/${pathWithoutLocale}`\n return cleanDoubleSlashes(`/${locale}${withSlash}`)\n}\n\n/**\n * Builds canonical path from a custom segment with optional locale prefix.\n */\nexport function buildCanonicalFromSegment(segment: string, locale: string | null): string | null {\n if (!segment) return null\n const normalized = segment.charCodeAt(0) === 47 ? segment : `/${segment}`\n if (!locale) return normalized\n return cleanDoubleSlashes(`/${locale}${normalized}`)\n}\n\n/**\n * Common prefix redirect logic shared by prefix and prefix_and_default strategies.\n */\nexport function prefixRedirect(host: PrefixRedirectHost, currentPath: string, detectedLocale: string): string | null {\n const gr = host.ctx.globalLocaleRoutes\n const { pathWithoutLocale, localeFromPath } = host.getPathWithoutLocale(currentPath)\n if (localeFromPath !== null && isUnlocalizedRoute(pathWithoutLocale, gr)) {\n return normalizePathForCompare(pathWithoutLocale)\n }\n if (localeFromPath === null && isUnlocalizedRoute(pathWithoutLocale, gr)) return null\n const expectedPath = buildPrefixedPath(host, pathWithoutLocale, detectedLocale)\n const currentPathOnly = getCleanPath(currentPath)\n if (localeFromPath === detectedLocale && isSamePath(currentPathOnly, expectedPath)) return null\n return expectedPath\n}\n\n/**\n * Checks if the current path should return 404.\n * @param parsed — pre-computed result of getPathWithoutLocale(currentPath); no callback needed.\n */\nexport function shouldReturn404(ctx: PathStrategyContext, parsed: { pathWithoutLocale: string; localeFromPath: string | null }): string | null {\n const { pathWithoutLocale, localeFromPath } = parsed\n if (localeFromPath === null) return null\n\n if (isUnlocalizedRoute(pathWithoutLocale, ctx.globalLocaleRoutes)) {\n return 'Unlocalized route cannot have locale prefix'\n }\n\n const rl = ctx.routeLocales\n if (rl && (ctx._hasRL ?? hasKeys(rl as Record<string, unknown>))) {\n const localeCodes = ctx.localeCodes ?? ctx.locales.map((l) => l.code)\n const rlKey = pathWithoutLocale === '/' ? '/' : withoutLeadingSlash(pathWithoutLocale)\n const allowed = rl[pathWithoutLocale] ?? rl[rlKey]\n if (Array.isArray(allowed) && allowed.length > 0) {\n const allowedCodes = allowed.filter((code) => localeCodes.includes(code))\n if (allowedCodes.length > 0 && !allowedCodes.includes(localeFromPath)) {\n return 'Locale not allowed for this route'\n }\n }\n }\n\n return null\n}\n","/**\n * BasePathStrategy — lean abstract base for all path strategies.\n * No RouteResolver class — uses pure functions from ../resolver.\n */\nimport type { Locale } from '@i18n-micro/types'\nimport {\n buildCanonicalFromSegment,\n detectLocaleFromName as helperDetectLocaleFromName,\n getCurrentLocale as helperGetCurrentLocale,\n getCurrentLocaleName as helperGetCurrentLocaleName,\n getPluginRouteName as helperGetPluginRouteName,\n shouldReturn404 as helperShouldReturn404,\n} from '../helpers'\nimport {\n buildUrl,\n hasKeys,\n hasProtocol,\n joinUrl,\n normalizePath,\n getLocaleFromPath as normalizerGetLocaleFromPath,\n getPathWithoutLocale as normalizerGetPathWithoutLocale,\n withoutTrailingSlash,\n} from '../path'\nimport {\n isIndexRouteName,\n resolveCustomPath,\n resolvePathForLocale as resolverResolvePathForLocale,\n buildLocalizedName as utilBuildLocalizedName,\n getRouteBaseName as utilGetRouteBaseName,\n} from '../resolver'\nimport type {\n NormalizedRouteInput,\n PathStrategy,\n PathStrategyContext,\n ResolvedRouteLike,\n RouteLike,\n RouterAdapter,\n SwitchLocaleOptions,\n} from '../types'\n\nexport abstract class BasePathStrategy implements PathStrategy {\n readonly ctx: PathStrategyContext\n\n constructor(ctx: PathStrategyContext) {\n if (!ctx.localeCodes) ctx.localeCodes = ctx.locales.map((l) => l.code)\n if (ctx._hasGR === undefined) ctx._hasGR = hasKeys(ctx.globalLocaleRoutes as Record<string, unknown> | undefined)\n if (ctx._hasRL === undefined) ctx._hasRL = hasKeys(ctx.routeLocales as Record<string, unknown> | undefined)\n this.ctx = ctx\n }\n\n // --- Getters (interface) ---\n\n setRouter(router: RouterAdapter): void {\n this.ctx.router = router\n }\n getDefaultLocale(): string {\n return this.ctx.defaultLocale\n }\n getLocales(): Locale[] {\n return this.ctx.locales\n }\n getStrategy(): PathStrategyContext['strategy'] {\n return this.ctx.strategy\n }\n getLocalizedRouteNamePrefix(): string {\n return this.ctx.localizedRouteNamePrefix || 'localized-'\n }\n getGlobalLocaleRoutes(): PathStrategyContext['globalLocaleRoutes'] {\n return this.ctx.globalLocaleRoutes\n }\n getRouteLocales(): PathStrategyContext['routeLocales'] {\n return this.ctx.routeLocales\n }\n getRoutesLocaleLinks(): PathStrategyContext['routesLocaleLinks'] {\n return this.ctx.routesLocaleLinks\n }\n getNoPrefixRedirect(): boolean | undefined {\n return this.ctx.noPrefixRedirect\n }\n\n // --- Route name helpers ---\n\n getRouteBaseName(route: RouteLike, locale?: string): string | null {\n const locales = locale ? [{ code: locale }] : this.ctx.locales\n return utilGetRouteBaseName(route, { locales, localizedRouteNamePrefix: this.getLocalizedRouteNamePrefix() })\n }\n\n getBaseRouteName(route: RouteLike, locale: string): string | null {\n return this.getRouteBaseName(route, locale)\n }\n\n buildLocalizedName(baseName: string, locale: string): string {\n return utilBuildLocalizedName(baseName, locale, this.getLocalizedRouteNamePrefix())\n }\n\n // --- Default implementations (overridable) ---\n\n buildLocalizedRouteName(baseName: string, locale: string): string {\n return this.buildLocalizedName(baseName, locale)\n }\n\n resolveLocaleFromPath(path: string): string | null {\n const { localeFromPath } = this.getPathWithoutLocale(path)\n return localeFromPath\n }\n\n detectLocaleFromName(name: string | null): string | null {\n return helperDetectLocaleFromName(name, this.ctx.locales)\n }\n\n // --- Abstract (strategy-specific) ---\n\n abstract switchLocaleRoute(fromLocale: string, toLocale: string, route: ResolvedRouteLike, options: SwitchLocaleOptions): RouteLike | string\n abstract resolveLocaleRoute(targetLocale: string, normalized: NormalizedRouteInput, _currentRoute?: ResolvedRouteLike): RouteLike | string\n abstract getRedirect(currentPath: string, targetLocale: string): string | null\n abstract getClientRedirect(currentPath: string, preferredLocale: string): string | null\n\n // --- Default implementations (overridable by strategies) ---\n\n buildLocalizedPath(path: string, locale: string, _isCustom: boolean): string {\n return joinUrl(locale, normalizePath(path))\n }\n\n formatPathForResolve(path: string, fromLocale: string, _toLocale: string): string {\n return `/${fromLocale}${path}`\n }\n\n // --- Core helpers (use pure resolver functions) ---\n\n resolvePathForLocale(path: string, targetLocale: string): string {\n return resolverResolvePathForLocale(this.ctx, path, targetLocale)\n }\n\n getPathWithoutLocale(path: string): { pathWithoutLocale: string; localeFromPath: string | null } {\n return normalizerGetPathWithoutLocale(path, this.ctx.localeCodes!)\n }\n\n getLocaleFromPath(path: string): string | null {\n return normalizerGetLocaleFromPath(path, this.ctx.localeCodes!)\n }\n\n getCanonicalPath(route: ResolvedRouteLike, targetLocale: string): string | null {\n return buildCanonicalFromSegment(resolveCustomPath(this.ctx, route, targetLocale) ?? '', targetLocale)\n }\n\n applyBaseUrl(localeCode: string, route: RouteLike | string): RouteLike | string {\n if (typeof route === 'string') {\n if (hasProtocol(route)) return route\n } else if (route.path && hasProtocol(route.path)) {\n return route\n }\n\n const locale = this.ctx.locales.find((l) => l.code === localeCode)\n if (!locale?.baseUrl) return route\n\n const baseUrl = withoutTrailingSlash(locale.baseUrl)\n\n if (typeof route === 'string') {\n return joinUrl(baseUrl, normalizePath(route.charCodeAt(0) === 47 ? route : `/${route}`))\n }\n\n const fullPath = joinUrl(baseUrl, normalizePath(route.path || ''))\n if (hasProtocol(fullPath)) return fullPath\n return { ...route, path: fullPath, fullPath }\n }\n\n getSwitchLocaleFallbackWhenNoRoute(route: ResolvedRouteLike, targetName: string): RouteLike | string {\n return { ...route, name: targetName }\n }\n\n // --- localeRoute template method ---\n\n localeRoute(targetLocale: string, routeOrPath: RouteLike | string, currentRoute?: ResolvedRouteLike): RouteLike {\n const normalized = this._normalizeRouteInput(routeOrPath, currentRoute)\n const raw = this.resolveLocaleRoute(targetLocale, normalized, currentRoute)\n return this._ensureRouteLike(raw, normalized.kind === 'route' ? normalized.sourceRoute : undefined)\n }\n\n _ensureRouteLike(value: RouteLike | string, source?: RouteLike | null): RouteLike {\n if (typeof value === 'string') {\n const path = value\n const fullPath = source?.query || source?.hash ? buildUrl(path, source?.query, source?.hash) : path\n const result: RouteLike = { path, fullPath }\n if (source?.query) result.query = source.query\n if (source?.hash) result.hash = source.hash\n return result\n }\n if (value.path && value.fullPath) return value\n let fullPath = value.fullPath ?? value.path ?? ''\n let path =\n value.path ??\n (fullPath.indexOf('?') !== -1\n ? fullPath.slice(0, fullPath.indexOf('?'))\n : fullPath.indexOf('#') !== -1\n ? fullPath.slice(0, fullPath.indexOf('#'))\n : fullPath)\n if (!path && !fullPath) {\n const name = value.name?.toString() ?? source?.name?.toString() ?? ''\n if (isIndexRouteName(name, { localizedRouteNamePrefix: this.getLocalizedRouteNamePrefix(), localeCodes: this.ctx.localeCodes! })) {\n path = '/'\n fullPath = '/'\n }\n }\n value.path = path\n value.fullPath = fullPath\n return value\n }\n\n _normalizeRouteInput(routeOrPath: RouteLike | string, _currentRoute?: ResolvedRouteLike): NormalizedRouteInput {\n if (typeof routeOrPath === 'string') return { kind: 'path', path: routeOrPath }\n const sourceRoute = routeOrPath\n const inputName = sourceRoute.name?.toString() ?? null\n let resolved: ResolvedRouteLike\n try {\n resolved = this.ctx.router.resolve(routeOrPath)\n } catch {\n resolved = {\n name: inputName,\n path: sourceRoute.path ?? '/',\n fullPath: sourceRoute.fullPath ?? sourceRoute.path ?? '/',\n params: sourceRoute.params ?? {},\n query: sourceRoute.query ?? {},\n hash: sourceRoute.hash ?? '',\n } as ResolvedRouteLike\n }\n return { kind: 'route', inputName, sourceRoute, resolved }\n }\n\n // --- Delegated to standalone helpers ---\n\n getCurrentLocale(route: ResolvedRouteLike, defaultLocaleOverride?: string | null): string {\n return helperGetCurrentLocale(this.ctx, route, defaultLocaleOverride)\n }\n\n getPluginRouteName(route: ResolvedRouteLike, locale: string): string {\n return helperGetPluginRouteName(this.ctx, route, locale, this.getLocalizedRouteNamePrefix())\n }\n\n getCurrentLocaleName(route: ResolvedRouteLike, defaultLocaleOverride?: string | null): string | null {\n return helperGetCurrentLocaleName(this.ctx, route, defaultLocaleOverride)\n }\n\n shouldReturn404(currentPath: string): string | null {\n return helperShouldReturn404(this.ctx, this.getPathWithoutLocale(currentPath))\n }\n}\n"],"names":["UNSAFE_CHARS_RE","withLeadingSlash","p","withoutLeadingSlash","withoutTrailingSlash","hasLeadingSlash","cleanDoubleSlashes","protoIdx","_dedupSlashes","s","out","prevSlash","i","isSlash","hasProtocol","idx","c","hasKeys","obj","_","parsePath","pathname","search","hash","hashIdx","searchIdx","parseFilename","isSamePath","p1","p2","normalizePathForCompare","joinURL","base","input","url","segment","clean","joinUrl","segments","a","b","_joinTwo","_normSimple","valid","rest","joined","aEnd","bStart","result","buildUrl","path","query","hasHash","separator","sepChar","key","value","keyPrefix","len","val","encodedVal","type","str","getPathSegments","pathOrSlashKey","normalizePath","getCleanPath","noHash","transformNameKeyToPath","nameKey","nameKeyFirstSlash","nameKeyLastSlash","parentKeyFromSlashKey","keyWithSlash","lastPathSegment","getPathWithoutLocale","localeCodes","normalized","nextSlash","firstSegment","lengthToCut","remaining","getLocaleFromPath","PARAM_PATTERN","resolvePathWithParams","params","match","optKey","reqKey","catchAllKey","getRouteBaseName","route","options","name","prefix","bestLen","bestSlice","code","dashPos","buildLocalizedName","baseName","locale","isIndexRouteName","localizedIndexPrefix","localePart","analyzeRoute","ctx","codes","l","pathWithoutLocale","baseRouteName","getLookupKeys","keys","pathKey","asPath","firstSlash","lastSlash","resolveCustomPath","targetLocale","precomputed","gr","rule","customPath","getPathForUnlocalizedRoute","pathForm","getPathForUnlocalizedRouteByName","routeName","resolvePathForLocale","customSegment","findLocalizedRouteName","router","withSuffix","withoutSuffix","resolveLocalizedRoute","localizedName","needsLocaleParam","sourceRoute","rejectRoot","resolveParams","resolved","tryResolveByLocalizedName","found","tryResolveByLocalizedNameWithParams","preserveQueryAndHash","target","source","basePath","extractLocaleFromPath","locales","start","first","getCurrentLocale","defaultLocaleOverride","localeFromPath","getPluginRouteName","localizedRouteNamePrefix","stripped","suffix","getCurrentLocaleName","detectLocaleFromName","isUnlocalizedRoute","buildPrefixedPath","host","withSlash","joinWithLocalePrefix","buildCanonicalFromSegment","prefixRedirect","currentPath","detectedLocale","expectedPath","currentPathOnly","shouldReturn404","parsed","rl","rlKey","allowed","allowedCodes","BasePathStrategy","utilGetRouteBaseName","utilBuildLocalizedName","helperDetectLocaleFromName","_isCustom","fromLocale","_toLocale","resolverResolvePathForLocale","normalizerGetPathWithoutLocale","normalizerGetLocaleFromPath","localeCode","baseUrl","fullPath","targetName","routeOrPath","currentRoute","raw","_currentRoute","inputName","helperGetCurrentLocale","helperGetPluginRouteName","helperGetCurrentLocaleName","helperShouldReturn404"],"mappings":"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"}
|