@remix-run/router 1.3.3 → 1.4.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/CHANGELOG.md +66 -0
- package/dist/history.d.ts +1 -0
- package/dist/index.d.ts +4 -3
- package/dist/router.cjs.js +220 -90
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.d.ts +6 -3
- package/dist/router.js +216 -90
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +220 -90
- package/dist/router.umd.js.map +1 -1
- package/dist/router.umd.min.js +2 -2
- package/dist/router.umd.min.js.map +1 -1
- package/dist/utils.d.ts +25 -6
- package/history.ts +1 -1
- package/index.ts +6 -2
- package/package.json +1 -1
- package/router.ts +239 -30
- package/utils.ts +102 -69
package/utils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Location, Path, To } from "./history";
|
|
2
|
-
import { invariant, parsePath } from "./history";
|
|
2
|
+
import { warning, invariant, parsePath } from "./history";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Map of routeId -> data returned from a loader/action/error
|
|
@@ -139,6 +139,44 @@ export interface ShouldRevalidateFunction {
|
|
|
139
139
|
}): boolean;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
+
/**
|
|
143
|
+
* Function provided by the framework-aware layers to set `hasErrorBoundary`
|
|
144
|
+
* from the framework-aware `errorElement` prop
|
|
145
|
+
*/
|
|
146
|
+
export interface DetectErrorBoundaryFunction {
|
|
147
|
+
(route: AgnosticRouteObject): boolean;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Keys we cannot change from within a lazy() function. We spread all other keys
|
|
152
|
+
* onto the route. Either they're meaningful to the router, or they'll get
|
|
153
|
+
* ignored.
|
|
154
|
+
*/
|
|
155
|
+
export type ImmutableRouteKey =
|
|
156
|
+
| "lazy"
|
|
157
|
+
| "caseSensitive"
|
|
158
|
+
| "path"
|
|
159
|
+
| "id"
|
|
160
|
+
| "index"
|
|
161
|
+
| "children";
|
|
162
|
+
|
|
163
|
+
export const immutableRouteKeys = new Set<ImmutableRouteKey>([
|
|
164
|
+
"lazy",
|
|
165
|
+
"caseSensitive",
|
|
166
|
+
"path",
|
|
167
|
+
"id",
|
|
168
|
+
"index",
|
|
169
|
+
"children",
|
|
170
|
+
]);
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* lazy() function to load a route definition, which can add non-matching
|
|
174
|
+
* related properties to a route
|
|
175
|
+
*/
|
|
176
|
+
export interface LazyRouteFunction<R extends AgnosticRouteObject> {
|
|
177
|
+
(): Promise<Omit<R, ImmutableRouteKey>>;
|
|
178
|
+
}
|
|
179
|
+
|
|
142
180
|
/**
|
|
143
181
|
* Base RouteObject with common props shared by all types of routes
|
|
144
182
|
*/
|
|
@@ -151,6 +189,7 @@ type AgnosticBaseRouteObject = {
|
|
|
151
189
|
hasErrorBoundary?: boolean;
|
|
152
190
|
shouldRevalidate?: ShouldRevalidateFunction;
|
|
153
191
|
handle?: any;
|
|
192
|
+
lazy?: LazyRouteFunction<AgnosticBaseRouteObject>;
|
|
154
193
|
};
|
|
155
194
|
|
|
156
195
|
/**
|
|
@@ -193,6 +232,8 @@ export type AgnosticDataRouteObject =
|
|
|
193
232
|
| AgnosticDataIndexRouteObject
|
|
194
233
|
| AgnosticDataNonIndexRouteObject;
|
|
195
234
|
|
|
235
|
+
export type RouteManifest = Record<string, AgnosticDataRouteObject | undefined>;
|
|
236
|
+
|
|
196
237
|
// Recursive helper for finding path parameters in the absence of wildcards
|
|
197
238
|
type _PathParam<Path extends string> =
|
|
198
239
|
// split path into individual path segments
|
|
@@ -217,7 +258,7 @@ type _PathParam<Path extends string> =
|
|
|
217
258
|
*/
|
|
218
259
|
type PathParam<Path extends string> =
|
|
219
260
|
// check if path is just a wildcard
|
|
220
|
-
Path extends "*"
|
|
261
|
+
Path extends "*" | "/*"
|
|
221
262
|
? "*"
|
|
222
263
|
: // look for wildcard at the end of the path
|
|
223
264
|
Path extends `${infer Rest}/*`
|
|
@@ -277,8 +318,9 @@ function isIndexRoute(
|
|
|
277
318
|
// solely with AgnosticDataRouteObject's within the Router
|
|
278
319
|
export function convertRoutesToDataRoutes(
|
|
279
320
|
routes: AgnosticRouteObject[],
|
|
321
|
+
detectErrorBoundary: DetectErrorBoundaryFunction,
|
|
280
322
|
parentPath: number[] = [],
|
|
281
|
-
|
|
323
|
+
manifest: RouteManifest = {}
|
|
282
324
|
): AgnosticDataRouteObject[] {
|
|
283
325
|
return routes.map((route, index) => {
|
|
284
326
|
let treePath = [...parentPath, index];
|
|
@@ -288,23 +330,37 @@ export function convertRoutesToDataRoutes(
|
|
|
288
330
|
`Cannot specify children on an index route`
|
|
289
331
|
);
|
|
290
332
|
invariant(
|
|
291
|
-
!
|
|
333
|
+
!manifest[id],
|
|
292
334
|
`Found a route id collision on id "${id}". Route ` +
|
|
293
335
|
"id's must be globally unique within Data Router usages"
|
|
294
336
|
);
|
|
295
|
-
allIds.add(id);
|
|
296
337
|
|
|
297
338
|
if (isIndexRoute(route)) {
|
|
298
|
-
let indexRoute: AgnosticDataIndexRouteObject = {
|
|
339
|
+
let indexRoute: AgnosticDataIndexRouteObject = {
|
|
340
|
+
...route,
|
|
341
|
+
hasErrorBoundary: detectErrorBoundary(route),
|
|
342
|
+
id,
|
|
343
|
+
};
|
|
344
|
+
manifest[id] = indexRoute;
|
|
299
345
|
return indexRoute;
|
|
300
346
|
} else {
|
|
301
347
|
let pathOrLayoutRoute: AgnosticDataNonIndexRouteObject = {
|
|
302
348
|
...route,
|
|
303
349
|
id,
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
: undefined,
|
|
350
|
+
hasErrorBoundary: detectErrorBoundary(route),
|
|
351
|
+
children: undefined,
|
|
307
352
|
};
|
|
353
|
+
manifest[id] = pathOrLayoutRoute;
|
|
354
|
+
|
|
355
|
+
if (route.children) {
|
|
356
|
+
pathOrLayoutRoute.children = convertRoutesToDataRoutes(
|
|
357
|
+
route.children,
|
|
358
|
+
detectErrorBoundary,
|
|
359
|
+
treePath,
|
|
360
|
+
manifest
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
|
|
308
364
|
return pathOrLayoutRoute;
|
|
309
365
|
}
|
|
310
366
|
});
|
|
@@ -621,7 +677,7 @@ export function generatePath<Path extends string>(
|
|
|
621
677
|
[key in PathParam<Path>]: string | null;
|
|
622
678
|
} = {} as any
|
|
623
679
|
): string {
|
|
624
|
-
let path = originalPath;
|
|
680
|
+
let path: string = originalPath;
|
|
625
681
|
if (path.endsWith("*") && path !== "*" && !path.endsWith("/*")) {
|
|
626
682
|
warning(
|
|
627
683
|
false,
|
|
@@ -633,49 +689,46 @@ export function generatePath<Path extends string>(
|
|
|
633
689
|
path = path.replace(/\*$/, "/*") as Path;
|
|
634
690
|
}
|
|
635
691
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
invariant(false, `Missing ":${key}" param`);
|
|
647
|
-
}
|
|
648
|
-
return param;
|
|
649
|
-
}
|
|
650
|
-
)
|
|
651
|
-
.replace(
|
|
652
|
-
/\/:(\w+)(\??)/g,
|
|
653
|
-
(_, key: PathParam<Path>, optional: string | undefined) => {
|
|
654
|
-
let param = params[key];
|
|
655
|
-
if (optional === "?") {
|
|
656
|
-
return param == null ? "" : `/${param}`;
|
|
657
|
-
}
|
|
658
|
-
if (param == null) {
|
|
659
|
-
invariant(false, `Missing ":${key}" param`);
|
|
660
|
-
}
|
|
661
|
-
return `/${param}`;
|
|
662
|
-
}
|
|
663
|
-
)
|
|
664
|
-
// Remove any optional markers from optional static segments
|
|
665
|
-
.replace(/\?/g, "")
|
|
666
|
-
.replace(/(\/?)\*/, (_, prefix, __, str) => {
|
|
692
|
+
// ensure `/` is added at the beginning if the path is absolute
|
|
693
|
+
const prefix = path.startsWith("/") ? "/" : "";
|
|
694
|
+
|
|
695
|
+
const segments = path
|
|
696
|
+
.split(/\/+/)
|
|
697
|
+
.map((segment, index, array) => {
|
|
698
|
+
const isLastSegment = index === array.length - 1;
|
|
699
|
+
|
|
700
|
+
// only apply the splat if it's the last segment
|
|
701
|
+
if (isLastSegment && segment === "*") {
|
|
667
702
|
const star = "*" as PathParam<Path>;
|
|
703
|
+
const starParam = params[star];
|
|
704
|
+
|
|
705
|
+
// Apply the splat
|
|
706
|
+
return starParam;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
const keyMatch = segment.match(/^:(\w+)(\??)$/);
|
|
710
|
+
if (keyMatch) {
|
|
711
|
+
const [, key, optional] = keyMatch;
|
|
712
|
+
let param = params[key as PathParam<Path>];
|
|
668
713
|
|
|
669
|
-
if (
|
|
670
|
-
|
|
671
|
-
// the entire path
|
|
672
|
-
return str === "/*" ? "/" : "";
|
|
714
|
+
if (optional === "?") {
|
|
715
|
+
return param == null ? "" : param;
|
|
673
716
|
}
|
|
674
717
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
718
|
+
if (param == null) {
|
|
719
|
+
invariant(false, `Missing ":${key}" param`);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
return param;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// Remove any optional markers from optional static segments
|
|
726
|
+
return segment.replace(/\?$/g, "");
|
|
727
|
+
})
|
|
728
|
+
// Remove empty segments
|
|
729
|
+
.filter((segment) => !!segment);
|
|
730
|
+
|
|
731
|
+
return prefix + segments.join("/");
|
|
679
732
|
}
|
|
680
733
|
|
|
681
734
|
/**
|
|
@@ -891,26 +944,6 @@ export function stripBasename(
|
|
|
891
944
|
return pathname.slice(startIndex) || "/";
|
|
892
945
|
}
|
|
893
946
|
|
|
894
|
-
/**
|
|
895
|
-
* @private
|
|
896
|
-
*/
|
|
897
|
-
export function warning(cond: any, message: string): void {
|
|
898
|
-
if (!cond) {
|
|
899
|
-
// eslint-disable-next-line no-console
|
|
900
|
-
if (typeof console !== "undefined") console.warn(message);
|
|
901
|
-
|
|
902
|
-
try {
|
|
903
|
-
// Welcome to debugging @remix-run/router!
|
|
904
|
-
//
|
|
905
|
-
// This error is thrown as a convenience so you can more easily
|
|
906
|
-
// find the source for a warning that appears in the console by
|
|
907
|
-
// enabling "pause on exceptions" in your JavaScript debugger.
|
|
908
|
-
throw new Error(message);
|
|
909
|
-
// eslint-disable-next-line no-empty
|
|
910
|
-
} catch (e) {}
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
|
|
914
947
|
/**
|
|
915
948
|
* Returns a resolved path object relative to the given pathname.
|
|
916
949
|
*
|