@remix-run/router 1.6.2 → 1.6.3-pre.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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @remix-run/router v1.6.2
2
+ * @remix-run/router v1.6.3-pre.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -16,14 +16,12 @@ function _extends() {
16
16
  _extends = Object.assign ? Object.assign.bind() : function (target) {
17
17
  for (var i = 1; i < arguments.length; i++) {
18
18
  var source = arguments[i];
19
-
20
19
  for (var key in source) {
21
20
  if (Object.prototype.hasOwnProperty.call(source, key)) {
22
21
  target[key] = source[key];
23
22
  }
24
23
  }
25
24
  }
26
-
27
25
  return target;
28
26
  };
29
27
  return _extends.apply(this, arguments);
@@ -37,17 +35,41 @@ function _extends() {
37
35
  * Actions represent the type of change to a location value.
38
36
  */
39
37
  exports.Action = void 0;
38
+
40
39
  /**
41
40
  * The pathname, search, and hash values of a URL.
42
41
  */
43
-
44
42
  (function (Action) {
45
43
  Action["Pop"] = "POP";
46
44
  Action["Push"] = "PUSH";
47
45
  Action["Replace"] = "REPLACE";
48
46
  })(exports.Action || (exports.Action = {}));
47
+ /**
48
+ * An entry in a history stack. A location contains information about the
49
+ * URL path, as well as possibly some arbitrary state and a key.
50
+ */
51
+ /**
52
+ * A change to the current location.
53
+ */
54
+ /**
55
+ * A function that receives notifications about location changes.
56
+ */
57
+ /**
58
+ * Describes a location that is the destination of some navigation, either via
59
+ * `history.push` or `history.replace`. May be either a URL or the pieces of a
60
+ * URL path.
61
+ */
62
+ /**
63
+ * A history is an interface to the navigation stack. The history serves as the
64
+ * source of truth for the current location, as well as provides a set of
65
+ * methods that may be used to change it.
66
+ *
67
+ * It is similar to the DOM's `window.history` object, but with a smaller, more
68
+ * focused API.
69
+ */
70
+ const PopStateEventType = "popstate";
71
+ //#endregion
49
72
 
50
- const PopStateEventType = "popstate"; //#endregion
51
73
  ////////////////////////////////////////////////////////////////////////////////
52
74
  //#region Memory History
53
75
  ////////////////////////////////////////////////////////////////////////////////
@@ -56,7 +78,11 @@ const PopStateEventType = "popstate"; //#endregion
56
78
  * A user-supplied object that describes a location. Used when providing
57
79
  * entries to `createMemoryHistory` via its `initialEntries` option.
58
80
  */
59
-
81
+ /**
82
+ * A memory history stores locations in memory. This is useful in stateful
83
+ * environments where there is no web browser, such as node tests or React
84
+ * Native.
85
+ */
60
86
  /**
61
87
  * Memory history stores the current location in memory. It is designed for use
62
88
  * in stateful non-browser environments like tests and React Native.
@@ -65,60 +91,47 @@ function createMemoryHistory(options) {
65
91
  if (options === void 0) {
66
92
  options = {};
67
93
  }
68
-
69
94
  let {
70
95
  initialEntries = ["/"],
71
96
  initialIndex,
72
97
  v5Compat = false
73
98
  } = options;
74
99
  let entries; // Declare so we can access from createMemoryLocation
75
-
76
100
  entries = initialEntries.map((entry, index) => createMemoryLocation(entry, typeof entry === "string" ? null : entry.state, index === 0 ? "default" : undefined));
77
101
  let index = clampIndex(initialIndex == null ? entries.length - 1 : initialIndex);
78
102
  let action = exports.Action.Pop;
79
103
  let listener = null;
80
-
81
104
  function clampIndex(n) {
82
105
  return Math.min(Math.max(n, 0), entries.length - 1);
83
106
  }
84
-
85
107
  function getCurrentLocation() {
86
108
  return entries[index];
87
109
  }
88
-
89
110
  function createMemoryLocation(to, state, key) {
90
111
  if (state === void 0) {
91
112
  state = null;
92
113
  }
93
-
94
114
  let location = createLocation(entries ? getCurrentLocation().pathname : "/", to, state, key);
95
115
  warning(location.pathname.charAt(0) === "/", "relative pathnames are not supported in memory history: " + JSON.stringify(to));
96
116
  return location;
97
117
  }
98
-
99
118
  function createHref(to) {
100
119
  return typeof to === "string" ? to : createPath(to);
101
120
  }
102
-
103
121
  let history = {
104
122
  get index() {
105
123
  return index;
106
124
  },
107
-
108
125
  get action() {
109
126
  return action;
110
127
  },
111
-
112
128
  get location() {
113
129
  return getCurrentLocation();
114
130
  },
115
-
116
131
  createHref,
117
-
118
132
  createURL(to) {
119
133
  return new URL(createHref(to), "http://localhost");
120
134
  },
121
-
122
135
  encodeLocation(to) {
123
136
  let path = typeof to === "string" ? parsePath(to) : to;
124
137
  return {
@@ -127,13 +140,11 @@ function createMemoryHistory(options) {
127
140
  hash: path.hash || ""
128
141
  };
129
142
  },
130
-
131
143
  push(to, state) {
132
144
  action = exports.Action.Push;
133
145
  let nextLocation = createMemoryLocation(to, state);
134
146
  index += 1;
135
147
  entries.splice(index, entries.length, nextLocation);
136
-
137
148
  if (v5Compat && listener) {
138
149
  listener({
139
150
  action,
@@ -142,12 +153,10 @@ function createMemoryHistory(options) {
142
153
  });
143
154
  }
144
155
  },
145
-
146
156
  replace(to, state) {
147
157
  action = exports.Action.Replace;
148
158
  let nextLocation = createMemoryLocation(to, state);
149
159
  entries[index] = nextLocation;
150
-
151
160
  if (v5Compat && listener) {
152
161
  listener({
153
162
  action,
@@ -156,13 +165,11 @@ function createMemoryHistory(options) {
156
165
  });
157
166
  }
158
167
  },
159
-
160
168
  go(delta) {
161
169
  action = exports.Action.Pop;
162
170
  let nextIndex = clampIndex(index + delta);
163
171
  let nextLocation = entries[nextIndex];
164
172
  index = nextIndex;
165
-
166
173
  if (listener) {
167
174
  listener({
168
175
  action,
@@ -171,17 +178,17 @@ function createMemoryHistory(options) {
171
178
  });
172
179
  }
173
180
  },
174
-
175
181
  listen(fn) {
176
182
  listener = fn;
177
183
  return () => {
178
184
  listener = null;
179
185
  };
180
186
  }
181
-
182
187
  };
183
188
  return history;
184
- } //#endregion
189
+ }
190
+ //#endregion
191
+
185
192
  ////////////////////////////////////////////////////////////////////////////////
186
193
  //#region Browser History
187
194
  ////////////////////////////////////////////////////////////////////////////////
@@ -193,7 +200,6 @@ function createMemoryHistory(options) {
193
200
  *
194
201
  * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#browserhistory
195
202
  */
196
-
197
203
  /**
198
204
  * Browser history stores the location in regular URLs. This is the standard for
199
205
  * most web apps, but it requires some configuration on the server to ensure you
@@ -205,7 +211,6 @@ function createBrowserHistory(options) {
205
211
  if (options === void 0) {
206
212
  options = {};
207
213
  }
208
-
209
214
  function createBrowserLocation(window, globalHistory) {
210
215
  let {
211
216
  pathname,
@@ -216,16 +221,17 @@ function createBrowserHistory(options) {
216
221
  pathname,
217
222
  search,
218
223
  hash
219
- }, // state defaults to `null` because `window.history.state` does
224
+ },
225
+ // state defaults to `null` because `window.history.state` does
220
226
  globalHistory.state && globalHistory.state.usr || null, globalHistory.state && globalHistory.state.key || "default");
221
227
  }
222
-
223
228
  function createBrowserHref(window, to) {
224
229
  return typeof to === "string" ? to : createPath(to);
225
230
  }
226
-
227
231
  return getUrlBasedHistory(createBrowserLocation, createBrowserHref, null, options);
228
- } //#endregion
232
+ }
233
+ //#endregion
234
+
229
235
  ////////////////////////////////////////////////////////////////////////////////
230
236
  //#region Hash History
231
237
  ////////////////////////////////////////////////////////////////////////////////
@@ -241,7 +247,6 @@ function createBrowserHistory(options) {
241
247
  *
242
248
  * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#hashhistory
243
249
  */
244
-
245
250
  /**
246
251
  * Hash history stores the location in window.location.hash. This makes it ideal
247
252
  * for situations where you don't want to send the location to the server for
@@ -254,7 +259,6 @@ function createHashHistory(options) {
254
259
  if (options === void 0) {
255
260
  options = {};
256
261
  }
257
-
258
262
  function createHashLocation(window, globalHistory) {
259
263
  let {
260
264
  pathname = "/",
@@ -265,29 +269,27 @@ function createHashHistory(options) {
265
269
  pathname,
266
270
  search,
267
271
  hash
268
- }, // state defaults to `null` because `window.history.state` does
272
+ },
273
+ // state defaults to `null` because `window.history.state` does
269
274
  globalHistory.state && globalHistory.state.usr || null, globalHistory.state && globalHistory.state.key || "default");
270
275
  }
271
-
272
276
  function createHashHref(window, to) {
273
277
  let base = window.document.querySelector("base");
274
278
  let href = "";
275
-
276
279
  if (base && base.getAttribute("href")) {
277
280
  let url = window.location.href;
278
281
  let hashIndex = url.indexOf("#");
279
282
  href = hashIndex === -1 ? url : url.slice(0, hashIndex);
280
283
  }
281
-
282
284
  return href + "#" + (typeof to === "string" ? to : createPath(to));
283
285
  }
284
-
285
286
  function validateHashLocation(location, to) {
286
287
  warning(location.pathname.charAt(0) === "/", "relative pathnames are not supported in hash history.push(" + JSON.stringify(to) + ")");
287
288
  }
288
-
289
289
  return getUrlBasedHistory(createHashLocation, createHashHref, validateHashLocation, options);
290
- } //#endregion
290
+ }
291
+ //#endregion
292
+
291
293
  ////////////////////////////////////////////////////////////////////////////////
292
294
  //#region UTILS
293
295
  ////////////////////////////////////////////////////////////////////////////////
@@ -295,7 +297,6 @@ function createHashHistory(options) {
295
297
  /**
296
298
  * @private
297
299
  */
298
-
299
300
  function invariant(value, message) {
300
301
  if (value === false || value === null || typeof value === "undefined") {
301
302
  throw new Error(message);
@@ -305,26 +306,24 @@ function warning(cond, message) {
305
306
  if (!cond) {
306
307
  // eslint-disable-next-line no-console
307
308
  if (typeof console !== "undefined") console.warn(message);
308
-
309
309
  try {
310
310
  // Welcome to debugging history!
311
311
  //
312
312
  // This error is thrown as a convenience so you can more easily
313
313
  // find the source for a warning that appears in the console by
314
314
  // enabling "pause on exceptions" in your JavaScript debugger.
315
- throw new Error(message); // eslint-disable-next-line no-empty
315
+ throw new Error(message);
316
+ // eslint-disable-next-line no-empty
316
317
  } catch (e) {}
317
318
  }
318
319
  }
319
-
320
320
  function createKey() {
321
321
  return Math.random().toString(36).substr(2, 8);
322
322
  }
323
+
323
324
  /**
324
325
  * For browser-based histories, we combine the state and key into an object
325
326
  */
326
-
327
-
328
327
  function getHistoryState(location, index) {
329
328
  return {
330
329
  usr: location.state,
@@ -332,16 +331,14 @@ function getHistoryState(location, index) {
332
331
  idx: index
333
332
  };
334
333
  }
334
+
335
335
  /**
336
336
  * Creates a Location object with a unique key from the given Path
337
337
  */
338
-
339
-
340
338
  function createLocation(current, to, state, key) {
341
339
  if (state === void 0) {
342
340
  state = null;
343
341
  }
344
-
345
342
  let location = _extends({
346
343
  pathname: typeof current === "string" ? current : current.pathname,
347
344
  search: "",
@@ -354,13 +351,12 @@ function createLocation(current, to, state, key) {
354
351
  // keep as is for the time being and just let any incoming keys take precedence
355
352
  key: to && to.key || key || createKey()
356
353
  });
357
-
358
354
  return location;
359
355
  }
356
+
360
357
  /**
361
358
  * Creates a string URL path from the given pathname, search, and hash components.
362
359
  */
363
-
364
360
  function createPath(_ref) {
365
361
  let {
366
362
  pathname = "/",
@@ -371,41 +367,33 @@ function createPath(_ref) {
371
367
  if (hash && hash !== "#") pathname += hash.charAt(0) === "#" ? hash : "#" + hash;
372
368
  return pathname;
373
369
  }
370
+
374
371
  /**
375
372
  * Parses a string URL path into its separate pathname, search, and hash components.
376
373
  */
377
-
378
374
  function parsePath(path) {
379
375
  let parsedPath = {};
380
-
381
376
  if (path) {
382
377
  let hashIndex = path.indexOf("#");
383
-
384
378
  if (hashIndex >= 0) {
385
379
  parsedPath.hash = path.substr(hashIndex);
386
380
  path = path.substr(0, hashIndex);
387
381
  }
388
-
389
382
  let searchIndex = path.indexOf("?");
390
-
391
383
  if (searchIndex >= 0) {
392
384
  parsedPath.search = path.substr(searchIndex);
393
385
  path = path.substr(0, searchIndex);
394
386
  }
395
-
396
387
  if (path) {
397
388
  parsedPath.pathname = path;
398
389
  }
399
390
  }
400
-
401
391
  return parsedPath;
402
392
  }
403
-
404
393
  function getUrlBasedHistory(getLocation, createHref, validateLocation, options) {
405
394
  if (options === void 0) {
406
395
  options = {};
407
396
  }
408
-
409
397
  let {
410
398
  window = document.defaultView,
411
399
  v5Compat = false
@@ -413,30 +401,27 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
413
401
  let globalHistory = window.history;
414
402
  let action = exports.Action.Pop;
415
403
  let listener = null;
416
- let index = getIndex(); // Index should only be null when we initialize. If not, it's because the
404
+ let index = getIndex();
405
+ // Index should only be null when we initialize. If not, it's because the
417
406
  // user called history.pushState or history.replaceState directly, in which
418
407
  // case we should log a warning as it will result in bugs.
419
-
420
408
  if (index == null) {
421
409
  index = 0;
422
410
  globalHistory.replaceState(_extends({}, globalHistory.state, {
423
411
  idx: index
424
412
  }), "");
425
413
  }
426
-
427
414
  function getIndex() {
428
415
  let state = globalHistory.state || {
429
416
  idx: null
430
417
  };
431
418
  return state.idx;
432
419
  }
433
-
434
420
  function handlePop() {
435
421
  action = exports.Action.Pop;
436
422
  let nextIndex = getIndex();
437
423
  let delta = nextIndex == null ? null : nextIndex - index;
438
424
  index = nextIndex;
439
-
440
425
  if (listener) {
441
426
  listener({
442
427
  action,
@@ -445,23 +430,29 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
445
430
  });
446
431
  }
447
432
  }
448
-
449
433
  function push(to, state) {
450
434
  action = exports.Action.Push;
451
435
  let location = createLocation(history.location, to, state);
452
436
  if (validateLocation) validateLocation(location, to);
453
437
  index = getIndex() + 1;
454
438
  let historyState = getHistoryState(location, index);
455
- let url = history.createHref(location); // try...catch because iOS limits us to 100 pushState calls :/
439
+ let url = history.createHref(location);
456
440
 
441
+ // try...catch because iOS limits us to 100 pushState calls :/
457
442
  try {
458
443
  globalHistory.pushState(historyState, "", url);
459
444
  } catch (error) {
445
+ // If the exception is because `state` can't be serialized, let that throw
446
+ // outwards just like a replace call would so the dev knows the cause
447
+ // https://html.spec.whatwg.org/multipage/nav-history-apis.html#shared-history-push/replace-state-steps
448
+ // https://html.spec.whatwg.org/multipage/structured-data.html#structuredserializeinternal
449
+ if (error instanceof DOMException && error.name === "DataCloneError") {
450
+ throw error;
451
+ }
460
452
  // They are going to lose state here, but there is no real
461
453
  // way to warn them about it since the page will refresh...
462
454
  window.location.assign(url);
463
455
  }
464
-
465
456
  if (v5Compat && listener) {
466
457
  listener({
467
458
  action,
@@ -470,7 +461,6 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
470
461
  });
471
462
  }
472
463
  }
473
-
474
464
  function replace(to, state) {
475
465
  action = exports.Action.Replace;
476
466
  let location = createLocation(history.location, to, state);
@@ -479,7 +469,6 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
479
469
  let historyState = getHistoryState(location, index);
480
470
  let url = history.createHref(location);
481
471
  globalHistory.replaceState(historyState, "", url);
482
-
483
472
  if (v5Compat && listener) {
484
473
  listener({
485
474
  action,
@@ -488,7 +477,6 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
488
477
  });
489
478
  }
490
479
  }
491
-
492
480
  function createURL(to) {
493
481
  // window.location.origin is "null" (the literal string value) in Firefox
494
482
  // under certain conditions, notably when serving from a local HTML file
@@ -498,21 +486,17 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
498
486
  invariant(base, "No window.location.(origin|href) available to create URL for href: " + href);
499
487
  return new URL(href, base);
500
488
  }
501
-
502
489
  let history = {
503
490
  get action() {
504
491
  return action;
505
492
  },
506
-
507
493
  get location() {
508
494
  return getLocation(window, globalHistory);
509
495
  },
510
-
511
496
  listen(fn) {
512
497
  if (listener) {
513
498
  throw new Error("A history only accepts one active listener");
514
499
  }
515
-
516
500
  window.addEventListener(PopStateEventType, handlePop);
517
501
  listener = fn;
518
502
  return () => {
@@ -520,13 +504,10 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
520
504
  listener = null;
521
505
  };
522
506
  },
523
-
524
507
  createHref(to) {
525
508
  return createHref(window, to);
526
509
  },
527
-
528
510
  createURL,
529
-
530
511
  encodeLocation(to) {
531
512
  // Encode a Location the same way window.location would
532
513
  let url = createURL(to);
@@ -536,66 +517,176 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
536
517
  hash: url.hash
537
518
  };
538
519
  },
539
-
540
520
  push,
541
521
  replace,
542
-
543
522
  go(n) {
544
523
  return globalHistory.go(n);
545
524
  }
546
-
547
525
  };
548
526
  return history;
549
- } //#endregion
527
+ }
528
+
529
+ //#endregion
550
530
 
551
531
  /**
552
532
  * Map of routeId -> data returned from a loader/action/error
553
533
  */
554
534
 
555
535
  let ResultType;
536
+
556
537
  /**
557
538
  * Successful result from a loader or action
558
539
  */
559
-
560
540
  (function (ResultType) {
561
541
  ResultType["data"] = "data";
562
542
  ResultType["deferred"] = "deferred";
563
543
  ResultType["redirect"] = "redirect";
564
544
  ResultType["error"] = "error";
565
545
  })(ResultType || (ResultType = {}));
566
-
546
+ /**
547
+ * Successful defer() result from a loader or action
548
+ */
549
+ /**
550
+ * Redirect result from a loader or action
551
+ */
552
+ /**
553
+ * Unsuccessful result from a loader or action
554
+ */
555
+ /**
556
+ * Result from a loader or action - potentially successful or unsuccessful
557
+ */
558
+ /**
559
+ * Users can specify either lowercase or uppercase form methods on <Form>,
560
+ * useSubmit(), <fetcher.Form>, etc.
561
+ */
562
+ /**
563
+ * Active navigation/fetcher form methods are exposed in lowercase on the
564
+ * RouterState
565
+ */
566
+ /**
567
+ * In v7, active navigation/fetcher form methods are exposed in uppercase on the
568
+ * RouterState. This is to align with the normalization done via fetch().
569
+ */
570
+ /**
571
+ * @private
572
+ * Internal interface to pass around for action submissions, not intended for
573
+ * external consumption
574
+ */
575
+ /**
576
+ * @private
577
+ * Arguments passed to route loader/action functions. Same for now but we keep
578
+ * this as a private implementation detail in case they diverge in the future.
579
+ */
580
+ /**
581
+ * Arguments passed to loader functions
582
+ */
583
+ /**
584
+ * Arguments passed to action functions
585
+ */
586
+ /**
587
+ * Loaders and actions can return anything except `undefined` (`null` is a
588
+ * valid return value if there is no data to return). Responses are preferred
589
+ * and will ease any future migration to Remix
590
+ */
591
+ /**
592
+ * Route loader function signature
593
+ */
594
+ /**
595
+ * Route action function signature
596
+ */
597
+ /**
598
+ * Route shouldRevalidate function signature. This runs after any submission
599
+ * (navigation or fetcher), so we flatten the navigation/fetcher submission
600
+ * onto the arguments. It shouldn't matter whether it came from a navigation
601
+ * or a fetcher, what really matters is the URLs and the formData since loaders
602
+ * have to re-run based on the data models that were potentially mutated.
603
+ */
604
+ /**
605
+ * Function provided by the framework-aware layers to set `hasErrorBoundary`
606
+ * from the framework-aware `errorElement` prop
607
+ *
608
+ * @deprecated Use `mapRouteProperties` instead
609
+ */
610
+ /**
611
+ * Function provided by the framework-aware layers to set any framework-specific
612
+ * properties from framework-agnostic properties
613
+ */
614
+ /**
615
+ * Keys we cannot change from within a lazy() function. We spread all other keys
616
+ * onto the route. Either they're meaningful to the router, or they'll get
617
+ * ignored.
618
+ */
567
619
  const immutableRouteKeys = new Set(["lazy", "caseSensitive", "path", "id", "index", "children"]);
620
+
568
621
  /**
569
622
  * lazy() function to load a route definition, which can add non-matching
570
623
  * related properties to a route
571
624
  */
572
625
 
626
+ /**
627
+ * Base RouteObject with common props shared by all types of routes
628
+ */
629
+
630
+ /**
631
+ * Index routes must not have children
632
+ */
633
+
634
+ /**
635
+ * Non-index routes may have children, but cannot have index
636
+ */
637
+
638
+ /**
639
+ * A route object represents a logical route, with (optionally) its child
640
+ * routes organized in a tree-like structure.
641
+ */
642
+
643
+ /**
644
+ * A data route object, which is just a RouteObject with a required unique ID
645
+ */
646
+
647
+ // Recursive helper for finding path parameters in the absence of wildcards
648
+
649
+ /**
650
+ * Examples:
651
+ * "/a/b/*" -> "*"
652
+ * ":a" -> "a"
653
+ * "/a/:b" -> "b"
654
+ * "/a/blahblahblah:b" -> "b"
655
+ * "/:a/:b" -> "a" | "b"
656
+ * "/:a/b/:c/*" -> "a" | "c" | "*"
657
+ */
658
+
659
+ // Attempt to parse the given string segment. If it fails, then just return the
660
+ // plain string type as a default fallback. Otherwise return the union of the
661
+ // parsed string literals that were referenced as dynamic segments in the route.
662
+ /**
663
+ * The parameters that were parsed from the URL path.
664
+ */
665
+ /**
666
+ * A RouteMatch contains info about how a route matched a URL.
667
+ */
573
668
  function isIndexRoute(route) {
574
669
  return route.index === true;
575
- } // Walk the route tree generating unique IDs where necessary so we are working
576
- // solely with AgnosticDataRouteObject's within the Router
577
-
670
+ }
578
671
 
672
+ // Walk the route tree generating unique IDs where necessary so we are working
673
+ // solely with AgnosticDataRouteObject's within the Router
579
674
  function convertRoutesToDataRoutes(routes, mapRouteProperties, parentPath, manifest) {
580
675
  if (parentPath === void 0) {
581
676
  parentPath = [];
582
677
  }
583
-
584
678
  if (manifest === void 0) {
585
679
  manifest = {};
586
680
  }
587
-
588
681
  return routes.map((route, index) => {
589
682
  let treePath = [...parentPath, index];
590
683
  let id = typeof route.id === "string" ? route.id : treePath.join("-");
591
684
  invariant(route.index !== true || !route.children, "Cannot specify children on an index route");
592
685
  invariant(!manifest[id], "Found a route id collision on id \"" + id + "\". Route " + "id's must be globally unique within Data Router usages");
593
-
594
686
  if (isIndexRoute(route)) {
595
687
  let indexRoute = _extends({}, route, mapRouteProperties(route), {
596
688
  id
597
689
  });
598
-
599
690
  manifest[id] = indexRoute;
600
691
  return indexRoute;
601
692
  } else {
@@ -603,41 +694,35 @@ function convertRoutesToDataRoutes(routes, mapRouteProperties, parentPath, manif
603
694
  id,
604
695
  children: undefined
605
696
  });
606
-
607
697
  manifest[id] = pathOrLayoutRoute;
608
-
609
698
  if (route.children) {
610
699
  pathOrLayoutRoute.children = convertRoutesToDataRoutes(route.children, mapRouteProperties, treePath, manifest);
611
700
  }
612
-
613
701
  return pathOrLayoutRoute;
614
702
  }
615
703
  });
616
704
  }
705
+
617
706
  /**
618
707
  * Matches the given routes to a location and returns the match data.
619
708
  *
620
709
  * @see https://reactrouter.com/utils/match-routes
621
710
  */
622
-
623
711
  function matchRoutes(routes, locationArg, basename) {
624
712
  if (basename === void 0) {
625
713
  basename = "/";
626
714
  }
627
-
628
715
  let location = typeof locationArg === "string" ? parsePath(locationArg) : locationArg;
629
716
  let pathname = stripBasename(location.pathname || "/", basename);
630
-
631
717
  if (pathname == null) {
632
718
  return null;
633
719
  }
634
-
635
720
  let branches = flattenRoutes(routes);
636
721
  rankRouteBranches(branches);
637
722
  let matches = null;
638
-
639
723
  for (let i = 0; matches == null && i < branches.length; ++i) {
640
- matches = matchRouteBranch(branches[i], // Incoming pathnames are generally encoded from either window.location
724
+ matches = matchRouteBranch(branches[i],
725
+ // Incoming pathnames are generally encoded from either window.location
641
726
  // or from router.navigate, but we want to match against the unencoded
642
727
  // paths in the route definitions. Memory router locations won't be
643
728
  // encoded here but there also shouldn't be anything to decode so this
@@ -645,23 +730,18 @@ function matchRoutes(routes, locationArg, basename) {
645
730
  // history-aware.
646
731
  safelyDecodeURI(pathname));
647
732
  }
648
-
649
733
  return matches;
650
734
  }
651
-
652
735
  function flattenRoutes(routes, branches, parentsMeta, parentPath) {
653
736
  if (branches === void 0) {
654
737
  branches = [];
655
738
  }
656
-
657
739
  if (parentsMeta === void 0) {
658
740
  parentsMeta = [];
659
741
  }
660
-
661
742
  if (parentPath === void 0) {
662
743
  parentPath = "";
663
744
  }
664
-
665
745
  let flattenRoute = (route, index, relativePath) => {
666
746
  let meta = {
667
747
  relativePath: relativePath === undefined ? route.path || "" : relativePath,
@@ -669,40 +749,37 @@ function flattenRoutes(routes, branches, parentsMeta, parentPath) {
669
749
  childrenIndex: index,
670
750
  route
671
751
  };
672
-
673
752
  if (meta.relativePath.startsWith("/")) {
674
753
  invariant(meta.relativePath.startsWith(parentPath), "Absolute route path \"" + meta.relativePath + "\" nested under path " + ("\"" + parentPath + "\" is not valid. An absolute child route path ") + "must start with the combined path of all its parent routes.");
675
754
  meta.relativePath = meta.relativePath.slice(parentPath.length);
676
755
  }
677
-
678
756
  let path = joinPaths([parentPath, meta.relativePath]);
679
- let routesMeta = parentsMeta.concat(meta); // Add the children before adding this route to the array so we traverse the
757
+ let routesMeta = parentsMeta.concat(meta);
758
+
759
+ // Add the children before adding this route to the array so we traverse the
680
760
  // route tree depth-first and child routes appear before their parents in
681
761
  // the "flattened" version.
682
-
683
762
  if (route.children && route.children.length > 0) {
684
- invariant( // Our types know better, but runtime JS may not!
763
+ invariant(
764
+ // Our types know better, but runtime JS may not!
685
765
  // @ts-expect-error
686
766
  route.index !== true, "Index routes must not have child routes. Please remove " + ("all child routes from route path \"" + path + "\"."));
687
767
  flattenRoutes(route.children, branches, routesMeta, path);
688
- } // Routes without a path shouldn't ever match by themselves unless they are
689
- // index routes, so don't add them to the list of possible branches.
690
-
768
+ }
691
769
 
770
+ // Routes without a path shouldn't ever match by themselves unless they are
771
+ // index routes, so don't add them to the list of possible branches.
692
772
  if (route.path == null && !route.index) {
693
773
  return;
694
774
  }
695
-
696
775
  branches.push({
697
776
  path,
698
777
  score: computeScore(path, route.index),
699
778
  routesMeta
700
779
  });
701
780
  };
702
-
703
781
  routes.forEach((route, index) => {
704
782
  var _route$path;
705
-
706
783
  // coarse-grain check for optional params
707
784
  if (route.path === "" || !((_route$path = route.path) != null && _route$path.includes("?"))) {
708
785
  flattenRoute(route, index);
@@ -714,6 +791,7 @@ function flattenRoutes(routes, branches, parentsMeta, parentPath) {
714
791
  });
715
792
  return branches;
716
793
  }
794
+
717
795
  /**
718
796
  * Computes all combinations of optional path segments for a given path,
719
797
  * excluding combinations that are ambiguous and of lower priority.
@@ -728,82 +806,74 @@ function flattenRoutes(routes, branches, parentsMeta, parentPath) {
728
806
  * - `/one/three/:four/:five`
729
807
  * - `/one/:two/three/:four/:five`
730
808
  */
731
-
732
-
733
809
  function explodeOptionalSegments(path) {
734
810
  let segments = path.split("/");
735
811
  if (segments.length === 0) return [];
736
- let [first, ...rest] = segments; // Optional path segments are denoted by a trailing `?`
737
-
738
- let isOptional = first.endsWith("?"); // Compute the corresponding required segment: `foo?` -> `foo`
812
+ let [first, ...rest] = segments;
739
813
 
814
+ // Optional path segments are denoted by a trailing `?`
815
+ let isOptional = first.endsWith("?");
816
+ // Compute the corresponding required segment: `foo?` -> `foo`
740
817
  let required = first.replace(/\?$/, "");
741
-
742
818
  if (rest.length === 0) {
743
819
  // Intepret empty string as omitting an optional segment
744
820
  // `["one", "", "three"]` corresponds to omitting `:two` from `/one/:two?/three` -> `/one/three`
745
821
  return isOptional ? [required, ""] : [required];
746
822
  }
747
-
748
823
  let restExploded = explodeOptionalSegments(rest.join("/"));
749
- let result = []; // All child paths with the prefix. Do this for all children before the
824
+ let result = [];
825
+
826
+ // All child paths with the prefix. Do this for all children before the
750
827
  // optional version for all children so we get consistent ordering where the
751
828
  // parent optional aspect is preferred as required. Otherwise, we can get
752
829
  // child sections interspersed where deeper optional segments are higher than
753
830
  // parent optional segments, where for example, /:two would explodes _earlier_
754
831
  // then /:one. By always including the parent as required _for all children_
755
832
  // first, we avoid this issue
833
+ result.push(...restExploded.map(subpath => subpath === "" ? required : [required, subpath].join("/")));
756
834
 
757
- result.push(...restExploded.map(subpath => subpath === "" ? required : [required, subpath].join("/"))); // Then if this is an optional value, add all child versions without
758
-
835
+ // Then if this is an optional value, add all child versions without
759
836
  if (isOptional) {
760
837
  result.push(...restExploded);
761
- } // for absolute paths, ensure `/` instead of empty segment
762
-
838
+ }
763
839
 
840
+ // for absolute paths, ensure `/` instead of empty segment
764
841
  return result.map(exploded => path.startsWith("/") && exploded === "" ? "/" : exploded);
765
842
  }
766
-
767
843
  function rankRouteBranches(branches) {
768
844
  branches.sort((a, b) => a.score !== b.score ? b.score - a.score // Higher score first
769
845
  : compareIndexes(a.routesMeta.map(meta => meta.childrenIndex), b.routesMeta.map(meta => meta.childrenIndex)));
770
846
  }
771
-
772
847
  const paramRe = /^:\w+$/;
773
848
  const dynamicSegmentValue = 3;
774
849
  const indexRouteValue = 2;
775
850
  const emptySegmentValue = 1;
776
851
  const staticSegmentValue = 10;
777
852
  const splatPenalty = -2;
778
-
779
853
  const isSplat = s => s === "*";
780
-
781
854
  function computeScore(path, index) {
782
855
  let segments = path.split("/");
783
856
  let initialScore = segments.length;
784
-
785
857
  if (segments.some(isSplat)) {
786
858
  initialScore += splatPenalty;
787
859
  }
788
-
789
860
  if (index) {
790
861
  initialScore += indexRouteValue;
791
862
  }
792
-
793
863
  return segments.filter(s => !isSplat(s)).reduce((score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue), initialScore);
794
864
  }
795
-
796
865
  function compareIndexes(a, b) {
797
866
  let siblings = a.length === b.length && a.slice(0, -1).every((n, i) => n === b[i]);
798
- return siblings ? // If two routes are siblings, we should try to match the earlier sibling
867
+ return siblings ?
868
+ // If two routes are siblings, we should try to match the earlier sibling
799
869
  // first. This allows people to have fine-grained control over the matching
800
870
  // behavior by simply putting routes with identical paths in the order they
801
871
  // want them tried.
802
- a[a.length - 1] - b[b.length - 1] : // Otherwise, it doesn't really make sense to rank non-siblings by index,
872
+ a[a.length - 1] - b[b.length - 1] :
873
+ // Otherwise, it doesn't really make sense to rank non-siblings by index,
803
874
  // so they sort equally.
804
875
  0;
805
876
  }
806
-
807
877
  function matchRouteBranch(branch, pathname) {
808
878
  let {
809
879
  routesMeta
@@ -811,7 +881,6 @@ function matchRouteBranch(branch, pathname) {
811
881
  let matchedParams = {};
812
882
  let matchedPathname = "/";
813
883
  let matches = [];
814
-
815
884
  for (let i = 0; i < routesMeta.length; ++i) {
816
885
  let meta = routesMeta[i];
817
886
  let end = i === routesMeta.length - 1;
@@ -831,72 +900,70 @@ function matchRouteBranch(branch, pathname) {
831
900
  pathnameBase: normalizePathname(joinPaths([matchedPathname, match.pathnameBase])),
832
901
  route
833
902
  });
834
-
835
903
  if (match.pathnameBase !== "/") {
836
904
  matchedPathname = joinPaths([matchedPathname, match.pathnameBase]);
837
905
  }
838
906
  }
839
-
840
907
  return matches;
841
908
  }
909
+
842
910
  /**
843
911
  * Returns a path with params interpolated.
844
912
  *
845
913
  * @see https://reactrouter.com/utils/generate-path
846
914
  */
847
-
848
-
849
915
  function generatePath(originalPath, params) {
850
916
  if (params === void 0) {
851
917
  params = {};
852
918
  }
853
-
854
919
  let path = originalPath;
855
-
856
920
  if (path.endsWith("*") && path !== "*" && !path.endsWith("/*")) {
857
921
  warning(false, "Route path \"" + path + "\" will be treated as if it were " + ("\"" + path.replace(/\*$/, "/*") + "\" because the `*` character must ") + "always follow a `/` in the pattern. To get rid of this warning, " + ("please change the route path to \"" + path.replace(/\*$/, "/*") + "\"."));
858
922
  path = path.replace(/\*$/, "/*");
859
- } // ensure `/` is added at the beginning if the path is absolute
860
-
923
+ }
861
924
 
925
+ // ensure `/` is added at the beginning if the path is absolute
862
926
  const prefix = path.startsWith("/") ? "/" : "";
863
927
  const segments = path.split(/\/+/).map((segment, index, array) => {
864
- const isLastSegment = index === array.length - 1; // only apply the splat if it's the last segment
928
+ const isLastSegment = index === array.length - 1;
865
929
 
930
+ // only apply the splat if it's the last segment
866
931
  if (isLastSegment && segment === "*") {
867
932
  const star = "*";
868
- const starParam = params[star]; // Apply the splat
933
+ const starParam = params[star];
869
934
 
935
+ // Apply the splat
870
936
  return starParam;
871
937
  }
872
-
873
938
  const keyMatch = segment.match(/^:(\w+)(\??)$/);
874
-
875
939
  if (keyMatch) {
876
940
  const [, key, optional] = keyMatch;
877
941
  let param = params[key];
878
-
879
942
  if (optional === "?") {
880
943
  return param == null ? "" : param;
881
944
  }
882
-
883
945
  if (param == null) {
884
946
  invariant(false, "Missing \":" + key + "\" param");
885
947
  }
886
-
887
948
  return param;
888
- } // Remove any optional markers from optional static segments
889
-
949
+ }
890
950
 
951
+ // Remove any optional markers from optional static segments
891
952
  return segment.replace(/\?$/g, "");
892
- }) // Remove empty segments
953
+ })
954
+ // Remove empty segments
893
955
  .filter(segment => !!segment);
894
956
  return prefix + segments.join("/");
895
957
  }
958
+
896
959
  /**
897
960
  * A PathPattern is used to match on some portion of a URL pathname.
898
961
  */
899
962
 
963
+ /**
964
+ * A PathMatch contains info about how a PathPattern matched on a URL pathname.
965
+ */
966
+
900
967
  /**
901
968
  * Performs pattern matching on a URL pathname and returns information about
902
969
  * the match.
@@ -911,7 +978,6 @@ function matchPath(pattern, pathname) {
911
978
  end: true
912
979
  };
913
980
  }
914
-
915
981
  let [matcher, paramNames] = compilePath(pattern.path, pattern.caseSensitive, pattern.end);
916
982
  let match = pathname.match(matcher);
917
983
  if (!match) return null;
@@ -925,7 +991,6 @@ function matchPath(pattern, pathname) {
925
991
  let splatValue = captureGroups[index] || "";
926
992
  pathnameBase = matchedPathname.slice(0, matchedPathname.length - splatValue.length).replace(/(.)\/+$/, "$1");
927
993
  }
928
-
929
994
  memo[paramName] = safelyDecodeURIComponent(captureGroups[index] || "", paramName);
930
995
  return memo;
931
996
  }, {});
@@ -936,16 +1001,13 @@ function matchPath(pattern, pathname) {
936
1001
  pattern
937
1002
  };
938
1003
  }
939
-
940
1004
  function compilePath(path, caseSensitive, end) {
941
1005
  if (caseSensitive === void 0) {
942
1006
  caseSensitive = false;
943
1007
  }
944
-
945
1008
  if (end === void 0) {
946
1009
  end = true;
947
1010
  }
948
-
949
1011
  warning(path === "*" || !path.endsWith("*") || path.endsWith("/*"), "Route path \"" + path + "\" will be treated as if it were " + ("\"" + path.replace(/\*$/, "/*") + "\" because the `*` character must ") + "always follow a `/` in the pattern. To get rid of this warning, " + ("please change the route path to \"" + path.replace(/\*$/, "/*") + "\"."));
950
1012
  let paramNames = [];
951
1013
  let regexpSource = "^" + path.replace(/\/*\*?$/, "") // Ignore trailing / and /*, we'll handle it below
@@ -955,7 +1017,6 @@ function compilePath(path, caseSensitive, end) {
955
1017
  paramNames.push(paramName);
956
1018
  return "/([^\\/]+)";
957
1019
  });
958
-
959
1020
  if (path.endsWith("*")) {
960
1021
  paramNames.push("*");
961
1022
  regexpSource += path === "*" || path === "/*" ? "(.*)$" // Already matched the initial /, just match the rest
@@ -973,11 +1034,9 @@ function compilePath(path, caseSensitive, end) {
973
1034
  // /user-preferences since `-` counts as a word boundary.
974
1035
  regexpSource += "(?:(?=\\/|$))";
975
1036
  } else ;
976
-
977
1037
  let matcher = new RegExp(regexpSource, caseSensitive ? undefined : "i");
978
1038
  return [matcher, paramNames];
979
1039
  }
980
-
981
1040
  function safelyDecodeURI(value) {
982
1041
  try {
983
1042
  return decodeURI(value);
@@ -986,7 +1045,6 @@ function safelyDecodeURI(value) {
986
1045
  return value;
987
1046
  }
988
1047
  }
989
-
990
1048
  function safelyDecodeURIComponent(value, paramName) {
991
1049
  try {
992
1050
  return decodeURIComponent(value);
@@ -995,41 +1053,36 @@ function safelyDecodeURIComponent(value, paramName) {
995
1053
  return value;
996
1054
  }
997
1055
  }
1056
+
998
1057
  /**
999
1058
  * @private
1000
1059
  */
1001
-
1002
-
1003
1060
  function stripBasename(pathname, basename) {
1004
1061
  if (basename === "/") return pathname;
1005
-
1006
1062
  if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {
1007
1063
  return null;
1008
- } // We want to leave trailing slash behavior in the user's control, so if they
1009
- // specify a basename with a trailing slash, we should support it
1010
-
1064
+ }
1011
1065
 
1066
+ // We want to leave trailing slash behavior in the user's control, so if they
1067
+ // specify a basename with a trailing slash, we should support it
1012
1068
  let startIndex = basename.endsWith("/") ? basename.length - 1 : basename.length;
1013
1069
  let nextChar = pathname.charAt(startIndex);
1014
-
1015
1070
  if (nextChar && nextChar !== "/") {
1016
1071
  // pathname does not start with basename/
1017
1072
  return null;
1018
1073
  }
1019
-
1020
1074
  return pathname.slice(startIndex) || "/";
1021
1075
  }
1076
+
1022
1077
  /**
1023
1078
  * Returns a resolved path object relative to the given pathname.
1024
1079
  *
1025
1080
  * @see https://reactrouter.com/utils/resolve-path
1026
1081
  */
1027
-
1028
1082
  function resolvePath(to, fromPathname) {
1029
1083
  if (fromPathname === void 0) {
1030
1084
  fromPathname = "/";
1031
1085
  }
1032
-
1033
1086
  let {
1034
1087
  pathname: toPathname,
1035
1088
  search = "",
@@ -1042,7 +1095,6 @@ function resolvePath(to, fromPathname) {
1042
1095
  hash: normalizeHash(hash)
1043
1096
  };
1044
1097
  }
1045
-
1046
1098
  function resolvePathname(relativePath, fromPathname) {
1047
1099
  let segments = fromPathname.replace(/\/+$/, "").split("/");
1048
1100
  let relativeSegments = relativePath.split("/");
@@ -1056,10 +1108,10 @@ function resolvePathname(relativePath, fromPathname) {
1056
1108
  });
1057
1109
  return segments.length > 1 ? segments.join("/") : "/";
1058
1110
  }
1059
-
1060
1111
  function getInvalidPathError(char, field, dest, path) {
1061
1112
  return "Cannot include a '" + char + "' character in a manually specified " + ("`to." + field + "` field [" + JSON.stringify(path) + "]. Please separate it out to the ") + ("`to." + dest + "` field. Alternatively you may provide the full path as ") + "a string in <Link to=\"...\"> and the router will parse it for you.";
1062
1113
  }
1114
+
1063
1115
  /**
1064
1116
  * @private
1065
1117
  *
@@ -1083,22 +1135,18 @@ function getInvalidPathError(char, field, dest, path) {
1083
1135
  * </Route>
1084
1136
  * </Route>
1085
1137
  */
1086
-
1087
-
1088
1138
  function getPathContributingMatches(matches) {
1089
1139
  return matches.filter((match, index) => index === 0 || match.route.path && match.route.path.length > 0);
1090
1140
  }
1141
+
1091
1142
  /**
1092
1143
  * @private
1093
1144
  */
1094
-
1095
1145
  function resolveTo(toArg, routePathnames, locationPathname, isPathRelative) {
1096
1146
  if (isPathRelative === void 0) {
1097
1147
  isPathRelative = false;
1098
1148
  }
1099
-
1100
1149
  let to;
1101
-
1102
1150
  if (typeof toArg === "string") {
1103
1151
  to = parsePath(toArg);
1104
1152
  } else {
@@ -1107,10 +1155,11 @@ function resolveTo(toArg, routePathnames, locationPathname, isPathRelative) {
1107
1155
  invariant(!to.pathname || !to.pathname.includes("#"), getInvalidPathError("#", "pathname", "hash", to));
1108
1156
  invariant(!to.search || !to.search.includes("#"), getInvalidPathError("#", "search", "hash", to));
1109
1157
  }
1110
-
1111
1158
  let isEmptyPath = toArg === "" || to.pathname === "";
1112
1159
  let toPathname = isEmptyPath ? "/" : to.pathname;
1113
- let from; // Routing is relative to the current pathname if explicitly requested.
1160
+ let from;
1161
+
1162
+ // Routing is relative to the current pathname if explicitly requested.
1114
1163
  //
1115
1164
  // If a pathname is explicitly provided in `to`, it should be relative to the
1116
1165
  // route context. This is explained in `Note on `<Link to>` values` in our
@@ -1119,71 +1168,66 @@ function resolveTo(toArg, routePathnames, locationPathname, isPathRelative) {
1119
1168
  // `to` values that do not provide a pathname. `to` can simply be a search or
1120
1169
  // hash string, in which case we should assume that the navigation is relative
1121
1170
  // to the current location's pathname and *not* the route pathname.
1122
-
1123
1171
  if (isPathRelative || toPathname == null) {
1124
1172
  from = locationPathname;
1125
1173
  } else {
1126
1174
  let routePathnameIndex = routePathnames.length - 1;
1127
-
1128
1175
  if (toPathname.startsWith("..")) {
1129
- let toSegments = toPathname.split("/"); // Each leading .. segment means "go up one route" instead of "go up one
1176
+ let toSegments = toPathname.split("/");
1177
+
1178
+ // Each leading .. segment means "go up one route" instead of "go up one
1130
1179
  // URL segment". This is a key difference from how <a href> works and a
1131
1180
  // major reason we call this a "to" value instead of a "href".
1132
-
1133
1181
  while (toSegments[0] === "..") {
1134
1182
  toSegments.shift();
1135
1183
  routePathnameIndex -= 1;
1136
1184
  }
1137
-
1138
1185
  to.pathname = toSegments.join("/");
1139
- } // If there are more ".." segments than parent routes, resolve relative to
1140
- // the root / URL.
1141
-
1186
+ }
1142
1187
 
1188
+ // If there are more ".." segments than parent routes, resolve relative to
1189
+ // the root / URL.
1143
1190
  from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
1144
1191
  }
1192
+ let path = resolvePath(to, from);
1145
1193
 
1146
- let path = resolvePath(to, from); // Ensure the pathname has a trailing slash if the original "to" had one
1147
-
1148
- let hasExplicitTrailingSlash = toPathname && toPathname !== "/" && toPathname.endsWith("/"); // Or if this was a link to the current path which has a trailing slash
1149
-
1194
+ // Ensure the pathname has a trailing slash if the original "to" had one
1195
+ let hasExplicitTrailingSlash = toPathname && toPathname !== "/" && toPathname.endsWith("/");
1196
+ // Or if this was a link to the current path which has a trailing slash
1150
1197
  let hasCurrentTrailingSlash = (isEmptyPath || toPathname === ".") && locationPathname.endsWith("/");
1151
-
1152
1198
  if (!path.pathname.endsWith("/") && (hasExplicitTrailingSlash || hasCurrentTrailingSlash)) {
1153
1199
  path.pathname += "/";
1154
1200
  }
1155
-
1156
1201
  return path;
1157
1202
  }
1203
+
1158
1204
  /**
1159
1205
  * @private
1160
1206
  */
1161
-
1162
1207
  function getToPathname(to) {
1163
1208
  // Empty strings should be treated the same as / paths
1164
1209
  return to === "" || to.pathname === "" ? "/" : typeof to === "string" ? parsePath(to).pathname : to.pathname;
1165
1210
  }
1211
+
1166
1212
  /**
1167
1213
  * @private
1168
1214
  */
1169
-
1170
1215
  const joinPaths = paths => paths.join("/").replace(/\/\/+/g, "/");
1216
+
1171
1217
  /**
1172
1218
  * @private
1173
1219
  */
1174
-
1175
1220
  const normalizePathname = pathname => pathname.replace(/\/+$/, "").replace(/^\/*/, "/");
1221
+
1176
1222
  /**
1177
1223
  * @private
1178
1224
  */
1179
-
1180
1225
  const normalizeSearch = search => !search || search === "?" ? "" : search.startsWith("?") ? search : "?" + search;
1226
+
1181
1227
  /**
1182
1228
  * @private
1183
1229
  */
1184
-
1185
1230
  const normalizeHash = hash => !hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash;
1186
-
1187
1231
  /**
1188
1232
  * This is a shortcut for creating `application/json` responses. Converts `data`
1189
1233
  * to JSON and sets the `Content-Type` header.
@@ -1192,16 +1236,13 @@ const json = function json(data, init) {
1192
1236
  if (init === void 0) {
1193
1237
  init = {};
1194
1238
  }
1195
-
1196
1239
  let responseInit = typeof init === "number" ? {
1197
1240
  status: init
1198
1241
  } : init;
1199
1242
  let headers = new Headers(responseInit.headers);
1200
-
1201
1243
  if (!headers.has("Content-Type")) {
1202
1244
  headers.set("Content-Type", "application/json; charset=utf-8");
1203
1245
  }
1204
-
1205
1246
  return new Response(JSON.stringify(data), _extends({}, responseInit, {
1206
1247
  headers
1207
1248
  }));
@@ -1212,17 +1253,15 @@ class DeferredData {
1212
1253
  this.pendingKeysSet = new Set();
1213
1254
  this.subscribers = new Set();
1214
1255
  this.deferredKeys = [];
1215
- invariant(data && typeof data === "object" && !Array.isArray(data), "defer() only accepts plain objects"); // Set up an AbortController + Promise we can race against to exit early
1216
- // cancellation
1256
+ invariant(data && typeof data === "object" && !Array.isArray(data), "defer() only accepts plain objects");
1217
1257
 
1258
+ // Set up an AbortController + Promise we can race against to exit early
1259
+ // cancellation
1218
1260
  let reject;
1219
1261
  this.abortPromise = new Promise((_, r) => reject = r);
1220
1262
  this.controller = new AbortController();
1221
-
1222
1263
  let onAbort = () => reject(new AbortedDeferredError("Deferred data aborted"));
1223
-
1224
1264
  this.unlistenAbortSignal = () => this.controller.signal.removeEventListener("abort", onAbort);
1225
-
1226
1265
  this.controller.signal.addEventListener("abort", onAbort);
1227
1266
  this.data = Object.entries(data).reduce((acc, _ref) => {
1228
1267
  let [key, value] = _ref;
@@ -1230,34 +1269,31 @@ class DeferredData {
1230
1269
  [key]: this.trackPromise(key, value)
1231
1270
  });
1232
1271
  }, {});
1233
-
1234
1272
  if (this.done) {
1235
1273
  // All incoming values were resolved
1236
1274
  this.unlistenAbortSignal();
1237
1275
  }
1238
-
1239
1276
  this.init = responseInit;
1240
1277
  }
1241
-
1242
1278
  trackPromise(key, value) {
1243
1279
  if (!(value instanceof Promise)) {
1244
1280
  return value;
1245
1281
  }
1246
-
1247
1282
  this.deferredKeys.push(key);
1248
- this.pendingKeysSet.add(key); // We store a little wrapper promise that will be extended with
1283
+ this.pendingKeysSet.add(key);
1284
+
1285
+ // We store a little wrapper promise that will be extended with
1249
1286
  // _data/_error props upon resolve/reject
1287
+ let promise = Promise.race([value, this.abortPromise]).then(data => this.onSettle(promise, key, null, data), error => this.onSettle(promise, key, error));
1250
1288
 
1251
- let promise = Promise.race([value, this.abortPromise]).then(data => this.onSettle(promise, key, null, data), error => this.onSettle(promise, key, error)); // Register rejection listeners to avoid uncaught promise rejections on
1289
+ // Register rejection listeners to avoid uncaught promise rejections on
1252
1290
  // errors or aborted deferred values
1253
-
1254
1291
  promise.catch(() => {});
1255
1292
  Object.defineProperty(promise, "_tracked", {
1256
1293
  get: () => true
1257
1294
  });
1258
1295
  return promise;
1259
1296
  }
1260
-
1261
1297
  onSettle(promise, key, error, data) {
1262
1298
  if (this.controller.signal.aborted && error instanceof AbortedDeferredError) {
1263
1299
  this.unlistenAbortSignal();
@@ -1266,14 +1302,11 @@ class DeferredData {
1266
1302
  });
1267
1303
  return Promise.reject(error);
1268
1304
  }
1269
-
1270
1305
  this.pendingKeysSet.delete(key);
1271
-
1272
1306
  if (this.done) {
1273
1307
  // Nothing left to abort!
1274
1308
  this.unlistenAbortSignal();
1275
1309
  }
1276
-
1277
1310
  if (error) {
1278
1311
  Object.defineProperty(promise, "_error", {
1279
1312
  get: () => error
@@ -1281,54 +1314,43 @@ class DeferredData {
1281
1314
  this.emit(false, key);
1282
1315
  return Promise.reject(error);
1283
1316
  }
1284
-
1285
1317
  Object.defineProperty(promise, "_data", {
1286
1318
  get: () => data
1287
1319
  });
1288
1320
  this.emit(false, key);
1289
1321
  return data;
1290
1322
  }
1291
-
1292
1323
  emit(aborted, settledKey) {
1293
1324
  this.subscribers.forEach(subscriber => subscriber(aborted, settledKey));
1294
1325
  }
1295
-
1296
1326
  subscribe(fn) {
1297
1327
  this.subscribers.add(fn);
1298
1328
  return () => this.subscribers.delete(fn);
1299
1329
  }
1300
-
1301
1330
  cancel() {
1302
1331
  this.controller.abort();
1303
1332
  this.pendingKeysSet.forEach((v, k) => this.pendingKeysSet.delete(k));
1304
1333
  this.emit(true);
1305
1334
  }
1306
-
1307
1335
  async resolveData(signal) {
1308
1336
  let aborted = false;
1309
-
1310
1337
  if (!this.done) {
1311
1338
  let onAbort = () => this.cancel();
1312
-
1313
1339
  signal.addEventListener("abort", onAbort);
1314
1340
  aborted = await new Promise(resolve => {
1315
1341
  this.subscribe(aborted => {
1316
1342
  signal.removeEventListener("abort", onAbort);
1317
-
1318
1343
  if (aborted || this.done) {
1319
1344
  resolve(aborted);
1320
1345
  }
1321
1346
  });
1322
1347
  });
1323
1348
  }
1324
-
1325
1349
  return aborted;
1326
1350
  }
1327
-
1328
1351
  get done() {
1329
1352
  return this.pendingKeysSet.size === 0;
1330
1353
  }
1331
-
1332
1354
  get unwrappedData() {
1333
1355
  invariant(this.data !== null && this.done, "Can only unwrap data on initialized and settled deferreds");
1334
1356
  return Object.entries(this.data).reduce((acc, _ref2) => {
@@ -1338,40 +1360,31 @@ class DeferredData {
1338
1360
  });
1339
1361
  }, {});
1340
1362
  }
1341
-
1342
1363
  get pendingKeys() {
1343
1364
  return Array.from(this.pendingKeysSet);
1344
1365
  }
1345
-
1346
1366
  }
1347
-
1348
1367
  function isTrackedPromise(value) {
1349
1368
  return value instanceof Promise && value._tracked === true;
1350
1369
  }
1351
-
1352
1370
  function unwrapTrackedPromise(value) {
1353
1371
  if (!isTrackedPromise(value)) {
1354
1372
  return value;
1355
1373
  }
1356
-
1357
1374
  if (value._error) {
1358
1375
  throw value._error;
1359
1376
  }
1360
-
1361
1377
  return value._data;
1362
1378
  }
1363
-
1364
1379
  const defer = function defer(data, init) {
1365
1380
  if (init === void 0) {
1366
1381
  init = {};
1367
1382
  }
1368
-
1369
1383
  let responseInit = typeof init === "number" ? {
1370
1384
  status: init
1371
1385
  } : init;
1372
1386
  return new DeferredData(data, responseInit);
1373
1387
  };
1374
-
1375
1388
  /**
1376
1389
  * A redirect response. Sets the status code and the `Location` header.
1377
1390
  * Defaults to "302 Found".
@@ -1380,9 +1393,7 @@ const redirect = function redirect(url, init) {
1380
1393
  if (init === void 0) {
1381
1394
  init = 302;
1382
1395
  }
1383
-
1384
1396
  let responseInit = init;
1385
-
1386
1397
  if (typeof responseInit === "number") {
1387
1398
  responseInit = {
1388
1399
  status: responseInit
@@ -1390,28 +1401,25 @@ const redirect = function redirect(url, init) {
1390
1401
  } else if (typeof responseInit.status === "undefined") {
1391
1402
  responseInit.status = 302;
1392
1403
  }
1393
-
1394
1404
  let headers = new Headers(responseInit.headers);
1395
1405
  headers.set("Location", url);
1396
1406
  return new Response(null, _extends({}, responseInit, {
1397
1407
  headers
1398
1408
  }));
1399
1409
  };
1410
+
1400
1411
  /**
1401
1412
  * @private
1402
1413
  * Utility class we use to hold auto-unwrapped 4xx/5xx Response bodies
1403
1414
  */
1404
-
1405
1415
  class ErrorResponse {
1406
1416
  constructor(status, statusText, data, internal) {
1407
1417
  if (internal === void 0) {
1408
1418
  internal = false;
1409
1419
  }
1410
-
1411
1420
  this.status = status;
1412
1421
  this.statusText = statusText || "";
1413
1422
  this.internal = internal;
1414
-
1415
1423
  if (data instanceof Error) {
1416
1424
  this.data = data.toString();
1417
1425
  this.error = data;
@@ -1419,24 +1427,82 @@ class ErrorResponse {
1419
1427
  this.data = data;
1420
1428
  }
1421
1429
  }
1422
-
1423
1430
  }
1431
+
1424
1432
  /**
1425
1433
  * Check if the given error is an ErrorResponse generated from a 4xx/5xx
1426
1434
  * Response thrown from an action/loader
1427
1435
  */
1428
-
1429
1436
  function isRouteErrorResponse(error) {
1430
1437
  return error != null && typeof error.status === "number" && typeof error.statusText === "string" && typeof error.internal === "boolean" && "data" in error;
1431
1438
  }
1432
1439
 
1440
+ ////////////////////////////////////////////////////////////////////////////////
1433
1441
  //#region Types and Constants
1434
1442
  ////////////////////////////////////////////////////////////////////////////////
1435
1443
 
1436
1444
  /**
1437
1445
  * A Router instance manages all navigation and data loading/mutations
1438
1446
  */
1439
-
1447
+ /**
1448
+ * State maintained internally by the router. During a navigation, all states
1449
+ * reflect the the "old" location unless otherwise noted.
1450
+ */
1451
+ /**
1452
+ * Data that can be passed into hydrate a Router from SSR
1453
+ */
1454
+ /**
1455
+ * Future flags to toggle new feature behavior
1456
+ */
1457
+ /**
1458
+ * Initialization options for createRouter
1459
+ */
1460
+ /**
1461
+ * State returned from a server-side query() call
1462
+ */
1463
+ /**
1464
+ * A StaticHandler instance manages a singular SSR navigation/fetch event
1465
+ */
1466
+ /**
1467
+ * Subscriber function signature for changes to router state
1468
+ */
1469
+ /**
1470
+ * Function signature for determining the key to be used in scroll restoration
1471
+ * for a given location
1472
+ */
1473
+ /**
1474
+ * Function signature for determining the current scroll position
1475
+ */
1476
+ /**
1477
+ * Options for a navigate() call for a Link navigation
1478
+ */
1479
+ /**
1480
+ * Options for a navigate() call for a Form navigation
1481
+ */
1482
+ /**
1483
+ * Options to pass to navigate() for either a Link or Form navigation
1484
+ */
1485
+ /**
1486
+ * Options to pass to fetch()
1487
+ */
1488
+ /**
1489
+ * Potential states for state.navigation
1490
+ */
1491
+ /**
1492
+ * Potential states for fetchers
1493
+ */
1494
+ /**
1495
+ * Cached info for active fetcher.load() instances so they can participate
1496
+ * in revalidation
1497
+ */
1498
+ /**
1499
+ * Identified fetcher.load() calls that need to be revalidated
1500
+ */
1501
+ /**
1502
+ * Wrapper object to allow us to throw any response out from callLoaderOrAction
1503
+ * for queryRouter while preserving whether or not it was thrown or returned
1504
+ * from the loader/action
1505
+ */
1440
1506
  const validMutationMethodsArr = ["post", "put", "patch", "delete"];
1441
1507
  const validMutationMethods = new Set(validMutationMethodsArr);
1442
1508
  const validRequestMethodsArr = ["get", ...validMutationMethodsArr];
@@ -1466,12 +1532,12 @@ const IDLE_BLOCKER = {
1466
1532
  location: undefined
1467
1533
  };
1468
1534
  const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
1469
- const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
1470
- const isServer = !isBrowser;
1471
-
1472
1535
  const defaultMapRouteProperties = route => ({
1473
1536
  hasErrorBoundary: Boolean(route.hasErrorBoundary)
1474
- }); //#endregion
1537
+ });
1538
+
1539
+ //#endregion
1540
+
1475
1541
  ////////////////////////////////////////////////////////////////////////////////
1476
1542
  //#region createRouter
1477
1543
  ////////////////////////////////////////////////////////////////////////////////
@@ -1479,57 +1545,54 @@ const defaultMapRouteProperties = route => ({
1479
1545
  /**
1480
1546
  * Create a router and listen to history POP navigations
1481
1547
  */
1482
-
1483
-
1484
1548
  function createRouter(init) {
1549
+ const routerWindow = init.window ? init.window : typeof window !== "undefined" ? window : undefined;
1550
+ const isBrowser = typeof routerWindow !== "undefined" && typeof routerWindow.document !== "undefined" && typeof routerWindow.document.createElement !== "undefined";
1551
+ const isServer = !isBrowser;
1485
1552
  invariant(init.routes.length > 0, "You must provide a non-empty routes array to createRouter");
1486
1553
  let mapRouteProperties;
1487
-
1488
1554
  if (init.mapRouteProperties) {
1489
1555
  mapRouteProperties = init.mapRouteProperties;
1490
1556
  } else if (init.detectErrorBoundary) {
1491
1557
  // If they are still using the deprecated version, wrap it with the new API
1492
1558
  let detectErrorBoundary = init.detectErrorBoundary;
1493
-
1494
1559
  mapRouteProperties = route => ({
1495
1560
  hasErrorBoundary: detectErrorBoundary(route)
1496
1561
  });
1497
1562
  } else {
1498
1563
  mapRouteProperties = defaultMapRouteProperties;
1499
- } // Routes keyed by ID
1500
-
1501
-
1502
- let manifest = {}; // Routes in tree format for matching
1564
+ }
1503
1565
 
1566
+ // Routes keyed by ID
1567
+ let manifest = {};
1568
+ // Routes in tree format for matching
1504
1569
  let dataRoutes = convertRoutesToDataRoutes(init.routes, mapRouteProperties, undefined, manifest);
1505
1570
  let inFlightDataRoutes;
1506
- let basename = init.basename || "/"; // Config driven behavior flags
1507
-
1571
+ let basename = init.basename || "/";
1572
+ // Config driven behavior flags
1508
1573
  let future = _extends({
1509
1574
  v7_normalizeFormMethod: false,
1510
1575
  v7_prependBasename: false
1511
- }, init.future); // Cleanup function for history
1512
-
1513
-
1514
- let unlistenHistory = null; // Externally-provided functions to call on all state changes
1515
-
1516
- let subscribers = new Set(); // Externally-provided object to hold scroll restoration locations during routing
1517
-
1518
- let savedScrollPositions = null; // Externally-provided function to get scroll restoration keys
1519
-
1520
- let getScrollRestorationKey = null; // Externally-provided function to get current scroll position
1521
-
1522
- let getScrollPosition = null; // One-time flag to control the initial hydration scroll restoration. Because
1576
+ }, init.future);
1577
+ // Cleanup function for history
1578
+ let unlistenHistory = null;
1579
+ // Externally-provided functions to call on all state changes
1580
+ let subscribers = new Set();
1581
+ // Externally-provided object to hold scroll restoration locations during routing
1582
+ let savedScrollPositions = null;
1583
+ // Externally-provided function to get scroll restoration keys
1584
+ let getScrollRestorationKey = null;
1585
+ // Externally-provided function to get current scroll position
1586
+ let getScrollPosition = null;
1587
+ // One-time flag to control the initial hydration scroll restoration. Because
1523
1588
  // we don't get the saved positions from <ScrollRestoration /> until _after_
1524
1589
  // the initial render, we need to manually trigger a separate updateState to
1525
1590
  // send along the restoreScrollPosition
1526
1591
  // Set to true if we have `hydrationData` since we assume we were SSR'd and that
1527
1592
  // SSR did the initial scroll restoration.
1528
-
1529
1593
  let initialScrollRestored = init.hydrationData != null;
1530
1594
  let initialMatches = matchRoutes(dataRoutes, init.history.location, basename);
1531
1595
  let initialErrors = null;
1532
-
1533
1596
  if (initialMatches == null) {
1534
1597
  // If we do not match a user-provided-route, fall back to the root
1535
1598
  // to allow the error boundary to take over
@@ -1545,10 +1608,11 @@ function createRouter(init) {
1545
1608
  [route.id]: error
1546
1609
  };
1547
1610
  }
1548
-
1549
- let initialized = // All initialMatches need to be loaded before we're ready. If we have lazy
1611
+ let initialized =
1612
+ // All initialMatches need to be loaded before we're ready. If we have lazy
1550
1613
  // functions around still then we'll need to run them in initialize()
1551
- !initialMatches.some(m => m.route.lazy) && ( // And we have to either have no loaders or have been provided hydrationData
1614
+ !initialMatches.some(m => m.route.lazy) && (
1615
+ // And we have to either have no loaders or have been provided hydrationData
1552
1616
  !initialMatches.some(m => m.route.loader) || init.hydrationData != null);
1553
1617
  let router;
1554
1618
  let state = {
@@ -1566,57 +1630,74 @@ function createRouter(init) {
1566
1630
  errors: init.hydrationData && init.hydrationData.errors || initialErrors,
1567
1631
  fetchers: new Map(),
1568
1632
  blockers: new Map()
1569
- }; // -- Stateful internal variables to manage navigations --
1633
+ };
1634
+
1635
+ // -- Stateful internal variables to manage navigations --
1570
1636
  // Current navigation in progress (to be committed in completeNavigation)
1637
+ let pendingAction = exports.Action.Pop;
1571
1638
 
1572
- let pendingAction = exports.Action.Pop; // Should the current navigation prevent the scroll reset if scroll cannot
1639
+ // Should the current navigation prevent the scroll reset if scroll cannot
1573
1640
  // be restored?
1641
+ let pendingPreventScrollReset = false;
1574
1642
 
1575
- let pendingPreventScrollReset = false; // AbortController for the active navigation
1643
+ // AbortController for the active navigation
1644
+ let pendingNavigationController;
1576
1645
 
1577
- let pendingNavigationController; // We use this to avoid touching history in completeNavigation if a
1646
+ // We use this to avoid touching history in completeNavigation if a
1578
1647
  // revalidation is entirely uninterrupted
1648
+ let isUninterruptedRevalidation = false;
1579
1649
 
1580
- let isUninterruptedRevalidation = false; // Use this internal flag to force revalidation of all loaders:
1650
+ // Use this internal flag to force revalidation of all loaders:
1581
1651
  // - submissions (completed or interrupted)
1582
1652
  // - useRevalidator()
1583
1653
  // - X-Remix-Revalidate (from redirect)
1654
+ let isRevalidationRequired = false;
1584
1655
 
1585
- let isRevalidationRequired = false; // Use this internal array to capture routes that require revalidation due
1656
+ // Use this internal array to capture routes that require revalidation due
1586
1657
  // to a cancelled deferred on action submission
1658
+ let cancelledDeferredRoutes = [];
1587
1659
 
1588
- let cancelledDeferredRoutes = []; // Use this internal array to capture fetcher loads that were cancelled by an
1660
+ // Use this internal array to capture fetcher loads that were cancelled by an
1589
1661
  // action navigation and require revalidation
1662
+ let cancelledFetcherLoads = [];
1590
1663
 
1591
- let cancelledFetcherLoads = []; // AbortControllers for any in-flight fetchers
1664
+ // AbortControllers for any in-flight fetchers
1665
+ let fetchControllers = new Map();
1592
1666
 
1593
- let fetchControllers = new Map(); // Track loads based on the order in which they started
1667
+ // Track loads based on the order in which they started
1668
+ let incrementingLoadId = 0;
1594
1669
 
1595
- let incrementingLoadId = 0; // Track the outstanding pending navigation data load to be compared against
1670
+ // Track the outstanding pending navigation data load to be compared against
1596
1671
  // the globally incrementing load when a fetcher load lands after a completed
1597
1672
  // navigation
1673
+ let pendingNavigationLoadId = -1;
1598
1674
 
1599
- let pendingNavigationLoadId = -1; // Fetchers that triggered data reloads as a result of their actions
1675
+ // Fetchers that triggered data reloads as a result of their actions
1676
+ let fetchReloadIds = new Map();
1600
1677
 
1601
- let fetchReloadIds = new Map(); // Fetchers that triggered redirect navigations
1678
+ // Fetchers that triggered redirect navigations
1679
+ let fetchRedirectIds = new Set();
1602
1680
 
1603
- let fetchRedirectIds = new Set(); // Most recent href/match for fetcher.load calls for fetchers
1681
+ // Most recent href/match for fetcher.load calls for fetchers
1682
+ let fetchLoadMatches = new Map();
1604
1683
 
1605
- let fetchLoadMatches = new Map(); // Store DeferredData instances for active route matches. When a
1684
+ // Store DeferredData instances for active route matches. When a
1606
1685
  // route loader returns defer() we stick one in here. Then, when a nested
1607
1686
  // promise resolves we update loaderData. If a new navigation starts we
1608
1687
  // cancel active deferreds for eliminated routes.
1688
+ let activeDeferreds = new Map();
1609
1689
 
1610
- let activeDeferreds = new Map(); // Store blocker functions in a separate Map outside of router state since
1690
+ // Store blocker functions in a separate Map outside of router state since
1611
1691
  // we don't need to update UI state if they change
1692
+ let blockerFunctions = new Map();
1612
1693
 
1613
- let blockerFunctions = new Map(); // Flag to ignore the next history update, so we can revert the URL change on
1694
+ // Flag to ignore the next history update, so we can revert the URL change on
1614
1695
  // a POP navigation that was blocked by the user without touching router state
1696
+ let ignoreNextHistoryUpdate = false;
1615
1697
 
1616
- let ignoreNextHistoryUpdate = false; // Initialize the router, all side effects should be kicked off from here.
1698
+ // Initialize the router, all side effects should be kicked off from here.
1617
1699
  // Implemented as a Fluent API for ease of:
1618
1700
  // let router = createRouter(init).initialize();
1619
-
1620
1701
  function initialize() {
1621
1702
  // If history informs us of a POP navigation, start the navigation but do not update
1622
1703
  // state. We'll update our own state once the navigation completes
@@ -1626,98 +1707,90 @@ function createRouter(init) {
1626
1707
  location,
1627
1708
  delta
1628
1709
  } = _ref;
1629
-
1630
1710
  // Ignore this event if it was just us resetting the URL from a
1631
1711
  // blocked POP navigation
1632
1712
  if (ignoreNextHistoryUpdate) {
1633
1713
  ignoreNextHistoryUpdate = false;
1634
1714
  return;
1635
1715
  }
1636
-
1637
1716
  warning(blockerFunctions.size === 0 || delta != null, "You are trying to use a blocker on a POP navigation to a location " + "that was not created by @remix-run/router. This will fail silently in " + "production. This can happen if you are navigating outside the router " + "via `window.history.pushState`/`window.location.hash` instead of using " + "router navigation APIs. This can also happen if you are using " + "createHashRouter and the user manually changes the URL.");
1638
1717
  let blockerKey = shouldBlockNavigation({
1639
1718
  currentLocation: state.location,
1640
1719
  nextLocation: location,
1641
1720
  historyAction
1642
1721
  });
1643
-
1644
1722
  if (blockerKey && delta != null) {
1645
1723
  // Restore the URL to match the current UI, but don't update router state
1646
1724
  ignoreNextHistoryUpdate = true;
1647
- init.history.go(delta * -1); // Put the blocker into a blocked state
1725
+ init.history.go(delta * -1);
1648
1726
 
1727
+ // Put the blocker into a blocked state
1649
1728
  updateBlocker(blockerKey, {
1650
1729
  state: "blocked",
1651
1730
  location,
1652
-
1653
1731
  proceed() {
1654
1732
  updateBlocker(blockerKey, {
1655
1733
  state: "proceeding",
1656
1734
  proceed: undefined,
1657
1735
  reset: undefined,
1658
1736
  location
1659
- }); // Re-do the same POP navigation we just blocked
1660
-
1737
+ });
1738
+ // Re-do the same POP navigation we just blocked
1661
1739
  init.history.go(delta);
1662
1740
  },
1663
-
1664
1741
  reset() {
1665
1742
  deleteBlocker(blockerKey);
1666
1743
  updateState({
1667
1744
  blockers: new Map(router.state.blockers)
1668
1745
  });
1669
1746
  }
1670
-
1671
1747
  });
1672
1748
  return;
1673
1749
  }
1674
-
1675
1750
  return startNavigation(historyAction, location);
1676
- }); // Kick off initial data load if needed. Use Pop to avoid modifying history
1751
+ });
1752
+
1753
+ // Kick off initial data load if needed. Use Pop to avoid modifying history
1677
1754
  // Note we don't do any handling of lazy here. For SPA's it'll get handled
1678
1755
  // in the normal navigation flow. For SSR it's expected that lazy modules are
1679
1756
  // resolved prior to router creation since we can't go into a fallbackElement
1680
1757
  // UI for SSR'd apps
1681
-
1682
1758
  if (!state.initialized) {
1683
1759
  startNavigation(exports.Action.Pop, state.location);
1684
1760
  }
1685
-
1686
1761
  return router;
1687
- } // Clean up a router and it's side effects
1688
-
1762
+ }
1689
1763
 
