@native-router/core 1.9.0 → 1.9.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/README.md +2 -0
- package/dist/index.cjs +10 -5
- package/dist/index.mjs +10 -5
- package/dist/types/types.d.ts +18 -4
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -141,6 +141,8 @@ const router = create(
|
|
|
141
141
|
|
|
142
142
|
- No `params` schema → behavior unchanged: the raw string map flows through
|
|
143
143
|
- The parse runs per level (shallow → deep): a level's schema validates the params merged up to it; a deeper schema sees the (possibly coerced) output of the shallower ones
|
|
144
|
+
- A `redirect` level skips its params schema entirely — the level's guard never runs, so there is nothing to hand coerced params to; the same asymmetry the search schema has (`redirect` wins over `beforeLoad`). Hanging a params schema on a redirect level is inert, it cannot fail the navigation
|
|
145
|
+
- A same-name param on both a parent and a child segment (`/users/:id/files/:id`): the deep-over-shallow merge operates on the **raw** strings, so the child segment's value overwrites the parent's coerced one — a child guard sees the raw string again. Declare the coercing schema on (or below) the deepest level that reads the param — a deeper schema validates the whole merged map anyway — or avoid reusing a param name across levels
|
|
144
146
|
- A rejected validation fails the resolution through the `errorHandler` channel with a `ParamsError` (a `NativeRouterError`) carrying the raw `params` and the reported `issues` — the same route a search-schema failure takes
|
|
145
147
|
- `parseParams`/`parseParamsSync` are exported for custom `resolveView` implementations (the async/sync flavors mirror `parseSearch`/`parseSearchSync`)
|
|
146
148
|
|
package/dist/index.cjs
CHANGED
|
@@ -528,11 +528,16 @@ async function resolveEntry(router, location, opts) {
|
|
|
528
528
|
...matched[i].params
|
|
529
529
|
};
|
|
530
530
|
// The level's params schema runs before its guard, so the guard
|
|
531
|
-
// sees the coerced output. A
|
|
532
|
-
//
|
|
533
|
-
//
|
|
534
|
-
//
|
|
535
|
-
|
|
531
|
+
// sees the coerced output. A redirect level never runs its guard,
|
|
532
|
+
// so its schema is skipped — the same asymmetry the level's
|
|
533
|
+
// search schema already has(`redirect` wins over `beforeLoad`):
|
|
534
|
+
// hanging a params schema on a redirect level must not be able to
|
|
535
|
+
// fail the navigation, its only observable effect would be the
|
|
536
|
+
// failure. A validation failure fails the resolution through the
|
|
537
|
+
// task's errorHandler channel — the same route a search-schema
|
|
538
|
+
// failure takes — instead of rejecting this entry, which preload
|
|
539
|
+
// consumers share.
|
|
540
|
+
if (route.params && !route.redirect) {
|
|
536
541
|
try {
|
|
537
542
|
// eslint-disable-next-line no-await-in-loop -- guards must run in declaration order, sequentially
|
|
538
543
|
params = await parseParams(route.params, params);
|
package/dist/index.mjs
CHANGED
|
@@ -526,11 +526,16 @@ async function resolveEntry(router, location, opts) {
|
|
|
526
526
|
...matched[i].params
|
|
527
527
|
};
|
|
528
528
|
// The level's params schema runs before its guard, so the guard
|
|
529
|
-
// sees the coerced output. A
|
|
530
|
-
//
|
|
531
|
-
//
|
|
532
|
-
//
|
|
533
|
-
|
|
529
|
+
// sees the coerced output. A redirect level never runs its guard,
|
|
530
|
+
// so its schema is skipped — the same asymmetry the level's
|
|
531
|
+
// search schema already has(`redirect` wins over `beforeLoad`):
|
|
532
|
+
// hanging a params schema on a redirect level must not be able to
|
|
533
|
+
// fail the navigation, its only observable effect would be the
|
|
534
|
+
// failure. A validation failure fails the resolution through the
|
|
535
|
+
// task's errorHandler channel — the same route a search-schema
|
|
536
|
+
// failure takes — instead of rejecting this entry, which preload
|
|
537
|
+
// consumers share.
|
|
538
|
+
if (route.params && !route.redirect) {
|
|
534
539
|
try {
|
|
535
540
|
// eslint-disable-next-line no-await-in-loop -- guards must run in declaration order, sequentially
|
|
536
541
|
params = await parseParams(route.params, params);
|
package/dist/types/types.d.ts
CHANGED
|
@@ -142,8 +142,16 @@ export type ExtractPathParams<P extends string> = P extends `${infer Head}/${inf
|
|
|
142
142
|
* Context passed to a route guard({@link BaseRoute.beforeLoad beforeLoad}).
|
|
143
143
|
* `params` are accumulated from the root level down to the level that
|
|
144
144
|
* owns the guard, so a guard only sees params of itself and its parents.
|
|
145
|
+
*
|
|
146
|
+
* Type arguments: `S` types {@link GuardContext.search search}(schema
|
|
147
|
+
* output, or the degraded input without a schema), `P` types
|
|
148
|
+
* {@link GuardContext.params params}. Both default to what a
|
|
149
|
+
* schema-less route produces — `search: unknown`, `params: the raw
|
|
150
|
+
* string map` — so plain guards keep compiling unchanged; thread a
|
|
151
|
+
* params schema's coerced output through `P` to type what the guard
|
|
152
|
+
* actually receives at runtime.
|
|
145
153
|
*/
|
|
146
|
-
export type GuardContext<R extends BaseRoute = BaseRoute, S = unknown
|
|
154
|
+
export type GuardContext<R extends BaseRoute = BaseRoute, S = unknown, P = Record<string, string>> = {
|
|
147
155
|
router: RouterInstance<R>;
|
|
148
156
|
location: Location;
|
|
149
157
|
/**
|
|
@@ -151,9 +159,13 @@ export type GuardContext<R extends BaseRoute = BaseRoute, S = unknown> = {
|
|
|
151
159
|
* declares a {@link BaseRoute.params params schema}, the merged raw
|
|
152
160
|
* params are parsed through the deepest matching schema before the
|
|
153
161
|
* guard runs; without schemas the raw string map the matcher
|
|
154
|
-
* extracted.
|
|
162
|
+
* extracted. The loose default models the raw map; give the third
|
|
163
|
+
* type argument the schema's output(`GuardContext<R, S, {id: number}>`
|
|
164
|
+
* for a `z.coerce.number()` id) — the runtime value is the parse
|
|
165
|
+
* result, which a coercing schema makes anything but
|
|
166
|
+
* `Record<string, string>`.
|
|
155
167
|
*/
|
|
156
|
-
params:
|
|
168
|
+
params: P;
|
|
157
169
|
/**
|
|
158
170
|
* The search the guard sees: the route's {@link BaseRoute.search search
|
|
159
171
|
* schema} output(parsed and validated before the guard runs), or the
|
|
@@ -193,7 +205,9 @@ export type BaseRoute<T = any> = {
|
|
|
193
205
|
* runs it in {@link resolveEntry} after matching and before the level's
|
|
194
206
|
* `beforeLoad`, so guards and loaders see coerced params(e.g. `:id`
|
|
195
207
|
* as a number) instead of raw strings; a validation failure fails the
|
|
196
|
-
* resolve like any other navigation error(via `ParamsError`).
|
|
208
|
+
* resolve like any other navigation error(via `ParamsError`). A level
|
|
209
|
+
* with a {@link BaseRoute.redirect redirect} skips the schema — the
|
|
210
|
+
* guard never runs there, so the schema would have no consumer.
|
|
197
211
|
*
|
|
198
212
|
* Omit it and the params stay the raw `Record<string, string>` the
|
|
199
213
|
* matcher extracted — behavior is unchanged.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@native-router/core",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.1",
|
|
4
4
|
"exports": {
|
|
5
5
|
".": {
|
|
6
6
|
"types": "./dist/types/index.d.ts",
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"lint": "eslint --fix src test *.js",
|
|
35
35
|
"doc:gen": "typedoc",
|
|
36
36
|
"deploy": "npm run doc:gen && gh-pages -d dist",
|
|
37
|
-
"test": "vitest run"
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"typecheck": "tsc -p tsconfig.test.json --noEmit"
|
|
38
39
|
},
|
|
39
40
|
"repository": {
|
|
40
41
|
"type": "git",
|