@real-router/core 0.45.0 → 0.45.1
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/package.json +6 -7
- package/src/Router.ts +0 -684
- package/src/RouterError.ts +0 -324
- package/src/api/cloneRouter.ts +0 -77
- package/src/api/getDependenciesApi.ts +0 -168
- package/src/api/getLifecycleApi.ts +0 -65
- package/src/api/getPluginApi.ts +0 -167
- package/src/api/getRoutesApi.ts +0 -573
- package/src/api/helpers.ts +0 -10
- package/src/api/index.ts +0 -16
- package/src/api/types.ts +0 -12
- package/src/constants.ts +0 -87
- package/src/createRouter.ts +0 -32
- package/src/fsm/index.ts +0 -5
- package/src/fsm/routerFSM.ts +0 -120
- package/src/getNavigator.ts +0 -30
- package/src/guards.ts +0 -46
- package/src/helpers.ts +0 -179
- package/src/index.ts +0 -50
- package/src/internals.ts +0 -173
- package/src/namespaces/DependenciesNamespace/dependenciesStore.ts +0 -30
- package/src/namespaces/DependenciesNamespace/index.ts +0 -5
- package/src/namespaces/EventBusNamespace/EventBusNamespace.ts +0 -311
- package/src/namespaces/EventBusNamespace/index.ts +0 -5
- package/src/namespaces/EventBusNamespace/types.ts +0 -11
- package/src/namespaces/NavigationNamespace/NavigationNamespace.ts +0 -405
- package/src/namespaces/NavigationNamespace/constants.ts +0 -55
- package/src/namespaces/NavigationNamespace/index.ts +0 -5
- package/src/namespaces/NavigationNamespace/transition/completeTransition.ts +0 -100
- package/src/namespaces/NavigationNamespace/transition/errorHandling.ts +0 -124
- package/src/namespaces/NavigationNamespace/transition/guardPhase.ts +0 -221
- package/src/namespaces/NavigationNamespace/types.ts +0 -100
- package/src/namespaces/OptionsNamespace/OptionsNamespace.ts +0 -28
- package/src/namespaces/OptionsNamespace/constants.ts +0 -19
- package/src/namespaces/OptionsNamespace/helpers.ts +0 -50
- package/src/namespaces/OptionsNamespace/index.ts +0 -7
- package/src/namespaces/OptionsNamespace/validators.ts +0 -13
- package/src/namespaces/PluginsNamespace/PluginsNamespace.ts +0 -291
- package/src/namespaces/PluginsNamespace/constants.ts +0 -34
- package/src/namespaces/PluginsNamespace/index.ts +0 -7
- package/src/namespaces/PluginsNamespace/types.ts +0 -22
- package/src/namespaces/PluginsNamespace/validators.ts +0 -28
- package/src/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.ts +0 -377
- package/src/namespaces/RouteLifecycleNamespace/index.ts +0 -5
- package/src/namespaces/RouteLifecycleNamespace/types.ts +0 -10
- package/src/namespaces/RouterLifecycleNamespace/RouterLifecycleNamespace.ts +0 -81
- package/src/namespaces/RouterLifecycleNamespace/constants.ts +0 -25
- package/src/namespaces/RouterLifecycleNamespace/index.ts +0 -5
- package/src/namespaces/RouterLifecycleNamespace/types.ts +0 -26
- package/src/namespaces/RoutesNamespace/RoutesNamespace.ts +0 -535
- package/src/namespaces/RoutesNamespace/constants.ts +0 -6
- package/src/namespaces/RoutesNamespace/forwardChain.ts +0 -34
- package/src/namespaces/RoutesNamespace/helpers.ts +0 -126
- package/src/namespaces/RoutesNamespace/index.ts +0 -11
- package/src/namespaces/RoutesNamespace/routeGuards.ts +0 -62
- package/src/namespaces/RoutesNamespace/routesStore.ts +0 -346
- package/src/namespaces/RoutesNamespace/types.ts +0 -81
- package/src/namespaces/StateNamespace/StateNamespace.ts +0 -211
- package/src/namespaces/StateNamespace/helpers.ts +0 -24
- package/src/namespaces/StateNamespace/index.ts +0 -5
- package/src/namespaces/StateNamespace/types.ts +0 -15
- package/src/namespaces/index.ts +0 -35
- package/src/stateMetaStore.ts +0 -15
- package/src/transitionPath.ts +0 -436
- package/src/typeGuards.ts +0 -59
- package/src/types/RouterValidator.ts +0 -154
- package/src/types.ts +0 -69
- package/src/utils/getStaticPaths.ts +0 -50
- package/src/utils/index.ts +0 -5
- package/src/utils/serializeState.ts +0 -22
- package/src/validation.ts +0 -12
- package/src/wiring/RouterWiringBuilder.ts +0 -261
- package/src/wiring/index.ts +0 -7
- package/src/wiring/types.ts +0 -47
- package/src/wiring/wireRouter.ts +0 -26
package/src/api/getRoutesApi.ts
DELETED
|
@@ -1,573 +0,0 @@
|
|
|
1
|
-
import { logger } from "@real-router/logger";
|
|
2
|
-
|
|
3
|
-
import { throwIfDisposed } from "./helpers";
|
|
4
|
-
import { guardRouteStructure } from "../guards";
|
|
5
|
-
import { createInterceptable, getInternals } from "../internals";
|
|
6
|
-
import {
|
|
7
|
-
clearConfigEntries,
|
|
8
|
-
removeFromDefinitions,
|
|
9
|
-
sanitizeRoute,
|
|
10
|
-
} from "../namespaces/RoutesNamespace/helpers";
|
|
11
|
-
import {
|
|
12
|
-
validateClearRoutes,
|
|
13
|
-
validateRemoveRoute,
|
|
14
|
-
} from "../namespaces/RoutesNamespace/routeGuards";
|
|
15
|
-
import {
|
|
16
|
-
clearRouteData,
|
|
17
|
-
refreshForwardMap,
|
|
18
|
-
registerAllRouteHandlers,
|
|
19
|
-
} from "../namespaces/RoutesNamespace/routesStore";
|
|
20
|
-
|
|
21
|
-
import type { RoutesApi } from "./types";
|
|
22
|
-
import type { RouterInternals } from "../internals";
|
|
23
|
-
import type { RouteLifecycleNamespace, RouteConfig } from "../namespaces";
|
|
24
|
-
import type { RoutesStore } from "../namespaces/RoutesNamespace";
|
|
25
|
-
import type { GuardFnFactory, Route } from "../types";
|
|
26
|
-
import type {
|
|
27
|
-
DefaultDependencies,
|
|
28
|
-
ForwardToCallback,
|
|
29
|
-
Params,
|
|
30
|
-
Router,
|
|
31
|
-
} from "@real-router/types";
|
|
32
|
-
import type { RouteDefinition, RouteTree } from "route-tree";
|
|
33
|
-
|
|
34
|
-
// ============================================================================
|
|
35
|
-
// Helpers
|
|
36
|
-
// ============================================================================
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Recursively finds a route definition by its full dotted name.
|
|
40
|
-
*/
|
|
41
|
-
function findDefinition(
|
|
42
|
-
definitions: RouteDefinition[],
|
|
43
|
-
fullName: string,
|
|
44
|
-
parentPrefix = "",
|
|
45
|
-
): RouteDefinition | undefined {
|
|
46
|
-
for (const def of definitions) {
|
|
47
|
-
const currentFullName = parentPrefix
|
|
48
|
-
? `${parentPrefix}.${def.name}`
|
|
49
|
-
: def.name;
|
|
50
|
-
|
|
51
|
-
if (currentFullName === fullName) {
|
|
52
|
-
return def;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (def.children && fullName.startsWith(`${currentFullName}.`)) {
|
|
56
|
-
return findDefinition(def.children, fullName, currentFullName);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/* v8 ignore next -- @preserve: defensive return, callers validate route exists before calling */
|
|
61
|
-
return undefined;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Clears all config entries and lifecycle handlers for a removed route
|
|
66
|
-
* (and all its descendants).
|
|
67
|
-
*/
|
|
68
|
-
function clearRouteConfigurations<
|
|
69
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
70
|
-
>(
|
|
71
|
-
routeName: string,
|
|
72
|
-
config: RouteConfig,
|
|
73
|
-
routeCustomFields: Record<string, Record<string, unknown>>,
|
|
74
|
-
lifecycleNamespace: RouteLifecycleNamespace<Dependencies>,
|
|
75
|
-
): void {
|
|
76
|
-
const shouldClear = (name: string): boolean =>
|
|
77
|
-
name === routeName || name.startsWith(`${routeName}.`);
|
|
78
|
-
|
|
79
|
-
clearConfigEntries(config.decoders, shouldClear);
|
|
80
|
-
clearConfigEntries(config.encoders, shouldClear);
|
|
81
|
-
clearConfigEntries(config.defaultParams, shouldClear);
|
|
82
|
-
clearConfigEntries(config.forwardMap, shouldClear);
|
|
83
|
-
clearConfigEntries(config.forwardFnMap, shouldClear);
|
|
84
|
-
clearConfigEntries(routeCustomFields, shouldClear);
|
|
85
|
-
|
|
86
|
-
// Clear forwardMap entries pointing TO the deleted route (or its descendants)
|
|
87
|
-
clearConfigEntries(config.forwardMap, (key) =>
|
|
88
|
-
shouldClear(config.forwardMap[key]),
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
// Clear lifecycle handlers
|
|
92
|
-
const [canDeactivateFactories, canActivateFactories] =
|
|
93
|
-
lifecycleNamespace.getFactories();
|
|
94
|
-
|
|
95
|
-
for (const name of Object.keys(canActivateFactories)) {
|
|
96
|
-
if (shouldClear(name)) {
|
|
97
|
-
lifecycleNamespace.clearCanActivate(name);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
for (const name of Object.keys(canDeactivateFactories)) {
|
|
102
|
-
if (shouldClear(name)) {
|
|
103
|
-
lifecycleNamespace.clearCanDeactivate(name);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Updates forwardTo for a route in config and returns the refreshed resolved
|
|
110
|
-
* forward map (REPLACE semantics — caller must call ctx.setResolvedForwardMap).
|
|
111
|
-
*/
|
|
112
|
-
function updateForwardTo<
|
|
113
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
114
|
-
>(
|
|
115
|
-
name: string,
|
|
116
|
-
forwardTo: string | ForwardToCallback<Dependencies> | null,
|
|
117
|
-
config: RouteConfig,
|
|
118
|
-
refreshForwardMapFn: (config: RouteConfig) => Record<string, string>,
|
|
119
|
-
): Record<string, string> {
|
|
120
|
-
if (forwardTo === null) {
|
|
121
|
-
delete config.forwardMap[name];
|
|
122
|
-
delete config.forwardFnMap[name];
|
|
123
|
-
} else if (typeof forwardTo === "string") {
|
|
124
|
-
delete config.forwardFnMap[name];
|
|
125
|
-
config.forwardMap[name] = forwardTo;
|
|
126
|
-
} else {
|
|
127
|
-
delete config.forwardMap[name];
|
|
128
|
-
config.forwardFnMap[name] = forwardTo;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return refreshForwardMapFn(config);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Builds a full Route object from a bare RouteDefinition by re-attaching
|
|
136
|
-
* config entries and lifecycle factories.
|
|
137
|
-
*
|
|
138
|
-
* RECURSIVE — call with the factories tuple obtained ONCE from
|
|
139
|
-
* `lifecycleNamespace.getFactories()` and pass it through to children.
|
|
140
|
-
*/
|
|
141
|
-
function enrichRoute<
|
|
142
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
143
|
-
>(
|
|
144
|
-
routeDef: RouteDefinition,
|
|
145
|
-
routeName: string,
|
|
146
|
-
config: RouteConfig,
|
|
147
|
-
factories: [
|
|
148
|
-
Record<string, GuardFnFactory<Dependencies>>,
|
|
149
|
-
Record<string, GuardFnFactory<Dependencies>>,
|
|
150
|
-
],
|
|
151
|
-
): Route<Dependencies> {
|
|
152
|
-
const route: Route<Dependencies> = {
|
|
153
|
-
name: routeDef.name,
|
|
154
|
-
path: routeDef.path,
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
const forwardToFn = config.forwardFnMap[routeName];
|
|
158
|
-
const forwardToStr = config.forwardMap[routeName];
|
|
159
|
-
|
|
160
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
161
|
-
if (forwardToFn !== undefined) {
|
|
162
|
-
route.forwardTo = forwardToFn;
|
|
163
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
164
|
-
} else if (forwardToStr !== undefined) {
|
|
165
|
-
route.forwardTo = forwardToStr;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (routeName in config.defaultParams) {
|
|
169
|
-
route.defaultParams = config.defaultParams[routeName];
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (routeName in config.decoders) {
|
|
173
|
-
route.decodeParams = config.decoders[routeName];
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (routeName in config.encoders) {
|
|
177
|
-
route.encodeParams = config.encoders[routeName];
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const [canDeactivateFactories, canActivateFactories] = factories;
|
|
181
|
-
|
|
182
|
-
if (routeName in canActivateFactories) {
|
|
183
|
-
route.canActivate = canActivateFactories[routeName];
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (routeName in canDeactivateFactories) {
|
|
187
|
-
route.canDeactivate = canDeactivateFactories[routeName];
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (routeDef.children) {
|
|
191
|
-
route.children = routeDef.children.map((child) =>
|
|
192
|
-
enrichRoute(child, `${routeName}.${child.name}`, config, factories),
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return route;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// ============================================================================
|
|
200
|
-
// CRUD operations
|
|
201
|
-
// ============================================================================
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Adds one or more routes to the router.
|
|
205
|
-
* Input already validated by facade.
|
|
206
|
-
*/
|
|
207
|
-
function addRoutes<
|
|
208
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
209
|
-
>(
|
|
210
|
-
store: RoutesStore<Dependencies>,
|
|
211
|
-
routes: Route<Dependencies>[],
|
|
212
|
-
parentName?: string,
|
|
213
|
-
): void {
|
|
214
|
-
if (parentName) {
|
|
215
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
216
|
-
const parentDef = findDefinition(store.definitions, parentName)!;
|
|
217
|
-
|
|
218
|
-
parentDef.children ??= [];
|
|
219
|
-
|
|
220
|
-
for (const route of routes) {
|
|
221
|
-
parentDef.children.push(sanitizeRoute(route));
|
|
222
|
-
}
|
|
223
|
-
} else {
|
|
224
|
-
for (const route of routes) {
|
|
225
|
-
store.definitions.push(sanitizeRoute(route));
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
registerAllRouteHandlers(
|
|
230
|
-
routes,
|
|
231
|
-
store.config,
|
|
232
|
-
store.routeCustomFields,
|
|
233
|
-
store.pendingCanActivate,
|
|
234
|
-
store.pendingCanDeactivate,
|
|
235
|
-
store.depsStore,
|
|
236
|
-
parentName ?? "",
|
|
237
|
-
);
|
|
238
|
-
|
|
239
|
-
store.treeOperations.commitTreeChanges(store);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Atomically replaces all routes with a new set.
|
|
244
|
-
* Follows RFC 6-step semantics for HMR support.
|
|
245
|
-
*/
|
|
246
|
-
function replaceRoutes<
|
|
247
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
248
|
-
>(
|
|
249
|
-
store: RoutesStore<Dependencies>,
|
|
250
|
-
routes: Route<Dependencies>[],
|
|
251
|
-
ctx: RouterInternals<Dependencies>,
|
|
252
|
-
currentPath: string | undefined,
|
|
253
|
-
): void {
|
|
254
|
-
// Step 2: Clear route data (WITHOUT tree rebuild)
|
|
255
|
-
clearRouteData(store);
|
|
256
|
-
|
|
257
|
-
// Step 3: Clear definition lifecycle handlers (preserve external guards)
|
|
258
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- guaranteed set after wiring
|
|
259
|
-
store.lifecycleNamespace!.clearDefinitionGuards();
|
|
260
|
-
|
|
261
|
-
// Step 4: Register new routes
|
|
262
|
-
for (const route of routes) {
|
|
263
|
-
store.definitions.push(sanitizeRoute(route));
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
registerAllRouteHandlers(
|
|
267
|
-
routes,
|
|
268
|
-
store.config,
|
|
269
|
-
store.routeCustomFields,
|
|
270
|
-
store.pendingCanActivate,
|
|
271
|
-
store.pendingCanDeactivate,
|
|
272
|
-
store.depsStore,
|
|
273
|
-
"",
|
|
274
|
-
);
|
|
275
|
-
|
|
276
|
-
// Step 5: One tree rebuild
|
|
277
|
-
store.treeOperations.commitTreeChanges(store);
|
|
278
|
-
|
|
279
|
-
// Step 6: Revalidate state
|
|
280
|
-
if (currentPath !== undefined) {
|
|
281
|
-
const revalidated = ctx.matchPath(currentPath, ctx.getOptions());
|
|
282
|
-
|
|
283
|
-
if (revalidated) {
|
|
284
|
-
ctx.setState(revalidated);
|
|
285
|
-
} else {
|
|
286
|
-
ctx.clearState();
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Removes a route and all its children.
|
|
293
|
-
*
|
|
294
|
-
* @returns true if removed, false if not found
|
|
295
|
-
*/
|
|
296
|
-
function removeRoute<
|
|
297
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
298
|
-
>(store: RoutesStore<Dependencies>, name: string): boolean {
|
|
299
|
-
const wasRemoved = removeFromDefinitions(store.definitions, name);
|
|
300
|
-
|
|
301
|
-
if (!wasRemoved) {
|
|
302
|
-
return false;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
clearRouteConfigurations(
|
|
306
|
-
name,
|
|
307
|
-
store.config,
|
|
308
|
-
store.routeCustomFields,
|
|
309
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
310
|
-
store.lifecycleNamespace!,
|
|
311
|
-
);
|
|
312
|
-
|
|
313
|
-
store.treeOperations.commitTreeChanges(store);
|
|
314
|
-
|
|
315
|
-
return true;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* Updates a route's configuration in place.
|
|
320
|
-
*/
|
|
321
|
-
function updateRouteConfig<
|
|
322
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
323
|
-
>(
|
|
324
|
-
store: RoutesStore<Dependencies>,
|
|
325
|
-
name: string,
|
|
326
|
-
updates: {
|
|
327
|
-
forwardTo?: string | ForwardToCallback<Dependencies> | null | undefined;
|
|
328
|
-
defaultParams?: Params | null | undefined;
|
|
329
|
-
decodeParams?: ((params: Params) => Params) | null | undefined;
|
|
330
|
-
encodeParams?: ((params: Params) => Params) | null | undefined;
|
|
331
|
-
},
|
|
332
|
-
): void {
|
|
333
|
-
if (updates.forwardTo !== undefined) {
|
|
334
|
-
store.resolvedForwardMap = updateForwardTo(
|
|
335
|
-
name,
|
|
336
|
-
updates.forwardTo,
|
|
337
|
-
store.config,
|
|
338
|
-
(config) => refreshForwardMap(config),
|
|
339
|
-
);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
if (updates.defaultParams !== undefined) {
|
|
343
|
-
if (updates.defaultParams === null) {
|
|
344
|
-
delete store.config.defaultParams[name];
|
|
345
|
-
} else {
|
|
346
|
-
store.config.defaultParams[name] = updates.defaultParams;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
if (updates.decodeParams !== undefined) {
|
|
351
|
-
if (updates.decodeParams === null) {
|
|
352
|
-
delete store.config.decoders[name];
|
|
353
|
-
} else {
|
|
354
|
-
const decoder = updates.decodeParams;
|
|
355
|
-
|
|
356
|
-
store.config.decoders[name] = (params: Params): Params =>
|
|
357
|
-
(decoder(params) as Params | undefined) ?? params;
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
if (updates.encodeParams !== undefined) {
|
|
362
|
-
if (updates.encodeParams === null) {
|
|
363
|
-
delete store.config.encoders[name];
|
|
364
|
-
} else {
|
|
365
|
-
const encoder = updates.encodeParams;
|
|
366
|
-
|
|
367
|
-
store.config.encoders[name] = (params: Params): Params =>
|
|
368
|
-
(encoder(params) as Params | undefined) ?? params;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* Gets a route by name with all its configuration.
|
|
375
|
-
*/
|
|
376
|
-
function getRoute<
|
|
377
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
378
|
-
>(
|
|
379
|
-
store: RoutesStore<Dependencies>,
|
|
380
|
-
name: string,
|
|
381
|
-
): Route<Dependencies> | undefined {
|
|
382
|
-
const segments = store.matcher.getSegmentsByName(name);
|
|
383
|
-
|
|
384
|
-
if (!segments) {
|
|
385
|
-
return undefined;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- segments is non-empty (checked above)
|
|
389
|
-
const targetNode = segments.at(-1)! as RouteTree;
|
|
390
|
-
const definition = store.treeOperations.nodeToDefinition(targetNode);
|
|
391
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
392
|
-
const factories = store.lifecycleNamespace!.getFactories();
|
|
393
|
-
|
|
394
|
-
return enrichRoute(definition, name, store.config, factories);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// ============================================================================
|
|
398
|
-
// API factory
|
|
399
|
-
// ============================================================================
|
|
400
|
-
|
|
401
|
-
export function getRoutesApi<
|
|
402
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
403
|
-
>(router: Router<Dependencies>): RoutesApi<Dependencies> {
|
|
404
|
-
const ctx = getInternals(router);
|
|
405
|
-
|
|
406
|
-
const store = ctx.routeGetStore();
|
|
407
|
-
|
|
408
|
-
const interceptableAdd = createInterceptable(
|
|
409
|
-
"add",
|
|
410
|
-
(routeArray: Route<Dependencies>[], options?: { parent?: string }) => {
|
|
411
|
-
addRoutes(store, routeArray, options?.parent);
|
|
412
|
-
},
|
|
413
|
-
ctx.interceptors,
|
|
414
|
-
);
|
|
415
|
-
|
|
416
|
-
return {
|
|
417
|
-
add: (routes, options) => {
|
|
418
|
-
throwIfDisposed(ctx.isDisposed);
|
|
419
|
-
|
|
420
|
-
const routeArray = Array.isArray(routes) ? routes : [routes];
|
|
421
|
-
const parentName = options?.parent;
|
|
422
|
-
|
|
423
|
-
guardRouteStructure(routeArray, ctx.validator);
|
|
424
|
-
|
|
425
|
-
if (parentName !== undefined) {
|
|
426
|
-
ctx.validator?.routes.validateParentOption(parentName, store.tree);
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
ctx.validator?.routes.throwIfInternalRouteInArray(routeArray, "addRoute");
|
|
430
|
-
ctx.validator?.routes.validateAddRouteArgs(routeArray);
|
|
431
|
-
ctx.validator?.routes.validateRoutes(routeArray, store);
|
|
432
|
-
|
|
433
|
-
interceptableAdd(
|
|
434
|
-
routeArray,
|
|
435
|
-
parentName === undefined ? undefined : { parent: parentName },
|
|
436
|
-
);
|
|
437
|
-
},
|
|
438
|
-
|
|
439
|
-
remove: (name) => {
|
|
440
|
-
throwIfDisposed(ctx.isDisposed);
|
|
441
|
-
|
|
442
|
-
ctx.validator?.routes.validateRemoveRouteArgs(name);
|
|
443
|
-
ctx.validator?.routes.throwIfInternalRoute(name, "removeRoute");
|
|
444
|
-
|
|
445
|
-
const canRemove = validateRemoveRoute(
|
|
446
|
-
name,
|
|
447
|
-
ctx.getStateName(),
|
|
448
|
-
ctx.isTransitioning(),
|
|
449
|
-
);
|
|
450
|
-
|
|
451
|
-
if (!canRemove) {
|
|
452
|
-
return;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
const wasRemoved = removeRoute(store, name);
|
|
456
|
-
|
|
457
|
-
if (!wasRemoved) {
|
|
458
|
-
logger.warn(
|
|
459
|
-
"router.removeRoute",
|
|
460
|
-
`Route "${name}" not found. No changes made.`,
|
|
461
|
-
);
|
|
462
|
-
}
|
|
463
|
-
},
|
|
464
|
-
|
|
465
|
-
update: (name, updates) => {
|
|
466
|
-
throwIfDisposed(ctx.isDisposed);
|
|
467
|
-
|
|
468
|
-
ctx.validator?.routes.validateUpdateRouteBasicArgs(name, updates);
|
|
469
|
-
ctx.validator?.routes.throwIfInternalRoute(name, "updateRoute");
|
|
470
|
-
|
|
471
|
-
const {
|
|
472
|
-
forwardTo,
|
|
473
|
-
defaultParams,
|
|
474
|
-
decodeParams,
|
|
475
|
-
encodeParams,
|
|
476
|
-
canActivate,
|
|
477
|
-
canDeactivate,
|
|
478
|
-
} = updates;
|
|
479
|
-
|
|
480
|
-
ctx.validator?.routes.validateUpdateRoutePropertyTypes(name, updates);
|
|
481
|
-
|
|
482
|
-
/* v8 ignore next 6 -- @preserve: race condition guard, mirrors Router.updateRoute() same-path guard tested via Router.ts unit tests */
|
|
483
|
-
if (ctx.isTransitioning()) {
|
|
484
|
-
logger.error(
|
|
485
|
-
"router.updateRoute",
|
|
486
|
-
`Updating route "${name}" while navigation is in progress. This may cause unexpected behavior.`,
|
|
487
|
-
);
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
ctx.validator?.routes.validateUpdateRoute(name, updates, store);
|
|
491
|
-
|
|
492
|
-
updateRouteConfig(store, name, {
|
|
493
|
-
forwardTo,
|
|
494
|
-
defaultParams,
|
|
495
|
-
decodeParams,
|
|
496
|
-
encodeParams,
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
if (canActivate !== undefined) {
|
|
500
|
-
if (canActivate === null) {
|
|
501
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- guaranteed set after wiring
|
|
502
|
-
store.lifecycleNamespace!.clearCanActivate(name);
|
|
503
|
-
} else {
|
|
504
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- guaranteed set after wiring
|
|
505
|
-
store.lifecycleNamespace!.addCanActivate(name, canActivate, true);
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
if (canDeactivate !== undefined) {
|
|
510
|
-
if (canDeactivate === null) {
|
|
511
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- guaranteed set after wiring
|
|
512
|
-
store.lifecycleNamespace!.clearCanDeactivate(name);
|
|
513
|
-
} else {
|
|
514
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- guaranteed set after wiring
|
|
515
|
-
store.lifecycleNamespace!.addCanDeactivate(name, canDeactivate, true);
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
},
|
|
519
|
-
|
|
520
|
-
clear: () => {
|
|
521
|
-
throwIfDisposed(ctx.isDisposed);
|
|
522
|
-
|
|
523
|
-
const canClear = validateClearRoutes(ctx.isTransitioning());
|
|
524
|
-
|
|
525
|
-
/* v8 ignore next 3 -- @preserve: race condition guard, mirrors Router.clearRoutes() same-path guard tested via validateClearRoutes unit tests */
|
|
526
|
-
if (!canClear) {
|
|
527
|
-
return;
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
store.treeOperations.resetStore(store);
|
|
531
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- guaranteed set after wiring
|
|
532
|
-
store.lifecycleNamespace!.clearAll();
|
|
533
|
-
ctx.clearState();
|
|
534
|
-
},
|
|
535
|
-
|
|
536
|
-
has: (name) => {
|
|
537
|
-
ctx.validator?.routes.validateRouteName(name, "hasRoute");
|
|
538
|
-
|
|
539
|
-
return store.matcher.hasRoute(name);
|
|
540
|
-
},
|
|
541
|
-
|
|
542
|
-
get: (name) => {
|
|
543
|
-
ctx.validator?.routes.validateRouteName(name, "getRoute");
|
|
544
|
-
|
|
545
|
-
return getRoute(store, name);
|
|
546
|
-
},
|
|
547
|
-
|
|
548
|
-
replace: (routes) => {
|
|
549
|
-
throwIfDisposed(ctx.isDisposed);
|
|
550
|
-
|
|
551
|
-
const routeArray = Array.isArray(routes) ? routes : [routes];
|
|
552
|
-
|
|
553
|
-
const canReplace = validateClearRoutes(ctx.isTransitioning());
|
|
554
|
-
|
|
555
|
-
if (!canReplace) {
|
|
556
|
-
return;
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
guardRouteStructure(routeArray, ctx.validator);
|
|
560
|
-
|
|
561
|
-
ctx.validator?.routes.throwIfInternalRouteInArray(
|
|
562
|
-
routeArray,
|
|
563
|
-
"replaceRoutes",
|
|
564
|
-
);
|
|
565
|
-
ctx.validator?.routes.validateAddRouteArgs(routeArray);
|
|
566
|
-
ctx.validator?.routes.validateRoutes(routeArray, store);
|
|
567
|
-
|
|
568
|
-
const currentPath = router.getState()?.path;
|
|
569
|
-
|
|
570
|
-
replaceRoutes(store, routeArray, ctx, currentPath);
|
|
571
|
-
},
|
|
572
|
-
};
|
|
573
|
-
}
|
package/src/api/helpers.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
// packages/core/src/api/helpers.ts
|
|
2
|
-
|
|
3
|
-
import { errorCodes } from "../constants";
|
|
4
|
-
import { RouterError } from "../RouterError";
|
|
5
|
-
|
|
6
|
-
export function throwIfDisposed(isDisposed: () => boolean): void {
|
|
7
|
-
if (isDisposed()) {
|
|
8
|
-
throw new RouterError(errorCodes.ROUTER_DISPOSED);
|
|
9
|
-
}
|
|
10
|
-
}
|
package/src/api/index.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export { getPluginApi } from "./getPluginApi";
|
|
2
|
-
|
|
3
|
-
export { getRoutesApi } from "./getRoutesApi";
|
|
4
|
-
|
|
5
|
-
export { getDependenciesApi } from "./getDependenciesApi";
|
|
6
|
-
|
|
7
|
-
export { getLifecycleApi } from "./getLifecycleApi";
|
|
8
|
-
|
|
9
|
-
export { cloneRouter } from "./cloneRouter";
|
|
10
|
-
|
|
11
|
-
export type {
|
|
12
|
-
PluginApi,
|
|
13
|
-
RoutesApi,
|
|
14
|
-
DependenciesApi,
|
|
15
|
-
LifecycleApi,
|
|
16
|
-
} from "./types";
|
package/src/api/types.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { PluginApi as BasePluginApi } from "@real-router/types";
|
|
2
|
-
import type { RouteTree } from "route-tree";
|
|
3
|
-
|
|
4
|
-
export interface PluginApi extends Omit<BasePluginApi, "getTree"> {
|
|
5
|
-
getTree: () => RouteTree;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export {
|
|
9
|
-
type RoutesApi,
|
|
10
|
-
type LifecycleApi,
|
|
11
|
-
type DependenciesApi,
|
|
12
|
-
} from "@real-router/types";
|
package/src/constants.ts
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
// packages/core/src/constants.ts
|
|
2
|
-
|
|
3
|
-
import type {
|
|
4
|
-
EventToNameMap,
|
|
5
|
-
EventToPluginMap,
|
|
6
|
-
ErrorCodeToValueMap,
|
|
7
|
-
ErrorCodeKeys,
|
|
8
|
-
ErrorCodeValues,
|
|
9
|
-
} from "@real-router/types";
|
|
10
|
-
|
|
11
|
-
export type ConstantsKeys = "UNKNOWN_ROUTE";
|
|
12
|
-
|
|
13
|
-
export type Constants = Record<ConstantsKeys, string>;
|
|
14
|
-
|
|
15
|
-
// =============================================================================
|
|
16
|
-
// Error Codes (migrated from router-error)
|
|
17
|
-
// =============================================================================
|
|
18
|
-
|
|
19
|
-
export type ErrorCodes = Record<ErrorCodeKeys, ErrorCodeValues>;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Error codes for router operations.
|
|
23
|
-
* Used to identify specific failure scenarios in navigation and lifecycle.
|
|
24
|
-
* Frozen to prevent accidental modifications.
|
|
25
|
-
*/
|
|
26
|
-
export const errorCodes: ErrorCodeToValueMap = Object.freeze({
|
|
27
|
-
ROUTER_NOT_STARTED: "NOT_STARTED", // navigate() called before start()
|
|
28
|
-
NO_START_PATH_OR_STATE: "NO_START_PATH_OR_STATE", // start() without initial route
|
|
29
|
-
ROUTER_ALREADY_STARTED: "ALREADY_STARTED", // start() called twice
|
|
30
|
-
ROUTE_NOT_FOUND: "ROUTE_NOT_FOUND", // Navigation to non-existent route
|
|
31
|
-
SAME_STATES: "SAME_STATES", // Navigate to current route without reload
|
|
32
|
-
CANNOT_DEACTIVATE: "CANNOT_DEACTIVATE", // canDeactivate guard blocked navigation
|
|
33
|
-
CANNOT_ACTIVATE: "CANNOT_ACTIVATE", // canActivate guard blocked navigation
|
|
34
|
-
TRANSITION_ERR: "TRANSITION_ERR", // Generic transition failure
|
|
35
|
-
TRANSITION_CANCELLED: "CANCELLED", // Navigation cancelled by user or new navigation
|
|
36
|
-
ROUTER_DISPOSED: "DISPOSED", // Router has been disposed
|
|
37
|
-
PLUGIN_CONFLICT: "PLUGIN_CONFLICT", // Plugin tried to extend router with already-existing property
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* General router constants.
|
|
42
|
-
* Special route names and identifiers.
|
|
43
|
-
*/
|
|
44
|
-
export const UNKNOWN_ROUTE = "@@router/UNKNOWN_ROUTE";
|
|
45
|
-
|
|
46
|
-
export const constants: Constants = {
|
|
47
|
-
UNKNOWN_ROUTE,
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Plugin method names.
|
|
52
|
-
* Maps to methods that plugins can implement to hook into router lifecycle.
|
|
53
|
-
*/
|
|
54
|
-
export const plugins: EventToPluginMap = {
|
|
55
|
-
ROUTER_START: "onStart", // Plugin method called when router starts
|
|
56
|
-
ROUTER_STOP: "onStop", // Plugin method called when router stops
|
|
57
|
-
TRANSITION_START: "onTransitionStart", // Plugin method called when navigation begins
|
|
58
|
-
TRANSITION_LEAVE_APPROVE: "onTransitionLeaveApprove", // Plugin method called when deactivation guards pass
|
|
59
|
-
TRANSITION_CANCEL: "onTransitionCancel", // Plugin method called when navigation cancelled
|
|
60
|
-
TRANSITION_SUCCESS: "onTransitionSuccess", // Plugin method called when navigation succeeds
|
|
61
|
-
TRANSITION_ERROR: "onTransitionError", // Plugin method called when navigation fails
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Event names for router event system.
|
|
66
|
-
* Used with addEventListener/removeEventListener for reactive subscriptions.
|
|
67
|
-
*/
|
|
68
|
-
export const events: EventToNameMap = {
|
|
69
|
-
ROUTER_START: "$start", // Emitted when router.start() succeeds
|
|
70
|
-
ROUTER_STOP: "$stop", // Emitted when router.stop() is called
|
|
71
|
-
TRANSITION_START: "$$start", // Emitted when navigation begins
|
|
72
|
-
TRANSITION_LEAVE_APPROVE: "$$leaveApprove", // Emitted when deactivation guards pass
|
|
73
|
-
TRANSITION_CANCEL: "$$cancel", // Emitted when navigation is cancelled
|
|
74
|
-
TRANSITION_SUCCESS: "$$success", // Emitted when navigation completes successfully
|
|
75
|
-
TRANSITION_ERROR: "$$error", // Emitted when navigation fails
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
export const DEFAULT_LIMITS = {
|
|
79
|
-
maxDependencies: 100,
|
|
80
|
-
maxPlugins: 50,
|
|
81
|
-
maxListeners: 10_000,
|
|
82
|
-
warnListeners: 1000,
|
|
83
|
-
maxEventDepth: 5,
|
|
84
|
-
maxLifecycleHandlers: 200,
|
|
85
|
-
} as const;
|
|
86
|
-
|
|
87
|
-
export const EMPTY_PARAMS: Readonly<Record<string, never>> = Object.freeze({});
|