1764
+ // Clean up a router and it's side effects
1690
1765
  function dispose() {
1691
1766
  if (unlistenHistory) {
1692
1767
  unlistenHistory();
1693
1768
  }
1694
-
1695
1769
  subscribers.clear();
1696
1770
  pendingNavigationController && pendingNavigationController.abort();
1697
1771
  state.fetchers.forEach((_, key) => deleteFetcher(key));
1698
1772
  state.blockers.forEach((_, key) => deleteBlocker(key));
1699
- } // Subscribe to state updates for the router
1700
-
1773
+ }
1701
1774
 
1775
+ // Subscribe to state updates for the router
1702
1776
  function subscribe(fn) {
1703
1777
  subscribers.add(fn);
1704
1778
  return () => subscribers.delete(fn);
1705
- } // Update our state and notify the calling context of the change
1706
-
1779
+ }
1707
1780
 
1781
+ // Update our state and notify the calling context of the change
1708
1782
  function updateState(newState) {
1709
1783
  state = _extends({}, state, newState);
1710
1784
  subscribers.forEach(subscriber => subscriber(state));
1711
- } // Complete a navigation returning the state.navigation back to the IDLE_NAVIGATION
1785
+ }
1786
+
1787
+ // Complete a navigation returning the state.navigation back to the IDLE_NAVIGATION
1712
1788
  // and setting state.[historyAction/location/matches] to the new route.
