@tanstack/router-core 0.0.1-beta.35 → 0.0.1-beta.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/index.js +2 -1
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/path.js +5 -7
- package/build/cjs/path.js.map +1 -1
- package/build/cjs/route.js +112 -96
- package/build/cjs/route.js.map +1 -1
- package/build/cjs/routeConfig.js +2 -2
- package/build/cjs/routeConfig.js.map +1 -1
- package/build/cjs/routeMatch.js +107 -65
- package/build/cjs/routeMatch.js.map +1 -1
- package/build/cjs/router.js +352 -372
- package/build/cjs/router.js.map +1 -1
- package/build/cjs/searchParams.js +4 -3
- package/build/cjs/searchParams.js.map +1 -1
- package/build/cjs/sharedClone.js +122 -0
- package/build/cjs/sharedClone.js.map +1 -0
- package/build/cjs/utils.js +1 -59
- package/build/cjs/utils.js.map +1 -1
- package/build/esm/index.js +686 -614
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +183 -158
- package/build/types/index.d.ts +61 -78
- package/build/umd/index.development.js +1032 -617
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +1 -1
- package/build/umd/index.production.js.map +1 -1
- package/package.json +2 -1
- package/src/index.ts +1 -0
- package/src/link.ts +20 -12
- package/src/route.ts +160 -140
- package/src/routeConfig.ts +7 -2
- package/src/routeMatch.ts +146 -99
- package/src/router.ts +462 -523
- package/src/sharedClone.ts +118 -0
- package/src/utils.ts +0 -65
- package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +0 -31
- package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +0 -1
package/build/esm/index.js
CHANGED
|
@@ -12,64 +12,8 @@ import { createMemoryHistory, createBrowserHistory } from 'history';
|
|
|
12
12
|
export { createBrowserHistory, createHashHistory, createMemoryHistory } from 'history';
|
|
13
13
|
import invariant from 'tiny-invariant';
|
|
14
14
|
export { default as invariant } from 'tiny-invariant';
|
|
15
|
+
import { createStore, batch } from '@solidjs/reactivity';
|
|
15
16
|
|
|
16
|
-
/**
|
|
17
|
-
* This function returns `a` if `b` is deeply equal.
|
|
18
|
-
* If not, it will replace any deeply equal children of `b` with those of `a`.
|
|
19
|
-
* This can be used for structural sharing between JSON values for example.
|
|
20
|
-
*/
|
|
21
|
-
function replaceEqualDeep(prev, next) {
|
|
22
|
-
if (prev === next) {
|
|
23
|
-
return prev;
|
|
24
|
-
}
|
|
25
|
-
const array = Array.isArray(prev) && Array.isArray(next);
|
|
26
|
-
if (array || isPlainObject(prev) && isPlainObject(next)) {
|
|
27
|
-
const aSize = array ? prev.length : Object.keys(prev).length;
|
|
28
|
-
const bItems = array ? next : Object.keys(next);
|
|
29
|
-
const bSize = bItems.length;
|
|
30
|
-
const copy = array ? [] : {};
|
|
31
|
-
let equalItems = 0;
|
|
32
|
-
for (let i = 0; i < bSize; i++) {
|
|
33
|
-
const key = array ? i : bItems[i];
|
|
34
|
-
copy[key] = replaceEqualDeep(prev[key], next[key]);
|
|
35
|
-
if (copy[key] === prev[key]) {
|
|
36
|
-
equalItems++;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return aSize === bSize && equalItems === aSize ? prev : copy;
|
|
40
|
-
}
|
|
41
|
-
return next;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Copied from: https://github.com/jonschlinkert/is-plain-object
|
|
45
|
-
function isPlainObject(o) {
|
|
46
|
-
if (!hasObjectPrototype(o)) {
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// If has modified constructor
|
|
51
|
-
const ctor = o.constructor;
|
|
52
|
-
if (typeof ctor === 'undefined') {
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// If has modified prototype
|
|
57
|
-
const prot = ctor.prototype;
|
|
58
|
-
if (!hasObjectPrototype(prot)) {
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// If constructor does not have an Object-specific method
|
|
63
|
-
if (!prot.hasOwnProperty('isPrototypeOf')) {
|
|
64
|
-
return false;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Most likely a plain Object
|
|
68
|
-
return true;
|
|
69
|
-
}
|
|
70
|
-
function hasObjectPrototype(o) {
|
|
71
|
-
return Object.prototype.toString.call(o) === '[object Object]';
|
|
72
|
-
}
|
|
73
17
|
function last(arr) {
|
|
74
18
|
return arr[arr.length - 1];
|
|
75
19
|
}
|
|
@@ -78,7 +22,7 @@ function warning(cond, message) {
|
|
|
78
22
|
if (typeof console !== 'undefined') console.warn(message);
|
|
79
23
|
try {
|
|
80
24
|
throw new Error(message);
|
|
81
|
-
} catch
|
|
25
|
+
} catch {}
|
|
82
26
|
}
|
|
83
27
|
return true;
|
|
84
28
|
}
|
|
@@ -115,8 +59,8 @@ function trimPath(path) {
|
|
|
115
59
|
return trimPathRight(trimPathLeft(path));
|
|
116
60
|
}
|
|
117
61
|
function resolvePath(basepath, base, to) {
|
|
118
|
-
base = base.replace(new RegExp(
|
|
119
|
-
to = to.replace(new RegExp(
|
|
62
|
+
base = base.replace(new RegExp(`^${basepath}`), '/');
|
|
63
|
+
to = to.replace(new RegExp(`^${basepath}`), '/');
|
|
120
64
|
let baseSegments = parsePathname(base);
|
|
121
65
|
const toSegments = parsePathname(to);
|
|
122
66
|
toSegments.forEach((toSegment, index) => {
|
|
@@ -197,8 +141,7 @@ function interpolatePath(path, params, leaveWildcard) {
|
|
|
197
141
|
return '';
|
|
198
142
|
}
|
|
199
143
|
if (segment.type === 'param') {
|
|
200
|
-
|
|
201
|
-
return (_segment$value$substr = params[segment.value.substring(1)]) != null ? _segment$value$substr : '';
|
|
144
|
+
return params[segment.value.substring(1)] ?? '';
|
|
202
145
|
}
|
|
203
146
|
return segment.value;
|
|
204
147
|
}));
|
|
@@ -210,16 +153,15 @@ function matchPathname(basepath, currentPathname, matchLocation) {
|
|
|
210
153
|
if (matchLocation.to && !pathParams) {
|
|
211
154
|
return;
|
|
212
155
|
}
|
|
213
|
-
return pathParams
|
|
156
|
+
return pathParams ?? {};
|
|
214
157
|
}
|
|
215
158
|
function matchByPath(basepath, from, matchLocation) {
|
|
216
|
-
var _matchLocation$to;
|
|
217
159
|
if (!from.startsWith(basepath)) {
|
|
218
160
|
return undefined;
|
|
219
161
|
}
|
|
220
162
|
from = basepath != '/' ? from.substring(basepath.length) : from;
|
|
221
163
|
const baseSegments = parsePathname(from);
|
|
222
|
-
const to =
|
|
164
|
+
const to = `${matchLocation.to ?? '*'}`;
|
|
223
165
|
const routeSegments = parsePathname(to);
|
|
224
166
|
const params = {};
|
|
225
167
|
let isMatch = (() => {
|
|
@@ -320,135 +262,136 @@ function decode(str) {
|
|
|
320
262
|
return out;
|
|
321
263
|
}
|
|
322
264
|
|
|
323
|
-
function
|
|
324
|
-
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
325
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
326
|
-
var source = arguments[i];
|
|
327
|
-
for (var key in source) {
|
|
328
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
329
|
-
target[key] = source[key];
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
return target;
|
|
334
|
-
};
|
|
335
|
-
return _extends.apply(this, arguments);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
function createRoute(routeConfig, options, parent, router) {
|
|
265
|
+
function createRoute(routeConfig, options, originalIndex, parent, router) {
|
|
339
266
|
const {
|
|
340
267
|
id,
|
|
341
268
|
routeId,
|
|
342
269
|
path: routePath,
|
|
343
270
|
fullPath
|
|
344
271
|
} = routeConfig;
|
|
345
|
-
const action = router.state.actions[id] || (() => {
|
|
346
|
-
router.state.actions[id] = {
|
|
347
|
-
submissions: [],
|
|
348
|
-
submit: async (submission, actionOpts) => {
|
|
349
|
-
var _actionOpts$invalidat;
|
|
350
|
-
if (!route) {
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
const invalidate = (_actionOpts$invalidat = actionOpts == null ? void 0 : actionOpts.invalidate) != null ? _actionOpts$invalidat : true;
|
|
354
|
-
if (!(actionOpts != null && actionOpts.multi)) {
|
|
355
|
-
action.submissions = action.submissions.filter(d => d.isMulti);
|
|
356
|
-
}
|
|
357
|
-
const actionState = {
|
|
358
|
-
submittedAt: Date.now(),
|
|
359
|
-
status: 'pending',
|
|
360
|
-
submission,
|
|
361
|
-
isMulti: !!(actionOpts != null && actionOpts.multi)
|
|
362
|
-
};
|
|
363
|
-
action.current = actionState;
|
|
364
|
-
action.latest = actionState;
|
|
365
|
-
action.submissions.push(actionState);
|
|
366
|
-
router.notify();
|
|
367
|
-
try {
|
|
368
|
-
const res = await (route.options.action == null ? void 0 : route.options.action(submission));
|
|
369
|
-
actionState.data = res;
|
|
370
|
-
if (invalidate) {
|
|
371
|
-
router.invalidateRoute({
|
|
372
|
-
to: '.',
|
|
373
|
-
fromCurrent: true
|
|
374
|
-
});
|
|
375
|
-
await router.reload();
|
|
376
|
-
}
|
|
377
|
-
actionState.status = 'success';
|
|
378
|
-
return res;
|
|
379
|
-
} catch (err) {
|
|
380
|
-
console.log('tanner');
|
|
381
|
-
console.error(err);
|
|
382
|
-
actionState.error = err;
|
|
383
|
-
actionState.status = 'error';
|
|
384
|
-
} finally {
|
|
385
|
-
router.notify();
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
};
|
|
389
|
-
return router.state.actions[id];
|
|
390
|
-
})();
|
|
391
|
-
const loader = router.state.loaders[id] || (() => {
|
|
392
|
-
router.state.loaders[id] = {
|
|
393
|
-
pending: [],
|
|
394
|
-
fetch: async loaderContext => {
|
|
395
|
-
if (!route) {
|
|
396
|
-
return;
|
|
397
|
-
}
|
|
398
|
-
const loaderState = {
|
|
399
|
-
loadedAt: Date.now(),
|
|
400
|
-
loaderContext
|
|
401
|
-
};
|
|
402
|
-
loader.current = loaderState;
|
|
403
|
-
loader.latest = loaderState;
|
|
404
|
-
loader.pending.push(loaderState);
|
|
405
|
-
|
|
406
|
-
// router.state = {
|
|
407
|
-
// ...router.state,
|
|
408
|
-
// currentAction: loaderState,
|
|
409
|
-
// latestAction: loaderState,
|
|
410
|
-
// }
|
|
411
|
-
|
|
412
|
-
router.notify();
|
|
413
|
-
try {
|
|
414
|
-
return await (route.options.loader == null ? void 0 : route.options.loader(loaderContext));
|
|
415
|
-
} finally {
|
|
416
|
-
loader.pending = loader.pending.filter(d => d !== loaderState);
|
|
417
|
-
// router.removeActionQueue.push({ loader, loaderState })
|
|
418
|
-
router.notify();
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
};
|
|
422
|
-
return router.state.loaders[id];
|
|
423
|
-
})();
|
|
424
272
|
let route = {
|
|
425
273
|
routeInfo: undefined,
|
|
426
274
|
routeId: id,
|
|
427
275
|
routeRouteId: routeId,
|
|
276
|
+
originalIndex,
|
|
428
277
|
routePath,
|
|
429
278
|
fullPath,
|
|
430
279
|
options,
|
|
431
280
|
router,
|
|
432
281
|
childRoutes: undefined,
|
|
433
282
|
parentRoute: parent,
|
|
434
|
-
action
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
283
|
+
get action() {
|
|
284
|
+
let action = router.store.actions[id] || (() => {
|
|
285
|
+
router.setStore(s => {
|
|
286
|
+
s.actions[id] = {
|
|
287
|
+
submissions: [],
|
|
288
|
+
submit: async (submission, actionOpts) => {
|
|
289
|
+
if (!route) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
const invalidate = (actionOpts == null ? void 0 : actionOpts.invalidate) ?? true;
|
|
293
|
+
const [actionStore, setActionStore] = createStore({
|
|
294
|
+
submittedAt: Date.now(),
|
|
295
|
+
status: 'pending',
|
|
296
|
+
submission,
|
|
297
|
+
isMulti: !!(actionOpts != null && actionOpts.multi)
|
|
298
|
+
});
|
|
299
|
+
router.setStore(s => {
|
|
300
|
+
if (!(actionOpts != null && actionOpts.multi)) {
|
|
301
|
+
s.actions[id].submissions = action.submissions.filter(d => d.isMulti);
|
|
302
|
+
}
|
|
303
|
+
s.actions[id].current = actionStore;
|
|
304
|
+
s.actions[id].latest = actionStore;
|
|
305
|
+
s.actions[id].submissions.push(actionStore);
|
|
306
|
+
});
|
|
307
|
+
try {
|
|
308
|
+
const res = await (route.options.action == null ? void 0 : route.options.action(submission));
|
|
309
|
+
setActionStore(s => {
|
|
310
|
+
s.data = res;
|
|
311
|
+
});
|
|
312
|
+
if (invalidate) {
|
|
313
|
+
router.invalidateRoute({
|
|
314
|
+
to: '.',
|
|
315
|
+
fromCurrent: true
|
|
316
|
+
});
|
|
317
|
+
await router.reload();
|
|
318
|
+
}
|
|
319
|
+
setActionStore(s => {
|
|
320
|
+
s.status = 'success';
|
|
321
|
+
});
|
|
322
|
+
return res;
|
|
323
|
+
} catch (err) {
|
|
324
|
+
console.error(err);
|
|
325
|
+
setActionStore(s => {
|
|
326
|
+
s.error = err;
|
|
327
|
+
s.status = 'error';
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
});
|
|
333
|
+
return router.store.actions[id];
|
|
334
|
+
})();
|
|
335
|
+
return action;
|
|
445
336
|
},
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
337
|
+
get loader() {
|
|
338
|
+
let loader = router.store.loaders[id] || (() => {
|
|
339
|
+
router.setStore(s => {
|
|
340
|
+
s.loaders[id] = {
|
|
341
|
+
pending: [],
|
|
342
|
+
fetch: async loaderContext => {
|
|
343
|
+
if (!route) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
const loaderState = {
|
|
347
|
+
loadedAt: Date.now(),
|
|
348
|
+
loaderContext
|
|
349
|
+
};
|
|
350
|
+
router.setStore(s => {
|
|
351
|
+
s.loaders[id].current = loaderState;
|
|
352
|
+
s.loaders[id].latest = loaderState;
|
|
353
|
+
s.loaders[id].pending.push(loaderState);
|
|
354
|
+
});
|
|
355
|
+
try {
|
|
356
|
+
return await (route.options.loader == null ? void 0 : route.options.loader(loaderContext));
|
|
357
|
+
} finally {
|
|
358
|
+
router.setStore(s => {
|
|
359
|
+
s.loaders[id].pending = s.loaders[id].pending.filter(d => d !== loaderState);
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
});
|
|
365
|
+
return router.store.loaders[id];
|
|
366
|
+
})();
|
|
367
|
+
return loader;
|
|
450
368
|
}
|
|
369
|
+
|
|
370
|
+
// buildLink: (options) => {
|
|
371
|
+
// return router.buildLink({
|
|
372
|
+
// ...options,
|
|
373
|
+
// from: fullPath,
|
|
374
|
+
// } as any) as any
|
|
375
|
+
// },
|
|
376
|
+
|
|
377
|
+
// navigate: (options) => {
|
|
378
|
+
// return router.navigate({
|
|
379
|
+
// ...options,
|
|
380
|
+
// from: fullPath,
|
|
381
|
+
// } as any) as any
|
|
382
|
+
// },
|
|
383
|
+
|
|
384
|
+
// matchRoute: (matchLocation, opts) => {
|
|
385
|
+
// return router.matchRoute(
|
|
386
|
+
// {
|
|
387
|
+
// ...matchLocation,
|
|
388
|
+
// from: fullPath,
|
|
389
|
+
// } as any,
|
|
390
|
+
// opts,
|
|
391
|
+
// ) as any
|
|
392
|
+
// },
|
|
451
393
|
};
|
|
394
|
+
|
|
452
395
|
router.options.createRoute == null ? void 0 : router.options.createRoute({
|
|
453
396
|
router,
|
|
454
397
|
route
|
|
@@ -457,7 +400,7 @@ function createRoute(routeConfig, options, parent, router) {
|
|
|
457
400
|
}
|
|
458
401
|
|
|
459
402
|
const rootRouteId = '__root__';
|
|
460
|
-
const createRouteConfig = function
|
|
403
|
+
const createRouteConfig = function (options, children, isRoot, parentId, parentPath) {
|
|
461
404
|
if (options === void 0) {
|
|
462
405
|
options = {};
|
|
463
406
|
}
|
|
@@ -497,53 +440,194 @@ const createRouteConfig = function createRouteConfig(options, children, isRoot,
|
|
|
497
440
|
addChildren: children => createRouteConfig(options, children, false, parentId, parentPath),
|
|
498
441
|
createRoute: childOptions => createRouteConfig(childOptions, undefined, false, id, fullPath),
|
|
499
442
|
generate: () => {
|
|
500
|
-
invariant(false,
|
|
443
|
+
invariant(false, `routeConfig.generate() is used by TanStack Router's file-based routing code generation and should not actually be called during runtime. `);
|
|
501
444
|
}
|
|
502
445
|
};
|
|
503
446
|
};
|
|
504
447
|
|
|
448
|
+
/**
|
|
449
|
+
* This function returns `a` if `b` is deeply equal.
|
|
450
|
+
* If not, it will replace any deeply equal children of `b` with those of `a`.
|
|
451
|
+
* This can be used for structural sharing between JSON values for example.
|
|
452
|
+
*/
|
|
453
|
+
function sharedClone(prev, next, touchAll) {
|
|
454
|
+
const things = new Map();
|
|
455
|
+
function recurse(prev, next) {
|
|
456
|
+
if (prev === next) {
|
|
457
|
+
return prev;
|
|
458
|
+
}
|
|
459
|
+
if (things.has(next)) {
|
|
460
|
+
return things.get(next);
|
|
461
|
+
}
|
|
462
|
+
const prevIsArray = Array.isArray(prev);
|
|
463
|
+
const nextIsArray = Array.isArray(next);
|
|
464
|
+
const prevIsObj = isPlainObject(prev);
|
|
465
|
+
const nextIsObj = isPlainObject(next);
|
|
466
|
+
const isArray = prevIsArray && nextIsArray;
|
|
467
|
+
const isObj = prevIsObj && nextIsObj;
|
|
468
|
+
const isSameStructure = isArray || isObj;
|
|
469
|
+
|
|
470
|
+
// Both are arrays or objects
|
|
471
|
+
if (isSameStructure) {
|
|
472
|
+
const aSize = isArray ? prev.length : Object.keys(prev).length;
|
|
473
|
+
const bItems = isArray ? next : Object.keys(next);
|
|
474
|
+
const bSize = bItems.length;
|
|
475
|
+
const copy = isArray ? [] : {};
|
|
476
|
+
let equalItems = 0;
|
|
477
|
+
for (let i = 0; i < bSize; i++) {
|
|
478
|
+
const key = isArray ? i : bItems[i];
|
|
479
|
+
if (copy[key] === prev[key]) {
|
|
480
|
+
equalItems++;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (aSize === bSize && equalItems === aSize) {
|
|
484
|
+
things.set(next, prev);
|
|
485
|
+
return prev;
|
|
486
|
+
}
|
|
487
|
+
things.set(next, copy);
|
|
488
|
+
for (let i = 0; i < bSize; i++) {
|
|
489
|
+
const key = isArray ? i : bItems[i];
|
|
490
|
+
if (typeof bItems[i] === 'function') {
|
|
491
|
+
copy[key] = prev[key];
|
|
492
|
+
} else {
|
|
493
|
+
copy[key] = recurse(prev[key], next[key]);
|
|
494
|
+
}
|
|
495
|
+
if (copy[key] === prev[key]) {
|
|
496
|
+
equalItems++;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return copy;
|
|
500
|
+
}
|
|
501
|
+
if (nextIsArray) {
|
|
502
|
+
const copy = [];
|
|
503
|
+
things.set(next, copy);
|
|
504
|
+
for (let i = 0; i < next.length; i++) {
|
|
505
|
+
copy[i] = recurse(undefined, next[i]);
|
|
506
|
+
}
|
|
507
|
+
return copy;
|
|
508
|
+
}
|
|
509
|
+
if (nextIsObj) {
|
|
510
|
+
const copy = {};
|
|
511
|
+
things.set(next, copy);
|
|
512
|
+
const nextKeys = Object.keys(next);
|
|
513
|
+
for (let i = 0; i < nextKeys.length; i++) {
|
|
514
|
+
const key = nextKeys[i];
|
|
515
|
+
copy[key] = recurse(undefined, next[key]);
|
|
516
|
+
}
|
|
517
|
+
return copy;
|
|
518
|
+
}
|
|
519
|
+
return next;
|
|
520
|
+
}
|
|
521
|
+
return recurse(prev, next);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// Copied from: https://github.com/jonschlinkert/is-plain-object
|
|
525
|
+
function isPlainObject(o) {
|
|
526
|
+
if (!hasObjectPrototype(o)) {
|
|
527
|
+
return false;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// If has modified constructor
|
|
531
|
+
const ctor = o.constructor;
|
|
532
|
+
if (typeof ctor === 'undefined') {
|
|
533
|
+
return true;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// If has modified prototype
|
|
537
|
+
const prot = ctor.prototype;
|
|
538
|
+
if (!hasObjectPrototype(prot)) {
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// If constructor does not have an Object-specific method
|
|
543
|
+
if (!prot.hasOwnProperty('isPrototypeOf')) {
|
|
544
|
+
return false;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// Most likely a plain Object
|
|
548
|
+
return true;
|
|
549
|
+
}
|
|
550
|
+
function hasObjectPrototype(o) {
|
|
551
|
+
return Object.prototype.toString.call(o) === '[object Object]';
|
|
552
|
+
}
|
|
553
|
+
|
|
505
554
|
const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
|
|
506
555
|
function createRouteMatch(router, route, opts) {
|
|
507
|
-
|
|
508
|
-
|
|
556
|
+
let componentsPromise;
|
|
557
|
+
let dataPromise;
|
|
558
|
+
let latestId = '';
|
|
559
|
+
let resolve = () => {};
|
|
560
|
+
function setLoaderData(loaderData) {
|
|
561
|
+
batch(() => {
|
|
562
|
+
setStore(s => {
|
|
563
|
+
s.routeLoaderData = sharedClone(s.routeLoaderData, loaderData);
|
|
564
|
+
});
|
|
565
|
+
updateLoaderData();
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
function updateLoaderData() {
|
|
569
|
+
setStore(s => {
|
|
570
|
+
var _store$parentMatch;
|
|
571
|
+
s.loaderData = sharedClone(s.loaderData, {
|
|
572
|
+
...((_store$parentMatch = store.parentMatch) == null ? void 0 : _store$parentMatch.store.loaderData),
|
|
573
|
+
...s.routeLoaderData
|
|
574
|
+
});
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
const [store, setStore] = createStore({
|
|
509
578
|
routeSearch: {},
|
|
510
579
|
search: {},
|
|
511
|
-
childMatches: [],
|
|
512
580
|
status: 'idle',
|
|
513
581
|
routeLoaderData: {},
|
|
514
582
|
loaderData: {},
|
|
515
583
|
isFetching: false,
|
|
516
|
-
|
|
584
|
+
invalid: false,
|
|
517
585
|
invalidAt: Infinity,
|
|
518
|
-
|
|
519
|
-
getIsInvalid: () => {
|
|
586
|
+
get isInvalid() {
|
|
520
587
|
const now = Date.now();
|
|
521
|
-
return
|
|
522
|
-
}
|
|
588
|
+
return this.invalid || this.invalidAt < now;
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
const routeMatch = {
|
|
592
|
+
...route,
|
|
593
|
+
...opts,
|
|
594
|
+
store,
|
|
595
|
+
// setStore,
|
|
596
|
+
router,
|
|
597
|
+
childMatches: [],
|
|
523
598
|
__: {
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
599
|
+
setParentMatch: parentMatch => {
|
|
600
|
+
batch(() => {
|
|
601
|
+
setStore(s => {
|
|
602
|
+
s.parentMatch = parentMatch;
|
|
603
|
+
});
|
|
604
|
+
updateLoaderData();
|
|
605
|
+
});
|
|
530
606
|
},
|
|
607
|
+
abortController: new AbortController(),
|
|
531
608
|
validate: () => {
|
|
532
|
-
var
|
|
609
|
+
var _store$parentMatch2;
|
|
533
610
|
// Validate the search params and stabilize them
|
|
534
|
-
const parentSearch = (
|
|
611
|
+
const parentSearch = ((_store$parentMatch2 = store.parentMatch) == null ? void 0 : _store$parentMatch2.store.search) ?? router.store.currentLocation.search;
|
|
535
612
|
try {
|
|
536
|
-
|
|
537
|
-
const prevSearch = routeMatch.routeSearch;
|
|
613
|
+
const prevSearch = store.routeSearch;
|
|
538
614
|
const validator = typeof routeMatch.options.validateSearch === 'object' ? routeMatch.options.validateSearch.parse : routeMatch.options.validateSearch;
|
|
539
|
-
let nextSearch =
|
|
615
|
+
let nextSearch = sharedClone(prevSearch, (validator == null ? void 0 : validator(parentSearch)) ?? {});
|
|
616
|
+
batch(() => {
|
|
617
|
+
// Invalidate route matches when search param stability changes
|
|
618
|
+
if (prevSearch !== nextSearch) {
|
|
619
|
+
setStore(s => s.invalid = true);
|
|
620
|
+
}
|
|
540
621
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
622
|
+
// TODO: Alright, do we need batch() here?
|
|
623
|
+
setStore(s => {
|
|
624
|
+
s.routeSearch = nextSearch;
|
|
625
|
+
s.search = sharedClone(parentSearch, {
|
|
626
|
+
...parentSearch,
|
|
627
|
+
...nextSearch
|
|
628
|
+
});
|
|
629
|
+
});
|
|
630
|
+
});
|
|
547
631
|
componentTypes.map(async type => {
|
|
548
632
|
const component = routeMatch.options[type];
|
|
549
633
|
if (typeof routeMatch.__[type] !== 'function') {
|
|
@@ -556,8 +640,11 @@ function createRouteMatch(router, route, opts) {
|
|
|
556
640
|
cause: err
|
|
557
641
|
});
|
|
558
642
|
error.code = 'INVALID_SEARCH_PARAMS';
|
|
559
|
-
|
|
560
|
-
|
|
643
|
+
setStore(s => {
|
|
644
|
+
s.status = 'error';
|
|
645
|
+
s.error = error;
|
|
646
|
+
});
|
|
647
|
+
|
|
561
648
|
// Do not proceed with loading the route
|
|
562
649
|
return;
|
|
563
650
|
}
|
|
@@ -568,7 +655,7 @@ function createRouteMatch(router, route, opts) {
|
|
|
568
655
|
(_routeMatch$__$abortC = routeMatch.__.abortController) == null ? void 0 : _routeMatch$__$abortC.abort();
|
|
569
656
|
},
|
|
570
657
|
invalidate: () => {
|
|
571
|
-
|
|
658
|
+
setStore(s => s.invalid = true);
|
|
572
659
|
},
|
|
573
660
|
hasLoaders: () => {
|
|
574
661
|
return !!(route.options.loader || componentTypes.some(d => {
|
|
@@ -583,17 +670,17 @@ function createRouteMatch(router, route, opts) {
|
|
|
583
670
|
// If this is a preload, add it to the preload cache
|
|
584
671
|
if (loaderOpts != null && loaderOpts.preload && minMaxAge > 0) {
|
|
585
672
|
// If the match is currently active, don't preload it
|
|
586
|
-
if (router.
|
|
673
|
+
if (router.store.currentMatches.find(d => d.matchId === routeMatch.matchId)) {
|
|
587
674
|
return;
|
|
588
675
|
}
|
|
589
|
-
router.matchCache[routeMatch.matchId] = {
|
|
676
|
+
router.store.matchCache[routeMatch.matchId] = {
|
|
590
677
|
gc: now + loaderOpts.gcMaxAge,
|
|
591
678
|
match: routeMatch
|
|
592
679
|
};
|
|
593
680
|
}
|
|
594
681
|
|
|
595
682
|
// If the match is invalid, errored or idle, trigger it to load
|
|
596
|
-
if (
|
|
683
|
+
if (store.status === 'success' && store.isInvalid || store.status === 'error' || store.status === 'idle') {
|
|
597
684
|
const maxAge = loaderOpts != null && loaderOpts.preload ? loaderOpts == null ? void 0 : loaderOpts.maxAge : undefined;
|
|
598
685
|
await routeMatch.fetch({
|
|
599
686
|
maxAge
|
|
@@ -602,29 +689,30 @@ function createRouteMatch(router, route, opts) {
|
|
|
602
689
|
},
|
|
603
690
|
fetch: async opts => {
|
|
604
691
|
const loadId = '' + Date.now() + Math.random();
|
|
605
|
-
|
|
692
|
+
latestId = loadId;
|
|
606
693
|
const checkLatest = async () => {
|
|
607
|
-
if (loadId !==
|
|
694
|
+
if (loadId !== latestId) {
|
|
608
695
|
// warning(true, 'Data loader is out of date!')
|
|
609
696
|
return new Promise(() => {});
|
|
610
697
|
}
|
|
611
698
|
};
|
|
699
|
+
batch(() => {
|
|
700
|
+
// If the match was in an error state, set it
|
|
701
|
+
// to a loading state again. Otherwise, keep it
|
|
702
|
+
// as loading or resolved
|
|
703
|
+
if (store.status === 'idle') {
|
|
704
|
+
setStore(s => s.status = 'loading');
|
|
705
|
+
}
|
|
612
706
|
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
routeMatch.status = 'loading';
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
// We started loading the route, so it's no longer invalid
|
|
621
|
-
routeMatch.isInvalid = false;
|
|
622
|
-
routeMatch.__.loadPromise = new Promise(async resolve => {
|
|
707
|
+
// We started loading the route, so it's no longer invalid
|
|
708
|
+
setStore(s => s.invalid = false);
|
|
709
|
+
});
|
|
710
|
+
routeMatch.__.loadPromise = new Promise(async r => {
|
|
623
711
|
// We are now fetching, even if it's in the background of a
|
|
624
712
|
// resolved state
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
713
|
+
setStore(s => s.isFetching = true);
|
|
714
|
+
resolve = r;
|
|
715
|
+
componentsPromise = (async () => {
|
|
628
716
|
// then run all component and data loaders in parallel
|
|
629
717
|
// For each component type, potentially load it asynchronously
|
|
630
718
|
|
|
@@ -636,49 +724,52 @@ function createRouteMatch(router, route, opts) {
|
|
|
636
724
|
}
|
|
637
725
|
}));
|
|
638
726
|
})();
|
|
639
|
-
|
|
727
|
+
dataPromise = Promise.resolve().then(async () => {
|
|
640
728
|
try {
|
|
641
|
-
var _ref, _ref2, _opts$maxAge;
|
|
642
729
|
if (routeMatch.options.loader) {
|
|
643
730
|
const data = await router.loadMatchData(routeMatch);
|
|
644
731
|
await checkLatest();
|
|
645
|
-
|
|
732
|
+
setLoaderData(data);
|
|
646
733
|
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
734
|
+
setStore(s => {
|
|
735
|
+
s.error = undefined;
|
|
736
|
+
s.status = 'success';
|
|
737
|
+
s.updatedAt = Date.now();
|
|
738
|
+
s.invalidAt = s.updatedAt + ((opts == null ? void 0 : opts.maxAge) ?? routeMatch.options.loaderMaxAge ?? router.options.defaultLoaderMaxAge ?? 0);
|
|
739
|
+
});
|
|
740
|
+
return store.routeLoaderData;
|
|
652
741
|
} catch (err) {
|
|
653
742
|
await checkLatest();
|
|
654
743
|
if (process.env.NODE_ENV !== 'production') {
|
|
655
744
|
console.error(err);
|
|
656
745
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
746
|
+
setStore(s => {
|
|
747
|
+
s.error = err;
|
|
748
|
+
s.status = 'error';
|
|
749
|
+
s.updatedAt = Date.now();
|
|
750
|
+
});
|
|
660
751
|
throw err;
|
|
661
752
|
}
|
|
662
753
|
});
|
|
663
754
|
const after = async () => {
|
|
664
755
|
await checkLatest();
|
|
665
|
-
|
|
756
|
+
setStore(s => s.isFetching = false);
|
|
666
757
|
delete routeMatch.__.loadPromise;
|
|
667
|
-
|
|
758
|
+
resolve();
|
|
668
759
|
};
|
|
669
760
|
try {
|
|
670
|
-
await Promise.all([
|
|
761
|
+
await Promise.all([componentsPromise, dataPromise.catch(() => {})]);
|
|
671
762
|
after();
|
|
672
|
-
} catch
|
|
763
|
+
} catch {
|
|
673
764
|
after();
|
|
674
765
|
}
|
|
675
766
|
});
|
|
676
767
|
await routeMatch.__.loadPromise;
|
|
677
768
|
await checkLatest();
|
|
678
769
|
}
|
|
679
|
-
}
|
|
770
|
+
};
|
|
680
771
|
if (!routeMatch.hasLoaders()) {
|
|
681
|
-
|
|
772
|
+
setStore(s => s.status = 'success');
|
|
682
773
|
}
|
|
683
774
|
return routeMatch;
|
|
684
775
|
}
|
|
@@ -708,7 +799,9 @@ function parseSearchWith(parser) {
|
|
|
708
799
|
}
|
|
709
800
|
function stringifySearchWith(stringify) {
|
|
710
801
|
return search => {
|
|
711
|
-
search =
|
|
802
|
+
search = {
|
|
803
|
+
...search
|
|
804
|
+
};
|
|
712
805
|
if (search) {
|
|
713
806
|
Object.keys(search).forEach(key => {
|
|
714
807
|
const val = search[key];
|
|
@@ -724,7 +817,7 @@ function stringifySearchWith(stringify) {
|
|
|
724
817
|
});
|
|
725
818
|
}
|
|
726
819
|
const searchStr = encode(search).toString();
|
|
727
|
-
return searchStr ?
|
|
820
|
+
return searchStr ? `?${searchStr}` : '';
|
|
728
821
|
};
|
|
729
822
|
}
|
|
730
823
|
|
|
@@ -737,216 +830,296 @@ const createDefaultHistory = () => isServer ? createMemoryHistory() : createBrow
|
|
|
737
830
|
function getInitialRouterState() {
|
|
738
831
|
return {
|
|
739
832
|
status: 'idle',
|
|
740
|
-
|
|
741
|
-
|
|
833
|
+
latestLocation: null,
|
|
834
|
+
currentLocation: null,
|
|
835
|
+
currentMatches: [],
|
|
742
836
|
actions: {},
|
|
743
837
|
loaders: {},
|
|
744
838
|
lastUpdated: Date.now(),
|
|
745
|
-
|
|
746
|
-
|
|
839
|
+
matchCache: {},
|
|
840
|
+
get isFetching() {
|
|
841
|
+
return this.status === 'loading' || this.currentMatches.some(d => d.store.isFetching);
|
|
842
|
+
},
|
|
843
|
+
get isPreloading() {
|
|
844
|
+
return Object.values(this.matchCache).some(d => d.match.store.isFetching && !this.currentMatches.find(dd => dd.matchId === d.match.matchId));
|
|
845
|
+
}
|
|
747
846
|
};
|
|
748
847
|
}
|
|
749
848
|
function createRouter(userOptions) {
|
|
750
|
-
|
|
751
|
-
const history = (userOptions == null ? void 0 : userOptions.history) || createDefaultHistory();
|
|
752
|
-
const originalOptions = _extends({
|
|
849
|
+
const originalOptions = {
|
|
753
850
|
defaultLoaderGcMaxAge: 5 * 60 * 1000,
|
|
754
851
|
defaultLoaderMaxAge: 0,
|
|
755
852
|
defaultPreloadMaxAge: 2000,
|
|
756
853
|
defaultPreloadDelay: 50,
|
|
757
|
-
context: undefined
|
|
758
|
-
|
|
759
|
-
stringifySearch: (
|
|
760
|
-
parseSearch: (
|
|
761
|
-
}
|
|
762
|
-
|
|
854
|
+
context: undefined,
|
|
855
|
+
...userOptions,
|
|
856
|
+
stringifySearch: (userOptions == null ? void 0 : userOptions.stringifySearch) ?? defaultStringifySearch,
|
|
857
|
+
parseSearch: (userOptions == null ? void 0 : userOptions.parseSearch) ?? defaultParseSearch
|
|
858
|
+
};
|
|
859
|
+
const [store, setStore] = createStore(getInitialRouterState());
|
|
860
|
+
let navigationPromise;
|
|
861
|
+
let startedLoadingAt = Date.now();
|
|
862
|
+
let resolveNavigation = () => {};
|
|
863
|
+
function onFocus() {
|
|
864
|
+
router.load();
|
|
865
|
+
}
|
|
866
|
+
function buildRouteTree(rootRouteConfig) {
|
|
867
|
+
const recurseRoutes = (routeConfigs, parent) => {
|
|
868
|
+
return routeConfigs.map((routeConfig, i) => {
|
|
869
|
+
const routeOptions = routeConfig.options;
|
|
870
|
+
const route = createRoute(routeConfig, routeOptions, i, parent, router);
|
|
871
|
+
const existingRoute = router.routesById[route.routeId];
|
|
872
|
+
if (existingRoute) {
|
|
873
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
874
|
+
console.warn(`Duplicate routes found with id: ${String(route.routeId)}`, router.routesById, route);
|
|
875
|
+
}
|
|
876
|
+
throw new Error();
|
|
877
|
+
}
|
|
878
|
+
router.routesById[route.routeId] = route;
|
|
879
|
+
const children = routeConfig.children;
|
|
880
|
+
route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
|
|
881
|
+
return route;
|
|
882
|
+
});
|
|
883
|
+
};
|
|
884
|
+
const routes = recurseRoutes([rootRouteConfig]);
|
|
885
|
+
return routes[0];
|
|
886
|
+
}
|
|
887
|
+
function parseLocation(location, previousLocation) {
|
|
888
|
+
const parsedSearch = router.options.parseSearch(location.search);
|
|
889
|
+
return {
|
|
890
|
+
pathname: location.pathname,
|
|
891
|
+
searchStr: location.search,
|
|
892
|
+
search: sharedClone(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
|
|
893
|
+
hash: location.hash.split('#').reverse()[0] ?? '',
|
|
894
|
+
href: `${location.pathname}${location.search}${location.hash}`,
|
|
895
|
+
state: location.state,
|
|
896
|
+
key: location.key
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
function navigate(location) {
|
|
900
|
+
const next = router.buildNext(location);
|
|
901
|
+
return commitLocation(next, location.replace);
|
|
902
|
+
}
|
|
903
|
+
function buildLocation(dest) {
|
|
904
|
+
var _last, _dest$__preSearchFilt, _dest$__preSearchFilt2, _dest$__postSearchFil;
|
|
905
|
+
if (dest === void 0) {
|
|
906
|
+
dest = {};
|
|
907
|
+
}
|
|
908
|
+
const fromPathname = dest.fromCurrent ? store.latestLocation.pathname : dest.from ?? store.latestLocation.pathname;
|
|
909
|
+
let pathname = resolvePath(router.basepath ?? '/', fromPathname, `${dest.to ?? '.'}`);
|
|
910
|
+
const fromMatches = router.matchRoutes(store.latestLocation.pathname, {
|
|
911
|
+
strictParseParams: true
|
|
912
|
+
});
|
|
913
|
+
const toMatches = router.matchRoutes(pathname);
|
|
914
|
+
const prevParams = {
|
|
915
|
+
...((_last = last(fromMatches)) == null ? void 0 : _last.params)
|
|
916
|
+
};
|
|
917
|
+
let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
|
|
918
|
+
if (nextParams) {
|
|
919
|
+
toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
|
|
920
|
+
Object.assign({}, nextParams, fn(nextParams));
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
pathname = interpolatePath(pathname, nextParams ?? {});
|
|
924
|
+
|
|
925
|
+
// Pre filters first
|
|
926
|
+
const preFilteredSearch = (_dest$__preSearchFilt = dest.__preSearchFilters) != null && _dest$__preSearchFilt.length ? dest.__preSearchFilters.reduce((prev, next) => next(prev), store.latestLocation.search) : store.latestLocation.search;
|
|
927
|
+
|
|
928
|
+
// Then the link/navigate function
|
|
929
|
+
const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
|
|
930
|
+
: dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
|
|
931
|
+
: (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
|
|
932
|
+
: {};
|
|
933
|
+
|
|
934
|
+
// Then post filters
|
|
935
|
+
const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
|
|
936
|
+
const search = sharedClone(store.latestLocation.search, postFilteredSearch);
|
|
937
|
+
const searchStr = router.options.stringifySearch(search);
|
|
938
|
+
let hash = dest.hash === true ? store.latestLocation.hash : functionalUpdate(dest.hash, store.latestLocation.hash);
|
|
939
|
+
hash = hash ? `#${hash}` : '';
|
|
940
|
+
return {
|
|
941
|
+
pathname,
|
|
942
|
+
search,
|
|
943
|
+
searchStr,
|
|
944
|
+
state: store.latestLocation.state,
|
|
945
|
+
hash,
|
|
946
|
+
href: `${pathname}${searchStr}${hash}`,
|
|
947
|
+
key: dest.key
|
|
948
|
+
};
|
|
949
|
+
}
|
|
950
|
+
function commitLocation(next, replace) {
|
|
951
|
+
const id = '' + Date.now() + Math.random();
|
|
952
|
+
let nextAction = 'replace';
|
|
953
|
+
if (!replace) {
|
|
954
|
+
nextAction = 'push';
|
|
955
|
+
}
|
|
956
|
+
const isSameUrl = parseLocation(router.history.location).href === next.href;
|
|
957
|
+
if (isSameUrl && !next.key) {
|
|
958
|
+
nextAction = 'replace';
|
|
959
|
+
}
|
|
960
|
+
router.history[nextAction]({
|
|
961
|
+
pathname: next.pathname,
|
|
962
|
+
hash: next.hash,
|
|
963
|
+
search: next.searchStr
|
|
964
|
+
}, {
|
|
965
|
+
id,
|
|
966
|
+
...next.state
|
|
967
|
+
});
|
|
968
|
+
return navigationPromise = new Promise(resolve => {
|
|
969
|
+
const previousNavigationResolve = resolveNavigation;
|
|
970
|
+
resolveNavigation = () => {
|
|
971
|
+
previousNavigationResolve();
|
|
972
|
+
resolve();
|
|
973
|
+
};
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
const router = {
|
|
763
977
|
types: undefined,
|
|
764
978
|
// public api
|
|
765
|
-
history,
|
|
979
|
+
history: (userOptions == null ? void 0 : userOptions.history) || createDefaultHistory(),
|
|
980
|
+
store,
|
|
981
|
+
setStore,
|
|
766
982
|
options: originalOptions,
|
|
767
|
-
listeners: [],
|
|
768
|
-
// Resolved after construction
|
|
769
983
|
basepath: '',
|
|
770
984
|
routeTree: undefined,
|
|
771
985
|
routesById: {},
|
|
772
|
-
__location: undefined,
|
|
773
|
-
//
|
|
774
|
-
resolveNavigation: () => {},
|
|
775
|
-
matchCache: {},
|
|
776
|
-
state: getInitialRouterState(),
|
|
777
986
|
reset: () => {
|
|
778
|
-
|
|
779
|
-
router.notify();
|
|
780
|
-
},
|
|
781
|
-
startedLoadingAt: Date.now(),
|
|
782
|
-
subscribe: listener => {
|
|
783
|
-
router.listeners.push(listener);
|
|
784
|
-
return () => {
|
|
785
|
-
router.listeners = router.listeners.filter(x => x !== listener);
|
|
786
|
-
};
|
|
987
|
+
setStore(s => Object.assign(s, getInitialRouterState()));
|
|
787
988
|
},
|
|
788
989
|
getRoute: id => {
|
|
789
990
|
return router.routesById[id];
|
|
790
991
|
},
|
|
791
|
-
notify: () => {
|
|
792
|
-
const isFetching = router.state.status === 'loading' || router.state.matches.some(d => d.isFetching);
|
|
793
|
-
const isPreloading = Object.values(router.matchCache).some(d => d.match.isFetching && !router.state.matches.find(dd => dd.matchId === d.match.matchId));
|
|
794
|
-
if (router.state.isFetching !== isFetching || router.state.isPreloading !== isPreloading) {
|
|
795
|
-
router.state = _extends({}, router.state, {
|
|
796
|
-
isFetching,
|
|
797
|
-
isPreloading
|
|
798
|
-
});
|
|
799
|
-
}
|
|
800
|
-
cascadeLoaderData(router.state.matches);
|
|
801
|
-
router.listeners.forEach(listener => listener(router));
|
|
802
|
-
},
|
|
803
992
|
dehydrate: () => {
|
|
804
993
|
return {
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
994
|
+
store: {
|
|
995
|
+
...pick(store, ['latestLocation', 'currentLocation', 'status', 'lastUpdated']),
|
|
996
|
+
currentMatches: store.currentMatches.map(match => ({
|
|
997
|
+
matchId: match.matchId,
|
|
998
|
+
store: pick(match.store, ['status', 'routeLoaderData', 'isInvalid', 'invalidAt'])
|
|
999
|
+
}))
|
|
1000
|
+
},
|
|
809
1001
|
context: router.options.context
|
|
810
1002
|
};
|
|
811
1003
|
},
|
|
812
|
-
hydrate:
|
|
813
|
-
|
|
814
|
-
|
|
1004
|
+
hydrate: dehydratedRouter => {
|
|
1005
|
+
setStore(s => {
|
|
1006
|
+
// Update the context TODO: make this part of state?
|
|
1007
|
+
router.options.context = dehydratedRouter.context;
|
|
815
1008
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
Object.assign(
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
matches
|
|
1009
|
+
// Match the routes
|
|
1010
|
+
const currentMatches = router.matchRoutes(dehydratedRouter.store.latestLocation.pathname, {
|
|
1011
|
+
strictParseParams: true
|
|
1012
|
+
});
|
|
1013
|
+
currentMatches.forEach((match, index) => {
|
|
1014
|
+
const dehydratedMatch = dehydratedRouter.store.currentMatches[index];
|
|
1015
|
+
invariant(dehydratedMatch && dehydratedMatch.matchId === match.matchId, 'Oh no! There was a hydration mismatch when attempting to restore the state of the router! 😬');
|
|
1016
|
+
Object.assign(match, dehydratedMatch);
|
|
1017
|
+
});
|
|
1018
|
+
currentMatches.forEach(match => match.__.validate());
|
|
1019
|
+
Object.assign(s, {
|
|
1020
|
+
...dehydratedRouter.store,
|
|
1021
|
+
currentMatches
|
|
1022
|
+
});
|
|
831
1023
|
});
|
|
832
1024
|
},
|
|
833
1025
|
mount: () => {
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
// router.__.commitLocation(next, true)
|
|
844
|
-
// }
|
|
845
|
-
|
|
846
|
-
if (!router.state.matches.length) {
|
|
847
|
-
router.load();
|
|
848
|
-
}
|
|
849
|
-
const unsub = router.history.listen(event => {
|
|
850
|
-
router.load(router.__.parseLocation(event.location, router.__location));
|
|
851
|
-
});
|
|
1026
|
+
// Mount only does anything on the client
|
|
1027
|
+
if (!isServer) {
|
|
1028
|
+
// If the router matches are empty, load the matches
|
|
1029
|
+
if (!store.currentMatches.length) {
|
|
1030
|
+
router.load();
|
|
1031
|
+
}
|
|
1032
|
+
const unsub = router.history.listen(event => {
|
|
1033
|
+
router.load(parseLocation(event.location, store.latestLocation));
|
|
1034
|
+
});
|
|
852
1035
|
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
return () => {
|
|
861
|
-
unsub();
|
|
862
|
-
if (!isServer && window.removeEventListener) {
|
|
863
|
-
// Be sure to unsubscribe if a new handler is set
|
|
864
|
-
window.removeEventListener('visibilitychange', router.onFocus);
|
|
865
|
-
window.removeEventListener('focus', router.onFocus);
|
|
1036
|
+
// addEventListener does not exist in React Native, but window does
|
|
1037
|
+
// In the future, we might need to invert control here for more adapters
|
|
1038
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1039
|
+
if (window.addEventListener) {
|
|
1040
|
+
// Listen to visibilitychange and focus
|
|
1041
|
+
window.addEventListener('visibilitychange', onFocus, false);
|
|
1042
|
+
window.addEventListener('focus', onFocus, false);
|
|
866
1043
|
}
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
1044
|
+
return () => {
|
|
1045
|
+
unsub();
|
|
1046
|
+
if (window.removeEventListener) {
|
|
1047
|
+
// Be sure to unsubscribe if a new handler is set
|
|
1048
|
+
window.removeEventListener('visibilitychange', onFocus);
|
|
1049
|
+
window.removeEventListener('focus', onFocus);
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
return () => {};
|
|
871
1054
|
},
|
|
872
1055
|
update: opts => {
|
|
873
|
-
var _trimPath;
|
|
874
1056
|
const newHistory = (opts == null ? void 0 : opts.history) !== router.history;
|
|
875
|
-
if (!
|
|
1057
|
+
if (!store.latestLocation || newHistory) {
|
|
876
1058
|
if (opts != null && opts.history) {
|
|
877
1059
|
router.history = opts.history;
|
|
878
1060
|
}
|
|
879
|
-
|
|
880
|
-
|
|
1061
|
+
setStore(s => {
|
|
1062
|
+
s.latestLocation = parseLocation(router.history.location);
|
|
1063
|
+
s.currentLocation = s.latestLocation;
|
|
1064
|
+
});
|
|
881
1065
|
}
|
|
882
1066
|
Object.assign(router.options, opts);
|
|
883
1067
|
const {
|
|
884
1068
|
basepath,
|
|
885
1069
|
routeConfig
|
|
886
1070
|
} = router.options;
|
|
887
|
-
router.basepath =
|
|
1071
|
+
router.basepath = `/${trimPath(basepath ?? '') ?? ''}`;
|
|
888
1072
|
if (routeConfig) {
|
|
889
1073
|
router.routesById = {};
|
|
890
|
-
router.routeTree =
|
|
1074
|
+
router.routeTree = buildRouteTree(routeConfig);
|
|
891
1075
|
}
|
|
892
1076
|
return router;
|
|
893
1077
|
},
|
|
894
1078
|
cancelMatches: () => {
|
|
895
|
-
|
|
896
|
-
[...router.state.matches, ...((_router$state$pending = (_router$state$pending2 = router.state.pending) == null ? void 0 : _router$state$pending2.matches) != null ? _router$state$pending : [])].forEach(match => {
|
|
1079
|
+
[...store.currentMatches, ...(store.pendingMatches || [])].forEach(match => {
|
|
897
1080
|
match.cancel();
|
|
898
1081
|
});
|
|
899
1082
|
},
|
|
900
1083
|
load: async next => {
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
// Ingest the new location
|
|
905
|
-
router.__location = next;
|
|
906
|
-
}
|
|
1084
|
+
let now = Date.now();
|
|
1085
|
+
const startedAt = now;
|
|
1086
|
+
startedLoadingAt = startedAt;
|
|
907
1087
|
|
|
908
1088
|
// Cancel any pending matches
|
|
909
1089
|
router.cancelMatches();
|
|
1090
|
+
let matches;
|
|
1091
|
+
batch(() => {
|
|
1092
|
+
if (next) {
|
|
1093
|
+
// Ingest the new location
|
|
1094
|
+
setStore(s => {
|
|
1095
|
+
s.latestLocation = next;
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
910
1098
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
});
|
|
915
|
-
if (typeof document !== 'undefined') {
|
|
916
|
-
router.state = _extends({}, router.state, {
|
|
917
|
-
pending: {
|
|
918
|
-
matches: matches,
|
|
919
|
-
location: router.__location
|
|
920
|
-
},
|
|
921
|
-
status: 'loading'
|
|
1099
|
+
// Match the routes
|
|
1100
|
+
matches = router.matchRoutes(store.latestLocation.pathname, {
|
|
1101
|
+
strictParseParams: true
|
|
922
1102
|
});
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
1103
|
+
console.log('set loading', matches);
|
|
1104
|
+
setStore(s => {
|
|
1105
|
+
s.status = 'loading';
|
|
1106
|
+
s.pendingMatches = matches;
|
|
1107
|
+
s.pendingLocation = store.latestLocation;
|
|
928
1108
|
});
|
|
929
|
-
}
|
|
1109
|
+
});
|
|
930
1110
|
|
|
931
|
-
//
|
|
1111
|
+
// Load the matches
|
|
932
1112
|
try {
|
|
933
|
-
await
|
|
934
|
-
router: router,
|
|
935
|
-
match
|
|
936
|
-
})));
|
|
1113
|
+
await router.loadMatches(matches);
|
|
937
1114
|
} catch (err) {
|
|
938
|
-
console.
|
|
939
|
-
invariant(false,
|
|
1115
|
+
console.log(err);
|
|
1116
|
+
invariant(false, 'Matches failed to load due to error above ☝️. Navigation cancelled!');
|
|
940
1117
|
}
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
await router.loadMatches(matches);
|
|
945
|
-
if (router.startedLoadingAt !== id) {
|
|
946
|
-
// Ignore side-effects of match loading
|
|
947
|
-
return router.navigationPromise;
|
|
1118
|
+
if (startedLoadingAt !== startedAt) {
|
|
1119
|
+
// Ignore side-effects of outdated side-effects
|
|
1120
|
+
return navigationPromise;
|
|
948
1121
|
}
|
|
949
|
-
const previousMatches =
|
|
1122
|
+
const previousMatches = store.currentMatches;
|
|
950
1123
|
const exiting = [],
|
|
951
1124
|
staying = [];
|
|
952
1125
|
previousMatches.forEach(d => {
|
|
@@ -959,22 +1132,21 @@ function createRouter(userOptions) {
|
|
|
959
1132
|
const entering = matches.filter(d => {
|
|
960
1133
|
return !previousMatches.find(dd => dd.matchId === d.matchId);
|
|
961
1134
|
});
|
|
962
|
-
|
|
1135
|
+
now = Date.now();
|
|
963
1136
|
exiting.forEach(d => {
|
|
964
|
-
var _ref, _d$options$loaderGcMa, _ref2, _d$options$loaderMaxA;
|
|
965
1137
|
d.__.onExit == null ? void 0 : d.__.onExit({
|
|
966
1138
|
params: d.params,
|
|
967
|
-
search: d.routeSearch
|
|
1139
|
+
search: d.store.routeSearch
|
|
968
1140
|
});
|
|
969
1141
|
|
|
970
1142
|
// Clear idle error states when match leaves
|
|
971
|
-
if (d.status === 'error' && !d.isFetching) {
|
|
972
|
-
d.status = 'idle';
|
|
973
|
-
d.error = undefined;
|
|
1143
|
+
if (d.store.status === 'error' && !d.store.isFetching) {
|
|
1144
|
+
d.store.status = 'idle';
|
|
1145
|
+
d.store.error = undefined;
|
|
974
1146
|
}
|
|
975
|
-
const gc = Math.max(
|
|
1147
|
+
const gc = Math.max(d.options.loaderGcMaxAge ?? router.options.defaultLoaderGcMaxAge ?? 0, d.options.loaderMaxAge ?? router.options.defaultLoaderMaxAge ?? 0);
|
|
976
1148
|
if (gc > 0) {
|
|
977
|
-
|
|
1149
|
+
store.matchCache[d.matchId] = {
|
|
978
1150
|
gc: gc == Infinity ? Number.MAX_SAFE_INTEGER : now + gc,
|
|
979
1151
|
match: d
|
|
980
1152
|
};
|
|
@@ -983,58 +1155,64 @@ function createRouter(userOptions) {
|
|
|
983
1155
|
staying.forEach(d => {
|
|
984
1156
|
d.options.onTransition == null ? void 0 : d.options.onTransition({
|
|
985
1157
|
params: d.params,
|
|
986
|
-
search: d.routeSearch
|
|
1158
|
+
search: d.store.routeSearch
|
|
987
1159
|
});
|
|
988
1160
|
});
|
|
989
1161
|
entering.forEach(d => {
|
|
990
1162
|
d.__.onExit = d.options.onLoaded == null ? void 0 : d.options.onLoaded({
|
|
991
1163
|
params: d.params,
|
|
992
|
-
search: d.search
|
|
1164
|
+
search: d.store.search
|
|
993
1165
|
});
|
|
994
|
-
delete
|
|
1166
|
+
delete store.matchCache[d.matchId];
|
|
995
1167
|
});
|
|
996
|
-
if (
|
|
1168
|
+
if (startedLoadingAt !== startedAt) {
|
|
997
1169
|
// Ignore side-effects of match loading
|
|
998
1170
|
return;
|
|
999
1171
|
}
|
|
1000
1172
|
matches.forEach(match => {
|
|
1001
1173
|
// Clear actions
|
|
1002
1174
|
if (match.action) {
|
|
1175
|
+
// TODO: Check reactivity here
|
|
1003
1176
|
match.action.current = undefined;
|
|
1004
1177
|
match.action.submissions = [];
|
|
1005
1178
|
}
|
|
1006
1179
|
});
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1180
|
+
setStore(s => {
|
|
1181
|
+
console.log('set', matches);
|
|
1182
|
+
Object.assign(s, {
|
|
1183
|
+
status: 'idle',
|
|
1184
|
+
currentLocation: store.latestLocation,
|
|
1185
|
+
currentMatches: matches,
|
|
1186
|
+
pendingLocation: undefined,
|
|
1187
|
+
pendingMatches: undefined
|
|
1188
|
+
});
|
|
1012
1189
|
});
|
|
1013
|
-
|
|
1014
|
-
router.resolveNavigation();
|
|
1190
|
+
resolveNavigation();
|
|
1015
1191
|
},
|
|
1016
1192
|
cleanMatchCache: () => {
|
|
1017
1193
|
const now = Date.now();
|
|
1018
|
-
|
|
1019
|
-
|
|
1194
|
+
setStore(s => {
|
|
1195
|
+
Object.keys(s.matchCache).forEach(matchId => {
|
|
1196
|
+
const entry = s.matchCache[matchId];
|
|
1020
1197
|
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1198
|
+
// Don't remove loading matches
|
|
1199
|
+
if (entry.match.store.status === 'loading') {
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1025
1202
|
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1203
|
+
// Do not remove successful matches that are still valid
|
|
1204
|
+
if (entry.gc > 0 && entry.gc > now) {
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1030
1207
|
|
|
1031
|
-
|
|
1032
|
-
|
|
1208
|
+
// Everything else gets removed
|
|
1209
|
+
delete s.matchCache[matchId];
|
|
1210
|
+
});
|
|
1033
1211
|
});
|
|
1034
1212
|
},
|
|
1035
|
-
loadRoute: async function
|
|
1213
|
+
loadRoute: async function (navigateOpts) {
|
|
1036
1214
|
if (navigateOpts === void 0) {
|
|
1037
|
-
navigateOpts =
|
|
1215
|
+
navigateOpts = store.latestLocation;
|
|
1038
1216
|
}
|
|
1039
1217
|
const next = router.buildNext(navigateOpts);
|
|
1040
1218
|
const matches = router.matchRoutes(next.pathname, {
|
|
@@ -1043,10 +1221,9 @@ function createRouter(userOptions) {
|
|
|
1043
1221
|
await router.loadMatches(matches);
|
|
1044
1222
|
return matches;
|
|
1045
1223
|
},
|
|
1046
|
-
preloadRoute: async function
|
|
1047
|
-
var _ref3, _ref4, _loaderOpts$maxAge, _ref5, _ref6, _loaderOpts$gcMaxAge;
|
|
1224
|
+
preloadRoute: async function (navigateOpts, loaderOpts) {
|
|
1048
1225
|
if (navigateOpts === void 0) {
|
|
1049
|
-
navigateOpts =
|
|
1226
|
+
navigateOpts = store.latestLocation;
|
|
1050
1227
|
}
|
|
1051
1228
|
const next = router.buildNext(navigateOpts);
|
|
1052
1229
|
const matches = router.matchRoutes(next.pathname, {
|
|
@@ -1054,28 +1231,27 @@ function createRouter(userOptions) {
|
|
|
1054
1231
|
});
|
|
1055
1232
|
await router.loadMatches(matches, {
|
|
1056
1233
|
preload: true,
|
|
1057
|
-
maxAge:
|
|
1058
|
-
gcMaxAge:
|
|
1234
|
+
maxAge: loaderOpts.maxAge ?? router.options.defaultPreloadMaxAge ?? router.options.defaultLoaderMaxAge ?? 0,
|
|
1235
|
+
gcMaxAge: loaderOpts.gcMaxAge ?? router.options.defaultPreloadGcMaxAge ?? router.options.defaultLoaderGcMaxAge ?? 0
|
|
1059
1236
|
});
|
|
1060
1237
|
return matches;
|
|
1061
1238
|
},
|
|
1062
1239
|
matchRoutes: (pathname, opts) => {
|
|
1063
|
-
var _router$state$pending3, _router$state$pending4;
|
|
1064
1240
|
router.cleanMatchCache();
|
|
1065
1241
|
const matches = [];
|
|
1066
1242
|
if (!router.routeTree) {
|
|
1067
1243
|
return matches;
|
|
1068
1244
|
}
|
|
1069
|
-
const existingMatches = [...
|
|
1245
|
+
const existingMatches = [...store.currentMatches, ...(store.pendingMatches ?? [])];
|
|
1070
1246
|
const recurse = async routes => {
|
|
1071
|
-
var
|
|
1247
|
+
var _foundRoute$childRout;
|
|
1072
1248
|
const parentMatch = last(matches);
|
|
1073
|
-
let params = (
|
|
1074
|
-
const filteredRoutes = (
|
|
1249
|
+
let params = (parentMatch == null ? void 0 : parentMatch.params) ?? {};
|
|
1250
|
+
const filteredRoutes = (router.options.filterRoutes == null ? void 0 : router.options.filterRoutes(routes)) ?? routes;
|
|
1075
1251
|
let foundRoutes = [];
|
|
1076
1252
|
const findMatchInRoutes = (parentRoutes, routes) => {
|
|
1077
1253
|
routes.some(route => {
|
|
1078
|
-
var _route$childRoutes, _route$childRoutes2
|
|
1254
|
+
var _route$childRoutes, _route$childRoutes2;
|
|
1079
1255
|
if (!route.routePath && (_route$childRoutes = route.childRoutes) != null && _route$childRoutes.length) {
|
|
1080
1256
|
return findMatchInRoutes([...foundRoutes, route], route.childRoutes);
|
|
1081
1257
|
}
|
|
@@ -1083,20 +1259,21 @@ function createRouter(userOptions) {
|
|
|
1083
1259
|
const matchParams = matchPathname(router.basepath, pathname, {
|
|
1084
1260
|
to: route.fullPath,
|
|
1085
1261
|
fuzzy,
|
|
1086
|
-
caseSensitive:
|
|
1262
|
+
caseSensitive: route.options.caseSensitive ?? router.options.caseSensitive
|
|
1087
1263
|
});
|
|
1088
|
-
console.log(router.basepath, route.fullPath, fuzzy, pathname, matchParams);
|
|
1089
1264
|
if (matchParams) {
|
|
1090
1265
|
let parsedParams;
|
|
1091
1266
|
try {
|
|
1092
|
-
|
|
1093
|
-
parsedParams = (_route$options$parseP = route.options.parseParams == null ? void 0 : route.options.parseParams(matchParams)) != null ? _route$options$parseP : matchParams;
|
|
1267
|
+
parsedParams = (route.options.parseParams == null ? void 0 : route.options.parseParams(matchParams)) ?? matchParams;
|
|
1094
1268
|
} catch (err) {
|
|
1095
1269
|
if (opts != null && opts.strictParseParams) {
|
|
1096
1270
|
throw err;
|
|
1097
1271
|
}
|
|
1098
1272
|
}
|
|
1099
|
-
params =
|
|
1273
|
+
params = {
|
|
1274
|
+
...params,
|
|
1275
|
+
...parsedParams
|
|
1276
|
+
};
|
|
1100
1277
|
}
|
|
1101
1278
|
if (!!matchParams) {
|
|
1102
1279
|
foundRoutes = [...parentRoutes, route];
|
|
@@ -1110,10 +1287,10 @@ function createRouter(userOptions) {
|
|
|
1110
1287
|
return;
|
|
1111
1288
|
}
|
|
1112
1289
|
foundRoutes.forEach(foundRoute => {
|
|
1113
|
-
var
|
|
1290
|
+
var _store$matchCache$mat;
|
|
1114
1291
|
const interpolatedPath = interpolatePath(foundRoute.routePath, params);
|
|
1115
1292
|
const matchId = interpolatePath(foundRoute.routeId, params, true);
|
|
1116
|
-
const match = existingMatches.find(d => d.matchId === matchId) || ((
|
|
1293
|
+
const match = existingMatches.find(d => d.matchId === matchId) || ((_store$matchCache$mat = store.matchCache[matchId]) == null ? void 0 : _store$matchCache$mat.match) || createRouteMatch(router, foundRoute, {
|
|
1117
1294
|
parentMatch,
|
|
1118
1295
|
matchId,
|
|
1119
1296
|
params,
|
|
@@ -1127,40 +1304,56 @@ function createRouter(userOptions) {
|
|
|
1127
1304
|
}
|
|
1128
1305
|
};
|
|
1129
1306
|
recurse([router.routeTree]);
|
|
1130
|
-
|
|
1307
|
+
linkMatches(matches);
|
|
1131
1308
|
return matches;
|
|
1132
1309
|
},
|
|
1133
1310
|
loadMatches: async (resolvedMatches, loaderOpts) => {
|
|
1134
|
-
|
|
1135
|
-
var _search$__data;
|
|
1311
|
+
resolvedMatches.forEach(async match => {
|
|
1136
1312
|
// Validate the match (loads search params etc)
|
|
1137
1313
|
match.__.validate();
|
|
1138
|
-
|
|
1314
|
+
});
|
|
1315
|
+
|
|
1316
|
+
// Check each match middleware to see if the route can be accessed
|
|
1317
|
+
await Promise.all(resolvedMatches.map(async match => {
|
|
1318
|
+
try {
|
|
1319
|
+
await (match.options.beforeLoad == null ? void 0 : match.options.beforeLoad({
|
|
1320
|
+
router: router,
|
|
1321
|
+
match
|
|
1322
|
+
}));
|
|
1323
|
+
} catch (err) {
|
|
1324
|
+
if (!(loaderOpts != null && loaderOpts.preload)) {
|
|
1325
|
+
match.options.onLoadError == null ? void 0 : match.options.onLoadError(err);
|
|
1326
|
+
}
|
|
1327
|
+
throw err;
|
|
1328
|
+
}
|
|
1329
|
+
}));
|
|
1330
|
+
const matchPromises = resolvedMatches.map(async match => {
|
|
1331
|
+
var _search$__data;
|
|
1332
|
+
const search = match.store.search;
|
|
1139
1333
|
if ((_search$__data = search.__data) != null && _search$__data.matchId && search.__data.matchId !== match.matchId) {
|
|
1140
1334
|
return;
|
|
1141
1335
|
}
|
|
1142
1336
|
match.load(loaderOpts);
|
|
1143
|
-
if (match.status !== 'success' && match.__.loadPromise) {
|
|
1337
|
+
if (match.store.status !== 'success' && match.__.loadPromise) {
|
|
1144
1338
|
// Wait for the first sign of activity from the match
|
|
1145
1339
|
await match.__.loadPromise;
|
|
1146
1340
|
}
|
|
1147
1341
|
});
|
|
1148
|
-
router.notify();
|
|
1149
1342
|
await Promise.all(matchPromises);
|
|
1150
1343
|
},
|
|
1151
1344
|
loadMatchData: async routeMatch => {
|
|
1152
1345
|
if (isServer || !router.options.useServerData) {
|
|
1153
|
-
|
|
1154
|
-
return (_await$routeMatch$opt = await (routeMatch.options.loader == null ? void 0 : routeMatch.options.loader({
|
|
1346
|
+
return (await (routeMatch.options.loader == null ? void 0 : routeMatch.options.loader({
|
|
1155
1347
|
// parentLoaderPromise: routeMatch.parentMatch?.__.dataPromise,
|
|
1156
1348
|
params: routeMatch.params,
|
|
1157
|
-
search: routeMatch.routeSearch,
|
|
1349
|
+
search: routeMatch.store.routeSearch,
|
|
1158
1350
|
signal: routeMatch.__.abortController.signal
|
|
1159
|
-
})))
|
|
1351
|
+
}))) || {};
|
|
1160
1352
|
} else {
|
|
1161
1353
|
const next = router.buildNext({
|
|
1162
1354
|
to: '.',
|
|
1163
|
-
search: d =>
|
|
1355
|
+
search: d => ({
|
|
1356
|
+
...(d ?? {}),
|
|
1164
1357
|
__data: {
|
|
1165
1358
|
matchId: routeMatch.matchId
|
|
1166
1359
|
}
|
|
@@ -1189,16 +1382,15 @@ function createRouter(userOptions) {
|
|
|
1189
1382
|
}
|
|
1190
1383
|
},
|
|
1191
1384
|
invalidateRoute: opts => {
|
|
1192
|
-
var _router$state$pending5, _router$state$pending6;
|
|
1193
1385
|
const next = router.buildNext(opts);
|
|
1194
1386
|
const unloadedMatchIds = router.matchRoutes(next.pathname).map(d => d.matchId);
|
|
1195
|
-
[...
|
|
1387
|
+
[...store.currentMatches, ...(store.pendingMatches ?? [])].forEach(match => {
|
|
1196
1388
|
if (unloadedMatchIds.includes(match.matchId)) {
|
|
1197
1389
|
match.invalidate();
|
|
1198
1390
|
}
|
|
1199
1391
|
});
|
|
1200
1392
|
},
|
|
1201
|
-
reload: () =>
|
|
1393
|
+
reload: () => navigate({
|
|
1202
1394
|
fromCurrent: true,
|
|
1203
1395
|
replace: true,
|
|
1204
1396
|
search: true
|
|
@@ -1207,27 +1399,28 @@ function createRouter(userOptions) {
|
|
|
1207
1399
|
return resolvePath(router.basepath, from, cleanPath(path));
|
|
1208
1400
|
},
|
|
1209
1401
|
matchRoute: (location, opts) => {
|
|
1210
|
-
var _location$from;
|
|
1211
1402
|
// const location = router.buildNext(opts)
|
|
1212
1403
|
|
|
1213
|
-
location =
|
|
1214
|
-
|
|
1215
|
-
|
|
1404
|
+
location = {
|
|
1405
|
+
...location,
|
|
1406
|
+
to: location.to ? router.resolvePath(location.from ?? '', location.to) : undefined
|
|
1407
|
+
};
|
|
1216
1408
|
const next = router.buildNext(location);
|
|
1217
1409
|
if (opts != null && opts.pending) {
|
|
1218
|
-
|
|
1219
|
-
if (!((_router$state$pending7 = router.state.pending) != null && _router$state$pending7.location)) {
|
|
1410
|
+
if (!store.pendingLocation) {
|
|
1220
1411
|
return false;
|
|
1221
1412
|
}
|
|
1222
|
-
return !!matchPathname(router.basepath,
|
|
1413
|
+
return !!matchPathname(router.basepath, store.pendingLocation.pathname, {
|
|
1414
|
+
...opts,
|
|
1223
1415
|
to: next.pathname
|
|
1224
|
-
})
|
|
1416
|
+
});
|
|
1225
1417
|
}
|
|
1226
|
-
return
|
|
1418
|
+
return matchPathname(router.basepath, store.currentLocation.pathname, {
|
|
1419
|
+
...opts,
|
|
1227
1420
|
to: next.pathname
|
|
1228
|
-
})
|
|
1421
|
+
});
|
|
1229
1422
|
},
|
|
1230
|
-
navigate: async
|
|
1423
|
+
navigate: async _ref => {
|
|
1231
1424
|
let {
|
|
1232
1425
|
from,
|
|
1233
1426
|
to = '.',
|
|
@@ -1235,7 +1428,7 @@ function createRouter(userOptions) {
|
|
|
1235
1428
|
hash,
|
|
1236
1429
|
replace,
|
|
1237
1430
|
params
|
|
1238
|
-
} =
|
|
1431
|
+
} = _ref;
|
|
1239
1432
|
// If this link simply reloads the current route,
|
|
1240
1433
|
// make sure it has a new key so it will trigger a data refresh
|
|
1241
1434
|
|
|
@@ -1245,11 +1438,11 @@ function createRouter(userOptions) {
|
|
|
1245
1438
|
const fromString = String(from);
|
|
1246
1439
|
let isExternal;
|
|
1247
1440
|
try {
|
|
1248
|
-
new URL(
|
|
1441
|
+
new URL(`${toString}`);
|
|
1249
1442
|
isExternal = true;
|
|
1250
1443
|
} catch (e) {}
|
|
1251
1444
|
invariant(!isExternal, 'Attempting to navigate to external url with router.navigate!');
|
|
1252
|
-
return
|
|
1445
|
+
return navigate({
|
|
1253
1446
|
from: fromString,
|
|
1254
1447
|
to: toString,
|
|
1255
1448
|
search,
|
|
@@ -1258,8 +1451,7 @@ function createRouter(userOptions) {
|
|
|
1258
1451
|
params
|
|
1259
1452
|
});
|
|
1260
1453
|
},
|
|
1261
|
-
buildLink:
|
|
1262
|
-
var _preload, _ref9;
|
|
1454
|
+
buildLink: _ref2 => {
|
|
1263
1455
|
let {
|
|
1264
1456
|
from,
|
|
1265
1457
|
to = '.',
|
|
@@ -1274,7 +1466,7 @@ function createRouter(userOptions) {
|
|
|
1274
1466
|
preloadGcMaxAge: userPreloadGcMaxAge,
|
|
1275
1467
|
preloadDelay: userPreloadDelay,
|
|
1276
1468
|
disabled
|
|
1277
|
-
} =
|
|
1469
|
+
} = _ref2;
|
|
1278
1470
|
// If this link simply reloads the current route,
|
|
1279
1471
|
// make sure it has a new key so it will trigger a data refresh
|
|
1280
1472
|
|
|
@@ -1282,7 +1474,7 @@ function createRouter(userOptions) {
|
|
|
1282
1474
|
// null for LinkUtils
|
|
1283
1475
|
|
|
1284
1476
|
try {
|
|
1285
|
-
new URL(
|
|
1477
|
+
new URL(`${to}`);
|
|
1286
1478
|
return {
|
|
1287
1479
|
type: 'external',
|
|
1288
1480
|
href: to
|
|
@@ -1297,15 +1489,15 @@ function createRouter(userOptions) {
|
|
|
1297
1489
|
replace
|
|
1298
1490
|
};
|
|
1299
1491
|
const next = router.buildNext(nextOpts);
|
|
1300
|
-
preload =
|
|
1301
|
-
const preloadDelay =
|
|
1492
|
+
preload = preload ?? router.options.defaultPreload;
|
|
1493
|
+
const preloadDelay = userPreloadDelay ?? router.options.defaultPreloadDelay ?? 0;
|
|
1302
1494
|
|
|
1303
1495
|
// Compare path/hash for matches
|
|
1304
|
-
const pathIsEqual =
|
|
1305
|
-
const currentPathSplit =
|
|
1496
|
+
const pathIsEqual = store.currentLocation.pathname === next.pathname;
|
|
1497
|
+
const currentPathSplit = store.currentLocation.pathname.split('/');
|
|
1306
1498
|
const nextPathSplit = next.pathname.split('/');
|
|
1307
1499
|
const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
|
|
1308
|
-
const hashIsEqual =
|
|
1500
|
+
const hashIsEqual = store.currentLocation.hash === next.hash;
|
|
1309
1501
|
// Combine the matches based on user options
|
|
1310
1502
|
const pathTest = activeOptions != null && activeOptions.exact ? pathIsEqual : pathIsFuzzyEqual;
|
|
1311
1503
|
const hashTest = activeOptions != null && activeOptions.includeHash ? hashIsEqual : true;
|
|
@@ -1321,8 +1513,8 @@ function createRouter(userOptions) {
|
|
|
1321
1513
|
router.invalidateRoute(nextOpts);
|
|
1322
1514
|
}
|
|
1323
1515
|
|
|
1324
|
-
// All is well? Navigate!
|
|
1325
|
-
|
|
1516
|
+
// All is well? Navigate!
|
|
1517
|
+
navigate(nextOpts);
|
|
1326
1518
|
}
|
|
1327
1519
|
};
|
|
1328
1520
|
|
|
@@ -1332,6 +1524,9 @@ function createRouter(userOptions) {
|
|
|
1332
1524
|
router.preloadRoute(nextOpts, {
|
|
1333
1525
|
maxAge: userPreloadMaxAge,
|
|
1334
1526
|
gcMaxAge: userPreloadGcMaxAge
|
|
1527
|
+
}).catch(err => {
|
|
1528
|
+
console.log(err);
|
|
1529
|
+
console.warn('Error preloading route! ☝️');
|
|
1335
1530
|
});
|
|
1336
1531
|
}
|
|
1337
1532
|
};
|
|
@@ -1346,6 +1541,9 @@ function createRouter(userOptions) {
|
|
|
1346
1541
|
router.preloadRoute(nextOpts, {
|
|
1347
1542
|
maxAge: userPreloadMaxAge,
|
|
1348
1543
|
gcMaxAge: userPreloadGcMaxAge
|
|
1544
|
+
}).catch(err => {
|
|
1545
|
+
console.log(err);
|
|
1546
|
+
console.warn('Error preloading route! ☝️');
|
|
1349
1547
|
});
|
|
1350
1548
|
}, preloadDelay);
|
|
1351
1549
|
}
|
|
@@ -1369,143 +1567,15 @@ function createRouter(userOptions) {
|
|
|
1369
1567
|
};
|
|
1370
1568
|
},
|
|
1371
1569
|
buildNext: opts => {
|
|
1372
|
-
const next =
|
|
1570
|
+
const next = buildLocation(opts);
|
|
1373
1571
|
const matches = router.matchRoutes(next.pathname);
|
|
1374
|
-
const __preSearchFilters = matches.map(match =>
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
const __postSearchFilters = matches.map(match => {
|
|
1379
|
-
var _match$options$postSe;
|
|
1380
|
-
return (_match$options$postSe = match.options.postSearchFilters) != null ? _match$options$postSe : [];
|
|
1381
|
-
}).flat().filter(Boolean);
|
|
1382
|
-
return router.__.buildLocation(_extends({}, opts, {
|
|
1572
|
+
const __preSearchFilters = matches.map(match => match.options.preSearchFilters ?? []).flat().filter(Boolean);
|
|
1573
|
+
const __postSearchFilters = matches.map(match => match.options.postSearchFilters ?? []).flat().filter(Boolean);
|
|
1574
|
+
return buildLocation({
|
|
1575
|
+
...opts,
|
|
1383
1576
|
__preSearchFilters,
|
|
1384
1577
|
__postSearchFilters
|
|
1385
|
-
})
|
|
1386
|
-
},
|
|
1387
|
-
__: {
|
|
1388
|
-
buildRouteTree: rootRouteConfig => {
|
|
1389
|
-
const recurseRoutes = (routeConfigs, parent) => {
|
|
1390
|
-
return routeConfigs.map(routeConfig => {
|
|
1391
|
-
const routeOptions = routeConfig.options;
|
|
1392
|
-
const route = createRoute(routeConfig, routeOptions, parent, router);
|
|
1393
|
-
const existingRoute = router.routesById[route.routeId];
|
|
1394
|
-
if (existingRoute) {
|
|
1395
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
1396
|
-
console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
|
|
1397
|
-
}
|
|
1398
|
-
throw new Error();
|
|
1399
|
-
}
|
|
1400
|
-
router.routesById[route.routeId] = route;
|
|
1401
|
-
const children = routeConfig.children;
|
|
1402
|
-
route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
|
|
1403
|
-
return route;
|
|
1404
|
-
});
|
|
1405
|
-
};
|
|
1406
|
-
const routes = recurseRoutes([rootRouteConfig]);
|
|
1407
|
-
return routes[0];
|
|
1408
|
-
},
|
|
1409
|
-
parseLocation: (location, previousLocation) => {
|
|
1410
|
-
var _location$hash$split$;
|
|
1411
|
-
const parsedSearch = router.options.parseSearch(location.search);
|
|
1412
|
-
return {
|
|
1413
|
-
pathname: location.pathname,
|
|
1414
|
-
searchStr: location.search,
|
|
1415
|
-
search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
|
|
1416
|
-
hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
|
|
1417
|
-
href: "" + location.pathname + location.search + location.hash,
|
|
1418
|
-
state: location.state,
|
|
1419
|
-
key: location.key
|
|
1420
|
-
};
|
|
1421
|
-
},
|
|
1422
|
-
navigate: location => {
|
|
1423
|
-
const next = router.buildNext(location);
|
|
1424
|
-
return router.__.commitLocation(next, location.replace);
|
|
1425
|
-
},
|
|
1426
|
-
buildLocation: function buildLocation(dest) {
|
|
1427
|
-
var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
|
|
1428
|
-
if (dest === void 0) {
|
|
1429
|
-
dest = {};
|
|
1430
|
-
}
|
|
1431
|
-
const fromPathname = dest.fromCurrent ? router.__location.pathname : (_dest$from = dest.from) != null ? _dest$from : router.__location.pathname;
|
|
1432
|
-
let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
|
|
1433
|
-
const fromMatches = router.matchRoutes(router.__location.pathname, {
|
|
1434
|
-
strictParseParams: true
|
|
1435
|
-
});
|
|
1436
|
-
const toMatches = router.matchRoutes(pathname);
|
|
1437
|
-
const prevParams = _extends({}, (_last = last(fromMatches)) == null ? void 0 : _last.params);
|
|
1438
|
-
let nextParams = ((_dest$params = dest.params) != null ? _dest$params : true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
|
|
1439
|
-
if (nextParams) {
|
|
1440
|
-
toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
|
|
1441
|
-
Object.assign({}, nextParams, fn(nextParams));
|
|
1442
|
-
});
|
|
1443
|
-
}
|
|
1444
|
-
pathname = interpolatePath(pathname, nextParams != null ? nextParams : {});
|
|
1445
|
-
|
|
1446
|
-
// Pre filters first
|
|
1447
|
-
const preFilteredSearch = (_dest$__preSearchFilt = dest.__preSearchFilters) != null && _dest$__preSearchFilt.length ? dest.__preSearchFilters.reduce((prev, next) => next(prev), router.__location.search) : router.__location.search;
|
|
1448
|
-
|
|
1449
|
-
// Then the link/navigate function
|
|
1450
|
-
const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
|
|
1451
|
-
: dest.search ? (_functionalUpdate = functionalUpdate(dest.search, preFilteredSearch)) != null ? _functionalUpdate : {} // Updater
|
|
1452
|
-
: (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
|
|
1453
|
-
: {};
|
|
1454
|
-
|
|
1455
|
-
// Then post filters
|
|
1456
|
-
const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
|
|
1457
|
-
const search = replaceEqualDeep(router.__location.search, postFilteredSearch);
|
|
1458
|
-
const searchStr = router.options.stringifySearch(search);
|
|
1459
|
-
let hash = dest.hash === true ? router.__location.hash : functionalUpdate(dest.hash, router.__location.hash);
|
|
1460
|
-
hash = hash ? "#" + hash : '';
|
|
1461
|
-
return {
|
|
1462
|
-
pathname,
|
|
1463
|
-
search,
|
|
1464
|
-
searchStr,
|
|
1465
|
-
state: router.__location.state,
|
|
1466
|
-
hash,
|
|
1467
|
-
href: "" + pathname + searchStr + hash,
|
|
1468
|
-
key: dest.key
|
|
1469
|
-
};
|
|
1470
|
-
},
|
|
1471
|
-
commitLocation: (next, replace) => {
|
|
1472
|
-
const id = '' + Date.now() + Math.random();
|
|
1473
|
-
if (router.navigateTimeout) clearTimeout(router.navigateTimeout);
|
|
1474
|
-
let nextAction = 'replace';
|
|
1475
|
-
if (!replace) {
|
|
1476
|
-
nextAction = 'push';
|
|
1477
|
-
}
|
|
1478
|
-
const isSameUrl = router.__.parseLocation(history.location).href === next.href;
|
|
1479
|
-
if (isSameUrl && !next.key) {
|
|
1480
|
-
nextAction = 'replace';
|
|
1481
|
-
}
|
|
1482
|
-
if (nextAction === 'replace') {
|
|
1483
|
-
history.replace({
|
|
1484
|
-
pathname: next.pathname,
|
|
1485
|
-
hash: next.hash,
|
|
1486
|
-
search: next.searchStr
|
|
1487
|
-
}, _extends({
|
|
1488
|
-
id
|
|
1489
|
-
}, next.state));
|
|
1490
|
-
} else {
|
|
1491
|
-
history.push({
|
|
1492
|
-
pathname: next.pathname,
|
|
1493
|
-
hash: next.hash,
|
|
1494
|
-
search: next.searchStr
|
|
1495
|
-
}, {
|
|
1496
|
-
id
|
|
1497
|
-
});
|
|
1498
|
-
}
|
|
1499
|
-
router.navigationPromise = new Promise(resolve => {
|
|
1500
|
-
const previousNavigationResolve = router.resolveNavigation;
|
|
1501
|
-
router.resolveNavigation = () => {
|
|
1502
|
-
previousNavigationResolve();
|
|
1503
|
-
resolve();
|
|
1504
|
-
delete router.navigationPromise;
|
|
1505
|
-
};
|
|
1506
|
-
});
|
|
1507
|
-
return router.navigationPromise;
|
|
1508
|
-
}
|
|
1578
|
+
});
|
|
1509
1579
|
}
|
|
1510
1580
|
};
|
|
1511
1581
|
router.update(userOptions);
|
|
@@ -1517,14 +1587,16 @@ function createRouter(userOptions) {
|
|
|
1517
1587
|
function isCtrlEvent(e) {
|
|
1518
1588
|
return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
|
|
1519
1589
|
}
|
|
1520
|
-
function
|
|
1590
|
+
function linkMatches(matches) {
|
|
1521
1591
|
matches.forEach((match, index) => {
|
|
1522
1592
|
const parent = matches[index - 1];
|
|
1523
1593
|
if (parent) {
|
|
1524
|
-
match.
|
|
1594
|
+
match.__.setParentMatch(parent);
|
|
1595
|
+
} else {
|
|
1596
|
+
match.__.setParentMatch(undefined);
|
|
1525
1597
|
}
|
|
1526
1598
|
});
|
|
1527
1599
|
}
|
|
1528
1600
|
|
|
1529
|
-
export { cleanPath, createRoute, createRouteConfig, createRouteMatch, createRouter, decode, defaultParseSearch, defaultStringifySearch, encode, functionalUpdate, interpolatePath, joinPaths, last, matchByPath, matchPathname, parsePathname, parseSearchWith, pick,
|
|
1601
|
+
export { cleanPath, createRoute, createRouteConfig, createRouteMatch, createRouter, decode, defaultParseSearch, defaultStringifySearch, encode, functionalUpdate, interpolatePath, joinPaths, last, matchByPath, matchPathname, parsePathname, parseSearchWith, pick, resolvePath, rootRouteId, sharedClone, stringifySearchWith, trimPath, trimPathLeft, trimPathRight, warning };
|
|
1530
1602
|
//# sourceMappingURL=index.js.map
|