@tanstack/router-core 0.0.1-alpha.5 → 0.0.1-alpha.7

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