1713
1789
  // - Location is a required param
1714
1790
  // - Navigation will always be set to IDLE_NAVIGATION
1715
1791
  // - Can pass any other state in newState
1716
-
1717
-
1718
1792
  function completeNavigation(location, newState) {
1719
1793
  var _location$state, _location$state2;
1720
-
1721
1794
  // Deduce if we're in a loading/actionReload state:
1722
1795
  // - We have committed actionData in the store
1723
1796
  // - The current navigation was a mutation submission
@@ -1725,7 +1798,6 @@ function createRouter(init) {
1725
1798
  // - The location being loaded is not the result of a redirect
1726
1799
  let isActionReload = state.actionData != null && state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && state.navigation.state === "loading" && ((_location$state = location.state) == null ? void 0 : _location$state._isRedirect) !== true;
1727
1800
  let actionData;
1728
-
1729
1801
  if (newState.actionData) {
1730
1802
  if (Object.keys(newState.actionData).length > 0) {
1731
1803
  actionData = newState.actionData;
@@ -1739,25 +1811,24 @@ function createRouter(init) {
1739
1811
  } else {
1740
1812
  // Clear actionData on any other completed navigations
1741
1813
  actionData = null;
1742
- } // Always preserve any existing loaderData from re-used routes
1814
+ }
1743
1815
 
1816
+ // Always preserve any existing loaderData from re-used routes
1817
+ let loaderData = newState.loaderData ? mergeLoaderData(state.loaderData, newState.loaderData, newState.matches || [], newState.errors) : state.loaderData;
1744
1818
 
1745
- let loaderData = newState.loaderData ? mergeLoaderData(state.loaderData, newState.loaderData, newState.matches || [], newState.errors) : state.loaderData; // On a successful navigation we can assume we got through all blockers
1819
+ // On a successful navigation we can assume we got through all blockers
1746
1820
  // so we can start fresh
1747
-
1748
1821
  for (let [key] of blockerFunctions) {
1749
1822
  deleteBlocker(key);
1750
- } // Always respect the user flag. Otherwise don't reset on mutation
1751
- // submission navigations unless they redirect
1752
-
1823
+ }
1753
1824
 
1825
+ // Always respect the user flag. Otherwise don't reset on mutation
1826
+ // submission navigations unless they redirect
1754
1827
  let preventScrollReset = pendingPreventScrollReset === true || state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && ((_location$state2 = location.state) == null ? void 0 : _location$state2._isRedirect) !== true;
1755
-
1756
1828
  if (inFlightDataRoutes) {
1757
1829
  dataRoutes = inFlightDataRoutes;
1758
1830
  inFlightDataRoutes = undefined;
1759
1831
  }
1760
-
1761
1832
  updateState(_extends({}, newState, {
1762
1833
  // matches, errors, fetchers go through as-is
1763
1834
  actionData,
@@ -1771,30 +1842,28 @@ function createRouter(init) {
1771
1842
  preventScrollReset,
1772
1843
  blockers: new Map(state.blockers)
1773
1844
  }));
1774
-
1775
1845
  if (isUninterruptedRevalidation) ; else if (pendingAction === exports.Action.Pop) ; else if (pendingAction === exports.Action.Push) {
1776
1846
  init.history.push(location, location.state);
1777
1847
  } else if (pendingAction === exports.Action.Replace) {
1778
1848
  init.history.replace(location, location.state);
1779
- } // Reset stateful navigation vars
1780
-
1849
+ }
1781
1850
 
1851
+ // Reset stateful navigation vars
1782
1852
  pendingAction = exports.Action.Pop;
1783
1853
  pendingPreventScrollReset = false;
1784
1854
  isUninterruptedRevalidation = false;
1785
1855
  isRevalidationRequired = false;
1786
1856
  cancelledDeferredRoutes = [];
1787
1857
  cancelledFetcherLoads = [];
1788
- } // Trigger a navigation event, which can either be a numerical POP or a PUSH
1789
- // replace with an optional submission
1790
-
1858
+ }
1791
1859
 
