react-router 8.3.0 → 8.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 +46 -2
- package/dist/development/dom-export.js +1 -1
- package/dist/development/index-react-server-client.js +1 -1
- package/dist/development/index-react-server.d.ts +50 -48
- package/dist/development/index-react-server.js +96 -43
- package/dist/development/index.d.ts +2 -2
- package/dist/development/index.js +3 -3
- package/dist/development/lib/actions.js +10 -5
- package/dist/development/lib/components.js +50 -10
- package/dist/development/lib/context.d.ts +14 -5
- package/dist/development/lib/context.js +11 -3
- package/dist/development/lib/dom/dom.js +2 -2
- package/dist/development/lib/dom/lib.js +33 -36
- package/dist/development/lib/dom/server.d.ts +6 -1
- package/dist/development/lib/dom/server.js +40 -14
- package/dist/development/lib/dom/ssr/components.js +16 -24
- package/dist/development/lib/dom/ssr/data.js +1 -1
- package/dist/development/lib/dom/ssr/entry.d.ts +4 -0
- package/dist/development/lib/dom/ssr/errorBoundaries.js +1 -1
- package/dist/development/lib/dom/ssr/fallback.js +1 -1
- package/dist/development/lib/dom/ssr/fog-of-war.js +34 -12
- package/dist/development/lib/dom/ssr/hydration.d.ts +3 -1
- package/dist/development/lib/dom/ssr/hydration.js +6 -4
- package/dist/development/lib/dom/ssr/invariant.js +1 -1
- package/dist/development/lib/dom/ssr/links.js +1 -1
- package/dist/development/lib/dom/ssr/markup.js +5 -2
- package/dist/development/lib/dom/ssr/routeModules.js +1 -1
- package/dist/development/lib/dom/ssr/routes-test-stub.js +1 -1
- package/dist/development/lib/dom/ssr/routes.js +1 -1
- package/dist/development/lib/dom/ssr/server.js +2 -2
- package/dist/development/lib/dom/ssr/single-fetch.js +13 -22
- package/dist/development/lib/dom-export/dom-router-provider.js +1 -1
- package/dist/development/lib/dom-export/hydrated-router.js +2 -1
- package/dist/development/lib/errors.js +1 -1
- package/dist/development/lib/hooks.js +54 -46
- package/dist/development/lib/href.js +1 -1
- package/dist/development/lib/router/history.js +2 -2
- package/dist/development/lib/router/instrumentation.js +1 -1
- package/dist/development/lib/router/matcher-route-pattern.d.ts +2 -0
- package/dist/development/lib/router/matcher-route-pattern.js +216 -0
- package/dist/development/lib/router/matcher-route-pattern.preload.d.ts +20 -0
- package/dist/development/lib/router/matcher-route-pattern.preload.js +36 -0
- package/dist/development/lib/router/matcher.d.ts +2 -0
- package/dist/development/lib/router/matcher.js +29 -0
- package/dist/development/lib/router/navigation.js +45 -0
- package/dist/development/lib/router/router.d.ts +21 -7
- package/dist/development/lib/router/router.js +111 -82
- package/dist/development/lib/router/url.js +1 -1
- package/dist/development/lib/router/utils.d.ts +6 -1
- package/dist/development/lib/router/utils.js +15 -9
- package/dist/development/lib/rsc/browser.js +5 -1
- package/dist/development/lib/rsc/errorBoundaries.js +1 -1
- package/dist/development/lib/rsc/html-stream/browser.js +1 -1
- package/dist/development/lib/rsc/html-stream/server.js +3 -5
- package/dist/development/lib/rsc/route-modules.js +1 -1
- package/dist/development/lib/rsc/server.rsc.d.ts +7 -0
- package/dist/development/lib/rsc/server.ssr.js +26 -22
- package/dist/development/lib/server-runtime/cookies.js +2 -2
- package/dist/development/lib/server-runtime/crypto.js +2 -2
- package/dist/development/lib/server-runtime/data.js +1 -1
- package/dist/development/lib/server-runtime/dev.js +2 -2
- package/dist/development/lib/server-runtime/entry.js +1 -1
- package/dist/development/lib/server-runtime/errors.js +1 -1
- package/dist/development/lib/server-runtime/headers.js +1 -1
- package/dist/development/lib/server-runtime/invariant.js +1 -1
- package/dist/development/lib/server-runtime/mode.js +1 -1
- package/dist/development/lib/server-runtime/routeMatching.js +3 -4
- package/dist/development/lib/server-runtime/routes.js +1 -1
- package/dist/development/lib/server-runtime/server.js +8 -7
- package/dist/development/lib/server-runtime/serverHandoff.js +1 -1
- package/dist/development/lib/server-runtime/sessions/cookieStorage.js +1 -1
- package/dist/development/lib/server-runtime/sessions/memoryStorage.js +1 -1
- package/dist/development/lib/server-runtime/sessions.js +1 -1
- package/dist/development/lib/server-runtime/single-fetch.js +2 -2
- package/dist/development/lib/server-runtime/urls.js +1 -1
- package/dist/development/lib/server-runtime/warnings.js +1 -1
- package/dist/development/lib/types/internal.js +1 -1
- package/dist/development/route-pattern.d.ts +3 -0
- package/dist/development/route-pattern.js +12 -0
- package/dist/development/vendor/turbo-stream-v2/flatten.js +1 -1
- package/dist/development/vendor/turbo-stream-v2/turbo-stream.js +4 -4
- package/dist/development/vendor/turbo-stream-v2/unflatten.js +1 -1
- package/dist/development/vendor/turbo-stream-v2/utils.js +1 -1
- package/dist/production/dom-export.js +1 -1
- package/dist/production/index-react-server-client.js +1 -1
- package/dist/production/index-react-server.d.ts +50 -48
- package/dist/production/index-react-server.js +96 -43
- package/dist/production/index.d.ts +2 -2
- package/dist/production/index.js +3 -3
- package/dist/production/lib/actions.js +10 -5
- package/dist/production/lib/components.js +50 -10
- package/dist/production/lib/context.d.ts +14 -5
- package/dist/production/lib/context.js +11 -3
- package/dist/production/lib/dom/dom.js +2 -2
- package/dist/production/lib/dom/lib.js +33 -36
- package/dist/production/lib/dom/server.d.ts +6 -1
- package/dist/production/lib/dom/server.js +40 -14
- package/dist/production/lib/dom/ssr/components.js +16 -24
- package/dist/production/lib/dom/ssr/data.js +1 -1
- package/dist/production/lib/dom/ssr/entry.d.ts +4 -0
- package/dist/production/lib/dom/ssr/errorBoundaries.js +1 -1
- package/dist/production/lib/dom/ssr/fallback.js +1 -1
- package/dist/production/lib/dom/ssr/fog-of-war.js +34 -12
- package/dist/production/lib/dom/ssr/hydration.d.ts +3 -1
- package/dist/production/lib/dom/ssr/hydration.js +6 -4
- package/dist/production/lib/dom/ssr/invariant.js +1 -1
- package/dist/production/lib/dom/ssr/links.js +1 -1
- package/dist/production/lib/dom/ssr/markup.js +5 -2
- package/dist/production/lib/dom/ssr/routeModules.js +1 -1
- package/dist/production/lib/dom/ssr/routes-test-stub.js +1 -1
- package/dist/production/lib/dom/ssr/routes.js +1 -1
- package/dist/production/lib/dom/ssr/server.js +2 -2
- package/dist/production/lib/dom/ssr/single-fetch.js +13 -22
- package/dist/production/lib/dom-export/dom-router-provider.js +1 -1
- package/dist/production/lib/dom-export/hydrated-router.js +2 -1
- package/dist/production/lib/errors.js +1 -1
- package/dist/production/lib/hooks.js +54 -46
- package/dist/production/lib/href.js +1 -1
- package/dist/production/lib/router/history.js +2 -2
- package/dist/production/lib/router/instrumentation.js +1 -1
- package/dist/production/lib/router/matcher-route-pattern.d.ts +2 -0
- package/dist/production/lib/router/matcher-route-pattern.js +216 -0
- package/dist/production/lib/router/matcher-route-pattern.preload.d.ts +20 -0
- package/dist/production/lib/router/matcher-route-pattern.preload.js +36 -0
- package/dist/production/lib/router/matcher.d.ts +2 -0
- package/dist/production/lib/router/matcher.js +29 -0
- package/dist/production/lib/router/navigation.js +45 -0
- package/dist/production/lib/router/router.d.ts +21 -7
- package/dist/production/lib/router/router.js +111 -82
- package/dist/production/lib/router/url.js +1 -1
- package/dist/production/lib/router/utils.d.ts +6 -1
- package/dist/production/lib/router/utils.js +15 -9
- package/dist/production/lib/rsc/browser.js +5 -1
- package/dist/production/lib/rsc/errorBoundaries.js +1 -1
- package/dist/production/lib/rsc/html-stream/browser.js +1 -1
- package/dist/production/lib/rsc/html-stream/server.js +3 -5
- package/dist/production/lib/rsc/route-modules.js +1 -1
- package/dist/production/lib/rsc/server.rsc.d.ts +7 -0
- package/dist/production/lib/rsc/server.ssr.js +26 -22
- package/dist/production/lib/server-runtime/cookies.js +2 -2
- package/dist/production/lib/server-runtime/crypto.js +2 -2
- package/dist/production/lib/server-runtime/data.js +1 -1
- package/dist/production/lib/server-runtime/dev.js +2 -2
- package/dist/production/lib/server-runtime/entry.js +1 -1
- package/dist/production/lib/server-runtime/errors.js +1 -1
- package/dist/production/lib/server-runtime/headers.js +1 -1
- package/dist/production/lib/server-runtime/invariant.js +1 -1
- package/dist/production/lib/server-runtime/mode.js +1 -1
- package/dist/production/lib/server-runtime/routeMatching.js +3 -4
- package/dist/production/lib/server-runtime/routes.js +1 -1
- package/dist/production/lib/server-runtime/server.js +8 -7
- package/dist/production/lib/server-runtime/serverHandoff.js +1 -1
- package/dist/production/lib/server-runtime/sessions/cookieStorage.js +1 -1
- package/dist/production/lib/server-runtime/sessions/memoryStorage.js +1 -1
- package/dist/production/lib/server-runtime/sessions.js +1 -1
- package/dist/production/lib/server-runtime/single-fetch.js +2 -2
- package/dist/production/lib/server-runtime/urls.js +1 -1
- package/dist/production/lib/server-runtime/warnings.js +1 -1
- package/dist/production/lib/types/internal.js +1 -1
- package/dist/production/route-pattern.d.ts +3 -0
- package/dist/production/route-pattern.js +12 -0
- package/dist/production/vendor/turbo-stream-v2/flatten.js +1 -1
- package/dist/production/vendor/turbo-stream-v2/turbo-stream.js +4 -4
- package/dist/production/vendor/turbo-stream-v2/unflatten.js +1 -1
- package/dist/production/vendor/turbo-stream-v2/utils.js +1 -1
- package/docs/how-to/fetchers.md +6 -1
- package/docs/how-to/middleware.md +3 -1
- package/docs/how-to/optimize-revalidation.md +178 -5
- package/docs/how-to/react-server-components.md +26 -3
- package/docs/how-to/resource-routes.md +3 -0
- package/docs/start/data/actions.md +2 -1
- package/docs/start/data/route-object.md +21 -6
- package/docs/start/framework/actions.md +4 -2
- package/docs/start/framework/route-module.md +32 -5
- package/docs/upgrading/future.md +68 -0
- package/package.json +11 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.
|
|
2
|
+
* react-router v8.4.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -10,8 +10,11 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { PROTOCOL_RELATIVE_URL_REGEX, normalizeProtocolRelativeUrl } from "./url.js";
|
|
12
12
|
import { createBrowserURLImpl, createLocation, createPath, invariant, parsePath, warning } from "./history.js";
|
|
13
|
-
import { ErrorResponseImpl, RouterContextProvider, convertRouteMatchToUiMatch, convertRoutesToDataRoutes, createDataFunctionUrl,
|
|
13
|
+
import { ErrorResponseImpl, RouterContextProvider, convertRouteMatchToUiMatch, convertRoutesToDataRoutes, createDataFunctionUrl, getPathContributingMatches, getResolveToMatches, getRoutePattern, isAbsoluteUrl, isRouteErrorResponse, isUnsupportedLazyRouteFunctionKey, isUnsupportedLazyRouteObjectKey, prependBasename, removeDoubleSlashes, resolveTo, stripBasename } from "./utils.js";
|
|
14
14
|
import { consumeInstrumentationClientResultMetaReceiver, getRouteInstrumentationUpdates, instrumentClientSideRouter } from "./instrumentation.js";
|
|
15
|
+
import { V6RegExMatcher } from "./matcher.js";
|
|
16
|
+
import { getRoutePatternMatcher } from "./matcher-route-pattern.preload.js";
|
|
17
|
+
import { validateNavigationTarget } from "./navigation.js";
|
|
15
18
|
//#region lib/router/router.ts
|
|
16
19
|
const validMutationMethodsArr = [
|
|
17
20
|
"POST",
|
|
@@ -60,18 +63,26 @@ const IDLE_BLOCKER = {
|
|
|
60
63
|
};
|
|
61
64
|
const TRANSITIONS_STORAGE_KEY = "remix-router-transitions";
|
|
62
65
|
const ResetLoaderDataSymbol = Symbol("ResetLoaderData");
|
|
66
|
+
function createDataRouteMatcher(future, basename) {
|
|
67
|
+
if (future.unstable_routePatternMatching) {
|
|
68
|
+
let RoutePatternMatcher = getRoutePatternMatcher();
|
|
69
|
+
invariant(RoutePatternMatcher, "You must call unstable_preloadRoutePattern() from \"react-router/route-pattern\" before enabling future.unstable_routePatternMatching.");
|
|
70
|
+
return new RoutePatternMatcher(basename);
|
|
71
|
+
}
|
|
72
|
+
return new V6RegExMatcher(basename);
|
|
73
|
+
}
|
|
63
74
|
/**
|
|
64
75
|
* Encapsulates the stable and in-flight route trees together with their
|
|
65
76
|
* pre-computed branch caches so the structures always stay in sync.
|
|
66
77
|
*/
|
|
67
78
|
var DataRoutes = class {
|
|
68
79
|
#routes;
|
|
69
|
-
#branches;
|
|
70
80
|
#hmrRoutes;
|
|
71
|
-
#
|
|
72
|
-
constructor(routes) {
|
|
81
|
+
#matcher;
|
|
82
|
+
constructor(routes, matcher) {
|
|
73
83
|
this.#routes = routes;
|
|
74
|
-
this.#
|
|
84
|
+
this.#matcher = matcher;
|
|
85
|
+
this.#matcher.update(routes);
|
|
75
86
|
}
|
|
76
87
|
/** The stable route tree */
|
|
77
88
|
get stableRoutes() {
|
|
@@ -81,30 +92,25 @@ var DataRoutes = class {
|
|
|
81
92
|
get activeRoutes() {
|
|
82
93
|
return this.#hmrRoutes ?? this.#routes;
|
|
83
94
|
}
|
|
84
|
-
/** Pre-computed branches */
|
|
85
|
-
get branches() {
|
|
86
|
-
return this.#hmrBranches ?? this.#branches;
|
|
87
|
-
}
|
|
88
95
|
get hasHMRRoutes() {
|
|
89
96
|
return this.#hmrRoutes != null;
|
|
90
97
|
}
|
|
91
98
|
/** Replace the stable route tree and recompute its branches */
|
|
92
99
|
setRoutes(routes) {
|
|
93
100
|
this.#routes = routes;
|
|
94
|
-
this.#
|
|
101
|
+
if (!this.#hmrRoutes) this.#matcher.update(routes);
|
|
95
102
|
}
|
|
96
103
|
/** Set a new in-flight route tree and recompute its branches */
|
|
97
104
|
setHmrRoutes(routes) {
|
|
98
105
|
this.#hmrRoutes = routes;
|
|
99
|
-
this.#
|
|
106
|
+
this.#matcher.update(routes);
|
|
100
107
|
}
|
|
101
108
|
/** Commit in-flight routes/branches to the stable slot and clear in-flight */
|
|
102
109
|
commitHmrRoutes() {
|
|
103
110
|
if (this.#hmrRoutes) {
|
|
104
111
|
this.#routes = this.#hmrRoutes;
|
|
105
|
-
this.#branches = this.#hmrBranches;
|
|
106
112
|
this.#hmrRoutes = void 0;
|
|
107
|
-
this.#
|
|
113
|
+
this.#matcher.update(this.#routes);
|
|
108
114
|
}
|
|
109
115
|
}
|
|
110
116
|
};
|
|
@@ -127,12 +133,13 @@ function createRouter(init) {
|
|
|
127
133
|
};
|
|
128
134
|
};
|
|
129
135
|
}
|
|
130
|
-
let
|
|
131
|
-
let dataRoutes = new DataRoutes(convertRoutesToDataRoutes(init.routes, mapRouteProperties, void 0, manifest));
|
|
136
|
+
let future = { ...init.future };
|
|
132
137
|
let basename = init.basename || "/";
|
|
133
138
|
if (!basename.startsWith("/")) basename = `/${basename}`;
|
|
139
|
+
let dataRouteMatcher = createDataRouteMatcher(future, basename);
|
|
140
|
+
let manifest = {};
|
|
141
|
+
let dataRoutes = new DataRoutes(convertRoutesToDataRoutes(init.routes, mapRouteProperties, void 0, manifest), dataRouteMatcher);
|
|
134
142
|
let dataStrategyImpl = init.dataStrategy || defaultDataStrategyWithMiddleware;
|
|
135
|
-
let future = { ...init.future };
|
|
136
143
|
let unlistenHistory = null;
|
|
137
144
|
let subscribers = /* @__PURE__ */ new Set();
|
|
138
145
|
let bufferedInitialStateUpdate = null;
|
|
@@ -140,7 +147,7 @@ function createRouter(init) {
|
|
|
140
147
|
let getScrollRestorationKey = null;
|
|
141
148
|
let getScrollPosition = null;
|
|
142
149
|
let initialScrollRestored = init.hydrationData != null;
|
|
143
|
-
let initialMatches =
|
|
150
|
+
let initialMatches = dataRouteMatcher.match(init.history.location);
|
|
144
151
|
let initialMatchesIsFOW = false;
|
|
145
152
|
let initialErrors = null;
|
|
146
153
|
let initialized;
|
|
@@ -154,13 +161,13 @@ function createRouter(init) {
|
|
|
154
161
|
initialErrors = { [route.id]: error };
|
|
155
162
|
} else {
|
|
156
163
|
if (initialMatches && !init.hydrationData) {
|
|
157
|
-
if (checkFogOfWar(initialMatches,
|
|
164
|
+
if (checkFogOfWar(initialMatches, init.history.location.pathname).active) initialMatches = null;
|
|
158
165
|
}
|
|
159
166
|
if (!initialMatches) {
|
|
160
167
|
initialized = false;
|
|
161
168
|
renderFallback = !initialized;
|
|
162
169
|
initialMatches = [];
|
|
163
|
-
let fogOfWar = checkFogOfWar(null,
|
|
170
|
+
let fogOfWar = checkFogOfWar(null, init.history.location.pathname);
|
|
164
171
|
if (fogOfWar.active && fogOfWar.matches) {
|
|
165
172
|
initialMatchesIsFOW = true;
|
|
166
173
|
initialMatches = fogOfWar.matches;
|
|
@@ -351,7 +358,7 @@ function createRouter(init) {
|
|
|
351
358
|
if (isUninterruptedRevalidation) {} else if (pendingAction === "POP") {} else if (pendingAction === "PUSH") init.history.push(location, location.state);
|
|
352
359
|
else if (pendingAction === "REPLACE") init.history.replace(location, location.state);
|
|
353
360
|
let viewTransitionOpts;
|
|
354
|
-
if (pendingAction === "POP") {
|
|
361
|
+
if (pendingAction === "POP" && !isUninterruptedRevalidation && location !== state.location) {
|
|
355
362
|
let priorPaths = appliedViewTransitions.get(state.location.pathname);
|
|
356
363
|
if (priorPaths && priorPaths.has(location.pathname)) viewTransitionOpts = {
|
|
357
364
|
currentLocation: state.location,
|
|
@@ -412,21 +419,27 @@ function createRouter(init) {
|
|
|
412
419
|
let instrumentationNavigateMetaReceiver = consumeInstrumentationClientResultMetaReceiver(router);
|
|
413
420
|
let { path, submission, error } = normalizeNavigateOptions(false, normalizeTo(state.location, state.matches, basename, to, opts?.fromRouteId, opts?.relative), opts);
|
|
414
421
|
let maskPath;
|
|
415
|
-
if (opts?.mask)
|
|
416
|
-
|
|
417
|
-
search: "",
|
|
418
|
-
hash: "",
|
|
419
|
-
...typeof opts.mask === "string" ? parsePath(opts.mask) : {
|
|
422
|
+
if (opts?.mask) {
|
|
423
|
+
let partialPath = typeof opts.mask === "string" ? parsePath(opts.mask) : {
|
|
420
424
|
...state.location.mask,
|
|
421
425
|
...opts.mask
|
|
422
|
-
}
|
|
423
|
-
|
|
426
|
+
};
|
|
427
|
+
maskPath = {
|
|
428
|
+
pathname: partialPath.pathname ?? "",
|
|
429
|
+
search: partialPath.search ?? "",
|
|
430
|
+
hash: partialPath.hash ?? ""
|
|
431
|
+
};
|
|
432
|
+
if (PROTOCOL_RELATIVE_URL_REGEX.test(maskPath.pathname)) throw new Error("External navigation is not allowed");
|
|
433
|
+
else if (maskPath.pathname.startsWith("\\")) maskPath.pathname = maskPath.pathname.replace(/^\\+/, "/");
|
|
434
|
+
validateNavigationTarget(typeof opts.mask === "string" ? opts.mask : createPath(opts.mask), createPath(maskPath), init.history.createURL("/"), "reject");
|
|
435
|
+
}
|
|
424
436
|
let currentLocation = state.location;
|
|
425
437
|
let nextLocation = createLocation(currentLocation, path, opts && opts.state, void 0, maskPath);
|
|
426
438
|
nextLocation = {
|
|
427
439
|
...nextLocation,
|
|
428
440
|
...init.history.encodeLocation(nextLocation)
|
|
429
441
|
};
|
|
442
|
+
validateNavigationTarget(to == null ? init.history.createHref(state.location) : typeof to === "string" ? to : createPath(to), init.history.createHref(nextLocation.mask || nextLocation), init.history.createURL("/"), "reject");
|
|
430
443
|
let userReplace = opts && opts.replace != null ? opts.replace : void 0;
|
|
431
444
|
let historyAction = "PUSH";
|
|
432
445
|
if (userReplace === true) historyAction = "REPLACE";
|
|
@@ -494,14 +507,13 @@ function createRouter(init) {
|
|
|
494
507
|
saveScrollPosition(state.location, state.matches);
|
|
495
508
|
pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
|
|
496
509
|
pendingViewTransitionEnabled = (opts && opts.enableViewTransition) === true;
|
|
497
|
-
let
|
|
498
|
-
let matches = opts?.initialHydration && state.matches && state.matches.length > 0 && !initialMatchesIsFOW ? state.matches : matchRoutesImpl(routesToUse, location, basename, false, dataRoutes.branches);
|
|
510
|
+
let matches = opts?.initialHydration && state.matches && state.matches.length > 0 && !initialMatchesIsFOW ? state.matches : dataRouteMatcher.match(location);
|
|
499
511
|
let flushSync = (opts && opts.flushSync) === true;
|
|
500
512
|
if (matches && state.initialized && !isRevalidationRequired && isHashChangeOnly(state.location, location) && !(opts && opts.submission && isMutationMethod(opts.submission.formMethod))) {
|
|
501
513
|
completeNavigation(location, { matches }, { flushSync });
|
|
502
514
|
return;
|
|
503
515
|
}
|
|
504
|
-
let fogOfWar = checkFogOfWar(matches,
|
|
516
|
+
let fogOfWar = checkFogOfWar(matches, location.pathname);
|
|
505
517
|
if (fogOfWar.active && fogOfWar.matches) matches = fogOfWar.matches;
|
|
506
518
|
if (opts?.instrumentationNavigateMetaReceiver) {
|
|
507
519
|
let meta = getInstrumentationNavigateMeta(init.history, location, matches);
|
|
@@ -687,8 +699,7 @@ function createRouter(init) {
|
|
|
687
699
|
};
|
|
688
700
|
} else matches = discoverResult.matches;
|
|
689
701
|
}
|
|
690
|
-
let
|
|
691
|
-
let { dsMatches, revalidatingFetchers } = getMatchesToLoad(request, scopedContext, mapRouteProperties, manifest, init.history, state, matches, activeSubmission, location, initialHydration ? [] : hydrationRouteProperties, initialHydration === true, isRevalidationRequired, cancelledFetcherLoads, fetchersQueuedForDeletion, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, init.patchRoutesOnNavigation != null, dataRoutes.branches, pendingActionResult, callSiteDefaultShouldRevalidate);
|
|
702
|
+
let { dsMatches, revalidatingFetchers } = getMatchesToLoad(request, scopedContext, mapRouteProperties, manifest, init.history, state, matches, activeSubmission, location, initialHydration ? [] : hydrationRouteProperties, initialHydration === true, isRevalidationRequired, cancelledFetcherLoads, fetchersQueuedForDeletion, fetchLoadMatches, fetchRedirectIds, dataRouteMatcher, pendingActionResult, callSiteDefaultShouldRevalidate);
|
|
692
703
|
pendingNavigationLoadId = ++incrementingLoadId;
|
|
693
704
|
if (!init.dataStrategy && !dsMatches.some((m) => m.shouldLoad) && !dsMatches.some((m) => m.route.middleware && m.route.middleware.length > 0) && revalidatingFetchers.length === 0) {
|
|
694
705
|
let workingFetchers = new Map(state.fetchers);
|
|
@@ -767,10 +778,9 @@ function createRouter(init) {
|
|
|
767
778
|
abortFetcher(key);
|
|
768
779
|
let flushSync = (opts && opts.flushSync) === true;
|
|
769
780
|
let instrumentationResultMetaReceiver = consumeInstrumentationClientResultMetaReceiver(router);
|
|
770
|
-
let routesToUse = dataRoutes.activeRoutes;
|
|
771
781
|
let normalizedPath = normalizeTo(state.location, state.matches, basename, href, routeId, opts?.relative);
|
|
772
|
-
let matches =
|
|
773
|
-
let fogOfWar = checkFogOfWar(matches,
|
|
782
|
+
let matches = dataRouteMatcher.match(normalizedPath);
|
|
783
|
+
let fogOfWar = checkFogOfWar(matches, normalizedPath);
|
|
774
784
|
if (fogOfWar.active && fogOfWar.matches) matches = fogOfWar.matches;
|
|
775
785
|
if (instrumentationResultMetaReceiver) instrumentationResultMetaReceiver(getInstrumentationNavigateMeta(init.history, normalizedPath, matches));
|
|
776
786
|
if (!matches) {
|
|
@@ -788,11 +798,13 @@ function createRouter(init) {
|
|
|
788
798
|
await handleFetcherAction(key, routeId, path, matches, scopedContext, fogOfWar.active, flushSync, preventScrollReset, submission, opts && opts.defaultShouldRevalidate);
|
|
789
799
|
return;
|
|
790
800
|
}
|
|
791
|
-
|
|
801
|
+
let loadMatch = {
|
|
792
802
|
routeId,
|
|
793
|
-
path
|
|
794
|
-
|
|
795
|
-
|
|
803
|
+
path,
|
|
804
|
+
isDiscovering: fogOfWar.active
|
|
805
|
+
};
|
|
806
|
+
fetchLoadMatches.set(key, loadMatch);
|
|
807
|
+
await handleFetcherLoader(key, loadMatch, matches, scopedContext, flushSync, preventScrollReset, submission);
|
|
796
808
|
}
|
|
797
809
|
async function handleFetcherAction(key, routeId, path, requestMatches, scopedContext, isFogOfWar, flushSync, preventScrollReset, submission, callSiteDefaultShouldRevalidate) {
|
|
798
810
|
interruptActiveLoads();
|
|
@@ -862,12 +874,11 @@ function createRouter(init) {
|
|
|
862
874
|
}
|
|
863
875
|
let nextLocation = state.navigation.location || state.location;
|
|
864
876
|
let revalidationRequest = createClientSideRequest(init.history, nextLocation, abortController.signal);
|
|
865
|
-
let
|
|
866
|
-
let matches = state.navigation.state !== "idle" ? matchRoutesImpl(routesToUse, state.navigation.location, basename, false, dataRoutes.branches) : state.matches;
|
|
877
|
+
let matches = state.navigation.state !== "idle" ? dataRouteMatcher.match(state.navigation.location) : state.matches;
|
|
867
878
|
invariant(matches, "Didn't find any matches after fetcher action");
|
|
868
879
|
let loadId = ++incrementingLoadId;
|
|
869
880
|
fetchReloadIds.set(key, loadId);
|
|
870
|
-
let { dsMatches, revalidatingFetchers } = getMatchesToLoad(revalidationRequest, scopedContext, mapRouteProperties, manifest, init.history, state, matches, submission, nextLocation, hydrationRouteProperties, false, isRevalidationRequired, cancelledFetcherLoads, fetchersQueuedForDeletion, fetchLoadMatches, fetchRedirectIds,
|
|
881
|
+
let { dsMatches, revalidatingFetchers } = getMatchesToLoad(revalidationRequest, scopedContext, mapRouteProperties, manifest, init.history, state, matches, submission, nextLocation, hydrationRouteProperties, false, isRevalidationRequired, cancelledFetcherLoads, fetchersQueuedForDeletion, fetchLoadMatches, fetchRedirectIds, dataRouteMatcher, [match.route.id, actionResult], callSiteDefaultShouldRevalidate);
|
|
871
882
|
let loadFetcher = getLoadingFetcher(submission, actionResult.data);
|
|
872
883
|
let workingFetchers = new Map(state.fetchers);
|
|
873
884
|
workingFetchers.set(key, loadFetcher);
|
|
@@ -883,7 +894,10 @@ function createRouter(init) {
|
|
|
883
894
|
let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach((rf) => abortFetcher(rf.key));
|
|
884
895
|
abortController.signal.addEventListener("abort", abortPendingFetchRevalidations);
|
|
885
896
|
let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(dsMatches, revalidatingFetchers, revalidationRequest, nextLocation, scopedContext);
|
|
886
|
-
if (abortController.signal.aborted)
|
|
897
|
+
if (abortController.signal.aborted) {
|
|
898
|
+
if (fetchReloadIds.get(key) === loadId) fetchReloadIds.delete(key);
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
887
901
|
abortController.signal.removeEventListener("abort", abortPendingFetchRevalidations);
|
|
888
902
|
fetchReloadIds.delete(key);
|
|
889
903
|
fetchControllers.delete(key);
|
|
@@ -931,12 +945,13 @@ function createRouter(init) {
|
|
|
931
945
|
isRevalidationRequired = false;
|
|
932
946
|
}
|
|
933
947
|
}
|
|
934
|
-
async function handleFetcherLoader(key,
|
|
948
|
+
async function handleFetcherLoader(key, loadMatch, matches, scopedContext, flushSync, preventScrollReset, submission) {
|
|
949
|
+
let { routeId, path } = loadMatch;
|
|
935
950
|
let existingFetcher = state.fetchers.get(key);
|
|
936
951
|
updateFetcherState(key, getLoadingFetcher(submission, existingFetcher ? existingFetcher.data : void 0), { flushSync });
|
|
937
952
|
let abortController = new AbortController();
|
|
938
953
|
let fetchRequest = createClientSideRequest(init.history, path, abortController.signal);
|
|
939
|
-
if (
|
|
954
|
+
if (loadMatch.isDiscovering) {
|
|
940
955
|
let discoverResult = await discoverRoutes(matches, new URL(fetchRequest.url).pathname, fetchRequest.signal, key);
|
|
941
956
|
if (discoverResult.type === "aborted") return;
|
|
942
957
|
else if (discoverResult.type === "error") {
|
|
@@ -945,7 +960,10 @@ function createRouter(init) {
|
|
|
945
960
|
} else if (!discoverResult.matches) {
|
|
946
961
|
setFetcherError(key, routeId, getInternalRouterError(404, { pathname: path }), { flushSync });
|
|
947
962
|
return;
|
|
948
|
-
} else
|
|
963
|
+
} else {
|
|
964
|
+
matches = discoverResult.matches;
|
|
965
|
+
loadMatch.isDiscovering = false;
|
|
966
|
+
}
|
|
949
967
|
}
|
|
950
968
|
let match = getTargetMatch(matches, path);
|
|
951
969
|
fetchControllers.set(key, abortController);
|
|
@@ -1005,7 +1023,10 @@ function createRouter(init) {
|
|
|
1005
1023
|
if (redirect.response.headers.has("X-Remix-Revalidate")) isRevalidationRequired = true;
|
|
1006
1024
|
let location = redirect.response.headers.get("Location");
|
|
1007
1025
|
invariant(location, "Expected a Location header on the redirect Response");
|
|
1008
|
-
|
|
1026
|
+
let originalLocation = location;
|
|
1027
|
+
let currentUrl = new URL(request.url);
|
|
1028
|
+
location = normalizeRedirectLocation(location, currentUrl, basename, init.history);
|
|
1029
|
+
validateNavigationTarget(originalLocation, location, currentUrl, "allow-explicit");
|
|
1009
1030
|
let redirectLocation = createLocation(state.location, location, { _isRedirect: true });
|
|
1010
1031
|
if (isBrowser) {
|
|
1011
1032
|
let isDocumentReload = false;
|
|
@@ -1251,16 +1272,15 @@ function createRouter(init) {
|
|
|
1251
1272
|
}
|
|
1252
1273
|
return null;
|
|
1253
1274
|
}
|
|
1254
|
-
function checkFogOfWar(matches,
|
|
1275
|
+
function checkFogOfWar(matches, pathname) {
|
|
1255
1276
|
if (init.patchRoutesOnNavigation) {
|
|
1256
|
-
let activeBranches = dataRoutes.branches;
|
|
1257
1277
|
if (!matches) return {
|
|
1258
1278
|
active: true,
|
|
1259
|
-
matches:
|
|
1279
|
+
matches: dataRouteMatcher.match(pathname, true) || []
|
|
1260
1280
|
};
|
|
1261
1281
|
else if (Object.keys(matches[0].params).length > 0) return {
|
|
1262
1282
|
active: true,
|
|
1263
|
-
matches:
|
|
1283
|
+
matches: dataRouteMatcher.match(pathname, true)
|
|
1264
1284
|
};
|
|
1265
1285
|
}
|
|
1266
1286
|
return {
|
|
@@ -1295,21 +1315,20 @@ function createRouter(init) {
|
|
|
1295
1315
|
};
|
|
1296
1316
|
}
|
|
1297
1317
|
if (signal.aborted) return { type: "aborted" };
|
|
1298
|
-
let
|
|
1299
|
-
let newMatches = matchRoutesImpl(dataRoutes.activeRoutes, pathname, basename, false, activeBranches);
|
|
1318
|
+
let newMatches = dataRouteMatcher.match(pathname);
|
|
1300
1319
|
let newPartialMatches = null;
|
|
1301
1320
|
if (newMatches) if (Object.keys(newMatches[0].params).length === 0) return {
|
|
1302
1321
|
type: "success",
|
|
1303
1322
|
matches: newMatches
|
|
1304
1323
|
};
|
|
1305
1324
|
else {
|
|
1306
|
-
newPartialMatches =
|
|
1325
|
+
newPartialMatches = dataRouteMatcher.match(pathname, true);
|
|
1307
1326
|
if (!(newPartialMatches && partialMatches.length < newPartialMatches.length && compareMatches(partialMatches, newPartialMatches.slice(0, partialMatches.length)))) return {
|
|
1308
1327
|
type: "success",
|
|
1309
1328
|
matches: newMatches
|
|
1310
1329
|
};
|
|
1311
1330
|
}
|
|
1312
|
-
if (!newPartialMatches) newPartialMatches =
|
|
1331
|
+
if (!newPartialMatches) newPartialMatches = dataRouteMatcher.match(pathname, true);
|
|
1313
1332
|
if (!newPartialMatches || compareMatches(partialMatches, newPartialMatches)) return {
|
|
1314
1333
|
type: "success",
|
|
1315
1334
|
matches: null
|
|
@@ -1341,8 +1360,8 @@ function createRouter(init) {
|
|
|
1341
1360
|
get routes() {
|
|
1342
1361
|
return dataRoutes.stableRoutes;
|
|
1343
1362
|
},
|
|
1344
|
-
|
|
1345
|
-
return
|
|
1363
|
+
match(locationArg) {
|
|
1364
|
+
return dataRouteMatcher.match(locationArg);
|
|
1346
1365
|
},
|
|
1347
1366
|
get manifest() {
|
|
1348
1367
|
return manifest;
|
|
@@ -1357,6 +1376,7 @@ function createRouter(init) {
|
|
|
1357
1376
|
fetch,
|
|
1358
1377
|
revalidate,
|
|
1359
1378
|
createHref: (to) => init.history.createHref(to),
|
|
1379
|
+
createURL: (to) => init.history.createURL(to),
|
|
1360
1380
|
encodeLocation: (to) => init.history.encodeLocation(to),
|
|
1361
1381
|
getFetcher,
|
|
1362
1382
|
resetFetcher,
|
|
@@ -1410,7 +1430,7 @@ function createStaticHandler(routes, opts) {
|
|
|
1410
1430
|
let basename = (opts ? opts.basename : null) || "/";
|
|
1411
1431
|
let _mapRouteProperties = opts?.mapRouteProperties;
|
|
1412
1432
|
let mapRouteProperties = _mapRouteProperties ? _mapRouteProperties : () => ({});
|
|
1413
|
-
({ ...opts?.future });
|
|
1433
|
+
let dataRouteMatcher = createDataRouteMatcher({ ...opts?.future }, basename);
|
|
1414
1434
|
if (opts?.instrumentations) {
|
|
1415
1435
|
let instrumentations = opts.instrumentations;
|
|
1416
1436
|
mapRouteProperties = (route) => {
|
|
@@ -1421,7 +1441,8 @@ function createStaticHandler(routes, opts) {
|
|
|
1421
1441
|
};
|
|
1422
1442
|
}
|
|
1423
1443
|
let dataRoutes = convertRoutesToDataRoutes(routes, mapRouteProperties, void 0, manifest);
|
|
1424
|
-
|
|
1444
|
+
dataRouteMatcher.update(dataRoutes);
|
|
1445
|
+
let match = (locationArg) => dataRouteMatcher.match(locationArg);
|
|
1425
1446
|
/**
|
|
1426
1447
|
* The query() method is intended for document requests, in which we want to
|
|
1427
1448
|
* call an optional action and potentially multiple loaders for all nested
|
|
@@ -1452,7 +1473,7 @@ function createStaticHandler(routes, opts) {
|
|
|
1452
1473
|
let normalizePathImpl = normalizePath || defaultNormalizePath;
|
|
1453
1474
|
let method = request.method;
|
|
1454
1475
|
let location = createLocation("", normalizePathImpl(request), null, "default");
|
|
1455
|
-
let matches =
|
|
1476
|
+
let matches = dataRouteMatcher.match(location);
|
|
1456
1477
|
requestContext = requestContext != null ? requestContext : new RouterContextProvider();
|
|
1457
1478
|
if (!isValidMethod(method) && method !== "HEAD") {
|
|
1458
1479
|
let error = getInternalRouterError(405, { method });
|
|
@@ -1466,7 +1487,8 @@ function createStaticHandler(routes, opts) {
|
|
|
1466
1487
|
errors: { [route.id]: error },
|
|
1467
1488
|
statusCode: error.status,
|
|
1468
1489
|
loaderHeaders: {},
|
|
1469
|
-
actionHeaders: {}
|
|
1490
|
+
actionHeaders: {},
|
|
1491
|
+
_match: match
|
|
1470
1492
|
};
|
|
1471
1493
|
return generateMiddlewareResponse ? generateMiddlewareResponse(() => Promise.resolve(staticContext)) : staticContext;
|
|
1472
1494
|
} else if (!matches) {
|
|
@@ -1481,7 +1503,8 @@ function createStaticHandler(routes, opts) {
|
|
|
1481
1503
|
errors: { [route.id]: error },
|
|
1482
1504
|
statusCode: error.status,
|
|
1483
1505
|
loaderHeaders: {},
|
|
1484
|
-
actionHeaders: {}
|
|
1506
|
+
actionHeaders: {},
|
|
1507
|
+
_match: match
|
|
1485
1508
|
};
|
|
1486
1509
|
return generateMiddlewareResponse ? generateMiddlewareResponse(() => Promise.resolve(staticContext)) : staticContext;
|
|
1487
1510
|
}
|
|
@@ -1504,7 +1527,8 @@ function createStaticHandler(routes, opts) {
|
|
|
1504
1527
|
renderedStaticContext = {
|
|
1505
1528
|
location,
|
|
1506
1529
|
basename,
|
|
1507
|
-
...result
|
|
1530
|
+
...result,
|
|
1531
|
+
_match: match
|
|
1508
1532
|
};
|
|
1509
1533
|
return renderedStaticContext;
|
|
1510
1534
|
});
|
|
@@ -1530,7 +1554,8 @@ function createStaticHandler(routes, opts) {
|
|
|
1530
1554
|
errors: { [skipLoaderErrorBubbling ? routeId : findNearestBoundary(matches, matches.find((m) => m.route.id === routeId || m.route.loader)?.route.id || routeId).route.id]: error },
|
|
1531
1555
|
statusCode: isRouteErrorResponse(error) ? error.status : 500,
|
|
1532
1556
|
actionHeaders: {},
|
|
1533
|
-
loaderHeaders: {}
|
|
1557
|
+
loaderHeaders: {},
|
|
1558
|
+
_match: match
|
|
1534
1559
|
};
|
|
1535
1560
|
return generateMiddlewareResponse(() => Promise.resolve(staticContext));
|
|
1536
1561
|
}
|
|
@@ -1547,7 +1572,8 @@ function createStaticHandler(routes, opts) {
|
|
|
1547
1572
|
return {
|
|
1548
1573
|
location,
|
|
1549
1574
|
basename,
|
|
1550
|
-
...result
|
|
1575
|
+
...result,
|
|
1576
|
+
_match: match
|
|
1551
1577
|
};
|
|
1552
1578
|
}
|
|
1553
1579
|
/**
|
|
@@ -1580,7 +1606,7 @@ function createStaticHandler(routes, opts) {
|
|
|
1580
1606
|
let normalizePathImpl = normalizePath || defaultNormalizePath;
|
|
1581
1607
|
let method = request.method;
|
|
1582
1608
|
let location = createLocation("", normalizePathImpl(request), null, "default");
|
|
1583
|
-
let matches =
|
|
1609
|
+
let matches = dataRouteMatcher.match(location);
|
|
1584
1610
|
requestContext = requestContext != null ? requestContext : new RouterContextProvider();
|
|
1585
1611
|
if (!isValidMethod(method) && method !== "HEAD" && method !== "OPTIONS") throw getInternalRouterError(405, { method });
|
|
1586
1612
|
else if (!matches) throw getInternalRouterError(404, { pathname: location.pathname });
|
|
@@ -1761,7 +1787,7 @@ function createStaticHandler(routes, opts) {
|
|
|
1761
1787
|
}
|
|
1762
1788
|
return {
|
|
1763
1789
|
dataRoutes,
|
|
1764
|
-
|
|
1790
|
+
match,
|
|
1765
1791
|
query,
|
|
1766
1792
|
queryRoute
|
|
1767
1793
|
};
|
|
@@ -1876,7 +1902,7 @@ function normalizeNavigateOptions(isFetcher, path, opts) {
|
|
|
1876
1902
|
text: void 0
|
|
1877
1903
|
}
|
|
1878
1904
|
};
|
|
1879
|
-
} catch
|
|
1905
|
+
} catch {
|
|
1880
1906
|
return getInvalidBodyError();
|
|
1881
1907
|
}
|
|
1882
1908
|
}
|
|
@@ -1899,7 +1925,7 @@ function normalizeNavigateOptions(isFetcher, path, opts) {
|
|
|
1899
1925
|
} else try {
|
|
1900
1926
|
searchParams = new URLSearchParams(opts.body);
|
|
1901
1927
|
formData = convertSearchParamsToFormData(searchParams);
|
|
1902
|
-
} catch
|
|
1928
|
+
} catch {
|
|
1903
1929
|
return getInvalidBodyError();
|
|
1904
1930
|
}
|
|
1905
1931
|
let submission = {
|
|
@@ -1922,7 +1948,7 @@ function normalizeNavigateOptions(isFetcher, path, opts) {
|
|
|
1922
1948
|
submission
|
|
1923
1949
|
};
|
|
1924
1950
|
}
|
|
1925
|
-
function getMatchesToLoad(request, scopedContext, mapRouteProperties, manifest, history, state, matches, submission, location, lazyRoutePropertiesToSkip, initialHydration, isRevalidationRequired, cancelledFetcherLoads, fetchersQueuedForDeletion, fetchLoadMatches, fetchRedirectIds,
|
|
1951
|
+
function getMatchesToLoad(request, scopedContext, mapRouteProperties, manifest, history, state, matches, submission, location, lazyRoutePropertiesToSkip, initialHydration, isRevalidationRequired, cancelledFetcherLoads, fetchersQueuedForDeletion, fetchLoadMatches, fetchRedirectIds, dataRouteMatcher, pendingActionResult, callSiteDefaultShouldRevalidate) {
|
|
1926
1952
|
let actionResult = pendingActionResult ? isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : pendingActionResult[1].data : void 0;
|
|
1927
1953
|
let currentUrl = history.createURL(state.location);
|
|
1928
1954
|
let nextUrl = history.createURL(location);
|
|
@@ -1972,12 +1998,11 @@ function getMatchesToLoad(request, scopedContext, mapRouteProperties, manifest,
|
|
|
1972
1998
|
});
|
|
1973
1999
|
let revalidatingFetchers = [];
|
|
1974
2000
|
fetchLoadMatches.forEach((f, key) => {
|
|
1975
|
-
if (initialHydration || !matches.some((m) => m.route.id === f.routeId) || fetchersQueuedForDeletion.has(key)) return;
|
|
2001
|
+
if (initialHydration || !matches.some((m) => m.route.id === f.routeId) || fetchersQueuedForDeletion.has(key) || f.isDiscovering) return;
|
|
1976
2002
|
let fetcher = state.fetchers.get(key);
|
|
1977
2003
|
let isMidInitialLoad = fetcher && fetcher.state !== "idle" && fetcher.data === void 0;
|
|
1978
|
-
let fetcherMatches =
|
|
2004
|
+
let fetcherMatches = dataRouteMatcher.match(f.path);
|
|
1979
2005
|
if (!fetcherMatches) {
|
|
1980
|
-
if (hasPatchRoutesOnNavigation && isMidInitialLoad) return;
|
|
1981
2006
|
revalidatingFetchers.push({
|
|
1982
2007
|
key,
|
|
1983
2008
|
routeId: f.routeId,
|
|
@@ -2415,7 +2440,7 @@ async function callDataStrategyImpl(dataStrategyImpl, request, path, matches, fe
|
|
|
2415
2440
|
});
|
|
2416
2441
|
try {
|
|
2417
2442
|
await Promise.all(matches.flatMap((m) => [m._lazyPromises?.handler, m._lazyPromises?.route]));
|
|
2418
|
-
} catch
|
|
2443
|
+
} catch {}
|
|
2419
2444
|
return results;
|
|
2420
2445
|
}
|
|
2421
2446
|
async function callLoaderOrAction({ request, path, pattern, match, lazyHandlerPromise, lazyRoutePromise, handlerOverride, scopedContext }) {
|
|
@@ -2598,7 +2623,7 @@ function normalizeRedirectLocation(location, currentUrl, basename, historyInstan
|
|
|
2598
2623
|
}
|
|
2599
2624
|
try {
|
|
2600
2625
|
if (hasInvalidProtocol(historyInstance.createURL(location).toString())) throw new Error("Invalid redirect location");
|
|
2601
|
-
} catch
|
|
2626
|
+
} catch {}
|
|
2602
2627
|
return location;
|
|
2603
2628
|
}
|
|
2604
2629
|
function createClientSideRequest(history, location, signal, submission) {
|
|
@@ -2703,12 +2728,16 @@ function mergeLoaderData(loaderData, newLoaderData, matches, errors) {
|
|
|
2703
2728
|
merged[k] = v;
|
|
2704
2729
|
return merged;
|
|
2705
2730
|
}, {});
|
|
2731
|
+
let preservedCount = 0;
|
|
2706
2732
|
for (let match of matches) {
|
|
2707
2733
|
let id = match.route.id;
|
|
2708
|
-
if (!newLoaderData.hasOwnProperty(id) && loaderData.hasOwnProperty(id) && match.route.loader)
|
|
2734
|
+
if (!newLoaderData.hasOwnProperty(id) && loaderData.hasOwnProperty(id) && match.route.loader) {
|
|
2735
|
+
mergedLoaderData[id] = loaderData[id];
|
|
2736
|
+
preservedCount++;
|
|
2737
|
+
}
|
|
2709
2738
|
if (errors && errors.hasOwnProperty(id)) break;
|
|
2710
2739
|
}
|
|
2711
|
-
return mergedLoaderData;
|
|
2740
|
+
return Object.keys(newLoaderData).length === 0 && preservedCount === Object.keys(loaderData).length ? loaderData : mergedLoaderData;
|
|
2712
2741
|
}
|
|
2713
2742
|
function getActionDataForCommit(pendingActionResult) {
|
|
2714
2743
|
if (!pendingActionResult) return {};
|
|
@@ -2948,7 +2977,7 @@ function restoreAppliedTransitions(_window, transitions) {
|
|
|
2948
2977
|
let json = JSON.parse(sessionPositions);
|
|
2949
2978
|
for (let [k, v] of Object.entries(json || {})) if (v && Array.isArray(v)) transitions.set(k, new Set(v || []));
|
|
2950
2979
|
}
|
|
2951
|
-
} catch
|
|
2980
|
+
} catch {}
|
|
2952
2981
|
}
|
|
2953
2982
|
function persistAppliedTransitions(_window, transitions) {
|
|
2954
2983
|
if (transitions.size > 0) {
|
|
@@ -2969,13 +2998,13 @@ function createDeferred() {
|
|
|
2969
2998
|
res(val);
|
|
2970
2999
|
try {
|
|
2971
3000
|
await promise;
|
|
2972
|
-
} catch
|
|
3001
|
+
} catch {}
|
|
2973
3002
|
};
|
|
2974
3003
|
reject = async (error) => {
|
|
2975
3004
|
rej(error);
|
|
2976
3005
|
try {
|
|
2977
3006
|
await promise;
|
|
2978
|
-
} catch
|
|
3007
|
+
} catch {}
|
|
2979
3008
|
};
|
|
2980
3009
|
});
|
|
2981
3010
|
return {
|
|
@@ -2985,4 +3014,4 @@ function createDeferred() {
|
|
|
2985
3014
|
};
|
|
2986
3015
|
}
|
|
2987
3016
|
//#endregion
|
|
2988
|
-
export { IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, createRouter, createStaticHandler, getStaticContextFromError, hasInvalidProtocol, isDataWithResponseInit, isMutationMethod, isRedirectResponse, isRedirectStatusCode, isResponse };
|
|
3017
|
+
export { IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, createDataRouteMatcher, createRouter, createStaticHandler, getStaticContextFromError, hasInvalidProtocol, isDataWithResponseInit, isMutationMethod, isRedirectResponse, isRedirectStatusCode, isResponse };
|
|
@@ -430,7 +430,7 @@ interface MapRoutePropertiesFunction {
|
|
|
430
430
|
* onto the route. Either they're meaningful to the router, or they'll get
|
|
431
431
|
* ignored.
|
|
432
432
|
*/
|
|
433
|
-
type UnsupportedLazyRouteObjectKey = "lazy" | "caseSensitive" | "path" | "id" | "index" | "children";
|
|
433
|
+
type UnsupportedLazyRouteObjectKey = "lazy" | "caseSensitive" | "path" | "id" | "index" | "children" | "unstable_validateParams";
|
|
434
434
|
/**
|
|
435
435
|
* Keys we cannot change from within a lazy() function. We spread all other keys
|
|
436
436
|
* onto the route. Either they're meaningful to the router, or they'll get
|
|
@@ -488,6 +488,11 @@ type BaseRouteObject = {
|
|
|
488
488
|
* See [`shouldRevalidate`](../../start/data/route-object#shouldRevalidate).
|
|
489
489
|
*/
|
|
490
490
|
shouldRevalidate?: ShouldRevalidateFunction;
|
|
491
|
+
/**
|
|
492
|
+
* A map of route param names to regular expressions used to validate params
|
|
493
|
+
* after a route-pattern match.
|
|
494
|
+
*/
|
|
495
|
+
unstable_validateParams?: Record<string, RegExp>;
|
|
491
496
|
/**
|
|
492
497
|
* The route handle.
|
|
493
498
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* react-router v8.
|
|
2
|
+
* react-router v8.4.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -135,7 +135,8 @@ const unsupportedLazyRouteObjectKeys = new Set([
|
|
|
135
135
|
"path",
|
|
136
136
|
"id",
|
|
137
137
|
"index",
|
|
138
|
-
"children"
|
|
138
|
+
"children",
|
|
139
|
+
"unstable_validateParams"
|
|
139
140
|
]);
|
|
140
141
|
function isUnsupportedLazyRouteObjectKey(key) {
|
|
141
142
|
return unsupportedLazyRouteObjectKeys.has(key);
|
|
@@ -147,7 +148,8 @@ const unsupportedLazyRouteFunctionKeys = new Set([
|
|
|
147
148
|
"id",
|
|
148
149
|
"index",
|
|
149
150
|
"middleware",
|
|
150
|
-
"children"
|
|
151
|
+
"children",
|
|
152
|
+
"unstable_validateParams"
|
|
151
153
|
]);
|
|
152
154
|
function isUnsupportedLazyRouteFunctionKey(key) {
|
|
153
155
|
return unsupportedLazyRouteFunctionKeys.has(key);
|
|
@@ -489,13 +491,13 @@ function matchPathImpl(pattern, pathname, matcher, compiledParams) {
|
|
|
489
491
|
let match = pathname.match(matcher);
|
|
490
492
|
if (!match) return null;
|
|
491
493
|
let matchedPathname = match[0];
|
|
492
|
-
let pathnameBase = matchedPathname
|
|
494
|
+
let pathnameBase = removeTrailingSlash(matchedPathname, 1);
|
|
493
495
|
let captureGroups = match.slice(1);
|
|
494
496
|
return {
|
|
495
497
|
params: compiledParams.reduce((memo, { paramName, isOptional }, index) => {
|
|
496
498
|
if (paramName === "*") {
|
|
497
499
|
let splatValue = captureGroups[index] || "";
|
|
498
|
-
pathnameBase = matchedPathname.slice(0, matchedPathname.length - splatValue.length)
|
|
500
|
+
pathnameBase = removeTrailingSlash(matchedPathname.slice(0, matchedPathname.length - splatValue.length), 1);
|
|
499
501
|
}
|
|
500
502
|
const value = captureGroups[index];
|
|
501
503
|
if (isOptional && !value) memo[paramName] = void 0;
|
|
@@ -564,7 +566,7 @@ function resolvePath(to, fromPathname = "/") {
|
|
|
564
566
|
let pathname;
|
|
565
567
|
if (toPathname) {
|
|
566
568
|
toPathname = removeDoubleSlashes(toPathname);
|
|
567
|
-
if (toPathname.startsWith("/")) pathname = resolvePathname(toPathname.substring(1), "/");
|
|
569
|
+
if (toPathname.startsWith("/") || toPathname.startsWith("\\")) pathname = resolvePathname(toPathname.substring(1), "/");
|
|
568
570
|
else pathname = resolvePathname(toPathname, fromPathname);
|
|
569
571
|
} else pathname = fromPathname;
|
|
570
572
|
return {
|
|
@@ -625,7 +627,11 @@ function resolveTo(toArg, routePathnames, locationPathname, isPathRelative = fal
|
|
|
625
627
|
}
|
|
626
628
|
const removeDoubleSlashes = (path) => path.replace(/[\\/]{2,}/g, "/");
|
|
627
629
|
const joinPaths = (paths) => removeDoubleSlashes(paths.join("/"));
|
|
628
|
-
|
|
630
|
+
function removeTrailingSlash(path, minLength = 0) {
|
|
631
|
+
let end = path.length;
|
|
632
|
+
while (end > minLength && path.charCodeAt(end - 1) === 47) end--;
|
|
633
|
+
return end === path.length ? path : path.slice(0, end);
|
|
634
|
+
}
|
|
629
635
|
const normalizePathname = (pathname) => removeTrailingSlash(pathname).replace(/^\/*/, "/");
|
|
630
636
|
const normalizeSearch = (search) => !search || search === "?" ? "" : search.startsWith("?") ? search : "?" + search;
|
|
631
637
|
const normalizeHash = (hash) => !hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash;
|
|
@@ -868,7 +874,7 @@ function parseToInfo(_to, basename) {
|
|
|
868
874
|
let path = stripBasename(targetUrl.pathname, basename);
|
|
869
875
|
if (targetUrl.origin === currentUrl.origin && path != null) to = path + targetUrl.search + targetUrl.hash;
|
|
870
876
|
else isExternal = true;
|
|
871
|
-
} catch
|
|
877
|
+
} catch {
|
|
872
878
|
warning(false, `<Link to="${to}"> contains an invalid URL which will probably break when clicked - please update to a valid URL path.`);
|
|
873
879
|
}
|
|
874
880
|
return {
|
|
@@ -878,4 +884,4 @@ function parseToInfo(_to, basename) {
|
|
|
878
884
|
};
|
|
879
885
|
}
|
|
880
886
|
//#endregion
|
|
881
|
-
export { ErrorResponseImpl, RouterContextProvider, SUPPORTED_ERROR_TYPES, compilePath, convertRouteMatchToUiMatch, convertRoutesToDataRoutes, createContext, createDataFunctionUrl, data, decodePath, defaultMapRouteProperties, encodePathParam, flattenAndRankRoutes, generatePath, getPathContributingMatches, getResolveToMatches, getRoutePattern, isAbsoluteUrl, isBrowser, isRouteErrorResponse, isUnsupportedLazyRouteFunctionKey, isUnsupportedLazyRouteObjectKey, joinPaths, matchPath, matchRoutes, matchRoutesImpl, parseToInfo, prependBasename, redirect, redirectDocument, removeDoubleSlashes, removeTrailingSlash, replace, resolvePath, resolveTo, stripBasename };
|
|
887
|
+
export { ErrorResponseImpl, RouterContextProvider, SUPPORTED_ERROR_TYPES, compilePath, convertRouteMatchToUiMatch, convertRoutesToDataRoutes, createContext, createDataFunctionUrl, data, decodePath, defaultMapRouteProperties, encodePathParam, explodeOptionalSegments, flattenAndRankRoutes, generatePath, getPathContributingMatches, getResolveToMatches, getRoutePattern, isAbsoluteUrl, isBrowser, isRouteErrorResponse, isUnsupportedLazyRouteFunctionKey, isUnsupportedLazyRouteObjectKey, joinPaths, matchPath, matchRoutes, matchRoutesImpl, normalizePathname, parseToInfo, prependBasename, redirect, redirectDocument, removeDoubleSlashes, removeTrailingSlash, replace, resolvePath, resolveTo, stripBasename };
|