@tanstack/router-core 0.0.1-beta.4 → 0.0.1-beta.41

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.
Files changed (61) hide show
  1. package/build/cjs/{packages/router-core/src/index.js → index.js} +25 -8
  2. package/build/cjs/{packages/router-core/src/index.js.map → index.js.map} +1 -1
  3. package/build/cjs/{packages/router-core/src/path.js → path.js} +19 -43
  4. package/build/cjs/path.js.map +1 -0
  5. package/build/cjs/{packages/router-core/src/qss.js → qss.js} +8 -13
  6. package/build/cjs/qss.js.map +1 -0
  7. package/build/cjs/route.js +155 -0
  8. package/build/cjs/route.js.map +1 -0
  9. package/build/cjs/{packages/router-core/src/routeConfig.js → routeConfig.js} +14 -13
  10. package/build/cjs/routeConfig.js.map +1 -0
  11. package/build/cjs/routeMatch.js +242 -0
  12. package/build/cjs/routeMatch.js.map +1 -0
  13. package/build/cjs/router.js +807 -0
  14. package/build/cjs/router.js.map +1 -0
  15. package/build/cjs/{packages/router-core/src/searchParams.js → searchParams.js} +10 -12
  16. package/build/cjs/searchParams.js.map +1 -0
  17. package/build/cjs/sharedClone.js +122 -0
  18. package/build/cjs/sharedClone.js.map +1 -0
  19. package/build/cjs/utils.js +47 -0
  20. package/build/cjs/utils.js.map +1 -0
  21. package/build/esm/index.js +890 -1739
  22. package/build/esm/index.js.map +1 -1
  23. package/build/stats-html.html +59 -49
  24. package/build/stats-react.json +196 -178
  25. package/build/types/index.d.ts +287 -283
  26. package/build/umd/index.development.js +1233 -922
  27. package/build/umd/index.development.js.map +1 -1
  28. package/build/umd/index.production.js +1 -1
  29. package/build/umd/index.production.js.map +1 -1
  30. package/package.json +4 -2
  31. package/src/frameworks.ts +2 -2
  32. package/src/index.ts +1 -1
  33. package/src/link.ts +86 -43
  34. package/src/path.ts +12 -8
  35. package/src/route.ts +170 -158
  36. package/src/routeConfig.ts +105 -77
  37. package/src/routeInfo.ts +26 -8
  38. package/src/routeMatch.ts +204 -217
  39. package/src/router.ts +680 -503
  40. package/src/sharedClone.ts +118 -0
  41. package/src/utils.ts +14 -72
  42. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +0 -33
  43. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +0 -1
  44. package/build/cjs/node_modules/@babel/runtime/helpers/esm/extends.js +0 -33
  45. package/build/cjs/node_modules/@babel/runtime/helpers/esm/extends.js.map +0 -1
  46. package/build/cjs/node_modules/history/index.js +0 -815
  47. package/build/cjs/node_modules/history/index.js.map +0 -1
  48. package/build/cjs/node_modules/tiny-invariant/dist/esm/tiny-invariant.js +0 -30
  49. package/build/cjs/node_modules/tiny-invariant/dist/esm/tiny-invariant.js.map +0 -1
  50. package/build/cjs/packages/router-core/src/path.js.map +0 -1
  51. package/build/cjs/packages/router-core/src/qss.js.map +0 -1
  52. package/build/cjs/packages/router-core/src/route.js +0 -161
  53. package/build/cjs/packages/router-core/src/route.js.map +0 -1
  54. package/build/cjs/packages/router-core/src/routeConfig.js.map +0 -1
  55. package/build/cjs/packages/router-core/src/routeMatch.js +0 -266
  56. package/build/cjs/packages/router-core/src/routeMatch.js.map +0 -1
  57. package/build/cjs/packages/router-core/src/router.js +0 -789
  58. package/build/cjs/packages/router-core/src/router.js.map +0 -1
  59. package/build/cjs/packages/router-core/src/searchParams.js.map +0 -1
  60. package/build/cjs/packages/router-core/src/utils.js +0 -118
  61. package/build/cjs/packages/router-core/src/utils.js.map +0 -1