1860
+ // Trigger a navigation event, which can either be a numerical POP or a PUSH
1861
+ // replace with an optional submission
1792
1862
  async function navigate(to, opts) {
1793
1863
  if (typeof to === "number") {
1794
1864
  init.history.go(to);
1795
1865
  return;
1796
1866
  }
1797
-
1798
1867
  let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, to, opts == null ? void 0 : opts.fromRouteId, opts == null ? void 0 : opts.relative);
1799
1868
  let {
1800
1869
  path,
@@ -1802,16 +1871,16 @@ function createRouter(init) {
1802
1871
  error
1803
1872
  } = normalizeNavigateOptions(future.v7_normalizeFormMethod, false, normalizedPath, opts);
1804
1873
  let currentLocation = state.location;
1805
- let nextLocation = createLocation(state.location, path, opts && opts.state); // When using navigate as a PUSH/REPLACE we aren't reading an already-encoded
1874
+ let nextLocation = createLocation(state.location, path, opts && opts.state);
1875
+
1876
+ // When using navigate as a PUSH/REPLACE we aren't reading an already-encoded
1806
1877
  // URL from window.location, so we need to encode it here so the behavior
1807
1878
  // remains the same as POP and non-data-router usages. new URL() does all
1808
1879
  // the same encoding we'd get from a history.pushState/window.location read
1809
1880
  // without having to touch history
1810
-
1811
1881
  nextLocation = _extends({}, nextLocation, init.history.encodeLocation(nextLocation));
1812
1882
  let userReplace = opts && opts.replace != null ? opts.replace : undefined;
1813
1883
  let historyAction = exports.Action.Push;
1814
-
1815
1884
  if (userReplace === true) {
1816
1885
  historyAction = exports.Action.Replace;
1817
1886
  } else if (userReplace === false) ; else if (submission != null && isMutationMethod(submission.formMethod) && submission.formAction === state.location.pathname + state.location.search) {
@@ -1821,42 +1890,36 @@ function createRouter(init) {
1821
1890
  // action/loader this will be ignored and the redirect will be a PUSH
1822
1891
  historyAction = exports.Action.Replace;
1823
1892
  }
1824
-
1825
1893
  let preventScrollReset = opts && "preventScrollReset" in opts ? opts.preventScrollReset === true : undefined;
1826
1894
  let blockerKey = shouldBlockNavigation({
1827
1895
  currentLocation,
1828
1896
  nextLocation,
1829
1897
  historyAction
1830
1898
  });
1831
-
1832
1899
  if (blockerKey) {
1833
1900
  // Put the blocker into a blocked state
1834
1901
  updateBlocker(blockerKey, {
1835
1902
  state: "blocked",
1836
1903
  location: nextLocation,
1837
-
1838
1904
  proceed() {
1839
1905
  updateBlocker(blockerKey, {
1840
1906
  state: "proceeding",
1841
1907
  proceed: undefined,
1842
1908
  reset: undefined,
1843
1909
  location: nextLocation
1844
- }); // Send the same navigation through
1845
-
1910
+ });
1911
+ // Send the same navigation through
1846
1912
  navigate(to, opts);
1847
1913
  },
1848
-
1849
1914
  reset() {
1850
1915
  deleteBlocker(blockerKey);
1851
1916
  updateState({
1852
1917
  blockers: new Map(state.blockers)
1853
1918
  });
1854
1919
  }
1855
-
1856
1920
  });
1857
1921
  return;
1858
1922
  }
1859
-
1860
1923
  return await startNavigation(historyAction, nextLocation, {
1861
1924
  submission,
1862
1925
  // Send through the formData serialization error if we have one so we can
@@ -1865,43 +1928,44 @@ function createRouter(init) {
1865
1928
  preventScrollReset,
1866
1929
  replace: opts && opts.replace
1867
1930
  });
1868
- } // Revalidate all current loaders. If a navigation is in progress or if this
1931
+ }
1932
+
1933
+ // Revalidate all current loaders. If a navigation is in progress or if this
1869
1934
  // is interrupted by a navigation, allow this to "succeed" by calling all
1870
1935
  // loaders during the next loader round
1871
-
1872
-
1873
1936
  function revalidate() {
1874
1937
  interruptActiveLoads();
1875
1938
  updateState({
1876
1939
  revalidation: "loading"
1877
- }); // If we're currently submitting an action, we don't need to start a new
1878
- // navigation, we'll just let the follow up loader execution call all loaders
1940
+ });
1879
1941
 
1942
+ // If we're currently submitting an action, we don't need to start a new
1943
+ // navigation, we'll just let the follow up loader execution call all loaders
1880
1944
  if (state.navigation.state === "submitting") {
1881
1945
  return;
1882
- } // If we're currently in an idle state, start a new navigation for the current
1946
+ }
1947
+
1948
+ // If we're currently in an idle state, start a new navigation for the current
1883
1949
  // action/location and mark it as uninterrupted, which will skip the history
1884
1950
  // update in completeNavigation
1885
-
1886
-
1887
1951
  if (state.navigation.state === "idle") {
1888
1952
  startNavigation(state.historyAction, state.location, {
1889
1953
  startUninterruptedRevalidation: true
1890
1954
  });
1891
1955
  return;
1892
- } // Otherwise, if we're currently in a loading state, just start a new
1956
+ }
1957
+
1958
+ // Otherwise, if we're currently in a loading state, just start a new
1893
1959
  // navigation to the navigation.location but do not trigger an uninterrupted
1894
1960
  // revalidation so that history correctly updates once the navigation completes
1895
-
1896
-
1897
1961
  startNavigation(pendingAction || state.historyAction, state.navigation.location, {
1898
1962
  overrideNavigation: state.navigation
1899
1963
  });
1900
- } // Start a navigation to the given action/location. Can optionally provide a
1964
+ }
1965
+
1966
+ // Start a navigation to the given action/location. Can optionally provide a
1901
1967
  // overrideNavigation which will override the normalLoad in the case of a redirect
1902
1968
  // navigation
1903
-
1904
-
1905
1969
  async function startNavigation(historyAction, location, opts) {
1906
1970
  // Abort any in-progress navigations and start a new one. Unset any ongoing
1907
1971
  // uninterrupted revalidations unless told otherwise, since we want this
@@ -1909,15 +1973,17 @@ function createRouter(init) {
1909
1973
  pendingNavigationController && pendingNavigationController.abort();
1910
1974
  pendingNavigationController = null;
1911
1975
  pendingAction = historyAction;
1912
- isUninterruptedRevalidation = (opts && opts.startUninterruptedRevalidation) === true; // Save the current scroll position every time we start a new navigation,
1913
- // and track whether we should reset scroll on completion
1976
+ isUninterruptedRevalidation = (opts && opts.startUninterruptedRevalidation) === true;
1914
1977
 
1978
+ // Save the current scroll position every time we start a new navigation,
1979
+ // and track whether we should reset scroll on completion
1915
1980
  saveScrollPosition(state.location, state.matches);
1916
1981
  pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
1917
1982
  let routesToUse = inFlightDataRoutes || dataRoutes;
1918
1983
  let loadingNavigation = opts && opts.overrideNavigation;
1919
- let matches = matchRoutes(routesToUse, location, basename); // Short circuit with a 404 on the root error boundary if we match nothing
1984
+ let matches = matchRoutes(routesToUse, location, basename);
1920
1985
 
1986
+ // Short circuit with a 404 on the root error boundary if we match nothing
1921
1987
  if (!matches) {
1922
1988
  let error = getInternalRouterError(404, {
1923
1989
  pathname: location.pathname
@@ -1925,8 +1991,8 @@ function createRouter(init) {
1925
1991
  let {
1926
1992
  matches: notFoundMatches,
1927
1993
  route
1928
- } = getShortCircuitMatches(routesToUse); // Cancel all pending deferred on 404s since we don't keep any routes
1929
-
1994
+ } = getShortCircuitMatches(routesToUse);
1995
+ // Cancel all pending deferred on 404s since we don't keep any routes
1930
1996
  cancelActiveDeferreds();
1931
1997
  completeNavigation(location, {
1932
1998
  matches: notFoundMatches,
@@ -1936,26 +2002,26 @@ function createRouter(init) {
1936
2002
  }
1937
2003
  });
1938
2004
  return;
1939
- } // Short circuit if it's only a hash change and not a mutation submission.
1940
- // Ignore on initial page loads because since the initial load will always
1941
- // be "same hash".
1942
- // For example, on /page#hash and submit a <Form method="post"> which will
1943
- // default to a navigation to /page
1944
-
2005
+ }
1945
2006
 
1946
- if (state.initialized && isHashChangeOnly(state.location, location) && !(opts && opts.submission && isMutationMethod(opts.submission.formMethod))) {
2007
+ // Short circuit if it's only a hash change and not a revalidation or
2008
+ // mutation submission.
2009
+ //
2010
+ // Ignore on initial page loads because since the initial load will always
2011
+ // be "same hash". For example, on /page#hash and submit a <Form method="post">
2012
+ // which will default to a navigation to /page
2013
+ if (state.initialized && !isRevalidationRequired && isHashChangeOnly(state.location, location) && !(opts && opts.submission && isMutationMethod(opts.submission.formMethod))) {
1947
2014
  completeNavigation(location, {
1948
2015
  matches
1949
2016
  });
1950
2017
  return;
1951
- } // Create a controller/Request for this navigation
1952
-
2018
+ }
1953
2019
 
2020
+ // Create a controller/Request for this navigation
1954
2021
  pendingNavigationController = new AbortController();
1955
2022
  let request = createClientSideRequest(init.history, location, pendingNavigationController.signal, opts && opts.submission);
1956
2023
  let pendingActionData;
1957
2024
  let pendingError;
1958
-
1959
2025
  if (opts && opts.pendingError) {
1960
2026
  // If we have a pendingError, it means the user attempted a GET submission
1961
2027
  // with binary FormData so assign here and skip to handleLoaders. That
@@ -1969,40 +2035,36 @@ function createRouter(init) {
1969
2035
  let actionOutput = await handleAction(request, location, opts.submission, matches, {
1970
2036
  replace: opts.replace
1971
2037
  });
1972
-
1973
2038
  if (actionOutput.shortCircuited) {
1974
2039
  return;
1975
2040
  }
1976
-
1977
2041
  pendingActionData = actionOutput.pendingActionData;
1978
2042
  pendingError = actionOutput.pendingActionError;
1979
-
1980
2043
  let navigation = _extends({
1981
2044
  state: "loading",
1982
2045
  location
1983
2046
  }, opts.submission);
2047
+ loadingNavigation = navigation;
1984
2048
 
1985
- loadingNavigation = navigation; // Create a GET request for the loaders
1986
-
2049
+ // Create a GET request for the loaders
1987
2050
  request = new Request(request.url, {
1988
2051
  signal: request.signal
1989
2052
  });
1990
- } // Call loaders
1991
-
2053
+ }
1992
2054
 
2055
+ // Call loaders
1993
2056
  let {
1994
2057
  shortCircuited,
1995
2058
  loaderData,
1996
2059
  errors
1997
2060
  } = await handleLoaders(request, location, matches, loadingNavigation, opts && opts.submission, opts && opts.fetcherSubmission, opts && opts.replace, pendingActionData, pendingError);
1998
-
1999
2061
  if (shortCircuited) {
2000
2062
  return;
2001
- } // Clean up now that the action/loaders have completed. Don't clean up if
2063
+ }
2064
+
2065
+ // Clean up now that the action/loaders have completed. Don't clean up if
2002
2066
  // we short circuited because pendingNavigationController will have already
2003
2067
  // been assigned to a new controller for the next navigation
2004
-
2005
-
2006
2068
  pendingNavigationController = null;
2007
2069
  completeNavigation(location, _extends({
2008
2070
  matches
@@ -2012,25 +2074,25 @@ function createRouter(init) {
2012
2074
  loaderData,
2013
2075
  errors
2014
2076
  }));
2015
- } // Call the action matched by the leaf route for this navigation and handle
2016
- // redirects/errors
2017
-
2077
+ }
2018
2078
 
2079
+ // Call the action matched by the leaf route for this navigation and handle
2080
+ // redirects/errors
2019
2081
  async function handleAction(request, location, submission, matches, opts) {
2020
- interruptActiveLoads(); // Put us in a submitting state
2082
+ interruptActiveLoads();
2021
2083
 
2084
+ // Put us in a submitting state
2022
2085
  let navigation = _extends({
2023
2086
  state: "submitting",
2024
2087
  location
2025
2088
  }, submission);
2026
-
2027
2089
  updateState({
2028
2090
  navigation
2029
- }); // Call our action and get the result
2091
+ });
2030
2092
 
2093
+ // Call our action and get the result
2031
2094
  let result;
2032
2095
  let actionMatch = getTargetMatch(matches, location);
2033
-
2034
2096
  if (!actionMatch.route.action && !actionMatch.route.lazy) {
2035
2097
  result = {
2036
2098
  type: ResultType.error,
@@ -2042,17 +2104,14 @@ function createRouter(init) {
2042
2104
  };
2043
2105
  } else {
2044
2106
  result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename);
2045
-
2046
2107
  if (request.signal.aborted) {
2047
2108
  return {
2048
2109
  shortCircuited: true
2049
2110
  };
2050
2111
  }
2051
2112
  }
