@real-router/core 0.56.0 → 0.57.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.
Files changed (108) hide show
  1. package/dist/cjs/Router-BSGzVINO.js +6 -0
  2. package/dist/cjs/Router-BSGzVINO.js.map +1 -0
  3. package/dist/cjs/api.d.ts +1 -1
  4. package/dist/cjs/api.js +1 -1
  5. package/dist/cjs/{cloneRouter-DRieJvam.js → cloneRouter-7z-60z_f.js} +2 -2
  6. package/dist/cjs/{cloneRouter-DRieJvam.js.map → cloneRouter-7z-60z_f.js.map} +1 -1
  7. package/dist/cjs/{index-C-i6vx5Y.d.ts → index-BWUmnecT.d.ts} +1 -2
  8. package/dist/cjs/index-BWUmnecT.d.ts.map +1 -0
  9. package/dist/cjs/index.d.ts +1 -1
  10. package/dist/cjs/index.js +1 -1
  11. package/dist/cjs/utils.js +1 -1
  12. package/dist/cjs/validation.d.ts +1 -1
  13. package/dist/esm/Router-B7txWo9N.mjs +6 -0
  14. package/dist/esm/Router-B7txWo9N.mjs.map +1 -0
  15. package/dist/esm/api.d.mts +1 -1
  16. package/dist/esm/api.mjs +1 -1
  17. package/dist/esm/{cloneRouter-DHrH6D_z.mjs → cloneRouter-BNCQ7tIa.mjs} +2 -2
  18. package/dist/esm/{cloneRouter-DHrH6D_z.mjs.map → cloneRouter-BNCQ7tIa.mjs.map} +1 -1
  19. package/dist/esm/{index-C-i6vx5Y.d.mts → index-BWUmnecT.d.mts} +1 -2
  20. package/dist/esm/index-BWUmnecT.d.mts.map +1 -0
  21. package/dist/esm/index.d.mts +1 -1
  22. package/dist/esm/index.mjs +1 -1
  23. package/dist/esm/utils.mjs +1 -1
  24. package/dist/esm/validation.d.mts +1 -1
  25. package/package.json +2 -3
  26. package/dist/cjs/Router-IEGavTKk.js +0 -6
  27. package/dist/cjs/Router-IEGavTKk.js.map +0 -1
  28. package/dist/cjs/index-C-i6vx5Y.d.ts.map +0 -1
  29. package/dist/esm/Router-B3aeavRb.mjs +0 -6
  30. package/dist/esm/Router-B3aeavRb.mjs.map +0 -1
  31. package/dist/esm/index-C-i6vx5Y.d.mts.map +0 -1
  32. package/src/Router.ts +0 -737
  33. package/src/RouterError.ts +0 -324
  34. package/src/api/cloneRouter.ts +0 -159
  35. package/src/api/getDependenciesApi.ts +0 -160
  36. package/src/api/getLifecycleApi.ts +0 -65
  37. package/src/api/getPluginApi.ts +0 -228
  38. package/src/api/getRoutesApi.ts +0 -831
  39. package/src/api/helpers.ts +0 -10
  40. package/src/api/index.ts +0 -16
  41. package/src/api/types.ts +0 -12
  42. package/src/constants.ts +0 -101
  43. package/src/createRouter.ts +0 -32
  44. package/src/fsm/index.ts +0 -5
  45. package/src/fsm/routerFSM.ts +0 -130
  46. package/src/getNavigator.ts +0 -30
  47. package/src/guards.ts +0 -46
  48. package/src/helpers.ts +0 -197
  49. package/src/index.ts +0 -66
  50. package/src/internals.ts +0 -228
  51. package/src/namespaces/DependenciesNamespace/dependenciesStore.ts +0 -30
  52. package/src/namespaces/DependenciesNamespace/index.ts +0 -5
  53. package/src/namespaces/EventBusNamespace/EventBusNamespace.ts +0 -522
  54. package/src/namespaces/EventBusNamespace/index.ts +0 -5
  55. package/src/namespaces/EventBusNamespace/types.ts +0 -11
  56. package/src/namespaces/NavigationNamespace/NavigationNamespace.ts +0 -552
  57. package/src/namespaces/NavigationNamespace/constants.ts +0 -55
  58. package/src/namespaces/NavigationNamespace/index.ts +0 -5
  59. package/src/namespaces/NavigationNamespace/transition/completeTransition.ts +0 -108
  60. package/src/namespaces/NavigationNamespace/transition/errorHandling.ts +0 -124
  61. package/src/namespaces/NavigationNamespace/transition/guardPhase.ts +0 -283
  62. package/src/namespaces/NavigationNamespace/types.ts +0 -110
  63. package/src/namespaces/OptionsNamespace/OptionsNamespace.ts +0 -28
  64. package/src/namespaces/OptionsNamespace/constants.ts +0 -19
  65. package/src/namespaces/OptionsNamespace/helpers.ts +0 -50
  66. package/src/namespaces/OptionsNamespace/index.ts +0 -7
  67. package/src/namespaces/OptionsNamespace/validators.ts +0 -13
  68. package/src/namespaces/PluginsNamespace/PluginsNamespace.ts +0 -291
  69. package/src/namespaces/PluginsNamespace/constants.ts +0 -34
  70. package/src/namespaces/PluginsNamespace/index.ts +0 -7
  71. package/src/namespaces/PluginsNamespace/types.ts +0 -22
  72. package/src/namespaces/PluginsNamespace/validators.ts +0 -28
  73. package/src/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.ts +0 -558
  74. package/src/namespaces/RouteLifecycleNamespace/index.ts +0 -5
  75. package/src/namespaces/RouteLifecycleNamespace/types.ts +0 -10
  76. package/src/namespaces/RouterLifecycleNamespace/RouterLifecycleNamespace.ts +0 -81
  77. package/src/namespaces/RouterLifecycleNamespace/constants.ts +0 -25
  78. package/src/namespaces/RouterLifecycleNamespace/index.ts +0 -5
  79. package/src/namespaces/RouterLifecycleNamespace/types.ts +0 -30
  80. package/src/namespaces/RoutesNamespace/RoutesNamespace.ts +0 -582
  81. package/src/namespaces/RoutesNamespace/constants.ts +0 -6
  82. package/src/namespaces/RoutesNamespace/forwardChain.ts +0 -34
  83. package/src/namespaces/RoutesNamespace/helpers.ts +0 -204
  84. package/src/namespaces/RoutesNamespace/index.ts +0 -11
  85. package/src/namespaces/RoutesNamespace/routeGuards.ts +0 -62
  86. package/src/namespaces/RoutesNamespace/routesStore.ts +0 -566
  87. package/src/namespaces/RoutesNamespace/types.ts +0 -81
  88. package/src/namespaces/StateNamespace/StateNamespace.ts +0 -224
  89. package/src/namespaces/StateNamespace/helpers.ts +0 -24
  90. package/src/namespaces/StateNamespace/index.ts +0 -5
  91. package/src/namespaces/StateNamespace/types.ts +0 -15
  92. package/src/namespaces/index.ts +0 -35
  93. package/src/stateMetaStore.ts +0 -15
  94. package/src/transitionPath.ts +0 -440
  95. package/src/typeGuards.ts +0 -59
  96. package/src/types/RouterValidator.ts +0 -156
  97. package/src/types.ts +0 -77
  98. package/src/utils/createRequestScope.ts +0 -174
  99. package/src/utils/getStaticPaths.ts +0 -50
  100. package/src/utils/hydrateRouter.ts +0 -89
  101. package/src/utils/index.ts +0 -27
  102. package/src/utils/serializeRouterState.ts +0 -120
  103. package/src/utils/serializeState.ts +0 -63
  104. package/src/validation.ts +0 -12
  105. package/src/wiring/RouterWiringBuilder.ts +0 -275
  106. package/src/wiring/index.ts +0 -7
  107. package/src/wiring/types.ts +0 -47
  108. package/src/wiring/wireRouter.ts +0 -26