@@ -0,0 +1,807 @@
1
+ /**
2
+ * router-core
3
+ *
4
+ * Copyright (c) TanStack
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE.md file in the root directory of this source tree.
8
+ *
9
+ * @license MIT
10
+ */
11
+ 'use strict';
12
+
13
+ Object.defineProperty(exports, '__esModule', { value: true });
14
+
15
+ var history = require('history');
16
+ var invariant = require('tiny-invariant');
17
+ var path = require('./path.js');
18
+ var route = require('./route.js');
19
+ var routeMatch = require('./routeMatch.js');
20
+ var searchParams = require('./searchParams.js');
21
+ var reactivity = require('@solidjs/reactivity');
22
+ var utils = require('./utils.js');
23
+ var sharedClone = require('./sharedClone.js');
24
+
25
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
26
+
27
+ var invariant__default = /*#__PURE__*/_interopDefaultLegacy(invariant);
28
+
29
+ var _window$document;
30
+ // Detect if we're in the DOM
31
+ const isServer = typeof window === 'undefined' || !((_window$document = window.document) != null && _window$document.createElement);
32
+
33
+ // This is the default history object if none is defined
34
+ const createDefaultHistory = () => isServer ? history.createMemoryHistory() : history.createBrowserHistory();
35
+ function getInitialRouterState() {
36
+ return {
37
+ status: 'idle',
38
+ latestLocation: null,
39
+ currentLocation: null,
40
+ currentMatches: [],
41
+ actions: {},
42
+ loaders: {},
43
+ lastUpdated: Date.now(),
44
+ matchCache: {},
45
+ get isFetching() {
46
+ return this.status === 'loading' || this.currentMatches.some(d => d.store.isFetching);
47
+ },
48
+ get isPreloading() {
49
+ return Object.values(this.matchCache).some(d => d.match.store.isFetching && !this.currentMatches.find(dd => dd.matchId === d.match.matchId));
50
+ }
51
+ };
52
+ }
53
+ function createRouter(userOptions) {
54
+ const originalOptions = {
55
+ defaultLoaderGcMaxAge: 5 * 60 * 1000,
56
+ defaultLoaderMaxAge: 0,
57
+ defaultPreloadMaxAge: 2000,
58
+ defaultPreloadDelay: 50,
59
+ context: undefined,
60
+ ...userOptions,
61
+ stringifySearch: (userOptions == null ? void 0 : userOptions.stringifySearch) ?? searchParams.defaultStringifySearch,
62
+ parseSearch: (userOptions == null ? void 0 : userOptions.parseSearch) ?? searchParams.defaultParseSearch
63
+ };
64
+ const [store, setStore] = reactivity.createStore(getInitialRouterState());
65
+ let navigationPromise;
66
+ let startedLoadingAt = Date.now();
67
+ let resolveNavigation = () => {};
68
+ function onFocus() {
69
+ router.load();
70
+ }
71
+ function buildRouteTree(rootRouteConfig) {
72
+ const recurseRoutes = (routeConfigs, parent) => {
73
+ return routeConfigs.map((routeConfig, i) => {
74
+ const routeOptions = routeConfig.options;
75
+ const route$1 = route.createRoute(routeConfig, routeOptions, i, parent, router);
76
+ const existingRoute = router.routesById[route$1.routeId];
77
+ if (existingRoute) {
78
+ if (process.env.NODE_ENV !== 'production') {
79
+ console.warn(`Duplicate routes found with id: ${String(route$1.routeId)}`, router.routesById, route$1);
80
+ }
81
+ throw new Error();
82
+ }
83
+ router.routesById[route$1.routeId] = route$1;
84
+ const children = routeConfig.children;
85
+ route$1.childRoutes = children != null && children.length ? recurseRoutes(children, route$1) : undefined;
86
+ return route$1;
87
+ });
88
+ };
89
+ const routes = recurseRoutes([rootRouteConfig]);
90
+ return routes[0];
91
+ }
92
+ function parseLocation(location, previousLocation) {
93
+ const parsedSearch = router.options.parseSearch(location.search);
94
+ return {
95
+ pathname: location.pathname,
96
+ searchStr: location.search,
97
+ search: sharedClone.sharedClone(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
98
+ hash: location.hash.split('#').reverse()[0] ?? '',
99
+ href: `${location.pathname}${location.search}${location.hash}`,
100
+ state: location.state,
101
+ key: location.key
102
+ };
103
+ }
104
+ function navigate(location) {
105
+ const next = router.buildNext(location);
106
+ return commitLocation(next, location.replace);
107
+ }
108
+ function buildLocation(dest) {
109
+ var _last, _dest$__preSearchFilt, _dest$__preSearchFilt2, _dest$__postSearchFil;
110
+ if (dest === void 0) {
111
+ dest = {};
112
+ }
113
+ const fromPathname = dest.fromCurrent ? store.latestLocation.pathname : dest.from ?? store.latestLocation.pathname;
114
+ let pathname = path.resolvePath(router.basepath ?? '/', fromPathname, `${dest.to ?? '.'}`);
115
+ const fromMatches = router.matchRoutes(store.latestLocation.pathname, {
116
+ strictParseParams: true
117
+ });
118
+ const toMatches = router.matchRoutes(pathname);
119
+ const prevParams = {
120
+ ...((_last = utils.last(fromMatches)) == null ? void 0 : _last.params)
121
+ };
122
+ let nextParams = (dest.params ?? true) === true ? prevParams : utils.functionalUpdate(dest.params, prevParams);
123
+ if (nextParams) {
124
+ toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
125
+ Object.assign({}, nextParams, fn(nextParams));
126
+ });
127
+ }
128
+ pathname = path.interpolatePath(pathname, nextParams ?? {});
129
+
130
+ // Pre filters first
131
+ const preFilteredSearch = (_dest$__preSearchFilt = dest.__preSearchFilters) != null && _dest$__preSearchFilt.length ? dest.__preSearchFilters.reduce((prev, next) => next(prev), store.latestLocation.search) : store.latestLocation.search;
132
+
133
+ // Then the link/navigate function
134
+ const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
135
+ : dest.search ? utils.functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
136
+ : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
137
+ : {};
138
+
139
+ // Then post filters
140
+ const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
141
+ const search = sharedClone.sharedClone(store.latestLocation.search, postFilteredSearch);
142
+ const searchStr = router.options.stringifySearch(search);
143
+ let hash = dest.hash === true ? store.latestLocation.hash : utils.functionalUpdate(dest.hash, store.latestLocation.hash);
144
+ hash = hash ? `#${hash}` : '';
145
+ return {
146
+ pathname,
147
+ search,
148
+ searchStr,
149
+ state: store.latestLocation.state,
150
+ hash,
151
+ href: `${pathname}${searchStr}${hash}`,
152
+ key: dest.key
153
+ };
154
+ }
155
+ function commitLocation(next, replace) {
156
+ const id = '' + Date.now() + Math.random();
157
+ let nextAction = 'replace';
158
+ if (!replace) {
159
+ nextAction = 'push';
160
+ }
161
+ const isSameUrl = parseLocation(router.history.location).href === next.href;
162
+ if (isSameUrl && !next.key) {
163
+ nextAction = 'replace';
164
+ }
165
+ router.history[nextAction]({
166
+ pathname: next.pathname,
167
+ hash: next.hash,
168
+ search: next.searchStr
169
+ }, {
170
+ id,
171
+ ...next.state
172
+ });
173
+ return navigationPromise = new Promise(resolve => {
174
+ const previousNavigationResolve = resolveNavigation;
175
+ resolveNavigation = () => {
176
+ previousNavigationResolve();
177
+ resolve();
178
+ };
179
+ });
180
+ }
181
+ const router = {
182
+ types: undefined,
183
+ // public api
184
+ history: (userOptions == null ? void 0 : userOptions.history) || createDefaultHistory(),
185
+ store,
186
+ setStore,
187
+ options: originalOptions,
188
+ basepath: '',
189
+ routeTree: undefined,
190
+ routesById: {},
191
+ reset: () => {
192
+ setStore(s => Object.assign(s, getInitialRouterState()));
193
+ },
194
+ getRoute: id => {
195
+ return router.routesById[id];
196
+ },
197
+ dehydrate: () => {
198
+ return {
199
+ store: {
200
+ ...utils.pick(store, ['latestLocation', 'currentLocation', 'status', 'lastUpdated']),
201
+ currentMatches: store.currentMatches.map(match => ({
202
+ matchId: match.matchId,
203
+ store: utils.pick(match.store, ['status', 'routeLoaderData', 'isInvalid', 'invalidAt'])
204
+ }))
205
+ },
206
+ context: router.options.context
207
+ };
208
+ },
209
+ hydrate: dehydratedRouter => {
210
+ setStore(s => {
211
+ // Update the context TODO: make this part of state?
212
+ router.options.context = dehydratedRouter.context;
213
+
214
+ // Match the routes
215
+ const currentMatches = router.matchRoutes(dehydratedRouter.store.latestLocation.pathname, {
216
+ strictParseParams: true
217
+ });
218
+ currentMatches.forEach((match, index) => {
219
+ const dehydratedMatch = dehydratedRouter.store.currentMatches[index];
220
+ invariant__default["default"](dehydratedMatch && dehydratedMatch.matchId === match.matchId, 'Oh no! There was a hydration mismatch when attempting to restore the state of the router! 😬');
221
+ Object.assign(match, dehydratedMatch);
222
+ });
223
+ currentMatches.forEach(match => match.__.validate());
224
+ Object.assign(s, {
225
+ ...dehydratedRouter.store,
226
+ currentMatches
227
+ });
228
+ });
229
+ },
230
+ mount: () => {
231
+ // Mount only does anything on the client
232
+ if (!isServer) {
233
+ // If the router matches are empty, load the matches
234
+ if (!store.currentMatches.length) {
235
+ router.load();
236
+ }
237
+ const unsub = router.history.listen(event => {
238
+ router.load(parseLocation(event.location, store.latestLocation));
239
+ });
240
+
241
+ // addEventListener does not exist in React Native, but window does
242
+ // In the future, we might need to invert control here for more adapters
243
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
244
+ if (window.addEventListener) {
245
+ // Listen to visibilitychange and focus
246
+ window.addEventListener('visibilitychange', onFocus, false);
247
+ window.addEventListener('focus', onFocus, false);
248
+ }
249
+ return () => {
250
+ unsub();
251
+ if (window.removeEventListener) {
252
+ // Be sure to unsubscribe if a new handler is set
253
+ window.removeEventListener('visibilitychange', onFocus);
254
+ window.removeEventListener('focus', onFocus);
255
+ }
256
+ };
257
+ }
258
+ return () => {};
259
+ },
260
+ update: opts => {
261
+ const newHistory = (opts == null ? void 0 : opts.history) !== router.history;
262
+ if (!store.latestLocation || newHistory) {
263
+ if (opts != null && opts.history) {
264
+ router.history = opts.history;
265
+ }
266
+ setStore(s => {
267
+ s.latestLocation = parseLocation(router.history.location);
268
+ s.currentLocation = s.latestLocation;
269
+ });
270
+ }
271
+ Object.assign(router.options, opts);
272
+ const {
273
+ basepath,
274
+ routeConfig
275
+ } = router.options;
276
+ router.basepath = `/${path.trimPath(basepath ?? '') ?? ''}`;
277
+ if (routeConfig) {
278
+ router.routesById = {};
279
+ router.routeTree = buildRouteTree(routeConfig);
280
+ }
281
+ return router;
282
+ },
283
+ cancelMatches: () => {
284
+ [...store.currentMatches, ...(store.pendingMatches || [])].forEach(match => {
285
+ match.cancel();
286
+ });
287
+ },
288
+ load: async next => {
289
+ let now = Date.now();
290
+ const startedAt = now;
291
+ startedLoadingAt = startedAt;
292
+
293
+ // Cancel any pending matches
294
+ router.cancelMatches();
295
+ let matches;
296
+ reactivity.batch(() => {
297
+ if (next) {
298
+ // Ingest the new location
299
+ setStore(s => {
300
+ s.latestLocation = next;
301
+ });
302
+ }
303
+
304
+ // Match the routes
305
+ matches = router.matchRoutes(store.latestLocation.pathname, {
306
+ strictParseParams: true
307
+ });
308
+ console.log('set loading', matches);
309
+ setStore(s => {
310
+ s.status = 'loading';
311
+ s.pendingMatches = matches;
312
+ s.pendingLocation = store.latestLocation;
313
+ });
314
+ });
315
+
316
+ // Load the matches
317
+ try {
318
+ await router.loadMatches(matches);
319
+ } catch (err) {
320
+ console.log(err);
321
+ invariant__default["default"](false, 'Matches failed to load due to error above ☝️. Navigation cancelled!');
322
+ }
323
+ if (startedLoadingAt !== startedAt) {
324
+ // Ignore side-effects of outdated side-effects
325
+ return navigationPromise;
326
+ }
327
+ const previousMatches = store.currentMatches;
328
+ const exiting = [],
329
+ staying = [];
330
+ previousMatches.forEach(d => {
331
+ if (matches.find(dd => dd.matchId === d.matchId)) {
332
+ staying.push(d);
333
+ } else {
334
+ exiting.push(d);
335
+ }
336
+ });
337
+ const entering = matches.filter(d => {
338
+ return !previousMatches.find(dd => dd.matchId === d.matchId);
339
+ });
340
+ now = Date.now();
341
+ exiting.forEach(d => {
342
+ d.__.onExit == null ? void 0 : d.__.onExit({
343
+ params: d.params,
344
+ search: d.store.routeSearch
345
+ });
346
+
347
+ // Clear idle error states when match leaves
348
+ if (d.store.status === 'error' && !d.store.isFetching) {
349
+ d.store.status = 'idle';
350
+ d.store.error = undefined;
351
+ }
352
+ const gc = Math.max(d.options.loaderGcMaxAge ?? router.options.defaultLoaderGcMaxAge ?? 0, d.options.loaderMaxAge ?? router.options.defaultLoaderMaxAge ?? 0);
353
+ if (gc > 0) {
354
+ store.matchCache[d.matchId] = {
355
+ gc: gc == Infinity ? Number.MAX_SAFE_INTEGER : now + gc,
356
+ match: d
357
+ };
358
+ }
359
+ });
360
+ staying.forEach(d => {
361
+ d.options.onTransition == null ? void 0 : d.options.onTransition({
362
+ params: d.params,
363
+ search: d.store.routeSearch
364
+ });
365
+ });
366
+ entering.forEach(d => {
367
+ d.__.onExit = d.options.onLoaded == null ? void 0 : d.options.onLoaded({
368
+ params: d.params,
369
+ search: d.store.search
370
+ });
371
+ delete store.matchCache[d.matchId];
372
+ });
373
+ if (startedLoadingAt !== startedAt) {
374
+ // Ignore side-effects of match loading
375
+ return;
376
+ }
377
+ matches.forEach(match => {
378
+ // Clear actions
379
+ if (match.action) {
380
+ // TODO: Check reactivity here
381
+ match.action.current = undefined;
382
+ match.action.submissions = [];
383
+ }
384
+ });
385
+ setStore(s => {
386
+ console.log('set', matches);
387
+ Object.assign(s, {
388
+ status: 'idle',
389
+ currentLocation: store.latestLocation,
390
+ currentMatches: matches,
391
+ pendingLocation: undefined,
392
+ pendingMatches: undefined
393
+ });
394
+ });
395
+ resolveNavigation();
396
+ },
397
+ cleanMatchCache: () => {
398
+ const now = Date.now();
399
+ setStore(s => {
400
+ Object.keys(s.matchCache).forEach(matchId => {
401
+ const entry = s.matchCache[matchId];
402
+
403
+ // Don't remove loading matches
404
+ if (entry.match.store.status === 'loading') {
405
+ return;
406
+ }
407
+
408
+ // Do not remove successful matches that are still valid
409
+ if (entry.gc > 0 && entry.gc > now) {
410
+ return;
411
+ }
412
+
413
+ // Everything else gets removed
414
+ delete s.matchCache[matchId];
415
+ });
416
+ });
417
+ },
418
+ loadRoute: async function (navigateOpts) {
419
+ if (navigateOpts === void 0) {
420
+ navigateOpts = store.latestLocation;
421
+ }
422
+ const next = router.buildNext(navigateOpts);
423
+ const matches = router.matchRoutes(next.pathname, {
424
+ strictParseParams: true
425
+ });
426
+ await router.loadMatches(matches);
427
+ return matches;
428
+ },
429
+ preloadRoute: async function (navigateOpts, loaderOpts) {
430
+ if (navigateOpts === void 0) {
431
+ navigateOpts = store.latestLocation;
432
+ }
433
+ const next = router.buildNext(navigateOpts);
434
+ const matches = router.matchRoutes(next.pathname, {
435
+ strictParseParams: true
436
+ });
437
+ await router.loadMatches(matches, {
438
+ preload: true,
439
+ maxAge: loaderOpts.maxAge ?? router.options.defaultPreloadMaxAge ?? router.options.defaultLoaderMaxAge ?? 0,
440
+ gcMaxAge: loaderOpts.gcMaxAge ?? router.options.defaultPreloadGcMaxAge ?? router.options.defaultLoaderGcMaxAge ?? 0
441
+ });
442
+ return matches;
443
+ },
444
+ matchRoutes: (pathname, opts) => {
445
+ router.cleanMatchCache();
446
+ const matches = [];
447
+ if (!router.routeTree) {
448
+ return matches;
449
+ }
450
+ const existingMatches = [...store.currentMatches, ...(store.pendingMatches ?? [])];
451
+ const recurse = async routes => {
452
+ var _foundRoute$childRout;
453
+ const parentMatch = utils.last(matches);
454
+ let params = (parentMatch == null ? void 0 : parentMatch.params) ?? {};
455
+ const filteredRoutes = (router.options.filterRoutes == null ? void 0 : router.options.filterRoutes(routes)) ?? routes;
456
+ let foundRoutes = [];
457
+ const findMatchInRoutes = (parentRoutes, routes) => {
458
+ routes.some(route => {
459
+ var _route$childRoutes, _route$childRoutes2;
460
+ if (!route.routePath && (_route$childRoutes = route.childRoutes) != null && _route$childRoutes.length) {
461
+ return findMatchInRoutes([...foundRoutes, route], route.childRoutes);
462
+ }
463
+ const fuzzy = !!(route.routePath !== '/' || (_route$childRoutes2 = route.childRoutes) != null && _route$childRoutes2.length);
464
+ const matchParams = path.matchPathname(router.basepath, pathname, {
465
+ to: route.fullPath,
466
+ fuzzy,
467
+ caseSensitive: route.options.caseSensitive ?? router.options.caseSensitive
468
+ });
469
+ if (matchParams) {
470
+ let parsedParams;
471
+ try {
472
+ parsedParams = (route.options.parseParams == null ? void 0 : route.options.parseParams(matchParams)) ?? matchParams;
473
+ } catch (err) {
474
+ if (opts != null && opts.strictParseParams) {
475
+ throw err;
476
+ }
477
+ }
478
+ params = {
479
+ ...params,
480
+ ...parsedParams
481
+ };
482
+ }
483
+ if (!!matchParams) {
484
+ foundRoutes = [...parentRoutes, route];
485
+ }
486
+ return !!foundRoutes.length;
487
+ });
488
+ return !!foundRoutes.length;
489
+ };
490
+ findMatchInRoutes([], filteredRoutes);
491
+ if (!foundRoutes.length) {
492
+ return;
493
+ }
494
+ foundRoutes.forEach(foundRoute => {
495
+ var _store$matchCache$mat;
496
+ const interpolatedPath = path.interpolatePath(foundRoute.routePath, params);
497
+ const matchId = path.interpolatePath(foundRoute.routeId, params, true);
498
+ const match = existingMatches.find(d => d.matchId === matchId) || ((_store$matchCache$mat = store.matchCache[matchId]) == null ? void 0 : _store$matchCache$mat.match) || routeMatch.createRouteMatch(router, foundRoute, {
499
+ parentMatch,
500
+ matchId,
501
+ params,
502
+ pathname: path.joinPaths([router.basepath, interpolatedPath])
503
+ });
504
+ matches.push(match);
505
+ });
506
+ const foundRoute = utils.last(foundRoutes);
507
+ if ((_foundRoute$childRout = foundRoute.childRoutes) != null && _foundRoute$childRout.length) {
508
+ recurse(foundRoute.childRoutes);
509
+ }
510
+ };
511
+ recurse([router.routeTree]);
512
+ linkMatches(matches);
513
+ return matches;
514
+ },
515
+ loadMatches: async (resolvedMatches, loaderOpts) => {
516
+ resolvedMatches.forEach(async match => {
517
+ // Validate the match (loads search params etc)
518
+ match.__.validate();
519
+ });
520
+
521
+ // Check each match middleware to see if the route can be accessed
522
+ await Promise.all(resolvedMatches.map(async match => {
523
+ try {
524
+ await (match.options.beforeLoad == null ? void 0 : match.options.beforeLoad({
525
+ router: router,
526
+ match
527
+ }));
528
+ } catch (err) {
529
+ if (!(loaderOpts != null && loaderOpts.preload)) {
530
+ match.options.onLoadError == null ? void 0 : match.options.onLoadError(err);
531
+ }
532
+ throw err;
533
+ }
534
+ }));
535
+ const matchPromises = resolvedMatches.map(async match => {
536
+ var _search$__data;
537
+ const search = match.store.search;
538
+ if ((_search$__data = search.__data) != null && _search$__data.matchId && search.__data.matchId !== match.matchId) {
539
+ return;
540
+ }
541
+ match.load(loaderOpts);
542
+ if (match.store.status !== 'success' && match.__.loadPromise) {
543
+ // Wait for the first sign of activity from the match
544
+ await match.__.loadPromise;
545
+ }
546
+ });
547
+ await Promise.all(matchPromises);
548
+ },
549
+ loadMatchData: async routeMatch => {
550
+ if (isServer || !router.options.useServerData) {
551
+ return (await (routeMatch.options.loader == null ? void 0 : routeMatch.options.loader({
552
+ // parentLoaderPromise: routeMatch.parentMatch?.__.dataPromise,
553
+ params: routeMatch.params,
554
+ search: routeMatch.store.routeSearch,
555
+ signal: routeMatch.__.abortController.signal
556
+ }))) || {};
557
+ } else {
558
+ const next = router.buildNext({
559
+ to: '.',
560
+ search: d => ({
561
+ ...(d ?? {}),
562
+ __data: {
563
+ matchId: routeMatch.matchId
564
+ }
565
+ })
566
+ });
567
+
568
+ // Refresh:
569
+ // '/dashboard'
570
+ // '/dashboard/invoices/'
571
+ // '/dashboard/invoices/123'
572
+
573
+ // New:
574
+ // '/dashboard/invoices/456'
575
+
576
+ // TODO: batch requests when possible
577
+
578
+ const res = await fetch(next.href, {
579
+ method: 'GET'
580
+ // signal: routeMatch.__.abortController.signal,
581
+ });
582
+
583
+ if (res.ok) {
584
+ return res.json();
585
+ }
586
+ throw new Error('Failed to fetch match data');
587
+ }
588
+ },
589
+ invalidateRoute: opts => {
590
+ const next = router.buildNext(opts);
591
+ const unloadedMatchIds = router.matchRoutes(next.pathname).map(d => d.matchId);
592
+ [...store.currentMatches, ...(store.pendingMatches ?? [])].forEach(match => {
593
+ if (unloadedMatchIds.includes(match.matchId)) {
594
+ match.invalidate();
595
+ }
596
+ });
597
+ },
598
+ reload: () => navigate({
599
+ fromCurrent: true,
600
+ replace: true,
601
+ search: true
602
+ }),
603
+ resolvePath: (from, path$1) => {
604
+ return path.resolvePath(router.basepath, from, path.cleanPath(path$1));
605
+ },
606
+ matchRoute: (location, opts) => {
607
+ // const location = router.buildNext(opts)
608
+
609
+ location = {
610
+ ...location,
611
+ to: location.to ? router.resolvePath(location.from ?? '', location.to) : undefined
612
+ };
613
+ const next = router.buildNext(location);
614
+ if (opts != null && opts.pending) {
615
+ if (!store.pendingLocation) {
616
+ return false;
617
+ }
618
+ return !!path.matchPathname(router.basepath, store.pendingLocation.pathname, {
619
+ ...opts,
620
+ to: next.pathname
621
+ });
622
+ }
623
+ return path.matchPathname(router.basepath, store.currentLocation.pathname, {
624
+ ...opts,
625
+ to: next.pathname
626
+ });
627
+ },
628
+ navigate: async _ref => {
629
+ let {
630
+ from,
631
+ to = '.',
632
+ search,
633
+ hash,
634
+ replace,
635
+ params
636
+ } = _ref;
637
+ // If this link simply reloads the current route,
638
+ // make sure it has a new key so it will trigger a data refresh
639
+
640
+ // If this `to` is a valid external URL, return
641
+ // null for LinkUtils
642
+ const toString = String(to);
643
+ const fromString = String(from);
644
+ let isExternal;
645
+ try {
646
+ new URL(`${toString}`);
647
+ isExternal = true;
648
+ } catch (e) {}
649
+ invariant__default["default"](!isExternal, 'Attempting to navigate to external url with router.navigate!');
650
+ return navigate({
651
+ from: fromString,
652
+ to: toString,
653
+ search,
654
+ hash,
655
+ replace,
656
+ params
657
+ });
658
+ },
659
+ buildLink: _ref2 => {
660
+ let {
661
+ from,
662
+ to = '.',
663
+ search,
664
+ params,
665
+ hash,
666
+ target,
667
+ replace,
668
+ activeOptions,
669
+ preload,
670
+ preloadMaxAge: userPreloadMaxAge,
671
+ preloadGcMaxAge: userPreloadGcMaxAge,
672
+ preloadDelay: userPreloadDelay,
673
+ disabled
674
+ } = _ref2;
675
+ // If this link simply reloads the current route,
676
+ // make sure it has a new key so it will trigger a data refresh
677
+
678
+ // If this `to` is a valid external URL, return
679
+ // null for LinkUtils
680
+
681
+ try {
682
+ new URL(`${to}`);
683
+ return {
684
+ type: 'external',
685
+ href: to
686
+ };
687
+ } catch (e) {}
688
+ const nextOpts = {
689
+ from,
690
+ to,
691
+ search,
692
+ params,
693
+ hash,
694
+ replace
695
+ };
696
+ const next = router.buildNext(nextOpts);
697
+ preload = preload ?? router.options.defaultPreload;
698
+ const preloadDelay = userPreloadDelay ?? router.options.defaultPreloadDelay ?? 0;
699
+
700
+ // Compare path/hash for matches
701
+ const pathIsEqual = store.currentLocation.pathname === next.pathname;
702
+ const currentPathSplit = store.currentLocation.pathname.split('/');
703
+ const nextPathSplit = next.pathname.split('/');
704
+ const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
705
+ const hashIsEqual = store.currentLocation.hash === next.hash;
706
+ // Combine the matches based on user options
707
+ const pathTest = activeOptions != null && activeOptions.exact ? pathIsEqual : pathIsFuzzyEqual;
708
+ const hashTest = activeOptions != null && activeOptions.includeHash ? hashIsEqual : true;
709
+
710
+ // The final "active" test
711
+ const isActive = pathTest && hashTest;
712
+
713
+ // The click handler
714
+ const handleClick = e => {
715
+ if (!disabled && !isCtrlEvent(e) && !e.defaultPrevented && (!target || target === '_self') && e.button === 0) {
716
+ e.preventDefault();
717
+ if (pathIsEqual && !search && !hash) {
718
+ router.invalidateRoute(nextOpts);
719
+ }
720
+
721
+ // All is well? Navigate!
722
+ navigate(nextOpts);
723
+ }
724
+ };
725
+
726
+ // The click handler
727
+ const handleFocus = e => {
728
+ if (preload) {
729
+ router.preloadRoute(nextOpts, {
730
+ maxAge: userPreloadMaxAge,
731
+ gcMaxAge: userPreloadGcMaxAge
732
+ }).catch(err => {
733
+ console.log(err);
734
+ console.warn('Error preloading route! ☝️');
735
+ });
736
+ }
737
+ };
738
+ const handleEnter = e => {
739
+ const target = e.target || {};
740
+ if (preload) {
741
+ if (target.preloadTimeout) {
742
+ return;
743
+ }
744
+ target.preloadTimeout = setTimeout(() => {
745
+ target.preloadTimeout = null;
746
+ router.preloadRoute(nextOpts, {
747
+ maxAge: userPreloadMaxAge,
748
+ gcMaxAge: userPreloadGcMaxAge
749
+ }).catch(err => {
750
+ console.log(err);
751
+ console.warn('Error preloading route! ☝️');
752
+ });
753
+ }, preloadDelay);
754
+ }
755
+ };
756
+ const handleLeave = e => {
757
+ const target = e.target || {};
758
+ if (target.preloadTimeout) {
759
+ clearTimeout(target.preloadTimeout);
760
+ target.preloadTimeout = null;
761
+ }
762
+ };
763
+ return {
764
+ type: 'internal',
765
+ next,
766
+ handleFocus,
767
+ handleClick,
768
+ handleEnter,
769
+ handleLeave,
770
+ isActive,
771
+ disabled
772
+ };
773
+ },
774
+ buildNext: opts => {
775
+ const next = buildLocation(opts);
776
+ const matches = router.matchRoutes(next.pathname);
777
+ const __preSearchFilters = matches.map(match => match.options.preSearchFilters ?? []).flat().filter(Boolean);
778
+ const __postSearchFilters = matches.map(match => match.options.postSearchFilters ?? []).flat().filter(Boolean);
779
+ return buildLocation({
780
+ ...opts,
781
+ __preSearchFilters,
782
+ __postSearchFilters
783
+ });
784
+ }
785
+ };
786
+ router.update(userOptions);
787
+
788
+ // Allow frameworks to hook into the router creation
789
+ router.options.createRouter == null ? void 0 : router.options.createRouter(router);
790
+ return router;
791
+ }
792
+ function isCtrlEvent(e) {
793
+ return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
794
+ }
795
+ function linkMatches(matches) {
796
+ matches.forEach((match, index) => {
797
+ const parent = matches[index - 1];
798
+ if (parent) {
799
+ match.__.setParentMatch(parent);
800
+ } else {
801
+ match.__.setParentMatch(undefined);
802
+ }
803
+ });
804
+ }
805
+
806
+ exports.createRouter = createRouter;
807
+ //# sourceMappingURL=router.js.map