2052
-
2053
2113
  if (isRedirectResult(result)) {
2054
2114
  let replace;
2055
-
2056
2115
  if (opts && opts.replace != null) {
2057
2116
  replace = opts.replace;
2058
2117
  } else {
@@ -2061,7 +2120,6 @@ function createRouter(init) {
2061
2120
  // double back-buttons
2062
2121
  replace = result.location === state.location.pathname + state.location.search;
2063
2122
  }
2064
-
2065
2123
  await startRedirectNavigation(state, result, {
2066
2124
  submission,
2067
2125
  replace
@@ -2070,19 +2128,18 @@ function createRouter(init) {
2070
2128
  shortCircuited: true
2071
2129
  };
2072
2130
  }
2073
-
2074
2131
  if (isErrorResult(result)) {
2075
2132
  // Store off the pending error - we use it to determine which loaders
2076
2133
  // to call and will commit it when we complete the navigation
2077
- let boundaryMatch = findNearestBoundary(matches, actionMatch.route.id); // By default, all submissions are REPLACE navigations, but if the
2134
+ let boundaryMatch = findNearestBoundary(matches, actionMatch.route.id);
2135
+
2136
+ // By default, all submissions are REPLACE navigations, but if the
2078
2137
  // action threw an error that'll be rendered in an errorElement, we fall
2079
2138
  // back to PUSH so that the user can use the back button to get back to
2080
2139
  // the pre-submission form location to try again
2081
-
2082
2140
  if ((opts && opts.replace) !== true) {
2083
2141
  pendingAction = exports.Action.Push;
2084
2142
  }
2085
-
2086
2143
  return {
2087
2144
  // Send back an empty object we can use to clear out any prior actionData
2088
2145
  pendingActionData: {},
@@ -2091,26 +2148,23 @@ function createRouter(init) {
2091
2148
  }
2092
2149
  };
2093
2150
  }
2094
-
2095
2151
  if (isDeferredResult(result)) {
2096
2152
  throw getInternalRouterError(400, {
2097
2153
  type: "defer-action"
2098
2154
  });
2099
2155
  }
2100
-
2101
2156
  return {
2102
2157
  pendingActionData: {
2103
2158
  [actionMatch.route.id]: result.data
2104
2159
  }
2105
2160
  };
2106
- } // Call all applicable loaders for the given matches, handling redirects,
2107
- // errors, etc.
2108
-
2161
+ }
2109
2162
 
2163
+ // Call all applicable loaders for the given matches, handling redirects,
2164
+ // errors, etc.
2110
2165
  async function handleLoaders(request, location, matches, overrideNavigation, submission, fetcherSubmission, replace, pendingActionData, pendingError) {
2111
2166
  // Figure out the right navigation we want to use for data loading
2112
2167
  let loadingNavigation = overrideNavigation;
2113
-
2114
2168
  if (!loadingNavigation) {
2115
2169
  let navigation = _extends({
2116
2170
  state: "loading",
@@ -2120,12 +2174,11 @@ function createRouter(init) {
2120
2174
  formEncType: undefined,
2121
2175
  formData: undefined
2122
2176
  }, submission);
2123
-
2124
2177
  loadingNavigation = navigation;
2125
- } // If this was a redirect from an action we don't have a "submission" but
2126
- // we have it on the loading navigation so use that if available
2127
-
2178
+ }
2128
2179
 
2180
+ // If this was a redirect from an action we don't have a "submission" but
2181
+ // we have it on the loading navigation so use that if available
2129
2182
  let activeSubmission = submission || fetcherSubmission ? submission || fetcherSubmission : loadingNavigation.formMethod && loadingNavigation.formAction && loadingNavigation.formData && loadingNavigation.formEncType ? {
2130
2183
  formMethod: loadingNavigation.formMethod,
2131
2184
  formAction: loadingNavigation.formAction,
@@ -2133,12 +2186,14 @@ function createRouter(init) {
2133
2186
  formEncType: loadingNavigation.formEncType
2134
2187
  } : undefined;
2135
2188
  let routesToUse = inFlightDataRoutes || dataRoutes;
2136
- let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, activeSubmission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, basename, pendingActionData, pendingError); // Cancel pending deferreds for no-longer-matched routes or routes we're
2189
+ let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, activeSubmission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, basename, pendingActionData, pendingError);
2190
+
2191
+ // Cancel pending deferreds for no-longer-matched routes or routes we're
2137
2192
  // about to reload. Note that if this is an action reload we would have
2138
2193
  // already cancelled all pending deferreds so this would be a no-op
2194
+ cancelActiveDeferreds(routeId => !(matches && matches.some(m => m.route.id === routeId)) || matchesToLoad && matchesToLoad.some(m => m.route.id === routeId));
2139
2195
 
2140
- cancelActiveDeferreds(routeId => !(matches && matches.some(m => m.route.id === routeId)) || matchesToLoad && matchesToLoad.some(m => m.route.id === routeId)); // Short circuit if we have no loaders to run
2141
-
2196
+ // Short circuit if we have no loaders to run
2142
2197
  if (matchesToLoad.length === 0 && revalidatingFetchers.length === 0) {
2143
2198
  let updatedFetchers = markFetchRedirectsDone();
2144
2199
  completeNavigation(location, _extends({
@@ -2154,12 +2209,12 @@ function createRouter(init) {
2154
2209
  return {
2155
2210
  shortCircuited: true
2156
2211
  };
2157
- } // If this is an uninterrupted revalidation, we remain in our current idle
2212
+ }
2213
+
2214
+ // If this is an uninterrupted revalidation, we remain in our current idle
2158
2215
  // state. If not, we need to switch to our loading state and load data,
2159
2216
  // preserving any new action data or existing action data (in the case of
2160
2217
  // a revalidation interrupting an actionReload)
2161
-
2162
-
2163
2218
  if (!isUninterruptedRevalidation) {
2164
2219
  revalidatingFetchers.forEach(rf => {
2165
2220
  let fetcher = state.fetchers.get(rf.key);
@@ -2185,7 +2240,6 @@ function createRouter(init) {
2185
2240
  fetchers: new Map(state.fetchers)
2186
2241
  } : {}));
2187
2242
  }
2188
-
2189
2243
  pendingNavigationLoadId = ++incrementingLoadId;
2190
2244
  revalidatingFetchers.forEach(rf => {
2191
2245
  if (rf.controller) {
@@ -2194,37 +2248,34 @@ function createRouter(init) {
2194
2248
  // triggered the revalidation
2195
2249
  fetchControllers.set(rf.key, rf.controller);
2196
2250
  }
2197
- }); // Proxy navigation abort through to revalidation fetchers
2251
+ });
2198
2252
 
2253
+ // Proxy navigation abort through to revalidation fetchers
2199
2254
  let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach(f => abortFetcher(f.key));
2200
-
2201
2255
  if (pendingNavigationController) {
2202
2256
  pendingNavigationController.signal.addEventListener("abort", abortPendingFetchRevalidations);
2203
2257
  }
2204
-
2205
2258
  let {
2206
2259
  results,
2207
2260
  loaderResults,
2208
2261
  fetcherResults
2209
2262
  } = await callLoadersAndMaybeResolveData(state.matches, matches, matchesToLoad, revalidatingFetchers, request);
2210
-
2211
2263
  if (request.signal.aborted) {
2212
2264
  return {
2213
2265
  shortCircuited: true
2214
2266
  };
2215
- } // Clean up _after_ loaders have completed. Don't clean up if we short
2267
+ }
2268
+
2269
+ // Clean up _after_ loaders have completed. Don't clean up if we short
2216
2270
  // circuited because fetchControllers would have been aborted and
2217
2271
  // reassigned to new controllers for the next navigation
2218
-
2219
-
2220
2272
  if (pendingNavigationController) {
2221
2273
  pendingNavigationController.signal.removeEventListener("abort", abortPendingFetchRevalidations);
2222
2274
  }
2275
+ revalidatingFetchers.forEach(rf => fetchControllers.delete(rf.key));
2223
2276
 
2224
- revalidatingFetchers.forEach(rf => fetchControllers.delete(rf.key)); // If any loaders returned a redirect Response, start a new REPLACE navigation
2225
-
2277
+ // If any loaders returned a redirect Response, start a new REPLACE navigation
2226
2278
  let redirect = findRedirect(results);
2227
-
2228
2279
  if (redirect) {
2229
2280
  await startRedirectNavigation(state, redirect, {
2230
2281
  replace
@@ -2232,14 +2283,15 @@ function createRouter(init) {
2232
2283
  return {
2233
2284
  shortCircuited: true
2234
2285
  };
2235
- } // Process and commit output from loaders
2236
-
2286
+ }
2237
2287
 
2288
+ // Process and commit output from loaders
2238
2289
  let {
2239
2290
  loaderData,
2240
2291
  errors
2241
- } = processLoaderData(state, matches, matchesToLoad, loaderResults, pendingError, revalidatingFetchers, fetcherResults, activeDeferreds); // Wire up subscribers to update loaderData as promises settle
2292
+ } = processLoaderData(state, matches, matchesToLoad, loaderResults, pendingError, revalidatingFetchers, fetcherResults, activeDeferreds);
2242
2293
 
2294
+ // Wire up subscribers to update loaderData as promises settle
2243
2295
  activeDeferreds.forEach((deferredData, routeId) => {
2244
2296
  deferredData.subscribe(aborted => {
2245
2297
  // Note: No need to updateState here since the TrackedPromise on
@@ -2260,56 +2312,50 @@ function createRouter(init) {
2260
2312
  fetchers: new Map(state.fetchers)
2261
2313
  } : {});
2262
2314
  }
2263
-
2264
2315
  function getFetcher(key) {
2265
2316
  return state.fetchers.get(key) || IDLE_FETCHER;
2266
- } // Trigger a fetcher load/submit for the given fetcher key
2267
-
2317
+ }
2268
2318
 
2319
+ // Trigger a fetcher load/submit for the given fetcher key
2269
2320
  function fetch(key, routeId, href, opts) {
2270
2321
  if (isServer) {
2271
2322
  throw new Error("router.fetch() was called during the server render, but it shouldn't be. " + "You are likely calling a useFetcher() method in the body of your component. " + "Try moving it to a useEffect or a callback.");
2272
2323
  }
2273
-
2274
2324
  if (fetchControllers.has(key)) abortFetcher(key);
2275
2325
  let routesToUse = inFlightDataRoutes || dataRoutes;
2276
2326
  let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, href, routeId, opts == null ? void 0 : opts.relative);
2277
2327
  let matches = matchRoutes(routesToUse, normalizedPath, basename);
2278
-
2279
2328
  if (!matches) {
2280
2329
  setFetcherError(key, routeId, getInternalRouterError(404, {
2281
2330
  pathname: normalizedPath
2282
2331
  }));
2283
2332
  return;
2284
2333
  }
2285
-
2286
2334
  let {
2287
2335
  path,
2288
2336
  submission
2289
2337
  } = normalizeNavigateOptions(future.v7_normalizeFormMethod, true, normalizedPath, opts);
2290
2338
  let match = getTargetMatch(matches, path);
2291
2339
  pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
2292
-
2293
2340
  if (submission && isMutationMethod(submission.formMethod)) {
2294
2341
  handleFetcherAction(key, routeId, path, match, matches, submission);
2295
2342
  return;
2296
- } // Store off the match so we can call it's shouldRevalidate on subsequent
2297
- // revalidations
2298
-
2343
+ }
2299
2344
 
2345
+ // Store off the match so we can call it's shouldRevalidate on subsequent
2346
+ // revalidations
2300
2347
  fetchLoadMatches.set(key, {
2301
2348
  routeId,
2302
2349
  path
2303
2350
  });
2304
2351
  handleFetcherLoader(key, routeId, path, match, matches, submission);
2305
- } // Call the action for the matched fetcher.submit(), and then handle redirects,
2306
- // errors, and revalidation
2307
-
2352
+ }
2308
2353
 
2354
+ // Call the action for the matched fetcher.submit(), and then handle redirects,
2355
+ // errors, and revalidation
2309
2356
  async function handleFetcherAction(key, routeId, path, match, requestMatches, submission) {
2310
2357
  interruptActiveLoads();
2311
2358
  fetchLoadMatches.delete(key);
2312
-
2313
2359
  if (!match.route.action && !match.route.lazy) {
2314
2360
  let error = getInternalRouterError(405, {
2315
2361
  method: submission.formMethod,
@@ -2318,49 +2364,43 @@ function createRouter(init) {
2318
2364
  });
2319
2365
  setFetcherError(key, routeId, error);
2320
2366
  return;
2321
- } // Put this fetcher into it's submitting state
2322
-
2367
+ }
2323
2368
 
2369
+ // Put this fetcher into it's submitting state
2324
2370
  let existingFetcher = state.fetchers.get(key);
2325
-
2326
2371
  let fetcher = _extends({
2327
2372
  state: "submitting"
2328
2373
  }, submission, {
2329
2374
  data: existingFetcher && existingFetcher.data,
2330
2375
  " _hasFetcherDoneAnything ": true
2331
2376
  });
2332
-
2333
2377
  state.fetchers.set(key, fetcher);
2334
2378
  updateState({
2335
2379
  fetchers: new Map(state.fetchers)
2336
- }); // Call the action for the fetcher
2380
+ });
2337
2381
 
2382
+ // Call the action for the fetcher
2338
2383
  let abortController = new AbortController();
2339
2384
  let fetchRequest = createClientSideRequest(init.history, path, abortController.signal, submission);
2340
2385
  fetchControllers.set(key, abortController);
2341
2386
  let actionResult = await callLoaderOrAction("action", fetchRequest, match, requestMatches, manifest, mapRouteProperties, basename);
2342
-
2343
2387
  if (fetchRequest.signal.aborted) {
2344
2388
  // We can delete this so long as we weren't aborted by ou our own fetcher
2345
2389
  // re-submit which would have put _new_ controller is in fetchControllers
2346
2390
  if (fetchControllers.get(key) === abortController) {
2347
2391
  fetchControllers.delete(key);
2348
2392
  }
2349
-
2350
2393
  return;
2351
2394
  }
2352
-
2353
2395
  if (isRedirectResult(actionResult)) {
2354
2396
  fetchControllers.delete(key);
2355
2397
  fetchRedirectIds.add(key);
2356
-
2357
2398
  let loadingFetcher = _extends({
2358
2399
  state: "loading"
2359
2400
  }, submission, {
2360
2401
  data: undefined,
2361
2402
  " _hasFetcherDoneAnything ": true
2362
2403
  });
2363
-
2364
2404
  state.fetchers.set(key, loadingFetcher);
2365
2405
  updateState({
2366
2406
  fetchers: new Map(state.fetchers)
@@ -2369,22 +2409,21 @@ function createRouter(init) {
2369
2409
  submission,
2370
2410
  isFetchActionRedirect: true
2371
2411
  });
2372
- } // Process any non-redirect errors thrown
2373
-
2412
+ }
2374
2413
 
2414
+ // Process any non-redirect errors thrown
2375
2415
  if (isErrorResult(actionResult)) {
2376
2416
  setFetcherError(key, routeId, actionResult.error);
2377
2417
  return;
2378
2418
  }
2379
-
2380
2419
  if (isDeferredResult(actionResult)) {
2381
2420
  throw getInternalRouterError(400, {
2382
2421
  type: "defer-action"
2383
2422
  });
2384
- } // Start the data load for current matches, or the next location if we're
2385
- // in the middle of a navigation
2386
-
2423
+ }
2387
2424
 
2425
+ // Start the data load for current matches, or the next location if we're
2426
+ // in the middle of a navigation
2388
2427
  let nextLocation = state.navigation.location || state.location;
2389
2428
  let revalidationRequest = createClientSideRequest(init.history, nextLocation, abortController.signal);
2390
2429
  let routesToUse = inFlightDataRoutes || dataRoutes;
@@ -2392,22 +2431,21 @@ function createRouter(init) {
2392
2431
  invariant(matches, "Didn't find any matches after fetcher action");
2393
2432
  let loadId = ++incrementingLoadId;
2394
2433
  fetchReloadIds.set(key, loadId);
2395
-
2396
2434
  let loadFetcher = _extends({
2397
2435
  state: "loading",
2398
2436
  data: actionResult.data
2399
2437
  }, submission, {
2400
2438
  " _hasFetcherDoneAnything ": true
2401
2439
  });
2402
-
2403
2440
  state.fetchers.set(key, loadFetcher);
2404
2441
  let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, basename, {
2405
2442
  [match.route.id]: actionResult.data
2406
2443
  }, undefined // No need to send through errors since we short circuit above
2407
- ); // Put all revalidating fetchers into the loading state, except for the
2444
+ );
2445
+
2446
+ // Put all revalidating fetchers into the loading state, except for the
2408
2447
  // current fetcher which we want to keep in it's current loading state which
2409
2448
  // contains it's action submission info + action data
2410
-
2411
2449
  revalidatingFetchers.filter(rf => rf.key !== key).forEach(rf => {
2412
2450
  let staleKey = rf.key;
2413
2451
  let existingFetcher = state.fetchers.get(staleKey);
@@ -2421,7 +2459,6 @@ function createRouter(init) {
2421
2459
  " _hasFetcherDoneAnything ": true
2422
2460
  };
2423
2461
  state.fetchers.set(staleKey, revalidatingFetcher);
2424
-
2425
2462
  if (rf.controller) {
2426
2463
  fetchControllers.set(staleKey, rf.controller);
2427
2464
  }
@@ -2429,49 +2466,50 @@ function createRouter(init) {
2429
2466
  updateState({
2430
2467
  fetchers: new Map(state.fetchers)
2431
2468
  });
2432
-
2433
2469
  let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach(rf => abortFetcher(rf.key));
2434
-
2435
2470
  abortController.signal.addEventListener("abort", abortPendingFetchRevalidations);
2436
2471
  let {
2437
2472
  results,
2438
2473
  loaderResults,
2439
2474
  fetcherResults
2440
2475
  } = await callLoadersAndMaybeResolveData(state.matches, matches, matchesToLoad, revalidatingFetchers, revalidationRequest);
2441
-
2442
2476
  if (abortController.signal.aborted) {
2443
2477
  return;
2444
2478
  }
2445
-
2446
2479
  abortController.signal.removeEventListener("abort", abortPendingFetchRevalidations);
2447
2480
  fetchReloadIds.delete(key);
2448
2481
  fetchControllers.delete(key);
2449
2482
  revalidatingFetchers.forEach(r => fetchControllers.delete(r.key));
2450
2483
  let redirect = findRedirect(results);
2451
-
2452
2484
  if (redirect) {
2453
2485
  return startRedirectNavigation(state, redirect);
2454
- } // Process and commit output from loaders
2455
-
2486
+ }
2456
2487
 
2488
+ // Process and commit output from loaders
2457
2489
  let {
2458
2490
  loaderData,
2459
2491
  errors
2460
2492
  } = processLoaderData(state, state.matches, matchesToLoad, loaderResults, undefined, revalidatingFetchers, fetcherResults, activeDeferreds);
2461
- let doneFetcher = {
2462
- state: "idle",
2463
- data: actionResult.data,
2464
- formMethod: undefined,
2465
- formAction: undefined,
2466
- formEncType: undefined,
2467
- formData: undefined,
2468
- " _hasFetcherDoneAnything ": true
2469
- };
2470
- state.fetchers.set(key, doneFetcher);
2471
- let didAbortFetchLoads = abortStaleFetchLoads(loadId); // If we are currently in a navigation loading state and this fetcher is
2493
+
2494
+ // Since we let revalidations complete even if the submitting fetcher was
2495
+ // deleted, only put it back to idle if it hasn't been deleted
2496
+ if (state.fetchers.has(key)) {
2497
+ let doneFetcher = {
2498
+ state: "idle",
2499
+ data: actionResult.data,
2500
+ formMethod: undefined,
2501
+ formAction: undefined,
2502
+ formEncType: undefined,
2503
+ formData: undefined,
2504
+ " _hasFetcherDoneAnything ": true
2505
+ };
2506
+ state.fetchers.set(key, doneFetcher);
2507
+ }
2508
+ let didAbortFetchLoads = abortStaleFetchLoads(loadId);
2509
+
2510
+ // If we are currently in a navigation loading state and this fetcher is
2472
2511
  // more recent than the navigation, we want the newer data so abort the
2473
2512
  // navigation and complete it with the fetcher data
2474
-
2475
2513
  if (state.navigation.state === "loading" && loadId > pendingNavigationLoadId) {
2476
2514
  invariant(pendingAction, "Expected pending action");
2477
2515
  pendingNavigationController && pendingNavigationController.abort();
@@ -2488,17 +2526,17 @@ function createRouter(init) {
2488
2526
  updateState(_extends({
2489
2527
  errors,
2490
2528
  loaderData: mergeLoaderData(state.loaderData, loaderData, matches, errors)
2491
- }, didAbortFetchLoads ? {
2529
+ }, didAbortFetchLoads || revalidatingFetchers.length > 0 ? {
2492
2530
  fetchers: new Map(state.fetchers)
2493
2531
  } : {}));
2494
2532
  isRevalidationRequired = false;
2495
2533
  }
2496
- } // Call the matched loader for fetcher.load(), handling redirects, errors, etc.
2497
-
2534
+ }
2498
2535
 
2536
+ // Call the matched loader for fetcher.load(), handling redirects, errors, etc.
2499
2537
  async function handleFetcherLoader(key, routeId, path, match, matches, submission) {
2500
- let existingFetcher = state.fetchers.get(key); // Put this fetcher into it's loading state
2501
-
2538
+ let existingFetcher = state.fetchers.get(key);
2539
+ // Put this fetcher into it's loading state
2502
2540
  let loadingFetcher = _extends({
2503
2541
  state: "loading",
2504
2542
  formMethod: undefined,
@@ -2509,48 +2547,48 @@ function createRouter(init) {
2509
2547
  data: existingFetcher && existingFetcher.data,
2510
2548
  " _hasFetcherDoneAnything ": true
2511
2549
  });
2512
-
2513
2550
  state.fetchers.set(key, loadingFetcher);
2514
2551
  updateState({
2515
2552
  fetchers: new Map(state.fetchers)
2516
- }); // Call the loader for this fetcher route match
2553
+ });
2517
2554
 
2555
+ // Call the loader for this fetcher route match
2518
2556
  let abortController = new AbortController();
2519
2557
  let fetchRequest = createClientSideRequest(init.history, path, abortController.signal);
2520
2558
  fetchControllers.set(key, abortController);
2521
- let result = await callLoaderOrAction("loader", fetchRequest, match, matches, manifest, mapRouteProperties, basename); // Deferred isn't supported for fetcher loads, await everything and treat it
2559
+ let result = await callLoaderOrAction("loader", fetchRequest, match, matches, manifest, mapRouteProperties, basename);
2560
+
2561
+ // Deferred isn't supported for fetcher loads, await everything and treat it
2522
2562
  // as a normal load. resolveDeferredData will return undefined if this
2523
2563
  // fetcher gets aborted, so we just leave result untouched and short circuit
2524
2564
  // below if that happens
2525
-
2526
2565
  if (isDeferredResult(result)) {
2527
2566
  result = (await resolveDeferredData(result, fetchRequest.signal, true)) || result;
2528
- } // We can delete this so long as we weren't aborted by our our own fetcher
2529
- // re-load which would have put _new_ controller is in fetchControllers
2530
-
2567
+ }
2531
2568
 
2569
+ // We can delete this so long as we weren't aborted by our our own fetcher
2570
+ // re-load which would have put _new_ controller is in fetchControllers
2532
2571
  if (fetchControllers.get(key) === abortController) {
2533
2572
  fetchControllers.delete(key);
2534
2573
  }
2535
-
2536
2574
  if (fetchRequest.signal.aborted) {
2537
2575
  return;
2538
- } // If the loader threw a redirect Response, start a new REPLACE navigation
2539
-
2576
+ }
2540
2577
 
2578
+ // If the loader threw a redirect Response, start a new REPLACE navigation
2541
2579
  if (isRedirectResult(result)) {
2542
2580
  fetchRedirectIds.add(key);
2543
2581
  await startRedirectNavigation(state, result);
2544
2582
  return;
2545
- } // Process any non-redirect errors thrown
2546
-
2583
+ }
2547
2584
 