@@ -1,30 +0,0 @@
1
- // packages/core/src/namespaces/RouterLifecycleNamespace/types.ts
2
-
3
- import type {
4
- NavigationOptions,
5
- Options,
6
- Params,
7
- State,
8
- } from "@real-router/types";
9
-
10
- export interface RouterLifecycleDependencies {
11
- getOptions: () => Options;
12
- /**
13
- * Commit a fully-resolved State without re-running `forwardState`/`buildPath`.
14
- * `start(path)` uses this to commit `matchPath(path)` directly — the same
15
- * primitive URL plugins use on popstate / navigate-event (#525). Keeps
16
- * `state.path` identical to the source URL (preserves trailing slash in
17
- * `trailingSlash:"preserve"` mode) and avoids the redundant
18
- * forwardState+buildPath round-trip in `buildNavigateState`.
19
- */
20
- navigateToState: (state: State, opts: NavigationOptions) => Promise<State>;
21
- navigateToNotFound: (path: string) => State;
22
- clearState: () => void;
23
- matchPath: <P extends Params = Params>(path: string) => State<P> | undefined;
24
- completeStart: () => void;
25
- emitTransitionError: (
26
- toState: State | undefined,
27
- fromState: State | undefined,
28
- error: Error,
29
- ) => void;
30
- }
@@ -1,582 +0,0 @@
1
- // packages/core/src/namespaces/RoutesNamespace/RoutesNamespace.ts
2
-
3
- import { DEFAULT_ROUTE_NAME } from "./constants";
4
- import {
5
- matchSourceTrailingSlash,
6
- paramsMatch,
7
- paramsMatchExcluding,
8
- stripQueryDefaults,
9
- } from "./helpers";
10
- import {
11
- createRoutesStore,
12
- rebuildTreeInPlace,
13
- resetStore,
14
- } from "./routesStore";
15
- import { constants, DEFAULT_TRANSITION } from "../../constants";
16
- import { getTransitionPath } from "../../transitionPath";
17
-
18
- import type { RoutesStore } from "./routesStore";
19
- import type { RoutesDependencies } from "./types";
20
- import type { Route } from "../../types";
21
- import type { RouteLifecycleNamespace } from "../RouteLifecycleNamespace";
22
- import type {
23
- DefaultDependencies,
24
- ForwardToCallback,
25
- Options,
26
- Params,
27
- State,
28
- } from "@real-router/types";
29
- import type {
30
- CreateMatcherOptions,
31
- RouteParams,
32
- RouteTree,
33
- RouteTreeState,
34
- } from "route-tree";
35
-
36
- function collectUrlParamsArray(segments: readonly RouteTree[]): string[] {
37
- const params: string[] = [];
38
-
39
- for (const segment of segments) {
40
- for (const param of segment.paramMeta.urlParams) {
41
- params.push(param);
42
- }
43
- }
44
-
45
- return params;
46
- }
47
-
48
- export function buildNameFromSegments(
49
- segments: readonly { fullName: string }[],
50
- ): string {
51
- return segments.at(-1)?.fullName ?? "";
52
- }
53
-
54
- export function createRouteState<P extends RouteParams = RouteParams>(
55
- matchResult: {
56
- readonly segments: readonly { fullName: string }[];
57
- readonly params: Readonly<Record<string, unknown>>;
58
- readonly meta: Readonly<Record<string, Record<string, "url" | "query">>>;
59
- },
60
- name?: string,
61
- ): RouteTreeState<P> {
62
- const resolvedName = name ?? buildNameFromSegments(matchResult.segments);
63
-
64
- return {
65
- name: resolvedName,
66
- params: matchResult.params as P,
67
- meta: matchResult.meta,
68
- };
69
- }
70
-
71
- interface CachedBuildPathOpts {
72
- readonly trailingSlash?: "always" | "never" | undefined;
73
- readonly queryParamsMode?: "default" | "strict" | "loose" | undefined;
74
- }
75
-
76
- /**
77
- * Independent namespace for managing routes.
78
- *
79
- * Static methods handle validation (called by facade).
80
- * Instance methods handle storage and business logic.
81
- */
82
- export class RoutesNamespace<
83
- Dependencies extends DefaultDependencies = DefaultDependencies,
84
- > {
85
- readonly #store: RoutesStore<Dependencies>;
86
- #cachedBuildPathOpts: CachedBuildPathOpts | undefined;
87
-
88
- get #deps(): RoutesDependencies<Dependencies> {
89
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
90
- return this.#store.depsStore!;
91
- }
92
-
93
- constructor(
94
- routes: Route<Dependencies>[] = [],
95
- matcherOptions?: CreateMatcherOptions,
96
- ) {
97
- this.#store = createRoutesStore(routes, matcherOptions);
98
- }
99
-
100
- /**
101
- * Creates a predicate function to check if a route node should be updated.
102
- * Note: Argument validation is done by facade (Router.ts) via validateShouldUpdateNodeArgs.
103
- */
104
- static shouldUpdateNode(
105
- nodeName: string,
106
- ): (toState: State, fromState?: State) => boolean {
107
- return (toState: State, fromState?: State): boolean => {
108
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
109
- if (!(toState && typeof toState === "object" && "name" in toState)) {
110
- throw new TypeError(
111
- "[router.shouldUpdateNode] toState must be valid State object",
112
- );
113
- }
114
-
115
- if (toState.transition.reload) {
116
- return true;
117
- }
118
-
119
- // Root node (DEFAULT_ROUTE_NAME === "") has no route-level identity — it
120
- // represents "any route". It must update on every transition so that
121
- // consumers subscribed via useRouteNode("") (including RouteView at
122
- // the top of the tree) see every change. This matches the documented
123
- // contract in adapter docs: `useRouteNode("")` — Root — ALL route
124
- // changes. See #519 for the missed transitions it was suffering from
125
- // (users → users.user had intersection="users", leaving the root node
126
- // un-updated under a flat <Match segment="users.user" exact> pattern).
127
- if (nodeName === DEFAULT_ROUTE_NAME) {
128
- return true;
129
- }
130
-
131
- const { intersection, toActivate, toDeactivate } = getTransitionPath(
132
- toState,
133
- fromState,
134
- );
135
-
136
- if (nodeName === intersection) {
137
- return true;
138
- }
139
-
140
- if (toActivate.includes(nodeName)) {
141
- return true;
142
- }
143
-
144
- return toDeactivate.includes(nodeName);
145
- };
146
- }
147
-
148
- // =========================================================================
149
- // Dependency injection
150
- // =========================================================================
151
-
152
- /**
153
- * Sets dependencies and registers pending canActivate handlers.
154
- * canActivate handlers from initial routes are deferred until deps are set.
155
- */
156
- setDependencies(deps: RoutesDependencies<Dependencies>): void {
157
- this.#store.depsStore = deps;
158
-
159
- for (const [routeName, handler] of this.#store.pendingCanActivate) {
160
- deps.addActivateGuard(routeName, handler);
161
- }
162
-
163
- this.#store.pendingCanActivate.clear();
164
-
165
- for (const [routeName, handler] of this.#store.pendingCanDeactivate) {
166
- deps.addDeactivateGuard(routeName, handler);
167
- }
168
-
169
- this.#store.pendingCanDeactivate.clear();
170
- }
171
-
172
- /**
173
- * Sets the lifecycle namespace reference.
174
- */
175
- setLifecycleNamespace(
176
- namespace: RouteLifecycleNamespace<Dependencies> | undefined,
177
- ): void {
178
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
179
- this.#store.lifecycleNamespace = namespace!;
180
- }
181
-
182
- // =========================================================================
183
- // Route tree operations
184
- // =========================================================================
185
-
186
- setRootPath(newRootPath: string): void {
187
- this.#store.rootPath = newRootPath;
188
- rebuildTreeInPlace(this.#store);
189
- }
190
-
191
- hasRoute(name: string): boolean {
192
- return this.#store.matcher.hasRoute(name);
193
- }
194
-
195
- clearRoutes(): void {
196
- resetStore(this.#store);
197
- }
198
-
199
- // =========================================================================
200
- // Path operations
201
- // =========================================================================
202
-
203
- /**
204
- * Builds a URL path for a route.
205
- * Note: Argument validation is done by facade (Router.ts) via validateBuildPathArgs.
206
- *
207
- * @param route - Route name
208
- * @param params - Route parameters
209
- * @param options - Router options
210
- */
211
- buildPath(route: string, params?: Params, options?: Options): string {
212
- if (route === constants.UNKNOWN_ROUTE) {
213
- return typeof params?.path === "string" ? params.path : "";
214
- }
215
-
216
- const paramsWithDefault = Object.hasOwn(
217
- this.#store.config.defaultParams,
218
- route,
219
- )
220
- ? { ...this.#store.config.defaultParams[route], ...params }
221
- : /* v8 ignore next -- @preserve: V8 can't track ?? branch in ternary; covered by buildPath tests without params */ (params ??
222
- {});
223
-
224
- const encodedParams =
225
- typeof this.#store.config.encoders[route] === "function"
226
- ? this.#store.config.encoders[route]({ ...paramsWithDefault })
227
- : paramsWithDefault;
228
-
229
- return this.#store.matcher.buildPath(
230
- route,
231
- encodedParams,
232
- this.#getBuildPathOptions(options),
233
- );
234
- }
235
-
236
- /**
237
- * Matches a URL path to a route in the tree.
238
- * Note: Argument validation is done by facade (Router.ts) via validateMatchPathArgs.
239
- */
240
- matchPath<P extends Params = Params>(
241
- path: string,
242
- options?: Options,
243
- ): State<P> | undefined {
244
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Router.ts always passes options
245
- const opts = options!;
246
-
247
- const matchResult = this.#store.matcher.match(path);
248
-
249
- if (!matchResult) {
250
- return undefined;
251
- }
252
-
253
- const routeState = createRouteState(matchResult);
254
- const { name, params, meta } = routeState;
255
-
256
- const decodedParams =
257
- typeof this.#store.config.decoders[name] === "function"
258
- ? this.#store.config.decoders[name](params)
259
- : params;
260
-
261
- const { name: routeName, params: routeParams } = this.#deps.forwardState<P>(
262
- name,
263
- decodedParams as P,
264
- );
265
-
266
- let builtPath = path;
267
-
268
- if (opts.rewritePathOnMatch) {
269
- const buildParams =
270
- typeof this.#store.config.encoders[routeName] === "function"
271
- ? this.#store.config.encoders[routeName]({
272
- ...(routeParams as Params),
273
- })
274
- : (routeParams as Record<string, unknown>);
275
-
276
- const ts = opts.trailingSlash;
277
-
278
- builtPath = this.#store.matcher.buildPath(routeName, buildParams, {
279
- trailingSlash: ts === "never" || ts === "always" ? ts : undefined,
280
- queryParamsMode: opts.queryParamsMode,
281
- });
282
-
283
- if (ts === "preserve") {
284
- builtPath = matchSourceTrailingSlash(path, builtPath);
285
- }
286
- }
287
-
288
- return this.#deps.makeState<P>(routeName, routeParams, builtPath, meta);
289
- }
290
-
291
- /**
292
- * Applies forwardTo and returns resolved state with merged defaultParams.
293
- *
294
- * Merges params in order:
295
- * 1. Source route defaultParams
296
- * 2. Provided params
297
- * 3. Target route defaultParams (after resolving forwardTo)
298
- */
299
- forwardState<P extends Params = Params>(
300
- name: string,
301
- params: P,
302
- ): { name: string; params: P } {
303
- if (Object.hasOwn(this.#store.config.forwardFnMap, name)) {
304
- const paramsWithSourceDefaults = this.#mergeDefaultParams(name, params);
305
- const dynamicForward = this.#store.config.forwardFnMap[name];
306
- const resolved = this.#resolveDynamicForward(
307
- name,
308
- dynamicForward,
309
- params,
310
- );
311
-
312
- return {
313
- name: resolved,
314
- params: this.#mergeDefaultParams(resolved, paramsWithSourceDefaults),
315
- };
316
- }
317
-
318
- const staticForward = this.#store.resolvedForwardMap[name] ?? name;
319
-
320
- if (
321
- staticForward !== name &&
322
- Object.hasOwn(this.#store.config.forwardFnMap, staticForward)
323
- ) {
324
- const paramsWithSourceDefaults = this.#mergeDefaultParams(name, params);
325
- const targetDynamicForward =
326
- this.#store.config.forwardFnMap[staticForward];
327
- const resolved = this.#resolveDynamicForward(
328
- staticForward,
329
- targetDynamicForward,
330
- params,
331
- );
332
-
333
- return {
334
- name: resolved,
335
- params: this.#mergeDefaultParams(resolved, paramsWithSourceDefaults),
336
- };
337
- }
338
-
339
- if (staticForward !== name) {
340
- const paramsWithSourceDefaults = this.#mergeDefaultParams(name, params);
341
-
342
- return {
343
- name: staticForward,
344
- params: this.#mergeDefaultParams(
345
- staticForward,
346
- paramsWithSourceDefaults,
347
- ),
348
- };
349
- }
350
-
351
- return { name, params: this.#mergeDefaultParams(name, params) };
352
- }
353
-
354
- /**
355
- * Builds a RouteTreeState from already-resolved route name and params.
356
- * Called by Router.buildState after forwardState is applied at facade level.
357
- * This allows plugins to intercept forwardState.
358
- */
359
- buildStateResolved(
360
- resolvedName: string,
361
- resolvedParams: Params,
362
- ): RouteTreeState | undefined {
363
- const segments = this.#store.matcher.getSegmentsByName(resolvedName);
364
-
365
- if (!segments) {
366
- return undefined;
367
- }
368
-
369
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
370
- const meta = this.#store.matcher.getMetaByName(resolvedName)!;
371
-
372
- return createRouteState(
373
- { segments, params: resolvedParams, meta },
374
- resolvedName,
375
- );
376
- }
377
-
378
- // =========================================================================
379
- // Query operations
380
- // =========================================================================
381
-
382
- /**
383
- * Checks if a route is currently active.
384
- */
385
- isActiveRoute(
386
- name: string,
387
- params: Params = {},
388
- strictEquality = false,
389
- ignoreQueryParams = true,
390
- ): boolean {
391
- // Note: empty string check is handled by Router.ts facade
392
- const activeState = this.#deps.getState();
393
-
394
- if (!activeState) {
395
- return false;
396
- }
397
-
398
- const activeName = activeState.name;
399
-
400
- // Fast path: check if routes are related before expensive operations
401
- if (
402
- activeName !== name &&
403
- !activeName.startsWith(`${name}.`) &&
404
- !name.startsWith(`${activeName}.`)
405
- ) {
406
- return false;
407
- }
408
-
409
- const defaultParams = this.#store.config.defaultParams[name] as
410
- | Params
411
- | undefined;
412
-
413
- // Exact match case
414
- if (strictEquality || activeName === name) {
415
- const effectiveParams = defaultParams
416
- ? { ...defaultParams, ...params }
417
- : params;
418
-
419
- const targetState: State = {
420
- name,
421
- params: effectiveParams,
422
- path: "",
423
- transition: DEFAULT_TRANSITION,
424
- context: {},
425
- };
426
-
427
- return this.#deps.areStatesEqual(
428
- targetState,
429
- activeState,
430
- ignoreQueryParams,
431
- );
432
- }
433
-
434
- // The fast path above lets through three relations: exact (handled in
435
- // the previous block), `activeName` descendant of `name`, and `name`
436
- // descendant of `activeName`. Only the first two count as "active" —
437
- // a link pointing DEEPER than the current state is a navigation option,
438
- // not an active state. Reject the descendant-of-active case explicitly.
439
- if (!activeName.startsWith(`${name}.`)) {
440
- return false;
441
- }
442
-
443
- // Hierarchical check: activeState is a descendant of target (name)
444
- const activeParams = activeState.params;
445
-
446
- if (!paramsMatch(params, activeParams)) {
447
- return false;
448
- }
449
-
450
- if (!defaultParams) {
451
- return true;
452
- }
453
-
454
- // Honor `ignoreQueryParams` symmetrically with the exact-match branch
455
- // above: query-only param differences (e.g. parent has
456
- // `defaultParams: { sort: "asc" }` while the active descendant is
457
- // `products.detail` with `params: { id: "6" }` and no sort) must not
458
- // disqualify an ancestor link from being active. Strip query-typed
459
- // keys of `name` from the defaults before comparison; URL-typed keys
460
- // (`:id`, `:role`, etc.) are still enforced.
461
- // `name` reaches this point only after the fast-path established a valid
462
- // hierarchical relation AND `defaultParams` is non-null — both imply the
463
- // matcher has registered the route, so `getMetaByName(name)![name]` is
464
- // always defined here. Non-null assertions trade a defensive guard for
465
- // honest 100% coverage.
466
- const defaultsToCheck = ignoreQueryParams
467
- ? stripQueryDefaults(
468
- defaultParams,
469
- this.#store.matcher.getMetaByName(name)?.[name],
470
- )
471
- : defaultParams;
472
-
473
- return paramsMatchExcluding(defaultsToCheck, activeParams, params);
474
- }
475
-
476
- getMetaForState(
477
- name: string,
478
- ): Record<string, Record<string, "url" | "query">> | undefined {
479
- return this.#store.matcher.hasRoute(name)
480
- ? this.#store.matcher.getMetaByName(name)
481
- : undefined;
482
- }
483
-
484
- getUrlParams(name: string): string[] {
485
- const segments = this.#store.matcher.getSegmentsByName(name);
486
-
487
- if (!segments) {
488
- return [];
489
- }
490
-
491
- return collectUrlParamsArray(segments as readonly RouteTree[]);
492
- }
493
-
494
- getStore(): RoutesStore<Dependencies> {
495
- return this.#store;
496
- }
497
-
498
- #mergeDefaultParams<P extends Params = Params>(
499
- routeName: string,
500
- params: P,
501
- ): P {
502
- if (Object.hasOwn(this.#store.config.defaultParams, routeName)) {
503
- return {
504
- ...this.#store.config.defaultParams[routeName],
505
- ...params,
506
- };
507
- }
508
-
509
- return params;
510
- }
511
-
512
- #getBuildPathOptions(options?: Options): CachedBuildPathOpts {
513
- if (this.#cachedBuildPathOpts) {
514
- return this.#cachedBuildPathOpts;
515
- }
516
-
517
- const ts = options?.trailingSlash;
518
-
519
- this.#cachedBuildPathOpts = Object.freeze({
520
- trailingSlash: ts === "never" || ts === "always" ? ts : undefined,
521
- queryParamsMode: options?.queryParamsMode,
522
- });
523
-
524
- return this.#cachedBuildPathOpts;
525
- }
526
-
527
- #resolveDynamicForward(
528
- startName: string,
529
- startFn: ForwardToCallback<Dependencies>,
530
- params: Params,
531
- ): string {
532
- const visited = new Set<string>([startName]);
533
-
534
- let current = startFn(this.#deps.getDependency, params);
535
- let depth = 0;
536
- const MAX_DEPTH = 100;
537
-
538
- if (typeof current !== "string") {
539
- throw new TypeError(
540
- `forwardTo callback must return a string, got ${typeof current}`,
541
- );
542
- }
543
-
544
- while (depth < MAX_DEPTH) {
545
- if (this.#store.matcher.getSegmentsByName(current) === undefined) {
546
- throw new Error(`Route "${current}" does not exist`);
547
- }
548
-
549
- if (visited.has(current)) {
550
- const chain = [...visited, current].join(" → ");
551
-
552
- throw new Error(`Circular forwardTo detected: ${chain}`);
553
- }
554
-
555
- visited.add(current);
556
-
557
- if (Object.hasOwn(this.#store.config.forwardFnMap, current)) {
558
- const fn = this.#store.config.forwardFnMap[
559
- current
560
- ] as ForwardToCallback<Dependencies>;
561
-
562
- current = fn(this.#deps.getDependency, params);
563
-
564
- depth++;
565
- continue;
566
- }
567
-
568
- const staticForward = this.#store.config.forwardMap[current];
569
-
570
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
571
- if (staticForward !== undefined) {
572
- current = staticForward;
573
- depth++;
574
- continue;
575
- }
576
-
577
- return current;
578
- }
579
-
580
- throw new Error(`forwardTo exceeds maximum depth of ${MAX_DEPTH}`);
581
- }
582
- }
@@ -1,6 +0,0 @@
1
- // packages/core/src/namespaces/RoutesNamespace/constants.ts
2
-
3
- /**
4
- * Default route name for the root node.
5
- */
6
- export const DEFAULT_ROUTE_NAME = "";
@@ -1,34 +0,0 @@
1
- // packages/core/src/namespaces/RoutesNamespace/forwardChain.ts
2
-
3
- export function resolveForwardChain(
4
- startRoute: string,
5
- forwardMap: Record<string, string>,
6
- maxDepth = 100,
7
- ): string {
8
- const visited = new Set<string>();
9
- const chain: string[] = [startRoute];
10
- let current = startRoute;
11
-
12
- while (forwardMap[current]) {
13
- const next = forwardMap[current];
14
-
15
- if (visited.has(next)) {
16
- const cycleStart = chain.indexOf(next);
17
- const cycle = [...chain.slice(cycleStart), next];
18
-
19
- throw new Error(`Circular forwardTo: ${cycle.join(" → ")}`);
20
- }
21
-
22
- visited.add(current);
23
- chain.push(next);
24
- current = next;
25
-
26
- if (chain.length > maxDepth) {
27
- throw new Error(
28
- `forwardTo chain exceeds maximum depth (${maxDepth}): ${chain.join(" → ")}`,
29
- );
30
- }
31
- }
32
-
33
- return current;
34
- }