@real-router/core 0.38.0 → 0.40.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 (89) hide show
  1. package/README.md +27 -5
  2. package/dist/cjs/Router-B-Pev7K2.d.ts +46 -0
  3. package/dist/cjs/RouterValidator-mx2Zooya.d.ts +136 -0
  4. package/dist/cjs/api.d.ts +2 -1
  5. package/dist/cjs/api.js +1 -1
  6. package/dist/cjs/api.js.map +1 -1
  7. package/dist/cjs/index.d-y2b-8_3Y.d.ts +236 -0
  8. package/dist/cjs/index.d.ts +7 -24
  9. package/dist/cjs/index.js +1 -1
  10. package/dist/cjs/index.js.map +1 -1
  11. package/dist/cjs/metafile-cjs.json +1 -1
  12. package/dist/cjs/utils.d.ts +6 -1
  13. package/dist/cjs/utils.js +1 -1
  14. package/dist/cjs/utils.js.map +1 -1
  15. package/dist/cjs/validation.d.ts +184 -0
  16. package/dist/cjs/validation.js +1 -0
  17. package/dist/cjs/validation.js.map +1 -0
  18. package/dist/esm/Router-B-Pev7K2.d.mts +46 -0
  19. package/dist/esm/RouterValidator-mx2Zooya.d.mts +136 -0
  20. package/dist/esm/api.d.mts +2 -1
  21. package/dist/esm/api.mjs +1 -1
  22. package/dist/esm/api.mjs.map +1 -1
  23. package/dist/esm/chunk-5QXFUUDL.mjs +1 -0
  24. package/dist/esm/chunk-5QXFUUDL.mjs.map +1 -0
  25. package/dist/esm/chunk-HHIXK5UM.mjs +1 -0
  26. package/dist/esm/chunk-HHIXK5UM.mjs.map +1 -0
  27. package/dist/esm/chunk-QUUNDESP.mjs +1 -0
  28. package/dist/esm/chunk-QUUNDESP.mjs.map +1 -0
  29. package/dist/esm/chunk-RA5VYM7M.mjs +1 -0
  30. package/dist/esm/chunk-RA5VYM7M.mjs.map +1 -0
  31. package/dist/esm/index.d-y2b-8_3Y.d.mts +236 -0
  32. package/dist/esm/index.d.mts +7 -24
  33. package/dist/esm/index.mjs +1 -1
  34. package/dist/esm/metafile-esm.json +1 -1
  35. package/dist/esm/utils.d.mts +6 -1
  36. package/dist/esm/utils.mjs +1 -1
  37. package/dist/esm/utils.mjs.map +1 -1
  38. package/dist/esm/validation.d.mts +184 -0
  39. package/dist/esm/validation.mjs +1 -0
  40. package/dist/esm/validation.mjs.map +1 -0
  41. package/package.json +18 -5
  42. package/src/Router.ts +73 -99
  43. package/src/api/cloneRouter.ts +1 -30
  44. package/src/api/getDependenciesApi.ts +45 -86
  45. package/src/api/getLifecycleApi.ts +24 -19
  46. package/src/api/getPluginApi.ts +20 -28
  47. package/src/api/getRoutesApi.ts +49 -106
  48. package/src/constants.ts +0 -30
  49. package/src/guards.ts +46 -0
  50. package/src/helpers.ts +0 -17
  51. package/src/index.ts +4 -0
  52. package/src/internals.ts +6 -5
  53. package/src/namespaces/EventBusNamespace/EventBusNamespace.ts +2 -2
  54. package/src/namespaces/NavigationNamespace/NavigationNamespace.ts +0 -25
  55. package/src/namespaces/OptionsNamespace/OptionsNamespace.ts +4 -26
  56. package/src/namespaces/OptionsNamespace/constants.ts +0 -20
  57. package/src/namespaces/OptionsNamespace/index.ts +1 -5
  58. package/src/namespaces/OptionsNamespace/validators.ts +6 -245
  59. package/src/namespaces/PluginsNamespace/PluginsNamespace.ts +18 -59
  60. package/src/namespaces/PluginsNamespace/constants.ts +3 -6
  61. package/src/namespaces/PluginsNamespace/validators.ts +2 -57
  62. package/src/namespaces/RouteLifecycleNamespace/RouteLifecycleNamespace.ts +27 -84
  63. package/src/namespaces/RouterLifecycleNamespace/RouterLifecycleNamespace.ts +0 -16
  64. package/src/namespaces/RoutesNamespace/RoutesNamespace.ts +3 -12
  65. package/src/namespaces/RoutesNamespace/constants.ts +0 -8
  66. package/src/namespaces/RoutesNamespace/forwardChain.ts +34 -0
  67. package/src/namespaces/RoutesNamespace/index.ts +1 -1
  68. package/src/namespaces/RoutesNamespace/routeGuards.ts +62 -0
  69. package/src/namespaces/RoutesNamespace/routesStore.ts +7 -51
  70. package/src/namespaces/StateNamespace/StateNamespace.ts +0 -33
  71. package/src/namespaces/StateNamespace/helpers.ts +1 -1
  72. package/src/namespaces/index.ts +0 -3
  73. package/src/typeGuards.ts +1 -15
  74. package/src/types/RouterValidator.ts +155 -0
  75. package/src/utils/getStaticPaths.ts +50 -0
  76. package/src/utils/index.ts +4 -0
  77. package/src/validation.ts +12 -0
  78. package/src/wiring/RouterWiringBuilder.ts +32 -9
  79. package/dist/cjs/index.d-DDimDpYc.d.ts +0 -165
  80. package/dist/esm/chunk-CG7TKDP3.mjs +0 -1
  81. package/dist/esm/chunk-CG7TKDP3.mjs.map +0 -1
  82. package/dist/esm/index.d-DDimDpYc.d.mts +0 -165
  83. package/src/namespaces/DependenciesNamespace/validators.ts +0 -103
  84. package/src/namespaces/EventBusNamespace/validators.ts +0 -36
  85. package/src/namespaces/NavigationNamespace/validators.ts +0 -47
  86. package/src/namespaces/RouteLifecycleNamespace/validators.ts +0 -65
  87. package/src/namespaces/RoutesNamespace/forwardToValidation.ts +0 -408
  88. package/src/namespaces/RoutesNamespace/validators.ts +0 -566
  89. package/src/namespaces/StateNamespace/validators.ts +0 -46