2585
+ // Process any non-redirect errors thrown
2548
2586
  if (isErrorResult(result)) {
2549
2587
  let boundaryMatch = findNearestBoundary(state.matches, routeId);
2550
- state.fetchers.delete(key); // TODO: In remix, this would reset to IDLE_NAVIGATION if it was a catch -
2588
+ state.fetchers.delete(key);
2589
+ // TODO: In remix, this would reset to IDLE_NAVIGATION if it was a catch -
2551
2590
  // do we need to behave any differently with our non-redirect errors?
2552
2591
  // What if it was a non-redirect Response?
2553
-
2554
2592
  updateState({
2555
2593
  fetchers: new Map(state.fetchers),
2556
2594
  errors: {
@@ -2559,9 +2597,9 @@ function createRouter(init) {
2559
2597
  });
2560
2598
  return;
2561
2599
  }
2600
+ invariant(!isDeferredResult(result), "Unhandled fetcher deferred data");
2562
2601
 
2563
- invariant(!isDeferredResult(result), "Unhandled fetcher deferred data"); // Put the fetcher back into an idle state
2564
-
2602
+ // Put the fetcher back into an idle state
2565
2603
  let doneFetcher = {
2566
2604
  state: "idle",
2567
2605
  data: result.data,
@@ -2576,6 +2614,7 @@ function createRouter(init) {
2576
2614
  fetchers: new Map(state.fetchers)
2577
2615
  });
2578
2616
  }
2617
+
2579
2618
  /**
2580
2619
  * Utility function to handle redirects returned from an action or loader.
2581
2620
  * Normally, a redirect "replaces" the navigation that triggered it. So, for
@@ -2595,57 +2634,49 @@ function createRouter(init) {
2595
2634
  * actually touch history until we've processed redirects, so we just use
2596
2635
  * the history action from the original navigation (PUSH or REPLACE).
2597
2636
  */
2598
-
2599
-
2600
2637
  async function startRedirectNavigation(state, redirect, _temp) {
2601
- var _window;
2602
-
2603
2638
  let {
2604
2639
  submission,
2605
2640
  replace,
2606
2641
  isFetchActionRedirect
2607
2642
  } = _temp === void 0 ? {} : _temp;
2608
-
2609
2643
  if (redirect.revalidate) {
2610
2644
  isRevalidationRequired = true;
2611
2645
  }
2612
-
2613
2646
  let redirectLocation = createLocation(state.location, redirect.location, // TODO: This can be removed once we get rid of useTransition in Remix v2
2614
2647
  _extends({
2615
2648
  _isRedirect: true
2616
2649
  }, isFetchActionRedirect ? {
2617
2650
  _isFetchActionRedirect: true
2618
2651
  } : {}));
2619
- invariant(redirectLocation, "Expected a location on the redirect navigation"); // Check if this an absolute external redirect that goes to a new origin
2620
-
2621
- if (ABSOLUTE_URL_REGEX.test(redirect.location) && isBrowser && typeof ((_window = window) == null ? void 0 : _window.location) !== "undefined") {
2652
+ invariant(redirectLocation, "Expected a location on the redirect navigation");
2653
+ // Check if this an absolute external redirect that goes to a new origin
2654
+ if (ABSOLUTE_URL_REGEX.test(redirect.location) && isBrowser) {
2622
2655
  let url = init.history.createURL(redirect.location);
2623
2656
  let isDifferentBasename = stripBasename(url.pathname, basename) == null;
2624
-
2625
- if (window.location.origin !== url.origin || isDifferentBasename) {
2657
+ if (routerWindow.location.origin !== url.origin || isDifferentBasename) {
2626
2658
  if (replace) {
2627
- window.location.replace(redirect.location);
2659
+ routerWindow.location.replace(redirect.location);
2628
2660
  } else {
2629
- window.location.assign(redirect.location);
2661
+ routerWindow.location.assign(redirect.location);
2630
2662
  }
2631
-
2632
2663
  return;
2633
2664
  }
2634
- } // There's no need to abort on redirects, since we don't detect the
2635
- // redirect until the action/loaders have settled
2636
-
2665
+ }
2637
2666
 
2667
+ // There's no need to abort on redirects, since we don't detect the
2668
+ // redirect until the action/loaders have settled
2638
2669
  pendingNavigationController = null;
2639
- let redirectHistoryAction = replace === true ? exports.Action.Replace : exports.Action.Push; // Use the incoming submission if provided, fallback on the active one in
2640
- // state.navigation
2670
+ let redirectHistoryAction = replace === true ? exports.Action.Replace : exports.Action.Push;
2641
2671
 
2672
+ // Use the incoming submission if provided, fallback on the active one in
2673
+ // state.navigation
2642
2674
  let {
2643
2675
  formMethod,
2644
2676
  formAction,
2645
2677
  formEncType,
2646
2678
  formData
2647
2679
  } = state.navigation;
2648
-
2649
2680
  if (!submission && formMethod && formAction && formData && formEncType) {
2650
2681
  submission = {
2651
2682
  formMethod,
@@ -2653,11 +2684,11 @@ function createRouter(init) {
2653
2684
  formEncType,
2654
2685
  formData
2655
2686
  };
2656
- } // If this was a 307/308 submission we want to preserve the HTTP method and
2687
+ }
2688
+
2689
+ // If this was a 307/308 submission we want to preserve the HTTP method and
2657
2690
  // re-submit the GET/POST/PUT/PATCH/DELETE as a submission navigation to the
2658
2691
  // redirected location
2659
-
2660
-
2661
2692
  if (redirectPreserveMethodStatusCodes.has(redirect.status) && submission && isMutationMethod(submission.formMethod)) {
2662
2693
  await startNavigation(redirectHistoryAction, redirectLocation, {
2663
2694
  submission: _extends({}, submission, {
@@ -2699,7 +2730,6 @@ function createRouter(init) {
2699
2730
  });
2700
2731
  }
2701
2732
  }
2702
-
2703
2733
  async function callLoadersAndMaybeResolveData(currentMatches, matches, matchesToLoad, fetchersToLoad, request) {
2704
2734
  // Call all navigation loaders and revalidating fetcher loaders in parallel,
2705
2735
  // then slice off the results into separate arrays so we can handle them
@@ -2726,14 +2756,15 @@ function createRouter(init) {
2726
2756
  fetcherResults
2727
2757
  };
2728
2758
  }
2729
-
2730
2759
  function interruptActiveLoads() {
2731
2760
  // Every interruption triggers a revalidation
2732
- isRevalidationRequired = true; // Cancel pending route-level deferreds and mark cancelled routes for
2733
- // revalidation
2761
+ isRevalidationRequired = true;
2734
2762
 
2735
- cancelledDeferredRoutes.push(...cancelActiveDeferreds()); // Abort in-flight fetcher loads
2763
+ // Cancel pending route-level deferreds and mark cancelled routes for
2764
+ // revalidation
2765
+ cancelledDeferredRoutes.push(...cancelActiveDeferreds());
2736
2766
 
2767
+ // Abort in-flight fetcher loads
2737
2768
  fetchLoadMatches.forEach((_, key) => {
2738
2769
  if (fetchControllers.has(key)) {
2739
2770
  cancelledFetcherLoads.push(key);
@@ -2741,7 +2772,6 @@ function createRouter(init) {
2741
2772
  }
2742
2773
  });
2743
2774
  }
2744
-
2745
2775
  function setFetcherError(key, routeId, error) {
2746
2776
  let boundaryMatch = findNearestBoundary(state.matches, routeId);
2747
2777
  deleteFetcher(key);
@@ -2752,22 +2782,25 @@ function createRouter(init) {
2752
2782
  fetchers: new Map(state.fetchers)
2753
2783
  });
2754
2784
  }
2755
-
2756
2785
  function deleteFetcher(key) {
2757
- if (fetchControllers.has(key)) abortFetcher(key);
2786
+ let fetcher = state.fetchers.get(key);
2787
+ // Don't abort the controller if this is a deletion of a fetcher.submit()
2788
+ // in it's loading phase since - we don't want to abort the corresponding
2789
+ // revalidation and want them to complete and land
2790
+ if (fetchControllers.has(key) && !(fetcher && fetcher.state === "loading" && fetchReloadIds.has(key))) {
2791
+ abortFetcher(key);
2792
+ }
2758
2793
  fetchLoadMatches.delete(key);
2759
2794
  fetchReloadIds.delete(key);
2760
2795
  fetchRedirectIds.delete(key);
2761
2796
  state.fetchers.delete(key);
2762
2797
  }
2763
-
2764
2798
  function abortFetcher(key) {
2765
2799
  let controller = fetchControllers.get(key);
2766
2800
  invariant(controller, "Expected fetch controller: " + key);
2767
2801
  controller.abort();
2768
2802
  fetchControllers.delete(key);
2769
2803
  }
2770
-
2771
2804
  function markFetchersDone(keys) {
2772
2805
  for (let key of keys) {
2773
2806
  let fetcher = getFetcher(key);
@@ -2783,34 +2816,27 @@ function createRouter(init) {
2783
2816
  state.fetchers.set(key, doneFetcher);
2784
2817
  }
2785
2818
  }
2786
-
2787
2819
  function markFetchRedirectsDone() {
2788
2820
  let doneKeys = [];
2789
2821
  let updatedFetchers = false;
2790
-
2791
2822
  for (let key of fetchRedirectIds) {
2792
2823
  let fetcher = state.fetchers.get(key);
2793
2824
  invariant(fetcher, "Expected fetcher: " + key);
2794
-
2795
2825
  if (fetcher.state === "loading") {
2796
2826
  fetchRedirectIds.delete(key);
2797
2827
  doneKeys.push(key);
2798
2828
  updatedFetchers = true;
2799
2829
  }
2800
2830
  }
2801
-
2802
2831
  markFetchersDone(doneKeys);
2803
2832
  return updatedFetchers;
2804
2833
  }
2805
-
2806
2834
  function abortStaleFetchLoads(landedId) {
2807
2835
  let yeetedKeys = [];
2808
-
2809
2836
  for (let [key, id] of fetchReloadIds) {
2810
2837
  if (id < landedId) {
2811
2838
  let fetcher = state.fetchers.get(key);
2812
2839
  invariant(fetcher, "Expected fetcher: " + key);
2813
-
2814
2840
  if (fetcher.state === "loading") {
2815
2841
  abortFetcher(key);
2816
2842
  fetchReloadIds.delete(key);
@@ -2818,67 +2844,59 @@ function createRouter(init) {
2818
2844
  }
2819
2845
  }
2820
2846
  }
2821
-
2822
2847
  markFetchersDone(yeetedKeys);
2823
2848
  return yeetedKeys.length > 0;
2824
2849
  }
2825
-
2826
2850
  function getBlocker(key, fn) {
2827
2851
  let blocker = state.blockers.get(key) || IDLE_BLOCKER;
2828
-
2829
2852
  if (blockerFunctions.get(key) !== fn) {
2830
2853
  blockerFunctions.set(key, fn);
2831
2854
  }
2832
-
2833
2855
  return blocker;
2834
2856
  }
2835
-
2836
2857
  function deleteBlocker(key) {
2837
2858
  state.blockers.delete(key);
2838
2859
  blockerFunctions.delete(key);
2839
- } // Utility function to update blockers, ensuring valid state transitions
2840
-
2860
+ }
2841
2861
 
2862
+ // Utility function to update blockers, ensuring valid state transitions
2842
2863
  function updateBlocker(key, newBlocker) {
2843
- let blocker = state.blockers.get(key) || IDLE_BLOCKER; // Poor mans state machine :)
2844
- // https://mermaid.live/edit#pako:eNqVkc9OwzAMxl8l8nnjAYrEtDIOHEBIgwvKJTReGy3_lDpIqO27k6awMG0XcrLlnz87nwdonESogKXXBuE79rq75XZO3-yHds0RJVuv70YrPlUrCEe2HfrORS3rubqZfuhtpg5C9wk5tZ4VKcRUq88q9Z8RS0-48cE1iHJkL0ugbHuFLus9L6spZy8nX9MP2CNdomVaposqu3fGayT8T8-jJQwhepo_UtpgBQaDEUom04dZhAN1aJBDlUKJBxE1ceB2Smj0Mln-IBW5AFU2dwUiktt_2Qaq2dBfaKdEup85UV7Yd-dKjlnkabl2Pvr0DTkTreM
2864
+ let blocker = state.blockers.get(key) || IDLE_BLOCKER;
2845
2865
 
2866
+ // Poor mans state machine :)
2867
+ // https://mermaid.live/edit#pako:eNqVkc9OwzAMxl8l8nnjAYrEtDIOHEBIgwvKJTReGy3_lDpIqO27k6awMG0XcrLlnz87nwdonESogKXXBuE79rq75XZO3-yHds0RJVuv70YrPlUrCEe2HfrORS3rubqZfuhtpg5C9wk5tZ4VKcRUq88q9Z8RS0-48cE1iHJkL0ugbHuFLus9L6spZy8nX9MP2CNdomVaposqu3fGayT8T8-jJQwhepo_UtpgBQaDEUom04dZhAN1aJBDlUKJBxE1ceB2Smj0Mln-IBW5AFU2dwUiktt_2Qaq2dBfaKdEup85UV7Yd-dKjlnkabl2Pvr0DTkTreM
2846
2868
  invariant(blocker.state === "unblocked" && newBlocker.state === "blocked" || blocker.state === "blocked" && newBlocker.state === "blocked" || blocker.state === "blocked" && newBlocker.state === "proceeding" || blocker.state === "blocked" && newBlocker.state === "unblocked" || blocker.state === "proceeding" && newBlocker.state === "unblocked", "Invalid blocker state transition: " + blocker.state + " -> " + newBlocker.state);
2847
2869
  state.blockers.set(key, newBlocker);
2848
2870
  updateState({
2849
2871
  blockers: new Map(state.blockers)
2850
2872
  });
2851
2873
  }
2852
-
2853
2874
  function shouldBlockNavigation(_ref2) {
2854
2875
  let {
2855
2876
  currentLocation,
2856
2877
  nextLocation,
2857
2878
  historyAction
2858
2879
  } = _ref2;
2859
-
2860
2880
  if (blockerFunctions.size === 0) {
2861
2881
  return;
2862
- } // We ony support a single active blocker at the moment since we don't have
2863
- // any compelling use cases for multi-blocker yet
2864
-
2882
+ }
2865
2883
 
2884
+ // We ony support a single active blocker at the moment since we don't have
2885
+ // any compelling use cases for multi-blocker yet
2866
2886
  if (blockerFunctions.size > 1) {
2867
2887
  warning(false, "A router only supports one blocker at a time");
2868
2888
  }
2869
-
2870
2889
  let entries = Array.from(blockerFunctions.entries());
2871
2890
  let [blockerKey, blockerFunction] = entries[entries.length - 1];
2872
2891
  let blocker = state.blockers.get(blockerKey);
2873
-
2874
2892
  if (blocker && blocker.state === "proceeding") {
2875
2893
  // If the blocker is currently proceeding, we don't need to re-check
2876
2894
  // it and can let this navigation continue
2877
2895
  return;
2878
- } // At this point, we know we're unblocked/blocked so we need to check the
2879
- // user-provided blocker function
2880
-
2896
+ }
2881
2897
 
2898
+ // At this point, we know we're unblocked/blocked so we need to check the
2899
+ // user-provided blocker function
2882
2900
  if (blockerFunction({
2883
2901
  currentLocation,
2884
2902
  nextLocation,
@@ -2887,7 +2905,6 @@ function createRouter(init) {
2887
2905
  return blockerKey;
2888
2906
  }
2889
2907
  }
2890
-
2891
2908
  function cancelActiveDeferreds(predicate) {
2892
2909
  let cancelledRouteIds = [];
2893
2910
  activeDeferreds.forEach((dfd, routeId) => {
@@ -2901,37 +2918,33 @@ function createRouter(init) {
2901
2918
  }
2902
2919
  });
2903
2920
  return cancelledRouteIds;
2904
- } // Opt in to capturing and reporting scroll positions during navigations,
2905
- // used by the <ScrollRestoration> component
2906
-
2921
+ }
2907
2922
 
2923
+ // Opt in to capturing and reporting scroll positions during navigations,
2924
+ // used by the <ScrollRestoration> component
2908
2925
  function enableScrollRestoration(positions, getPosition, getKey) {
2909
2926
  savedScrollPositions = positions;
2910
2927
  getScrollPosition = getPosition;
2928
+ getScrollRestorationKey = getKey || (location => location.key);
2911
2929
 
2912
- getScrollRestorationKey = getKey || (location => location.key); // Perform initial hydration scroll restoration, since we miss the boat on
2930
+ // Perform initial hydration scroll restoration, since we miss the boat on
2913
2931
  // the initial updateState() because we've not yet rendered <ScrollRestoration/>
2914
2932
  // and therefore have no savedScrollPositions available
2915
-
2916
-
2917
2933
  if (!initialScrollRestored && state.navigation === IDLE_NAVIGATION) {
2918
2934
  initialScrollRestored = true;
2919
2935
  let y = getSavedScrollPosition(state.location, state.matches);
2920
-
2921
2936
  if (y != null) {
2922
2937
  updateState({
2923
2938
  restoreScrollPosition: y
2924
2939
  });
2925
2940
  }
2926
2941
  }
2927
-
2928
2942
  return () => {
2929
2943
  savedScrollPositions = null;
2930
2944
  getScrollPosition = null;
2931
2945
  getScrollRestorationKey = null;
2932
2946
  };
2933
2947
  }
2934
-
2935
2948
  function saveScrollPosition(location, matches) {
2936
2949
  if (savedScrollPositions && getScrollRestorationKey && getScrollPosition) {
2937
2950
  let userMatches = matches.map(m => createUseMatchesMatch(m, state.loaderData));
@@ -2939,39 +2952,31 @@ function createRouter(init) {
2939
2952
  savedScrollPositions[key] = getScrollPosition();
2940
2953
  }
2941
2954
  }
2942
-
2943
2955
  function getSavedScrollPosition(location, matches) {
2944
2956
  if (savedScrollPositions && getScrollRestorationKey && getScrollPosition) {
2945
2957
  let userMatches = matches.map(m => createUseMatchesMatch(m, state.loaderData));
2946
2958
  let key = getScrollRestorationKey(location, userMatches) || location.key;
2947
2959
  let y = savedScrollPositions[key];
2948
-
2949
2960
  if (typeof y === "number") {
2950
2961
  return y;
2951
2962
  }
2952
2963
  }
2953
-
2954
2964
  return null;
2955
2965
  }
2956
-
2957
2966
  function _internalSetRoutes(newRoutes) {
2958
2967
  manifest = {};
2959
2968
  inFlightDataRoutes = convertRoutesToDataRoutes(newRoutes, mapRouteProperties, undefined, manifest);
2960
2969
  }
2961
-
2962
2970
  router = {
2963
2971
  get basename() {
2964
2972
  return basename;
2965
2973
  },
2966
-
2967
2974
  get state() {
2968
2975
  return state;
2969
2976
  },
2970
-
2971
2977
  get routes() {
2972
2978
  return dataRoutes;
2973
2979
  },
2974
-
2975
2980
  initialize,
2976
2981
  subscribe,
2977
2982
  enableScrollRestoration,
@@ -2994,7 +2999,9 @@ function createRouter(init) {
2994
2999
  _internalSetRoutes
2995
3000
  };
2996
3001
  return router;
2997
- } //#endregion
3002
+ }
3003
+ //#endregion
3004
+
2998
3005
  ////////////////////////////////////////////////////////////////////////////////
2999
3006
  //#region createStaticHandler
3000
3007
  ////////////////////////////////////////////////////////////////////////////////
@@ -3005,21 +3012,19 @@ function createStaticHandler(routes, opts) {
3005
3012
  let manifest = {};
3006
3013
  let basename = (opts ? opts.basename : null) || "/";
3007
3014
  let mapRouteProperties;
3008
-
3009
3015
  if (opts != null && opts.mapRouteProperties) {
3010
3016
  mapRouteProperties = opts.mapRouteProperties;
3011
3017
  } else if (opts != null && opts.detectErrorBoundary) {
3012
3018
  // If they are still using the deprecated version, wrap it with the new API
3013
3019
  let detectErrorBoundary = opts.detectErrorBoundary;
3014
-
3015
3020
  mapRouteProperties = route => ({
3016
3021
  hasErrorBoundary: detectErrorBoundary(route)
3017
3022
  });
3018
3023
  } else {
3019
3024
  mapRouteProperties = defaultMapRouteProperties;
3020
3025
  }
3021
-
3022
3026
  let dataRoutes = convertRoutesToDataRoutes(routes, mapRouteProperties, undefined, manifest);
3027
+
3023
3028
  /**
3024
3029
  * The query() method is intended for document requests, in which we want to
3025
3030
  * call an optional action and potentially multiple loaders for all nested
@@ -3039,7 +3044,6 @@ function createStaticHandler(routes, opts) {
3039
3044
  * propagate that out and return the raw Response so the HTTP server can
3040
3045
  * return it directly.
3041
3046
  */
3042
-
3043
3047
  async function query(request, _temp2) {
3044
3048
  let {
3045
3049
  requestContext
@@ -3047,8 +3051,9 @@ function createStaticHandler(routes, opts) {
3047
3051
  let url = new URL(request.url);
3048
3052
  let method = request.method;
3049
3053
  let location = createLocation("", createPath(url), null, "default");
3050
- let matches = matchRoutes(dataRoutes, location, basename); // SSR supports HEAD requests while SPA doesn't
3054
+ let matches = matchRoutes(dataRoutes, location, basename);
3051
3055
 
3056
+ // SSR supports HEAD requests while SPA doesn't
3052
3057
  if (!isValidMethod(method) && method !== "HEAD") {
3053
3058
  let error = getInternalRouterError(405, {
3054
3059
  method
@@ -3094,21 +3099,20 @@ function createStaticHandler(routes, opts) {
3094
3099
  activeDeferreds: null
3095
3100
  };
3096
3101
  }
3097
-
3098
3102
  let result = await queryImpl(request, location, matches, requestContext);
3099
-
3100
3103
  if (isResponse(result)) {
3101
3104
  return result;
3102
- } // When returning StaticHandlerContext, we patch back in the location here
3105
+ }
3106
+
3107
+ // When returning StaticHandlerContext, we patch back in the location here
3103
3108
  // since we need it for React Context. But this helps keep our submit and
3104
3109
  // loadRouteData operating on a Request instead of a Location
3105
-
3106
-
3107
3110
  return _extends({
3108
3111
  location,
3109
3112
  basename
3110
3113
  }, result);
3111
3114
  }
3115
+
3112
3116
  /**
3113
3117
  * The queryRoute() method is intended for targeted route requests, either
3114
3118
  * for fetch ?_data requests or resource route requests. In this case, we
@@ -3129,8 +3133,6 @@ function createStaticHandler(routes, opts) {
3129
3133
  * code. Examples here are 404 and 405 errors that occur prior to reaching
3130
3134
  * any user-defined loaders.
3131
3135
  */
3132
-
3133
-
3134
3136
  async function queryRoute(request, _temp3) {
3135
3137
  let {
3136
3138
  routeId,
@@ -3139,8 +3141,9 @@ function createStaticHandler(routes, opts) {
3139
3141
  let url = new URL(request.url);
3140
3142
  let method = request.method;
3141
3143
  let location = createLocation("", createPath(url), null, "default");
3142
- let matches = matchRoutes(dataRoutes, location, basename); // SSR supports HEAD requests while SPA doesn't
3144
+ let matches = matchRoutes(dataRoutes, location, basename);
3143
3145
 
3146
+ // SSR supports HEAD requests while SPA doesn't
3144
3147
  if (!isValidMethod(method) && method !== "HEAD" && method !== "OPTIONS") {
3145
3148
  throw getInternalRouterError(405, {
3146
3149
  method
@@ -3150,9 +3153,7 @@ function createStaticHandler(routes, opts) {
3150
3153
  pathname: location.pathname
3151
3154
  });
3152
3155
  }
3153
-
3154
3156
  let match = routeId ? matches.find(m => m.route.id === routeId) : getTargetMatch(matches, location);
3155
-
3156
3157
  if (routeId && !match) {
3157
3158
  throw getInternalRouterError(403, {
3158
3159
  pathname: location.pathname,
@@ -3164,52 +3165,40 @@ function createStaticHandler(routes, opts) {
3164
3165
  pathname: location.pathname
3165
3166
  });
3166
3167
  }
3167
-
3168
3168
  let result = await queryImpl(request, location, matches, requestContext, match);
3169
-
3170
3169
  if (isResponse(result)) {
3171
3170
  return result;
3172
3171
  }
3173
-
3174
3172
  let error = result.errors ? Object.values(result.errors)[0] : undefined;
3175
-
3176
3173
  if (error !== undefined) {
3177
3174
  // If we got back result.errors, that means the loader/action threw
3178
3175
  // _something_ that wasn't a Response, but it's not guaranteed/required
3179
3176
  // to be an `instanceof Error` either, so we have to use throw here to
3180
3177
  // preserve the "error" state outside of queryImpl.
3181
3178
  throw error;
3182
- } // Pick off the right state value to return
3183
-
3179
+ }
3184
3180
 
3181
+ // Pick off the right state value to return
3185
3182
  if (result.actionData) {
3186
3183
  return Object.values(result.actionData)[0];
3187
3184
  }
3188
-
3189
3185
  if (result.loaderData) {
3190
3186
  var _result$activeDeferre;
3191
-
3192
3187
  let data = Object.values(result.loaderData)[0];
3193
-
3194
3188
  if ((_result$activeDeferre = result.activeDeferreds) != null && _result$activeDeferre[match.route.id]) {
3195
3189
  data[UNSAFE_DEFERRED_SYMBOL] = result.activeDeferreds[match.route.id];
3196
3190
  }
3197
-
3198
3191
  return data;
3199
3192
  }
3200
-
3201
3193
  return undefined;
3202
3194
  }
3203
-
3204
3195
  async function queryImpl(request, location, matches, requestContext, routeMatch) {
3205
3196
  invariant(request.signal, "query()/queryRoute() requests must contain an AbortController signal");
3206
-
3207
3197
  try {
3208
3198
  if (isMutationMethod(request.method.toLowerCase())) {
3209
3199
  let result = await submit(request, matches, routeMatch || getTargetMatch(matches, location), requestContext, routeMatch != null);
3210
3200
  return result;
3211
3201
  }
3212
-
3213
3202
  let result = await loadRouteData(request, matches, requestContext, routeMatch);
3214
3203
  return isResponse(result) ? result : _extends({}, result, {
3215
3204
  actionData: null,
@@ -3223,47 +3212,38 @@ function createStaticHandler(routes, opts) {
3223
3212
  if (e.type === ResultType.error && !isRedirectResponse(e.response)) {
3224
3213
  throw e.response;
3225
3214
  }
3226
-
3227
3215
  return e.response;
3228
- } // Redirects are always returned since they don't propagate to catch
3216
+ }
3217
+ // Redirects are always returned since they don't propagate to catch
3229
3218
  // boundaries
3230
-
3231
-
3232
3219
  if (isRedirectResponse(e)) {
3233
3220
  return e;
3234
3221
  }
3235
-
3236
3222
  throw e;
3237
3223
  }
3238
3224
  }
3239
-
3240
3225
  async function submit(request, matches, actionMatch, requestContext, isRouteRequest) {
3241
3226
  let result;
3242
-
3243
3227
  if (!actionMatch.route.action && !actionMatch.route.lazy) {
3244
3228
  let error = getInternalRouterError(405, {
3245
3229
  method: request.method,
3246
3230
  pathname: new URL(request.url).pathname,
3247
3231
  routeId: actionMatch.route.id
3248
3232
  });
3249
-
3250
3233
  if (isRouteRequest) {
3251
3234
  throw error;
3252
3235
  }
3253
-
3254
3236
  result = {
3255
3237
  type: ResultType.error,
3256
3238
  error
3257
3239
  };
3258
3240
  } else {
3259
3241
  result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename, true, isRouteRequest, requestContext);
3260
-
3261
3242
  if (request.signal.aborted) {
3262
3243
  let method = isRouteRequest ? "queryRoute" : "query";
3263
3244
  throw new Error(method + "() call aborted");
3264
3245
  }
3265
3246
  }
3266
-
3267
3247
  if (isRedirectResult(result)) {
3268
3248
  // Uhhhh - this should never happen, we should always throw these from
3269
3249
  // callLoaderOrAction, but the type narrowing here keeps TS happy and we
@@ -3276,29 +3256,24 @@ function createStaticHandler(routes, opts) {
3276
3256
  }
3277
3257
  });
3278
3258
  }
3279
-
3280
3259
  if (isDeferredResult(result)) {
3281
3260
  let error = getInternalRouterError(400, {
3282
3261
  type: "defer-action"
3283
3262
  });
3284
-
3285
3263
  if (isRouteRequest) {
3286
3264
  throw error;
3287
3265
  }
3288
-
3289
3266
  result = {
3290
3267
  type: ResultType.error,
3291
3268
  error
3292
3269
  };
3293
3270
  }
3294
-
3295
3271
  if (isRouteRequest) {
3296
3272
  // Note: This should only be non-Response values if we get here, since
3297
3273
  // isRouteRequest should throw any Response received in callLoaderOrAction
3298
3274
  if (isErrorResult(result)) {
3299
3275
  throw result.error;
3300
3276
  }
3301
-
3302
3277
  return {
3303
3278
  matches: [actionMatch],
3304
3279
  loaderData: {},
@@ -3314,15 +3289,15 @@ function createStaticHandler(routes, opts) {
3314
3289
  activeDeferreds: null
3315
3290
  };
3316
3291
  }
3317
-
3318
3292
  if (isErrorResult(result)) {
3319
3293
  // Store off the pending error - we use it to determine which loaders
3320
3294
  // to call and will commit it when we complete the navigation
3321
3295
  let boundaryMatch = findNearestBoundary(matches, actionMatch.route.id);
3322
3296
  let context = await loadRouteData(request, matches, requestContext, undefined, {
3323
3297
  [boundaryMatch.route.id]: result.error
3324
- }); // action status codes take precedence over loader status codes
3298
+ });
3325
3299
 
3300
+ // action status codes take precedence over loader status codes
3326
3301
  return _extends({}, context, {
3327
3302
  statusCode: isRouteErrorResponse(result.error) ? result.error.status : 500,
3328
3303
  actionData: null,
@@ -3330,9 +3305,9 @@ function createStaticHandler(routes, opts) {
3330
3305
  [actionMatch.route.id]: result.headers
3331
3306
  } : {})
3332
3307
  });
3333
- } // Create a GET request for the loaders
3334
-
3308
+ }
3335
3309
 
3310
+ // Create a GET request for the loaders
3336
3311
  let loaderRequest = new Request(request.url, {
3337
3312
  headers: request.headers,
3338
3313
  redirect: request.redirect,
@@ -3350,10 +3325,10 @@ function createStaticHandler(routes, opts) {
3350
3325
  } : {})
3351
3326
  });
3352
3327
  }
3353
-
3354
3328
  async function loadRouteData(request, matches, requestContext, routeMatch, pendingActionError) {
3355
- let isRouteRequest = routeMatch != null; // Short circuit if we have no loaders to run (queryRoute())
3329
+ let isRouteRequest = routeMatch != null;
3356
3330
 
3331
+ // Short circuit if we have no loaders to run (queryRoute())
3357
3332
  if (isRouteRequest && !(routeMatch != null && routeMatch.route.loader) && !(routeMatch != null && routeMatch.route.lazy)) {
3358
3333
  throw getInternalRouterError(400, {
3359
3334
  method: request.method,
@@ -3361,10 +3336,10 @@ function createStaticHandler(routes, opts) {
3361
3336
  routeId: routeMatch == null ? void 0 : routeMatch.route.id
3362
3337
  });
3363
3338
  }
3364
-
3365
3339
  let requestMatches = routeMatch ? [routeMatch] : getLoaderMatchesUntilBoundary(matches, Object.keys(pendingActionError || {})[0]);
3366
- let matchesToLoad = requestMatches.filter(m => m.route.loader || m.route.lazy); // Short circuit if we have no loaders to run (query())
3340
+ let matchesToLoad = requestMatches.filter(m => m.route.loader || m.route.lazy);
3367
3341
 
3342
+ // Short circuit if we have no loaders to run (query())
3368
3343
  if (matchesToLoad.length === 0) {
3369
3344
  return {
3370
3345
  matches,
@@ -3378,18 +3353,17 @@ function createStaticHandler(routes, opts) {
3378
3353
  activeDeferreds: null
3379
3354
  };
3380
3355
  }
3381
-
3382
3356
  let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest, mapRouteProperties, basename, true, isRouteRequest, requestContext))]);
3383
-
3384
3357
  if (request.signal.aborted) {
3385
3358
  let method = isRouteRequest ? "queryRoute" : "query";
3386
3359
  throw new Error(method + "() call aborted");
3387
- } // Process and commit output from loaders
3388
-
3360
+ }
3389
3361
 
3362
+ // Process and commit output from loaders
3390
3363
  let activeDeferreds = new Map();
3391
- let context = processRouteLoaderData(matches, matchesToLoad, results, pendingActionError, activeDeferreds); // Add a null for any non-loader matches for proper revalidation on the client
3364
+ let context = processRouteLoaderData(matches, matchesToLoad, results, pendingActionError, activeDeferreds);
3392
3365
 
3366
+ // Add a null for any non-loader matches for proper revalidation on the client
3393
3367
  let executedLoaders = new Set(matchesToLoad.map(match => match.route.id));
3394
3368
  matches.forEach(match => {
3395
3369
  if (!executedLoaders.has(match.route.id)) {
@@ -3401,13 +3375,15 @@ function createStaticHandler(routes, opts) {
3401
3375
  activeDeferreds: activeDeferreds.size > 0 ? Object.fromEntries(activeDeferreds.entries()) : null
3402
3376
  });
3403
3377
  }
3404
-
3405
3378
  return {
3406
3379
  dataRoutes,
3407
3380
  query,
3408
3381
  queryRoute
3409
3382
  };
3410
- } //#endregion
3383
+ }
3384
+
3385
+ //#endregion
3386
+
3411
3387
  ////////////////////////////////////////////////////////////////////////////////
3412
3388
  //#region Helpers
3413
3389
  ////////////////////////////////////////////////////////////////////////////////
@@ -3416,7 +3392,6 @@ function createStaticHandler(routes, opts) {
3416
3392
  * Given an existing StaticHandlerContext and an error thrown at render time,
3417
3393
  * provide an updated StaticHandlerContext suitable for a second SSR render
3418
3394
  */
3419
-
3420
3395
  function getStaticContextFromError(routes, context, error) {
3421
3396
  let newContext = _extends({}, context, {
3422
3397
  statusCode: 500,
@@ -3424,28 +3399,22 @@ function getStaticContextFromError(routes, context, error) {
3424
3399
  [context._deepestRenderedBoundaryId || routes[0].id]: error
3425
3400
  }
3426
3401
  });
3427
-
3428
3402
  return newContext;
3429
3403
  }
3430
-
3431
3404
  function isSubmissionNavigation(opts) {
3432
3405
  return opts != null && "formData" in opts;
3433
3406
  }
3434
-
3435
3407
  function normalizeTo(location, matches, basename, prependBasename, to, fromRouteId, relative) {
3436
3408
  let contextualMatches;
3437
3409
  let activeRouteMatch;
3438
-
3439
3410
  if (fromRouteId != null && relative !== "path") {
3440
3411
  // Grab matches up to the calling route so our route-relative logic is
3441
3412
  // relative to the correct source route. When using relative:path,
3442
3413
  // fromRouteId is ignored since that is always relative to the current
3443
3414
  // location path
3444
3415
  contextualMatches = [];
3445
-
3446
3416
  for (let match of matches) {
3447
3417
  contextualMatches.push(match);
3448
-
3449
3418
  if (match.route.id === fromRouteId) {
3450
3419
  activeRouteMatch = match;
3451
3420
  break;
@@ -3454,36 +3423,36 @@ function normalizeTo(location, matches, basename, prependBasename, to, fromRoute
3454
3423
  } else {
3455
3424
  contextualMatches = matches;
3456
3425
  activeRouteMatch = matches[matches.length - 1];
3457
- } // Resolve the relative path
3426
+ }
3458
3427
 
3428
+ // Resolve the relative path
3429
+ let path = resolveTo(to ? to : ".", getPathContributingMatches(contextualMatches).map(m => m.pathnameBase), stripBasename(location.pathname, basename) || location.pathname, relative === "path");
3459
3430
 
3460
- let path = resolveTo(to ? to : ".", getPathContributingMatches(contextualMatches).map(m => m.pathnameBase), stripBasename(location.pathname, basename) || location.pathname, relative === "path"); // When `to` is not specified we inherit search/hash from the current
3431
+ // When `to` is not specified we inherit search/hash from the current
3461
3432
  // location, unlike when to="." and we just inherit the path.
3462
3433
  // See https://github.com/remix-run/remix/issues/927
3463
-
3464
3434
  if (to == null) {
3465
3435
  path.search = location.search;
3466
3436
  path.hash = location.hash;
3467
- } // Add an ?index param for matched index routes if we don't already have one
3468
-
3437
+ }
3469
3438
 
3439
+ // Add an ?index param for matched index routes if we don't already have one
3470
3440
  if ((to == null || to === "" || to === ".") && activeRouteMatch && activeRouteMatch.route.index && !hasNakedIndexQuery(path.search)) {
3471
3441
  path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index";
3472
- } // If we're operating within a basename, prepend it to the pathname. If
3442
+ }
3443
+
3444
+ // If we're operating within a basename, prepend it to the pathname. If
3473
3445
  // this is a root navigation, then just use the raw basename which allows
3474
3446
  // the basename to have full control over the presence of a trailing slash
3475
3447
  // on root actions
3476
-
3477
-
3478
3448
  if (prependBasename && basename !== "/") {
3479
3449
  path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]);
3480
3450
  }
3481
-
3482
3451
  return createPath(path);
3483
- } // Normalize navigation options by converting formMethod=GET formData objects to
3484
- // URLSearchParams so they behave identically to links with query params
3485
-
3452
+ }
3486
3453
 
3454
+ // Normalize navigation options by converting formMethod=GET formData objects to
3455
+ // URLSearchParams so they behave identically to links with query params
3487
3456
  function normalizeNavigateOptions(normalizeFormMethod, isFetcher, path, opts) {
3488
3457
  // Return location verbatim on non-submission navigations
3489
3458
  if (!opts || !isSubmissionNavigation(opts)) {
@@ -3491,7 +3460,6 @@ function normalizeNavigateOptions(normalizeFormMethod, isFetcher, path, opts) {
3491
3460
  path
3492
3461
  };
3493
3462
  }
3494
-
3495
3463
  if (opts.formMethod && !isValidMethod(opts.formMethod)) {
3496
3464
  return {
3497
3465
  path,
@@ -3499,11 +3467,10 @@ function normalizeNavigateOptions(normalizeFormMethod, isFetcher, path, opts) {
3499
3467
  method: opts.formMethod
3500
3468
  })
3501
3469
  };
3502
- } // Create a Submission on non-GET navigations
3503
-
3470
+ }
3504
3471
 
3472
+ // Create a Submission on non-GET navigations
3505
3473
  let submission;
3506
-
3507
3474
  if (opts.formData) {
3508
3475
  let formMethod = opts.formMethod || "get";
3509
3476
  submission = {
@@ -3512,53 +3479,48 @@ function normalizeNavigateOptions(normalizeFormMethod, isFetcher, path, opts) {
3512
3479
  formEncType: opts && opts.formEncType || "application/x-www-form-urlencoded",
3513
3480
  formData: opts.formData
3514
3481
  };
3515
-
3516
3482
  if (isMutationMethod(submission.formMethod)) {
3517
3483
  return {
3518
3484
  path,
3519
3485
  submission
3520
3486
  };
3521
3487
  }
3522
- } // Flatten submission onto URLSearchParams for GET submissions
3523
-
3488
+ }
3524
3489
 
3490
+ // Flatten submission onto URLSearchParams for GET submissions
3525
3491
  let parsedPath = parsePath(path);
3526
- let searchParams = convertFormDataToSearchParams(opts.formData); // On GET navigation submissions we can drop the ?index param from the
3492
+ let searchParams = convertFormDataToSearchParams(opts.formData);
3493
+ // On GET navigation submissions we can drop the ?index param from the
3527
3494
  // resulting location since all loaders will run. But fetcher GET submissions
3528
3495
  // only run a single loader so we need to preserve any incoming ?index params
3529
-
3530
3496
  if (isFetcher && parsedPath.search && hasNakedIndexQuery(parsedPath.search)) {
3531
3497
  searchParams.append("index", "");
3532
3498
  }
3533
-
3534
3499
  parsedPath.search = "?" + searchParams;
3535
3500
  return {
3536
3501
  path: createPath(parsedPath),
3537
3502
  submission
3538
3503
  };
3539
- } // Filter out all routes below any caught error as they aren't going to
3540
- // render so we don't need to load them
3541
-
3504
+ }
3542
3505
 
3506
+ // Filter out all routes below any caught error as they aren't going to
3507
+ // render so we don't need to load them
3543
3508
  function getLoaderMatchesUntilBoundary(matches, boundaryId) {
3544
3509
  let boundaryMatches = matches;
3545
-
3546
3510
  if (boundaryId) {
3547
3511
  let index = matches.findIndex(m => m.route.id === boundaryId);
3548
-
3549
3512
  if (index >= 0) {
3550
3513
  boundaryMatches = matches.slice(0, index);
3551
3514
  }
3552
3515
  }
3553
-
3554
3516
  return boundaryMatches;
3555
3517
  }
3556
-
3557
3518
  function getMatchesToLoad(history, state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, basename, pendingActionData, pendingError) {
3558
3519
  let actionResult = pendingError ? Object.values(pendingError)[0] : pendingActionData ? Object.values(pendingActionData)[0] : undefined;
3559
3520
  let currentUrl = history.createURL(state.location);
3560
- let nextUrl = history.createURL(location); // Pick navigation matches that are net-new or qualify for revalidation
3521
+ let nextUrl = history.createURL(location);
3561
3522
 
3523
+ // Pick navigation matches that are net-new or qualify for revalidation
3562
3524
  let boundaryId = pendingError ? Object.keys(pendingError)[0] : undefined;
3563
3525
  let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);
3564
3526
  let navigationMatches = boundaryMatches.filter((match, index) => {
@@ -3566,20 +3528,19 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
3566
3528
  // We haven't loaded this route yet so we don't know if it's got a loader!
3567
3529
  return true;
3568
3530
  }
3569
-
3570
3531
  if (match.route.loader == null) {
3571
3532
  return false;
3572
- } // Always call the loader on new route instances and pending defer cancellations
3573
-
3533
+ }
3574
3534
 
3535
+ // Always call the loader on new route instances and pending defer cancellations
3575
3536
  if (isNewLoader(state.loaderData, state.matches[index], match) || cancelledDeferredRoutes.some(id => id === match.route.id)) {
3576
3537
  return true;
3577
- } // This is the default implementation for when we revalidate. If the route
3538
+ }
3539
+
3540
+ // This is the default implementation for when we revalidate. If the route
3578
3541
  // provides it's own implementation, then we give them full control but
3579
3542
  // provide this value so they can leverage it if needed after they check
3580
3543
  // their own specific use cases
3581
-
3582
-
3583
3544
  let currentRouteMatch = state.matches[index];
3584
3545
  let nextRouteMatch = match;
3585
3546
  return shouldRevalidateLoader(match, _extends({
@@ -3589,23 +3550,27 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
3589
3550
  nextParams: nextRouteMatch.params
3590
3551
  }, submission, {
3591
3552
  actionResult,
3592
- defaultShouldRevalidate: // Forced revalidation due to submission, useRevalidator, or X-Remix-Revalidate
3593
- isRevalidationRequired || // Clicked the same link, resubmitted a GET form
3594
- currentUrl.pathname + currentUrl.search === nextUrl.pathname + nextUrl.search || // Search params affect all loaders
3553
+ defaultShouldRevalidate:
3554
+ // Forced revalidation due to submission, useRevalidator, or X-Remix-Revalidate
3555
+ isRevalidationRequired ||
3556
+ // Clicked the same link, resubmitted a GET form
3557
+ currentUrl.pathname + currentUrl.search === nextUrl.pathname + nextUrl.search ||
3558
+ // Search params affect all loaders
3595
3559
  currentUrl.search !== nextUrl.search || isNewRouteInstance(currentRouteMatch, nextRouteMatch)
3596
3560
  }));
3597
- }); // Pick fetcher.loads that need to be revalidated
3561
+ });
3598
3562
 
3563
+ // Pick fetcher.loads that need to be revalidated
3599
3564
  let revalidatingFetchers = [];