@@ -1,165 +0,0 @@
1
- import { DefaultDependencies, Router as Router$1, Route, Options, Params, State, PluginFactory, Unsubscribe, SubscribeFn, NavigationOptions } from '@real-router/types';
2
-
3
- /**
4
- * Router class with integrated namespace architecture.
5
- *
6
- * All functionality is provided by namespace classes:
7
- * - OptionsNamespace: getOptions (immutable)
8
- * - DependenciesStore: get/set/remove dependencies
9
- * - EventEmitter: subscribe
10
- * - StateNamespace: state storage (getState, setState, getPreviousState)
11
- * - RoutesNamespace: route tree operations
12
- * - RouteLifecycleNamespace: canActivate/canDeactivate guards
13
- * - PluginsNamespace: plugin lifecycle
14
- * - NavigationNamespace: navigate
15
- * - RouterLifecycleNamespace: start, stop, isStarted
16
- *
17
- * @internal This class implementation is internal. Use createRouter() instead.
18
- */
19
- declare class Router<Dependencies extends DefaultDependencies = DefaultDependencies> implements Router$1<Dependencies> {
20
- #private;
21
- [key: string]: unknown;
22
- /**
23
- * @param routes - Route definitions
24
- * @param options - Router options
25
- * @param dependencies - DI dependencies
26
- */
27
- constructor(routes?: Route<Dependencies>[], options?: Partial<Options>, dependencies?: Dependencies);
28
- isActiveRoute(name: string, params?: Params, strictEquality?: boolean, ignoreQueryParams?: boolean): boolean;
29
- buildPath(route: string, params?: Params): string;
30
- getState<P extends Params = Params, MP extends Params = Params>(): State<P, MP> | undefined;
31
- getPreviousState(): State | undefined;
32
- areStatesEqual(state1: State | undefined, state2: State | undefined, ignoreQueryParams?: boolean): boolean;
33
- shouldUpdateNode(nodeName: string): (toState: State, fromState?: State) => boolean;
34
- isActive(): boolean;
35
- start(startPath: string): Promise<State>;
36
- stop(): this;
37
- dispose(): void;
38
- canNavigateTo(name: string, params?: Params): boolean;
39
- usePlugin(...plugins: PluginFactory<Dependencies>[]): Unsubscribe;
40
- subscribe(listener: SubscribeFn): Unsubscribe;
41
- navigate(routeName: string, routeParams?: Params, options?: NavigationOptions): Promise<State>;
42
- navigateToDefault(options?: NavigationOptions): Promise<State>;
43
- navigateToNotFound(path?: string): State;
44
- }
45
-
46
- /**
47
- * Path Matcher Type Definitions.
48
- *
49
- * Core types for path matching and parameter extraction.
50
- *
51
- * @module path-matcher/types
52
- */
53
- /**
54
- * Constraint pattern for a URL parameter.
55
- */
56
- interface ConstraintPattern {
57
- /**
58
- * Compiled RegExp for validating the parameter value.
59
- *
60
- * @example /^(\d+)$/ for constraint "<\\d+>"
61
- */
62
- readonly pattern: RegExp;
63
- /**
64
- * Raw constraint string from the route pattern.
65
- *
66
- * @example "<\\d+>"
67
- */
68
- readonly constraint: string;
69
- }
70
- /**
71
- * Parameter metadata extracted from a route path pattern.
72
- */
73
- interface ParamMeta {
74
- /**
75
- * URL parameter names extracted from the path pattern.
76
- *
77
- * @example [":id", ":postId"] from "/users/:id/posts/:postId"
78
- */
79
- readonly urlParams: readonly string[];
80
- /**
81
- * Query parameter names extracted from the path pattern.
82
- *
83
- * @example ["q", "page"] from "/search?q&page"
84
- */
85
- readonly queryParams: readonly string[];
86
- /**
87
- * Splat parameter names extracted from the path pattern.
88
- *
89
- * @example ["path"] from "/files/*path"
90
- */
91
- readonly spatParams: readonly string[];
92
- /**
93
- * Map of parameter names to their type (url or query).
94
- *
95
- * @example { id: "url", q: "query" }
96
- */
97
- readonly paramTypeMap: Readonly<Record<string, "url" | "query">>;
98
- /**
99
- * Map of parameter names to their constraint patterns.
100
- *
101
- * Only includes parameters with explicit constraints (e.g., `:id<\\d+>`).
102
- * Parameters without constraints are not included in this map.
103
- *
104
- * @example
105
- * ```typescript
106
- * buildParamMeta("/users/:id<\\d+>").constraintPatterns.get("id")
107
- * // → { pattern: /^(\d+)$/, constraint: "<\\d+>" }
108
- *
109
- * buildParamMeta("/users/:id").constraintPatterns.size
110
- * // → 0 (no constraints)
111
- * ```
112
- */
113
- readonly constraintPatterns: ReadonlyMap<string, ConstraintPattern>;
114
- /**
115
- * Path pattern without query string, pre-computed for buildPath.
116
- *
117
- * @example "/users/:id" from "/users/:id?q&page"
118
- */
119
- readonly pathPattern: string;
120
- }
121
-
122
- /**
123
- * Immutable route tree node.
124
- *
125
- * This is the core data structure of the new route-tree architecture.
126
- * It contains only data (no methods) and is created by the builder.
127
- *
128
- * All caches are pre-computed at build time:
129
- * - nonAbsoluteChildren: filtered children without absolute paths
130
- * - absoluteDescendants: all descendants with absolute paths (recursive)
131
- * - parentSegments: array from root to parent
132
- * - fullName: pre-computed "users.profile" instead of runtime join
133
- */
134
- interface RouteTree {
135
- /** Route segment name (e.g., "users" in "users.profile") */
136
- readonly name: string;
137
- /** Route path pattern (e.g., "/users/:id") */
138
- readonly path: string;
139
- /** Whether this route uses absolute path matching (path starts with "~") */
140
- readonly absolute: boolean;
141
- /** Child route nodes (Map for O(1) lookup by name) */
142
- readonly children: ReadonlyMap<string, RouteTree>;
143
- /** Parameter metadata extracted from path pattern (replaces parser dependency) */
144
- readonly paramMeta: ParamMeta;
145
- /** Parent node (null for root) */
146
- readonly parent: RouteTree | null;
147
- /** Children without absolute paths (for regular matching) */
148
- readonly nonAbsoluteChildren: readonly RouteTree[];
149
- /** Pre-computed full name (e.g., "users.profile") */
150
- readonly fullName: string;
151
- /**
152
- * Pre-computed static path for routes without parameters.
153
- * Used by buildPath fast path to avoid inject() overhead.
154
- * Only set when route has no URL params, query params, or splat params.
155
- */
156
- readonly staticPath: string | null;
157
- /**
158
- * Pre-computed parameter type map for this segment.
159
- * Cached to avoid recomputing on every navigation.
160
- * Maps param name → "url" | "query".
161
- */
162
- readonly paramTypeMap: Readonly<Record<string, "url" | "query">>;
163
- }
164
-
165
- export { Router as R, type RouteTree as a };
@@ -1,103 +0,0 @@
1
- // packages/core/src/namespaces/DependenciesNamespace/validators.ts
2
-
3
- /**
4
- * Static validation functions for dependencies.
5
- * Called by Router facade and getDependenciesApi before store operations.
6
- */
7
-
8
- import { getTypeDescription } from "type-guards";
9
-
10
- import { DEFAULT_LIMITS } from "../../constants";
11
-
12
- /**
13
- * Validates that dependency name is a string.
14
- * Called by facade before get/remove/has operations.
15
- */
16
- export function validateDependencyName(
17
- name: unknown,
18
- methodName: string,
19
- ): asserts name is string {
20
- if (typeof name !== "string") {
21
- throw new TypeError(
22
- `[router.${methodName}]: dependency name must be a string, got ${typeof name}`,
23
- );
24
- }
25
- }
26
-
27
- /**
28
- * Validates setDependency name argument.
29
- * Value is not validated - any value is valid.
30
- */
31
- export function validateSetDependencyArgs(
32
- name: unknown,
33
- ): asserts name is string {
34
- if (typeof name !== "string") {
35
- throw new TypeError(
36
- `[router.setDependency]: dependency name must be a string, got ${typeof name}`,
37
- );
38
- }
39
- }
40
-
41
- /**
42
- * Validates that dependencies object is a plain object without getters.
43
- * Called by facade before setMultiple/constructor.
44
- */
45
- export function validateDependenciesObject(
46
- deps: unknown,
47
- methodName: string,
48
- ): asserts deps is Record<string, unknown> {
49
- // Reject non-plain objects (classes, Date, Map, Array)
50
- if (!(deps && typeof deps === "object" && deps.constructor === Object)) {
51
- throw new TypeError(
52
- `[router.${methodName}] Invalid argument: expected plain object, received ${getTypeDescription(deps)}`,
53
- );
54
- }
55
-
56
- // Getters can throw, return different values, or have side effects
57
- for (const key in deps) {
58
- if (Object.getOwnPropertyDescriptor(deps, key)?.get) {
59
- throw new TypeError(
60
- `[router.${methodName}] Getters not allowed: "${key}"`,
61
- );
62
- }
63
- }
64
- }
65
-
66
- /**
67
- * Validates that dependency exists (not undefined).
68
- * Throws ReferenceError if dependency is not found.
69
- */
70
- export function validateDependencyExists(
71
- value: unknown,
72
- dependencyName: string,
73
- ): asserts value is NonNullable<unknown> {
74
- if (value === undefined) {
75
- throw new ReferenceError(
76
- `[router.getDependency]: dependency "${dependencyName}" not found`,
77
- );
78
- }
79
- }
80
-
81
- /**
82
- * Validates that adding dependencies won't exceed the hard limit.
83
- * Called before bulk operations to ensure atomicity.
84
- */
85
- export function validateDependencyLimit(
86
- currentCount: number,
87
- newCount: number,
88
- methodName: string,
89
- maxDependencies: number = DEFAULT_LIMITS.maxDependencies,
90
- ): void {
91
- if (maxDependencies === 0) {
92
- return;
93
- }
94
-
95
- const totalCount = currentCount + newCount;
96
-
97
- if (totalCount >= maxDependencies) {
98
- throw new Error(
99
- `[router.${methodName}] Dependency limit exceeded (${maxDependencies}). ` +
100
- `Current: ${totalCount}. This is likely a bug in your code.`,
101
- );
102
- }
103
- }
@@ -1,36 +0,0 @@
1
- // packages/core/src/namespaces/EventBusNamespace/validators.ts
2
-
3
- /**
4
- * Static validation functions for EventBusNamespace.
5
- * Called by Router facade before instance methods.
6
- */
7
-
8
- import { validEventNames } from "../../constants";
9
-
10
- import type { EventMethodMap } from "../../types";
11
- import type { EventName, Plugin } from "@real-router/types";
12
-
13
- /**
14
- * Validates event name is one of the known event names.
15
- */
16
- export function validateEventName(eventName: unknown): void {
17
- if (!validEventNames.has(eventName as EventName)) {
18
- throw new Error(`Invalid event name: ${String(eventName)}`);
19
- }
20
- }
21
-
22
- /**
23
- * Validates addEventListener arguments (event name + callback).
24
- */
25
- export function validateListenerArgs<E extends EventName>(
26
- eventName: E,
27
- cb: Plugin[EventMethodMap[E]],
28
- ): void {
29
- validateEventName(eventName);
30
-
31
- if (typeof cb !== "function") {
32
- throw new TypeError(
33
- `Expected callback to be a function for event ${eventName}`,
34
- );
35
- }
36
- }
@@ -1,47 +0,0 @@
1
- // packages/core/src/namespaces/NavigationNamespace/validators.ts
2
-
3
- /**
4
- * Static validation functions for NavigationNamespace.
5
- * Called by Router facade before instance methods.
6
- */
7
-
8
- import { getTypeDescription, isNavigationOptions } from "type-guards";
9
-
10
- import type { NavigationOptions } from "@real-router/types";
11
-
12
- /**
13
- * Validates navigate route name argument.
14
- */
15
- export function validateNavigateArgs(name: unknown): asserts name is string {
16
- if (typeof name !== "string") {
17
- throw new TypeError(
18
- `[router.navigate] Invalid route name: expected string, got ${getTypeDescription(name)}`,
19
- );
20
- }
21
- }
22
-
23
- /**
24
- * Validates navigateToDefault arguments.
25
- */
26
- export function validateNavigateToDefaultArgs(opts: unknown): void {
27
- // If opts is provided, it must be an object (NavigationOptions)
28
- if (opts !== undefined && (typeof opts !== "object" || opts === null)) {
29
- throw new TypeError(
30
- `[router.navigateToDefault] Invalid options: ${getTypeDescription(opts)}. Expected NavigationOptions object.`,
31
- );
32
- }
33
- }
34
-
35
- /**
36
- * Validates that opts is a valid NavigationOptions object.
37
- */
38
- export function validateNavigationOptions(
39
- opts: unknown,
40
- methodName: string,
41
- ): asserts opts is NavigationOptions {
42
- if (!isNavigationOptions(opts)) {
43
- throw new TypeError(
44
- `[router.${methodName}] Invalid options: ${getTypeDescription(opts)}. Expected NavigationOptions object.`,
45
- );
46
- }
47
- }
@@ -1,65 +0,0 @@
1
- // packages/core/src/namespaces/RouteLifecycleNamespace/validators.ts
2
-
3
- /**
4
- * Static validation functions for RouteLifecycleNamespace.
5
- * Called by Router facade before instance methods.
6
- */
7
-
8
- import { isBoolean, getTypeDescription } from "type-guards";
9
-
10
- import { DEFAULT_LIMITS } from "../../constants";
11
-
12
- import type { GuardFnFactory } from "../../types";
13
- import type { DefaultDependencies } from "@real-router/types";
14
-
15
- /**
16
- * Validates that a handler is either a boolean or a factory function.
17
- */
18
- export function validateHandler<D extends DefaultDependencies>(
19
- handler: unknown,
20
- methodName: string,
21
- ): asserts handler is GuardFnFactory<D> | boolean {
22
- if (!isBoolean(handler) && typeof handler !== "function") {
23
- throw new TypeError(
24
- `[router.${methodName}] Handler must be a boolean or factory function, ` +
25
- `got ${getTypeDescription(handler)}`,
26
- );
27
- }
28
- }
29
-
30
- /**
31
- * Validates that a route is not currently being registered.
32
- * Prevents self-modification during factory compilation.
33
- */
34
- export function validateNotRegistering(
35
- isRegistering: boolean,
36
- name: string,
37
- methodName: string,
38
- ): void {
39
- if (isRegistering) {
40
- throw new Error(
41
- `[router.${methodName}] Cannot modify route "${name}" during its own registration`,
42
- );
43
- }
44
- }
45
-
46
- /**
47
- * Validates that adding a new handler won't exceed the hard limit.
48
- */
49
- export function validateHandlerLimit(
50
- currentCount: number,
51
- methodName: string,
52
- maxLifecycleHandlers: number = DEFAULT_LIMITS.maxLifecycleHandlers,
53
- ): void {
54
- if (maxLifecycleHandlers === 0) {
55
- return;
56
- }
57
-
58
- if (currentCount >= maxLifecycleHandlers) {
59
- throw new Error(
60
- `[router.${methodName}] Lifecycle handler limit exceeded (${maxLifecycleHandlers}). ` +
61
- `This indicates too many routes with individual handlers. ` +
62
- `Consider using plugins for cross-cutting concerns.`,
63
- );
64
- }
65
- }