3600
3565
  fetchLoadMatches.forEach((f, key) => {
3601
3566
  // Don't revalidate if fetcher won't be present in the subsequent render
3602
3567
  if (!matches.some(m => m.route.id === f.routeId)) {
3603
3568
  return;
3604
3569
  }
3570
+ let fetcherMatches = matchRoutes(routesToUse, f.path, basename);
3605
3571
 
3606
- let fetcherMatches = matchRoutes(routesToUse, f.path, basename); // If the fetcher path no longer matches, push it in with null matches so
3572
+ // If the fetcher path no longer matches, push it in with null matches so
3607
3573
  // we can trigger a 404 in callLoadersAndMaybeResolveData
3608
-
3609
3574
  if (!fetcherMatches) {
3610
3575
  revalidatingFetchers.push({
3611
3576
  key,
@@ -3617,9 +3582,7 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
3617
3582
  });
3618
3583
  return;
3619
3584
  }
3620
-
3621
3585
  let fetcherMatch = getTargetMatch(fetcherMatches, f.path);
3622
-
3623
3586
  if (cancelledFetcherLoads.includes(key)) {
3624
3587
  revalidatingFetchers.push({
3625
3588
  key,
@@ -3630,12 +3593,12 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
3630
3593
  controller: new AbortController()
3631
3594
  });
3632
3595
  return;
3633
- } // Revalidating fetchers are decoupled from the route matches since they
3596
+ }
3597
+
3598
+ // Revalidating fetchers are decoupled from the route matches since they
3634
3599
  // hit a static href, so they _always_ check shouldRevalidate and the
3635
3600
  // default is strictly if a revalidation is explicitly required (action
3636
3601
  // submissions, useRevalidator, X-Remix-Revalidate).
3637
-
3638
-
3639
3602
  let shouldRevalidate = shouldRevalidateLoader(fetcherMatch, _extends({
3640
3603
  currentUrl,
3641
3604
  currentParams: state.matches[state.matches.length - 1].params,
@@ -3646,7 +3609,6 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
3646
3609
  // Forced revalidation due to submission, useRevalidator, or X-Remix-Revalidate
3647
3610
  defaultShouldRevalidate: isRevalidationRequired
3648
3611
  }));
3649
-
3650
3612
  if (shouldRevalidate) {
3651
3613
  revalidatingFetchers.push({
3652
3614
  key,
@@ -3660,60 +3622,61 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
3660
3622
  });
3661
3623
  return [navigationMatches, revalidatingFetchers];
3662
3624
  }
3663
-
3664
3625
  function isNewLoader(currentLoaderData, currentMatch, match) {
3665
- let isNew = // [a] -> [a, b]
3666
- !currentMatch || // [a, b] -> [a, c]
3667
- match.route.id !== currentMatch.route.id; // Handle the case that we don't have data for a re-used route, potentially
3668
- // from a prior error or from a cancelled pending deferred
3626
+ let isNew =
3627
+ // [a] -> [a, b]
3628
+ !currentMatch ||
3629
+ // [a, b] -> [a, c]
3630
+ match.route.id !== currentMatch.route.id;
3669
3631
 
3670
- let isMissingData = currentLoaderData[match.route.id] === undefined; // Always load if this is a net-new route or we don't yet have data
3632
+ // Handle the case that we don't have data for a re-used route, potentially
3633
+ // from a prior error or from a cancelled pending deferred
3634
+ let isMissingData = currentLoaderData[match.route.id] === undefined;
3671
3635
 
3636
+ // Always load if this is a net-new route or we don't yet have data
3672
3637
  return isNew || isMissingData;
3673
3638
  }
3674
-
3675
3639
  function isNewRouteInstance(currentMatch, match) {
3676
3640
  let currentPath = currentMatch.route.path;
3677
- return (// param change for this match, /users/123 -> /users/456
3678
- currentMatch.pathname !== match.pathname || // splat param changed, which is not present in match.path
3641
+ return (
3642
+ // param change for this match, /users/123 -> /users/456
3643
+ currentMatch.pathname !== match.pathname ||
3644
+ // splat param changed, which is not present in match.path
3679
3645
  // e.g. /files/images/avatar.jpg -> files/finances.xls
3680
3646
  currentPath != null && currentPath.endsWith("*") && currentMatch.params["*"] !== match.params["*"]
3681
3647
  );
3682
3648
  }
3683
-
3684
3649
  function shouldRevalidateLoader(loaderMatch, arg) {
3685
3650
  if (loaderMatch.route.shouldRevalidate) {
3686
3651
  let routeChoice = loaderMatch.route.shouldRevalidate(arg);
3687
-
3688
3652
  if (typeof routeChoice === "boolean") {
3689
3653
  return routeChoice;
3690
3654
  }
3691
3655
  }
3692
-
3693
3656
  return arg.defaultShouldRevalidate;
3694
3657
  }
3658
+
3695
3659
  /**
3696
3660
  * Execute route.lazy() methods to lazily load route modules (loader, action,
3697
3661
  * shouldRevalidate) and update the routeManifest in place which shares objects
3698
3662
  * with dataRoutes so those get updated as well.
3699
3663
  */
3700
-
3701
-
3702
3664
  async function loadLazyRouteModule(route, mapRouteProperties, manifest) {
3703
3665
  if (!route.lazy) {
3704
3666
  return;
3705
3667
  }
3668
+ let lazyRoute = await route.lazy();
3706
3669
 
3707
- let lazyRoute = await route.lazy(); // If the lazy route function was executed and removed by another parallel
3670
+ // If the lazy route function was executed and removed by another parallel
3708
3671
  // call then we can return - first lazy() to finish wins because the return
3709
3672
  // value of lazy is expected to be static
3710
-
3711
3673
  if (!route.lazy) {
3712
3674
  return;
3713
3675
  }
3714
-
3715
3676
  let routeToUpdate = manifest[route.id];
3716
- invariant(routeToUpdate, "No route found in manifest"); // Update the route in place. This should be safe because there's no way
3677
+ invariant(routeToUpdate, "No route found in manifest");
3678
+
3679
+ // Update the route in place. This should be safe because there's no way
3717
3680
  // we could yet be sitting on this route as we can't get there without
3718
3681
  // resolving lazy() first.
3719
3682
  //
@@ -3721,52 +3684,45 @@ async function loadLazyRouteModule(route, mapRouteProperties, manifest) {
3721
3684
  // on the route being updated. The main concern boils down to "does this
3722
3685
  // mutation affect any ongoing navigations or any current state.matches
3723
3686
  // values?". If not, it should be safe to update in place.
3724
-
3725
3687
  let routeUpdates = {};
3726
-
3727
3688
  for (let lazyRouteProperty in lazyRoute) {
3728
3689
  let staticRouteValue = routeToUpdate[lazyRouteProperty];
3729
- let isPropertyStaticallyDefined = staticRouteValue !== undefined && // This property isn't static since it should always be updated based
3690
+ let isPropertyStaticallyDefined = staticRouteValue !== undefined &&
3691
+ // This property isn't static since it should always be updated based
3730
3692
  // on the route updates
3731
3693
  lazyRouteProperty !== "hasErrorBoundary";
3732
3694
  warning(!isPropertyStaticallyDefined, "Route \"" + routeToUpdate.id + "\" has a static property \"" + lazyRouteProperty + "\" " + "defined but its lazy function is also returning a value for this property. " + ("The lazy route property \"" + lazyRouteProperty + "\" will be ignored."));
3733
-
3734
3695
  if (!isPropertyStaticallyDefined && !immutableRouteKeys.has(lazyRouteProperty)) {
3735
3696
  routeUpdates[lazyRouteProperty] = lazyRoute[lazyRouteProperty];
3736
3697
  }
3737
- } // Mutate the route with the provided updates. Do this first so we pass
3738
- // the updated version to mapRouteProperties
3698
+ }
3739
3699
 
3700
+ // Mutate the route with the provided updates. Do this first so we pass
3701
+ // the updated version to mapRouteProperties
3702
+ Object.assign(routeToUpdate, routeUpdates);
3740
3703
 
3741
- Object.assign(routeToUpdate, routeUpdates); // Mutate the `hasErrorBoundary` property on the route based on the route
3704
+ // Mutate the `hasErrorBoundary` property on the route based on the route
3742
3705
  // updates and remove the `lazy` function so we don't resolve the lazy
3743
3706
  // route again.
3744
-
3745
3707
  Object.assign(routeToUpdate, _extends({}, mapRouteProperties(routeToUpdate), {
3746
3708
  lazy: undefined
3747
3709
  }));
3748
3710
  }
3749
-
3750
3711
  async function callLoaderOrAction(type, request, match, matches, manifest, mapRouteProperties, basename, isStaticRequest, isRouteRequest, requestContext) {
3751
3712
  if (isStaticRequest === void 0) {
3752
3713
  isStaticRequest = false;
3753
3714
  }
3754
-
3755
3715
  if (isRouteRequest === void 0) {
3756
3716
  isRouteRequest = false;
3757
3717
  }
3758
-
3759
3718
  let resultType;
3760
3719
  let result;
3761
3720
  let onReject;
3762
-
3763
3721
  let runHandler = handler => {
3764
3722
  // Setup a promise we can race against so that abort signals short circuit
3765
3723
  let reject;
3766
3724
  let abortPromise = new Promise((_, r) => reject = r);
3767
-
3768
3725
  onReject = () => reject();
3769
-
3770
3726
  request.signal.addEventListener("abort", onReject);
3771
3727
  return Promise.race([handler({
3772
3728
  request,
@@ -3774,10 +3730,8 @@ async function callLoaderOrAction(type, request, match, matches, manifest, mapRo
3774
3730
  context: requestContext
3775
3731
  }), abortPromise]);
3776
3732
  };
3777
-
3778
3733
  try {
3779
3734
  let handler = match.route[type];
3780
-
3781
3735
  if (match.route.lazy) {
3782
3736
  if (handler) {
3783
3737
  // Run statically defined handler in parallel with lazy()
@@ -3787,7 +3741,6 @@ async function callLoaderOrAction(type, request, match, matches, manifest, mapRo
3787
3741
  // Load lazy route module, then run any returned handler
3788
3742
  await loadLazyRouteModule(match.route, mapRouteProperties, manifest);
3789
3743
  handler = match.route[type];
3790
-
3791
3744
  if (handler) {
3792
3745
  // Handler still run even if we got interrupted to maintain consistency
3793
3746
  // with un-abortable behavior of handler execution on non-lazy or
@@ -3819,7 +3772,6 @@ async function callLoaderOrAction(type, request, match, matches, manifest, mapRo
3819
3772
  } else {
3820
3773
  result = await runHandler(handler);
3821
3774
  }
3822
-
3823
3775
  invariant(result !== undefined, "You defined " + (type === "action" ? "an action" : "a loader") + " for route " + ("\"" + match.route.id + "\" but didn't return anything from your `" + type + "` ") + "function. Please return a value or `null`.");
3824
3776
  } catch (e) {
3825
3777
  resultType = ResultType.error;
@@ -3829,14 +3781,15 @@ async function callLoaderOrAction(type, request, match, matches, manifest, mapRo
3829
3781
  request.signal.removeEventListener("abort", onReject);
3830
3782
  }
3831
3783
  }
3832
-
3833
3784
  if (isResponse(result)) {
3834
- let status = result.status; // Process redirects
3785
+ let status = result.status;
3835
3786
 
3787
+ // Process redirects
3836
3788
  if (redirectStatusCodes.has(status)) {
3837
3789
  let location = result.headers.get("Location");
3838
- invariant(location, "Redirects returned/thrown from loaders/actions must have a Location header"); // Support relative routing in internal redirects
3790
+ invariant(location, "Redirects returned/thrown from loaders/actions must have a Location header");
3839
3791
 
3792
+ // Support relative routing in internal redirects
3840
3793
  if (!ABSOLUTE_URL_REGEX.test(location)) {
3841
3794
  location = normalizeTo(new URL(request.url), matches.slice(0, matches.indexOf(match) + 1), basename, true, location);
3842
3795
  } else if (!isStaticRequest) {
@@ -3846,32 +3799,30 @@ async function callLoaderOrAction(type, request, match, matches, manifest, mapRo
3846
3799
  let currentUrl = new URL(request.url);
3847
3800
  let url = location.startsWith("//") ? new URL(currentUrl.protocol + location) : new URL(location);
3848
3801
  let isSameBasename = stripBasename(url.pathname, basename) != null;
3849
-
3850
3802
  if (url.origin === currentUrl.origin && isSameBasename) {
3851
3803
  location = url.pathname + url.search + url.hash;
3852
3804
  }
3853
- } // Don't process redirects in the router during static requests requests.
3805
+ }
3806
+
3807
+ // Don't process redirects in the router during static requests requests.
3854
3808
  // Instead, throw the Response and let the server handle it with an HTTP
3855
3809
  // redirect. We also update the Location header in place in this flow so
3856
3810
  // basename and relative routing is taken into account
3857
-
3858
-
3859
3811
  if (isStaticRequest) {
3860
3812
  result.headers.set("Location", location);
3861
3813
  throw result;
3862
3814
  }
3863
-
3864
3815
  return {
3865
3816
  type: ResultType.redirect,
3866
3817
  status,
3867
3818
  location,
3868
3819
  revalidate: result.headers.get("X-Remix-Revalidate") !== null
3869
3820
  };
3870
- } // For SSR single-route requests, we want to hand Responses back directly
3821
+ }
3822
+
3823
+ // For SSR single-route requests, we want to hand Responses back directly
3871
3824
  // without unwrapping. We do this with the QueryRouteResponse wrapper
3872
3825
  // interface so we can know whether it was returned or thrown
3873
-
3874
-
3875
3826
  if (isRouteRequest) {
3876
3827
  // eslint-disable-next-line no-throw-literal
3877
3828
  throw {
@@ -3879,17 +3830,15 @@ async function callLoaderOrAction(type, request, match, matches, manifest, mapRo
3879
3830
  response: result
3880
3831
  };
3881
3832
  }
3882
-
3883
3833
  let data;
3884
- let contentType = result.headers.get("Content-Type"); // Check between word boundaries instead of startsWith() due to the last
3834
+ let contentType = result.headers.get("Content-Type");
3835
+ // Check between word boundaries instead of startsWith() due to the last
3885
3836
  // paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type
3886
-
3887
3837
  if (contentType && /\bapplication\/json\b/.test(contentType)) {
3888
3838
  data = await result.json();
3889
3839
  } else {
3890
3840
  data = await result.text();
3891
3841
  }
3892
-
3893
3842
  if (resultType === ResultType.error) {
3894
3843
  return {
3895
3844
  type: resultType,
@@ -3897,7 +3846,6 @@ async function callLoaderOrAction(type, request, match, matches, manifest, mapRo
3897
3846
  headers: result.headers
3898
3847
  };
3899
3848
  }
3900
-
3901
3849
  return {
3902
3850
  type: ResultType.data,
3903
3851
  data,
@@ -3905,17 +3853,14 @@ async function callLoaderOrAction(type, request, match, matches, manifest, mapRo
3905
3853
  headers: result.headers
3906
3854
  };
3907
3855
  }
3908
-
3909
3856
  if (resultType === ResultType.error) {
3910
3857
  return {
3911
3858
  type: resultType,
3912
3859
  error: result
3913
3860
  };
3914
3861
  }
3915
-
3916
3862
  if (isDeferredData(result)) {
3917
3863
  var _result$init, _result$init2;
3918
-
3919
3864
  return {
3920
3865
  type: ResultType.deferred,
3921
3866
  deferredData: result,
@@ -3923,90 +3868,84 @@ async function callLoaderOrAction(type, request, match, matches, manifest, mapRo
3923
3868
  headers: ((_result$init2 = result.init) == null ? void 0 : _result$init2.headers) && new Headers(result.init.headers)
3924
3869
  };
3925
3870
  }
3926
-
3927
3871
  return {
3928
3872
  type: ResultType.data,
3929
3873
  data: result
3930
3874
  };
3931
- } // Utility method for creating the Request instances for loaders/actions during
3875
+ }
3876
+
3877
+ // Utility method for creating the Request instances for loaders/actions during
3932
3878
  // client-side navigations and fetches. During SSR we will always have a
3933
3879
  // Request instance from the static handler (query/queryRoute)
3934
-
3935
-
3936
3880
  function createClientSideRequest(history, location, signal, submission) {
3937
3881
  let url = history.createURL(stripHashFromPath(location)).toString();
3938
3882
  let init = {
3939
3883
  signal
3940
3884
  };
3941
-
3942
3885
  if (submission && isMutationMethod(submission.formMethod)) {
3943
3886
  let {
3944
3887
  formMethod,
3945
3888
  formEncType,
3946
3889
  formData
3947
- } = submission; // Didn't think we needed this but it turns out unlike other methods, patch
3890
+ } = submission;
3891
+ // Didn't think we needed this but it turns out unlike other methods, patch
3948
3892
  // won't be properly normalized to uppercase and results in a 405 error.
3949
3893
  // See: https://fetch.spec.whatwg.org/#concept-method
3950
-
3951
3894
  init.method = formMethod.toUpperCase();
3952
3895
  init.body = formEncType === "application/x-www-form-urlencoded" ? convertFormDataToSearchParams(formData) : formData;
3953
- } // Content-Type is inferred (https://fetch.spec.whatwg.org/#dom-request)
3954
-
3896
+ }
3955
3897
 
3898
+ // Content-Type is inferred (https://fetch.spec.whatwg.org/#dom-request)
3956
3899
  return new Request(url, init);
3957
3900
  }
3958
-
3959
3901
  function convertFormDataToSearchParams(formData) {
3960
3902
  let searchParams = new URLSearchParams();
3961
-
3962
3903
  for (let [key, value] of formData.entries()) {
3963
3904
  // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#converting-an-entry-list-to-a-list-of-name-value-pairs
3964
3905
  searchParams.append(key, value instanceof File ? value.name : value);
3965
3906
  }
3966
-
3967
3907
  return searchParams;
3968
3908
  }
3969
-
3970
3909
  function processRouteLoaderData(matches, matchesToLoad, results, pendingError, activeDeferreds) {
3971
3910
  // Fill in loaderData/errors from our loaders
3972
3911
  let loaderData = {};
3973
3912
  let errors = null;
3974
3913
  let statusCode;
3975
3914
  let foundError = false;
3976
- let loaderHeaders = {}; // Process loader results into state.loaderData/state.errors
3915
+ let loaderHeaders = {};
3977
3916
 
3917
+ // Process loader results into state.loaderData/state.errors
3978
3918
  results.forEach((result, index) => {
3979
3919
  let id = matchesToLoad[index].route.id;
3980
3920
  invariant(!isRedirectResult(result), "Cannot handle redirect results in processLoaderData");
3981
-
3982
3921
  if (isErrorResult(result)) {
3983
3922
  // Look upwards from the matched route for the closest ancestor
3984
3923
  // error boundary, defaulting to the root match
3985
3924
  let boundaryMatch = findNearestBoundary(matches, id);
3986
- let error = result.error; // If we have a pending action error, we report it at the highest-route
3925
+ let error = result.error;
3926
+ // If we have a pending action error, we report it at the highest-route
3987
3927
  // that throws a loader error, and then clear it out to indicate that
3988
3928
  // it was consumed
3989
-
3990
3929
  if (pendingError) {
3991
3930
  error = Object.values(pendingError)[0];
3992
3931
  pendingError = undefined;
3993
3932
  }
3933
+ errors = errors || {};
3994
3934
 
3995
- errors = errors || {}; // Prefer higher error values if lower errors bubble to the same boundary
3996
-
3935
+ // Prefer higher error values if lower errors bubble to the same boundary
3997
3936
  if (errors[boundaryMatch.route.id] == null) {
3998
3937
  errors[boundaryMatch.route.id] = error;
3999
- } // Clear our any prior loaderData for the throwing route
3938
+ }
4000
3939
 
3940
+ // Clear our any prior loaderData for the throwing route
3941
+ loaderData[id] = undefined;
4001
3942
 
4002
- loaderData[id] = undefined; // Once we find our first (highest) error, we set the status code and
3943
+ // Once we find our first (highest) error, we set the status code and
4003
3944
  // prevent deeper status codes from overriding
4004
-
4005
3945
  if (!foundError) {
4006
3946
  foundError = true;
4007
3947
  statusCode = isRouteErrorResponse(result.error) ? result.error.status : 500;
4008
3948
  }
4009
-
4010
3949
  if (result.headers) {
4011
3950
  loaderHeaders[id] = result.headers;
4012
3951
  }
@@ -4016,27 +3955,26 @@ function processRouteLoaderData(matches, matchesToLoad, results, pendingError, a
4016
3955
  loaderData[id] = result.deferredData.data;
4017
3956
  } else {
4018
3957
  loaderData[id] = result.data;
4019
- } // Error status codes always override success status codes, but if all
4020
- // loaders are successful we take the deepest status code.
4021
-
3958
+ }
4022
3959
 
3960
+ // Error status codes always override success status codes, but if all
3961
+ // loaders are successful we take the deepest status code.
4023
3962
  if (result.statusCode != null && result.statusCode !== 200 && !foundError) {
4024
3963
  statusCode = result.statusCode;
4025
3964
  }
4026
-
4027
3965
  if (result.headers) {
4028
3966
  loaderHeaders[id] = result.headers;
4029
3967
  }
4030
3968
  }
4031
- }); // If we didn't consume the pending action error (i.e., all loaders
3969
+ });
3970
+
3971
+ // If we didn't consume the pending action error (i.e., all loaders
4032
3972
  // resolved), then consume it here. Also clear out any loaderData for the
4033
3973
  // throwing route
4034
-
4035
3974
  if (pendingError) {
4036
3975
  errors = pendingError;
4037
3976
  loaderData[Object.keys(pendingError)[0]] = undefined;
4038
3977
  }
4039
-
4040
3978
  return {
4041
3979
  loaderData,
4042
3980
  errors,
@@ -4044,13 +3982,13 @@ function processRouteLoaderData(matches, matchesToLoad, results, pendingError, a
4044
3982
  loaderHeaders
4045
3983
  };
4046
3984
  }
4047
-
4048
3985
  function processLoaderData(state, matches, matchesToLoad, results, pendingError, revalidatingFetchers, fetcherResults, activeDeferreds) {
4049
3986
  let {
4050
3987
  loaderData,
4051
3988
  errors
4052
- } = processRouteLoaderData(matches, matchesToLoad, results, pendingError, activeDeferreds); // Process results from our revalidating fetchers
3989
+ } = processRouteLoaderData(matches, matchesToLoad, results, pendingError, activeDeferreds);
4053
3990
 
3991
+ // Process results from our revalidating fetchers
4054
3992
  for (let index = 0; index < revalidatingFetchers.length; index++) {
4055
3993
  let {
4056
3994
  key,
@@ -4058,20 +3996,19 @@ function processLoaderData(state, matches, matchesToLoad, results, pendingError,
4058
3996
  controller
4059
3997
  } = revalidatingFetchers[index];
4060
3998
  invariant(fetcherResults !== undefined && fetcherResults[index] !== undefined, "Did not find corresponding fetcher result");
4061
- let result = fetcherResults[index]; // Process fetcher non-redirect errors
3999
+ let result = fetcherResults[index];
4062
4000
 
4001
+ // Process fetcher non-redirect errors
4063
4002
  if (controller && controller.signal.aborted) {
4064
4003
  // Nothing to do for aborted fetchers
4065
4004
  continue;
4066
4005
  } else if (isErrorResult(result)) {
4067
4006
  let boundaryMatch = findNearestBoundary(state.matches, match == null ? void 0 : match.route.id);
4068
-
4069
4007
  if (!(errors && errors[boundaryMatch.route.id])) {
4070
4008
  errors = _extends({}, errors, {
4071
4009
  [boundaryMatch.route.id]: result.error
4072
4010
  });
4073
4011
  }
4074
-
4075
4012
  state.fetchers.delete(key);
4076
4013
  } else if (isRedirectResult(result)) {
4077
4014
  // Should never get here, redirects should get processed above, but we
@@ -4094,19 +4031,15 @@ function processLoaderData(state, matches, matchesToLoad, results, pendingError,
4094
4031
  state.fetchers.set(key, doneFetcher);
4095
4032
  }
4096
4033
  }
4097
-
4098
4034
  return {
4099
4035
  loaderData,
4100
4036
  errors
4101
4037
  };
4102
4038
  }
4103
-
4104
4039
  function mergeLoaderData(loaderData, newLoaderData, matches, errors) {
4105
4040
  let mergedLoaderData = _extends({}, newLoaderData);
4106
-
4107
4041
  for (let match of matches) {
4108
4042
  let id = match.route.id;
4109
-
4110
4043
  if (newLoaderData.hasOwnProperty(id)) {
4111
4044
  if (newLoaderData[id] !== undefined) {
4112
4045
  mergedLoaderData[id] = newLoaderData[id];
@@ -4116,24 +4049,21 @@ function mergeLoaderData(loaderData, newLoaderData, matches, errors) {
4116
4049
  // wasn't removed by HMR
4117
4050
  mergedLoaderData[id] = loaderData[id];
4118
4051
  }
4119
-
4120
4052
  if (errors && errors.hasOwnProperty(id)) {
4121
4053
  // Don't keep any loader data below the boundary
4122
4054
  break;
4123
4055
  }
4124
4056
  }
4125
-
4126
4057
  return mergedLoaderData;
4127
- } // Find the nearest error boundary, looking upwards from the leaf route (or the
4058
+ }
4059
+
4060
+ // Find the nearest error boundary, looking upwards from the leaf route (or the
4128
4061
  // route specified by routeId) for the closest ancestor error boundary,
4129
4062
  // defaulting to the root match
4130
-
4131
-
4132
4063
  function findNearestBoundary(matches, routeId) {
4133
4064
  let eligibleMatches = routeId ? matches.slice(0, matches.findIndex(m => m.route.id === routeId) + 1) : [...matches];
4134
4065
  return eligibleMatches.reverse().find(m => m.route.hasErrorBoundary === true) || matches[0];
4135
4066
  }
4136
-
4137
4067
  function getShortCircuitMatches(routes) {
4138
4068
  // Prefer a root layout route if present, otherwise shim in a route object
4139
4069
  let route = routes.find(r => r.index || !r.path || r.path === "/") || {
@@ -4149,7 +4079,6 @@ function getShortCircuitMatches(routes) {
4149
4079
  route
4150
4080
  };
4151
4081
  }
4152
-
4153
4082
  function getInternalRouterError(status, _temp4) {
4154
4083
  let {
4155
4084
  pathname,
@@ -4159,10 +4088,8 @@ function getInternalRouterError(status, _temp4) {
4159
4088
  } = _temp4 === void 0 ? {} : _temp4;
4160
4089
  let statusText = "Unknown Server Error";
4161
4090
  let errorMessage = "Unknown @remix-run/router error";
4162
-
4163
4091
  if (status === 400) {
4164
4092
  statusText = "Bad Request";
4165
-
4166
4093
  if (method && pathname && routeId) {
4167
4094
  errorMessage = "You made a " + method + " request to \"" + pathname + "\" but " + ("did not provide a `loader` for route \"" + routeId + "\", ") + "so there is no way to handle the request.";
4168
4095
  } else if (type === "defer-action") {
@@ -4176,40 +4103,34 @@ function getInternalRouterError(status, _temp4) {
4176
4103
  errorMessage = "No route matches URL \"" + pathname + "\"";
4177
4104
  } else if (status === 405) {
4178
4105
  statusText = "Method Not Allowed";
4179
-
4180
4106
  if (method && pathname && routeId) {
4181
4107
  errorMessage = "You made a " + method.toUpperCase() + " request to \"" + pathname + "\" but " + ("did not provide an `action` for route \"" + routeId + "\", ") + "so there is no way to handle the request.";
4182
4108
  } else if (method) {
4183
4109
  errorMessage = "Invalid request method \"" + method.toUpperCase() + "\"";
4184
4110
  }
4185
4111
  }
4186
-
4187
4112
  return new ErrorResponse(status || 500, statusText, new Error(errorMessage), true);
4188
- } // Find any returned redirect errors, starting from the lowest match
4189
-
4113
+ }
4190
4114
 
4115
+ // Find any returned redirect errors, starting from the lowest match
4191
4116
  function findRedirect(results) {
4192
4117
  for (let i = results.length - 1; i >= 0; i--) {
4193
4118
  let result = results[i];
4194
-
4195
4119
  if (isRedirectResult(result)) {
4196
4120
  return result;
4197
4121
  }
4198
4122
  }
4199
4123
  }
4200
-
4201
4124
  function stripHashFromPath(path) {
4202
4125
  let parsedPath = typeof path === "string" ? parsePath(path) : path;
4203
4126
  return createPath(_extends({}, parsedPath, {
4204
4127
  hash: ""
4205
4128
  }));
4206
4129
  }
4207
-
4208
4130
  function isHashChangeOnly(a, b) {
4209
4131
  if (a.pathname !== b.pathname || a.search !== b.search) {
4210
4132
  return false;
4211
4133
  }
4212
-
4213
4134
  if (a.hash === "") {
4214
4135
  // /page -> /page#hash
4215
4136
  return b.hash !== "";
@@ -4219,70 +4140,57 @@ function isHashChangeOnly(a, b) {
4219
4140
  } else if (b.hash !== "") {
4220
4141
  // /page#hash -> /page#other
4221
4142
  return true;
4222
- } // If the hash is removed the browser will re-perform a request to the server
4223
- // /page#hash -> /page
4224
-
4143
+ }
4225
4144
 
4145
+ // If the hash is removed the browser will re-perform a request to the server
4146
+ // /page#hash -> /page
4226
4147
  return false;
4227
4148
  }
4228
-
4229
4149
  function isDeferredResult(result) {
4230
4150
  return result.type === ResultType.deferred;
4231
4151
  }
4232
-
4233
4152
  function isErrorResult(result) {
4234
4153
  return result.type === ResultType.error;
4235
4154
  }
4236
-
4237
4155
  function isRedirectResult(result) {
4238
4156
  return (result && result.type) === ResultType.redirect;
4239
4157
  }
4240
-
4241
4158
  function isDeferredData(value) {
4242
4159
  let deferred = value;
4243
4160
  return deferred && typeof deferred === "object" && typeof deferred.data === "object" && typeof deferred.subscribe === "function" && typeof deferred.cancel === "function" && typeof deferred.resolveData === "function";
4244
4161
  }
4245
-
4246
4162
  function isResponse(value) {
4247
4163
  return value != null && typeof value.status === "number" && typeof value.statusText === "string" && typeof value.headers === "object" && typeof value.body !== "undefined";
4248
4164
  }
4249
-
4250
4165
  function isRedirectResponse(result) {
4251
4166
  if (!isResponse(result)) {
4252
4167
  return false;
4253
4168
  }
4254
-
4255
4169
  let status = result.status;
4256
4170
  let location = result.headers.get("Location");
4257
4171
  return status >= 300 && status <= 399 && location != null;
4258
4172
  }
4259
-
4260
4173
  function isQueryRouteResponse(obj) {
4261
4174
  return obj && isResponse(obj.response) && (obj.type === ResultType.data || ResultType.error);
4262
4175
  }
4263
-
4264
4176
  function isValidMethod(method) {
4265
4177
  return validRequestMethods.has(method.toLowerCase());
4266
4178
  }
4267
-
4268
4179
  function isMutationMethod(method) {
4269
4180
  return validMutationMethods.has(method.toLowerCase());
4270
4181
  }
4271
-
4272
4182
  async function resolveDeferredResults(currentMatches, matchesToLoad, results, signals, isFetcher, currentLoaderData) {
4273
4183
  for (let index = 0; index < results.length; index++) {
4274
4184
  let result = results[index];
4275
- let match = matchesToLoad[index]; // If we don't have a match, then we can have a deferred result to do
4185
+ let match = matchesToLoad[index];
4186
+ // If we don't have a match, then we can have a deferred result to do
4276
4187
  // anything with. This is for revalidating fetchers where the route was
4277
4188
  // removed during HMR
4278
-
4279
4189
  if (!match) {
4280
4190
  continue;
4281
4191
  }
4282
-
4283
4192
  let currentMatch = currentMatches.find(m => m.route.id === match.route.id);
4284
4193
  let isRevalidatingLoader = currentMatch != null && !isNewRouteInstance(currentMatch, match) && (currentLoaderData && currentLoaderData[match.route.id]) !== undefined;
4285
-
4286
4194
  if (isDeferredResult(result) && (isFetcher || isRevalidatingLoader)) {
4287
4195
  // Note: we do not have to touch activeDeferreds here since we race them
4288
4196
  // against the signal in resolveDeferredData and they'll get aborted
@@ -4297,18 +4205,14 @@ async function resolveDeferredResults(currentMatches, matchesToLoad, results, si
4297
4205
  }
4298
4206
  }
4299
4207
  }
4300
-
4301
4208
  async function resolveDeferredData(result, signal, unwrap) {
4302
4209
  if (unwrap === void 0) {
4303
4210
  unwrap = false;
4304
4211
  }
4305
-
4306
4212
  let aborted = await result.deferredData.resolveData(signal);
4307
-
4308
4213
  if (aborted) {
4309
4214
  return;
4310
4215
  }
4311
-
4312
4216
  if (unwrap) {
4313
4217
  try {
4314
4218
  return {
@@ -4323,19 +4227,17 @@ async function resolveDeferredData(result, signal, unwrap) {
4323
4227
  };
4324
4228
  }
4325
4229
  }
4326
-
4327
4230
  return {
4328
4231
  type: ResultType.data,
4329
4232
  data: result.deferredData.data
4330
4233
  };
4331
4234
  }
4332
-
4333
4235
  function hasNakedIndexQuery(search) {
4334
4236
  return new URLSearchParams(search).getAll("index").some(v => v === "");
4335
- } // Note: This should match the format exported by useMatches, so if you change
4336
- // this please also change that :) Eventually we'll DRY this up
4337
-
4237
+ }
4338
4238
 
4239
+ // Note: This should match the format exported by useMatches, so if you change
4240
+ // this please also change that :) Eventually we'll DRY this up
4339
4241
  function createUseMatchesMatch(match, loaderData) {
4340
4242
  let {
4341
4243
  route,
@@ -4350,20 +4252,18 @@ function createUseMatchesMatch(match, loaderData) {
4350
4252
  handle: route.handle
4351
4253
  };
4352
4254
  }
4353
-
4354
4255
  function getTargetMatch(matches, location) {
4355
4256
  let search = typeof location === "string" ? parsePath(location).search : location.search;
4356
-
4357
4257
  if (matches[matches.length - 1].route.index && hasNakedIndexQuery(search || "")) {
4358
4258
  // Return the leaf index route when index is present
4359
4259
  return matches[matches.length - 1];
4360
- } // Otherwise grab the deepest "path contributing" match (ignoring index and
4260
+ }
4261
+ // Otherwise grab the deepest "path contributing" match (ignoring index and
4361
4262
  // pathless layout routes)
4362
-
4363
-
4364
4263
  let pathMatches = getPathContributingMatches(matches);
4365
4264
  return pathMatches[pathMatches.length - 1];
4366
- } //#endregion
4265
+ }
4266
+ //#endregion
4367
4267
 
4368
4268
  exports.AbortedDeferredError = AbortedDeferredError;
4369
4269
  exports.ErrorResponse = ErrorResponse;