@angular/router 14.0.0-next.9 → 14.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/esm2020/src/apply_redirects.mjs +57 -47
  2. package/esm2020/src/components/empty_outlet.mjs +3 -3
  3. package/esm2020/src/create_url_tree.mjs +25 -11
  4. package/esm2020/src/directives/router_link.mjs +6 -6
  5. package/esm2020/src/directives/router_link_active.mjs +22 -4
  6. package/esm2020/src/directives/router_outlet.mjs +25 -16
  7. package/esm2020/src/events.mjs +57 -1
  8. package/esm2020/src/index.mjs +1 -1
  9. package/esm2020/src/models.mjs +2 -7
  10. package/esm2020/src/operators/activate_routes.mjs +7 -14
  11. package/esm2020/src/operators/apply_redirects.mjs +3 -3
  12. package/esm2020/src/operators/resolve_data.mjs +14 -24
  13. package/esm2020/src/page_title_strategy.mjs +3 -3
  14. package/esm2020/src/recognize.mjs +24 -6
  15. package/esm2020/src/router.mjs +43 -25
  16. package/esm2020/src/router_config_loader.mjs +74 -27
  17. package/esm2020/src/router_module.mjs +14 -14
  18. package/esm2020/src/router_outlet_context.mjs +6 -1
  19. package/esm2020/src/router_preloader.mjs +48 -32
  20. package/esm2020/src/router_scroller.mjs +3 -3
  21. package/esm2020/src/router_state.mjs +4 -4
  22. package/esm2020/src/url_tree.mjs +1 -1
  23. package/esm2020/src/utils/config.mjs +71 -11
  24. package/esm2020/src/utils/config_matching.mjs +4 -1
  25. package/esm2020/src/utils/preactivation.mjs +5 -14
  26. package/esm2020/src/version.mjs +1 -1
  27. package/esm2020/testing/src/router_testing_module.mjs +4 -4
  28. package/fesm2015/router.mjs +917 -670
  29. package/fesm2015/router.mjs.map +1 -1
  30. package/fesm2015/testing.mjs +5 -5
  31. package/fesm2015/upgrade.mjs +1 -1
  32. package/fesm2020/router.mjs +902 -673
  33. package/fesm2020/router.mjs.map +1 -1
  34. package/fesm2020/testing.mjs +5 -5
  35. package/fesm2020/upgrade.mjs +1 -1
  36. package/{router.d.ts → index.d.ts} +3858 -3730
  37. package/package.json +9 -9
  38. package/testing/{testing.d.ts → index.d.ts} +65 -64
  39. package/upgrade/{upgrade.d.ts → index.d.ts} +51 -50
  40. package/testing/package.json +0 -9
  41. package/upgrade/package.json +0 -10
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v14.0.0-next.9
2
+ * @license Angular v14.0.0-rc.0
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -7,9 +7,9 @@
7
7
  import * as i3 from '@angular/common';
8
8
  import { Location, LocationStrategy, PlatformLocation, APP_BASE_HREF, ViewportScroller, HashLocationStrategy, PathLocationStrategy, LOCATION_INITIALIZED } from '@angular/common';
9
9
  import * as i0 from '@angular/core';
10
- import { ɵisObservable, ɵisPromise, EventEmitter, Directive, Attribute, Output, Component, NgModuleRef, InjectionToken, InjectFlags, NgModuleFactory, ɵConsole, NgZone, Injectable, ɵcoerceToBoolean, Input, HostListener, HostBinding, Optional, ContentChildren, Injector, Compiler, NgProbeToken, ANALYZE_FOR_ENTRY_COMPONENTS, SkipSelf, Inject, APP_INITIALIZER, APP_BOOTSTRAP_LISTENER, NgModule, ApplicationRef, Version } from '@angular/core';
10
+ import { ɵisObservable, ɵisPromise, EventEmitter, Directive, Attribute, Output, Component, ɵisStandalone, ComponentFactoryResolver, createEnvironmentInjector, InjectionToken, InjectFlags, NgModuleFactory, Injectable, NgModuleRef, ɵConsole, NgZone, ɵcoerceToBoolean, Input, HostListener, HostBinding, Optional, ContentChildren, Injector, Compiler, NgProbeToken, ANALYZE_FOR_ENTRY_COMPONENTS, SkipSelf, Inject, APP_INITIALIZER, APP_BOOTSTRAP_LISTENER, NgModule, ApplicationRef, Version } from '@angular/core';
11
11
  import { from, of, BehaviorSubject, combineLatest, throwError, EmptyError, concat, defer, Observable, EMPTY, ConnectableObservable, Subject } from 'rxjs';
12
- import { map, switchMap, take, startWith, scan, filter, catchError, concatMap, last as last$1, first, mergeMap, tap, takeLast, refCount, finalize, mergeAll } from 'rxjs/operators';
12
+ import { map, switchMap, take, startWith, scan, filter, catchError, concatMap, last as last$1, first, mergeMap, tap, takeLast, mapTo, finalize, refCount, defaultIfEmpty, mergeAll } from 'rxjs/operators';
13
13
  import * as i1 from '@angular/platform-browser';
14
14
 
15
15
  /**
@@ -69,6 +69,7 @@ class NavigationStart extends RouterEvent {
69
69
  /** @docsNotRequired */
70
70
  restoredState = null) {
71
71
  super(id, url);
72
+ this.type = 0 /* EventType.NavigationStart */;
72
73
  this.navigationTrigger = navigationTrigger;
73
74
  this.restoredState = restoredState;
74
75
  }
@@ -96,6 +97,7 @@ class NavigationEnd extends RouterEvent {
96
97
  urlAfterRedirects) {
97
98
  super(id, url);
98
99
  this.urlAfterRedirects = urlAfterRedirects;
100
+ this.type = 1 /* EventType.NavigationEnd */;
99
101
  }
100
102
  /** @docsNotRequired */
101
103
  toString() {
@@ -123,6 +125,7 @@ class NavigationCancel extends RouterEvent {
123
125
  reason) {
124
126
  super(id, url);
125
127
  this.reason = reason;
128
+ this.type = 2 /* EventType.NavigationCancel */;
126
129
  }
127
130
  /** @docsNotRequired */
128
131
  toString() {
@@ -148,6 +151,7 @@ class NavigationError extends RouterEvent {
148
151
  error) {
149
152
  super(id, url);
150
153
  this.error = error;
154
+ this.type = 3 /* EventType.NavigationError */;
151
155
  }
152
156
  /** @docsNotRequired */
153
157
  toString() {
@@ -172,6 +176,7 @@ class RoutesRecognized extends RouterEvent {
172
176
  super(id, url);
173
177
  this.urlAfterRedirects = urlAfterRedirects;
174
178
  this.state = state;
179
+ this.type = 4 /* EventType.RoutesRecognized */;
175
180
  }
176
181
  /** @docsNotRequired */
177
182
  toString() {
@@ -198,6 +203,7 @@ class GuardsCheckStart extends RouterEvent {
198
203
  super(id, url);
199
204
  this.urlAfterRedirects = urlAfterRedirects;
200
205
  this.state = state;
206
+ this.type = 7 /* EventType.GuardsCheckStart */;
201
207
  }
202
208
  toString() {
203
209
  return `GuardsCheckStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
@@ -226,6 +232,7 @@ class GuardsCheckEnd extends RouterEvent {
226
232
  this.urlAfterRedirects = urlAfterRedirects;
227
233
  this.state = state;
228
234
  this.shouldActivate = shouldActivate;
235
+ this.type = 8 /* EventType.GuardsCheckEnd */;
229
236
  }
230
237
  toString() {
231
238
  return `GuardsCheckEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state}, shouldActivate: ${this.shouldActivate})`;
@@ -254,6 +261,7 @@ class ResolveStart extends RouterEvent {
254
261
  super(id, url);
255
262
  this.urlAfterRedirects = urlAfterRedirects;
256
263
  this.state = state;
264
+ this.type = 5 /* EventType.ResolveStart */;
257
265
  }
258
266
  toString() {
259
267
  return `ResolveStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
@@ -278,6 +286,7 @@ class ResolveEnd extends RouterEvent {
278
286
  super(id, url);
279
287
  this.urlAfterRedirects = urlAfterRedirects;
280
288
  this.state = state;
289
+ this.type = 6 /* EventType.ResolveEnd */;
281
290
  }
282
291
  toString() {
283
292
  return `ResolveEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
@@ -295,6 +304,7 @@ class RouteConfigLoadStart {
295
304
  /** @docsNotRequired */
296
305
  route) {
297
306
  this.route = route;
307
+ this.type = 9 /* EventType.RouteConfigLoadStart */;
298
308
  }
299
309
  toString() {
300
310
  return `RouteConfigLoadStart(path: ${this.route.path})`;
@@ -312,6 +322,7 @@ class RouteConfigLoadEnd {
312
322
  /** @docsNotRequired */
313
323
  route) {
314
324
  this.route = route;
325
+ this.type = 10 /* EventType.RouteConfigLoadEnd */;
315
326
  }
316
327
  toString() {
317
328
  return `RouteConfigLoadEnd(path: ${this.route.path})`;
@@ -330,6 +341,7 @@ class ChildActivationStart {
330
341
  /** @docsNotRequired */
331
342
  snapshot) {
332
343
  this.snapshot = snapshot;
344
+ this.type = 11 /* EventType.ChildActivationStart */;
333
345
  }
334
346
  toString() {
335
347
  const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || '';
@@ -348,6 +360,7 @@ class ChildActivationEnd {
348
360
  /** @docsNotRequired */
349
361
  snapshot) {
350
362
  this.snapshot = snapshot;
363
+ this.type = 12 /* EventType.ChildActivationEnd */;
351
364
  }
352
365
  toString() {
353
366
  const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || '';
@@ -367,6 +380,7 @@ class ActivationStart {
367
380
  /** @docsNotRequired */
368
381
  snapshot) {
369
382
  this.snapshot = snapshot;
383
+ this.type = 13 /* EventType.ActivationStart */;
370
384
  }
371
385
  toString() {
372
386
  const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || '';
@@ -386,6 +400,7 @@ class ActivationEnd {
386
400
  /** @docsNotRequired */
387
401
  snapshot) {
388
402
  this.snapshot = snapshot;
403
+ this.type = 14 /* EventType.ActivationEnd */;
389
404
  }
390
405
  toString() {
391
406
  const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || '';
@@ -408,12 +423,53 @@ class Scroll {
408
423
  this.routerEvent = routerEvent;
409
424
  this.position = position;
410
425
  this.anchor = anchor;
426
+ this.type = 15 /* EventType.Scroll */;
411
427
  }
412
428
  toString() {
413
429
  const pos = this.position ? `${this.position[0]}, ${this.position[1]}` : null;
414
430
  return `Scroll(anchor: '${this.anchor}', position: '${pos}')`;
415
431
  }
416
432
  }
433
+ function stringifyEvent(routerEvent) {
434
+ if (!('type' in routerEvent)) {
435
+ return `Unknown Router Event: ${routerEvent.constructor.name}`;
436
+ }
437
+ switch (routerEvent.type) {
438
+ case 14 /* EventType.ActivationEnd */:
439
+ return `ActivationEnd(path: '${routerEvent.snapshot.routeConfig?.path || ''}')`;
440
+ case 13 /* EventType.ActivationStart */:
441
+ return `ActivationStart(path: '${routerEvent.snapshot.routeConfig?.path || ''}')`;
442
+ case 12 /* EventType.ChildActivationEnd */:
443
+ return `ChildActivationEnd(path: '${routerEvent.snapshot.routeConfig?.path || ''}')`;
444
+ case 11 /* EventType.ChildActivationStart */:
445
+ return `ChildActivationStart(path: '${routerEvent.snapshot.routeConfig?.path || ''}')`;
446
+ case 8 /* EventType.GuardsCheckEnd */:
447
+ return `GuardsCheckEnd(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state}, shouldActivate: ${routerEvent.shouldActivate})`;
448
+ case 7 /* EventType.GuardsCheckStart */:
449
+ return `GuardsCheckStart(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state})`;
450
+ case 2 /* EventType.NavigationCancel */:
451
+ return `NavigationCancel(id: ${routerEvent.id}, url: '${routerEvent.url}')`;
452
+ case 1 /* EventType.NavigationEnd */:
453
+ return `NavigationEnd(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}')`;
454
+ case 3 /* EventType.NavigationError */:
455
+ return `NavigationError(id: ${routerEvent.id}, url: '${routerEvent.url}', error: ${routerEvent.error})`;
456
+ case 0 /* EventType.NavigationStart */:
457
+ return `NavigationStart(id: ${routerEvent.id}, url: '${routerEvent.url}')`;
458
+ case 6 /* EventType.ResolveEnd */:
459
+ return `ResolveEnd(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state})`;
460
+ case 5 /* EventType.ResolveStart */:
461
+ return `ResolveStart(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state})`;
462
+ case 10 /* EventType.RouteConfigLoadEnd */:
463
+ return `RouteConfigLoadEnd(path: ${routerEvent.route.path})`;
464
+ case 9 /* EventType.RouteConfigLoadStart */:
465
+ return `RouteConfigLoadStart(path: ${routerEvent.route.path})`;
466
+ case 4 /* EventType.RoutesRecognized */:
467
+ return `RoutesRecognized(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state})`;
468
+ case 15 /* EventType.Scroll */:
469
+ const pos = routerEvent.position ? `${routerEvent.position[0]}, ${routerEvent.position[1]}` : null;
470
+ return `Scroll(anchor: '${routerEvent.anchor}', position: '${pos}')`;
471
+ }
472
+ }
417
473
 
418
474
  /**
419
475
  * @license
@@ -1362,7 +1418,6 @@ class ActivatedRoute {
1362
1418
  /** The outlet name of the route, a constant. */
1363
1419
  outlet,
1364
1420
  /** The component of the route, a constant. */
1365
- // TODO(vsavkin): remove |string
1366
1421
  component, futureSnapshot) {
1367
1422
  this.url = url;
1368
1423
  this.params = params;
@@ -1456,7 +1511,7 @@ function flattenInherited(pathFromRoot) {
1456
1511
  return pathFromRoot.reduce((res, curr) => {
1457
1512
  const params = { ...res.params, ...curr.params };
1458
1513
  const data = { ...res.data, ...curr.data };
1459
- const resolve = { ...res.resolve, ...curr._resolvedData };
1514
+ const resolve = { ...curr.data, ...res.resolve, ...curr.routeConfig?.data, ...curr._resolvedData };
1460
1515
  return { params, data, resolve };
1461
1516
  }, { params: {}, data: {}, resolve: {} });
1462
1517
  }
@@ -1517,7 +1572,7 @@ class ActivatedRouteSnapshot {
1517
1572
  /** The outlet name of the route */
1518
1573
  outlet,
1519
1574
  /** The component of the route */
1520
- component, routeConfig, urlSegment, lastPathIndex, resolve) {
1575
+ component, routeConfig, urlSegment, lastPathIndex, resolve, correctedLastPathIndex) {
1521
1576
  this.url = url;
1522
1577
  this.params = params;
1523
1578
  this.queryParams = queryParams;
@@ -1528,6 +1583,7 @@ class ActivatedRouteSnapshot {
1528
1583
  this.routeConfig = routeConfig;
1529
1584
  this._urlSegment = urlSegment;
1530
1585
  this._lastPathIndex = lastPathIndex;
1586
+ this._correctedLastPathIndex = correctedLastPathIndex ?? lastPathIndex;
1531
1587
  this._resolve = resolve;
1532
1588
  }
1533
1589
  /** The root of the router state */
@@ -1719,11 +1775,26 @@ function createUrlTree(route, urlTree, commands, queryParams, fragment) {
1719
1775
  if (nav.toRoot()) {
1720
1776
  return tree(urlTree.root, urlTree.root, new UrlSegmentGroup([], {}), queryParams, fragment);
1721
1777
  }
1722
- const startingPosition = findStartingPosition(nav, urlTree, route);
1723
- const segmentGroup = startingPosition.processChildren ?
1724
- updateSegmentGroupChildren(startingPosition.segmentGroup, startingPosition.index, nav.commands) :
1725
- updateSegmentGroup(startingPosition.segmentGroup, startingPosition.index, nav.commands);
1726
- return tree(urlTree.root, startingPosition.segmentGroup, segmentGroup, queryParams, fragment);
1778
+ function createTreeUsingPathIndex(lastPathIndex) {
1779
+ const startingPosition = findStartingPosition(nav, urlTree, route.snapshot?._urlSegment, lastPathIndex);
1780
+ const segmentGroup = startingPosition.processChildren ?
1781
+ updateSegmentGroupChildren(startingPosition.segmentGroup, startingPosition.index, nav.commands) :
1782
+ updateSegmentGroup(startingPosition.segmentGroup, startingPosition.index, nav.commands);
1783
+ return tree(urlTree.root, startingPosition.segmentGroup, segmentGroup, queryParams, fragment);
1784
+ }
1785
+ // Note: The types should disallow `snapshot` from being `undefined` but due to test mocks, this
1786
+ // may be the case. Since we try to access it at an earlier point before the refactor to add the
1787
+ // warning for `relativeLinkResolution: 'legacy'`, this may cause failures in tests where it
1788
+ // didn't before.
1789
+ const result = createTreeUsingPathIndex(route.snapshot?._lastPathIndex);
1790
+ // Check if application is relying on `relativeLinkResolution: 'legacy'`
1791
+ if (typeof ngDevMode === 'undefined' || !!ngDevMode) {
1792
+ const correctedResult = createTreeUsingPathIndex(route.snapshot?._correctedLastPathIndex);
1793
+ if (correctedResult.toString() !== result.toString()) {
1794
+ console.warn(`relativeLinkResolution: 'legacy' is deprecated and will be removed in a future version of Angular. The link to ${result.toString()} will change to ${correctedResult.toString()} if the code is not updated before then.`);
1795
+ }
1796
+ }
1797
+ return result;
1727
1798
  }
1728
1799
  function isMatrixParams(command) {
1729
1800
  return typeof command === 'object' && command != null && !command.outlets && !command.segmentPath;
@@ -1828,12 +1899,11 @@ class Position {
1828
1899
  this.index = index;
1829
1900
  }
1830
1901
  }
1831
- function findStartingPosition(nav, tree, route) {
1902
+ function findStartingPosition(nav, tree, segmentGroup, lastPathIndex) {
1832
1903
  if (nav.isAbsolute) {
1833
1904
  return new Position(tree.root, true, 0);
1834
1905
  }
1835
- if (route.snapshot._lastPathIndex === -1) {
1836
- const segmentGroup = route.snapshot._urlSegment;
1906
+ if (lastPathIndex === -1) {
1837
1907
  // Pathless ActivatedRoute has _lastPathIndex === -1 but should not process children
1838
1908
  // see issue #26224, #13011, #35687
1839
1909
  // However, if the ActivatedRoute is the root we should process children like above.
@@ -1841,8 +1911,8 @@ function findStartingPosition(nav, tree, route) {
1841
1911
  return new Position(segmentGroup, processChildren, 0);
1842
1912
  }
1843
1913
  const modifier = isMatrixParams(nav.commands[0]) ? 0 : 1;
1844
- const index = route.snapshot._lastPathIndex + modifier;
1845
- return createPositionApplyingDoubleDots(route.snapshot._urlSegment, index, nav.numberOfDoubleDots);
1914
+ const index = lastPathIndex + modifier;
1915
+ return createPositionApplyingDoubleDots(segmentGroup, index, nav.numberOfDoubleDots);
1846
1916
  }
1847
1917
  function createPositionApplyingDoubleDots(group, index, numberOfDoubleDots) {
1848
1918
  let g = group;
@@ -2005,181 +2075,76 @@ function compare(path, params, segment) {
2005
2075
  * Use of this source code is governed by an MIT-style license that can be
2006
2076
  * found in the LICENSE file at https://angular.io/license
2007
2077
  */
2008
- const activateRoutes = (rootContexts, routeReuseStrategy, forwardEvent) => map(t => {
2009
- new ActivateRoutes(routeReuseStrategy, t.targetRouterState, t.currentRouterState, forwardEvent)
2010
- .activate(rootContexts);
2011
- return t;
2012
- });
2013
- class ActivateRoutes {
2014
- constructor(routeReuseStrategy, futureState, currState, forwardEvent) {
2015
- this.routeReuseStrategy = routeReuseStrategy;
2016
- this.futureState = futureState;
2017
- this.currState = currState;
2018
- this.forwardEvent = forwardEvent;
2019
- }
2020
- activate(parentContexts) {
2021
- const futureRoot = this.futureState._root;
2022
- const currRoot = this.currState ? this.currState._root : null;
2023
- this.deactivateChildRoutes(futureRoot, currRoot, parentContexts);
2024
- advanceActivatedRoute(this.futureState.root);
2025
- this.activateChildRoutes(futureRoot, currRoot, parentContexts);
2026
- }
2027
- // De-activate the child route that are not re-used for the future state
2028
- deactivateChildRoutes(futureNode, currNode, contexts) {
2029
- const children = nodeChildrenAsMap(currNode);
2030
- // Recurse on the routes active in the future state to de-activate deeper children
2031
- futureNode.children.forEach(futureChild => {
2032
- const childOutletName = futureChild.value.outlet;
2033
- this.deactivateRoutes(futureChild, children[childOutletName], contexts);
2034
- delete children[childOutletName];
2035
- });
2036
- // De-activate the routes that will not be re-used
2037
- forEach(children, (v, childName) => {
2038
- this.deactivateRouteAndItsChildren(v, contexts);
2039
- });
2040
- }
2041
- deactivateRoutes(futureNode, currNode, parentContext) {
2042
- const future = futureNode.value;
2043
- const curr = currNode ? currNode.value : null;
2044
- if (future === curr) {
2045
- // Reusing the node, check to see if the children need to be de-activated
2046
- if (future.component) {
2047
- // If we have a normal route, we need to go through an outlet.
2048
- const context = parentContext.getContext(future.outlet);
2049
- if (context) {
2050
- this.deactivateChildRoutes(futureNode, currNode, context.children);
2051
- }
2052
- }
2053
- else {
2054
- // if we have a componentless route, we recurse but keep the same outlet map.
2055
- this.deactivateChildRoutes(futureNode, currNode, parentContext);
2056
- }
2057
- }
2058
- else {
2059
- if (curr) {
2060
- // Deactivate the current route which will not be re-used
2061
- this.deactivateRouteAndItsChildren(currNode, parentContext);
2062
- }
2063
- }
2078
+ /**
2079
+ * Store contextual information about a `RouterOutlet`
2080
+ *
2081
+ * @publicApi
2082
+ */
2083
+ class OutletContext {
2084
+ constructor() {
2085
+ this.outlet = null;
2086
+ this.route = null;
2087
+ /**
2088
+ * @deprecated Passing a resolver to retrieve a component factory is not required and is
2089
+ * deprecated since v14.
2090
+ */
2091
+ this.resolver = null;
2092
+ this.injector = null;
2093
+ this.children = new ChildrenOutletContexts();
2094
+ this.attachRef = null;
2064
2095
  }
2065
- deactivateRouteAndItsChildren(route, parentContexts) {
2066
- // If there is no component, the Route is never attached to an outlet (because there is no
2067
- // component to attach).
2068
- if (route.value.component && this.routeReuseStrategy.shouldDetach(route.value.snapshot)) {
2069
- this.detachAndStoreRouteSubtree(route, parentContexts);
2070
- }
2071
- else {
2072
- this.deactivateRouteAndOutlet(route, parentContexts);
2073
- }
2096
+ }
2097
+ /**
2098
+ * Store contextual information about the children (= nested) `RouterOutlet`
2099
+ *
2100
+ * @publicApi
2101
+ */
2102
+ class ChildrenOutletContexts {
2103
+ constructor() {
2104
+ // contexts for child outlets, by name.
2105
+ this.contexts = new Map();
2074
2106
  }
2075
- detachAndStoreRouteSubtree(route, parentContexts) {
2076
- const context = parentContexts.getContext(route.value.outlet);
2077
- const contexts = context && route.value.component ? context.children : parentContexts;
2078
- const children = nodeChildrenAsMap(route);
2079
- for (const childOutlet of Object.keys(children)) {
2080
- this.deactivateRouteAndItsChildren(children[childOutlet], contexts);
2081
- }
2082
- if (context && context.outlet) {
2083
- const componentRef = context.outlet.detach();
2084
- const contexts = context.children.onOutletDeactivated();
2085
- this.routeReuseStrategy.store(route.value.snapshot, { componentRef, route, contexts });
2086
- }
2107
+ /** Called when a `RouterOutlet` directive is instantiated */
2108
+ onChildOutletCreated(childName, outlet) {
2109
+ const context = this.getOrCreateContext(childName);
2110
+ context.outlet = outlet;
2111
+ this.contexts.set(childName, context);
2087
2112
  }
2088
- deactivateRouteAndOutlet(route, parentContexts) {
2089
- const context = parentContexts.getContext(route.value.outlet);
2090
- // The context could be `null` if we are on a componentless route but there may still be
2091
- // children that need deactivating.
2092
- const contexts = context && route.value.component ? context.children : parentContexts;
2093
- const children = nodeChildrenAsMap(route);
2094
- for (const childOutlet of Object.keys(children)) {
2095
- this.deactivateRouteAndItsChildren(children[childOutlet], contexts);
2096
- }
2097
- if (context && context.outlet) {
2098
- // Destroy the component
2099
- context.outlet.deactivate();
2100
- // Destroy the contexts for all the outlets that were in the component
2101
- context.children.onOutletDeactivated();
2102
- // Clear the information about the attached component on the context but keep the reference to
2103
- // the outlet.
2113
+ /**
2114
+ * Called when a `RouterOutlet` directive is destroyed.
2115
+ * We need to keep the context as the outlet could be destroyed inside a NgIf and might be
2116
+ * re-created later.
2117
+ */
2118
+ onChildOutletDestroyed(childName) {
2119
+ const context = this.getContext(childName);
2120
+ if (context) {
2121
+ context.outlet = null;
2104
2122
  context.attachRef = null;
2105
- context.resolver = null;
2106
- context.route = null;
2107
2123
  }
2108
2124
  }
2109
- activateChildRoutes(futureNode, currNode, contexts) {
2110
- const children = nodeChildrenAsMap(currNode);
2111
- futureNode.children.forEach(c => {
2112
- this.activateRoutes(c, children[c.value.outlet], contexts);
2113
- this.forwardEvent(new ActivationEnd(c.value.snapshot));
2114
- });
2115
- if (futureNode.children.length) {
2116
- this.forwardEvent(new ChildActivationEnd(futureNode.value.snapshot));
2117
- }
2125
+ /**
2126
+ * Called when the corresponding route is deactivated during navigation.
2127
+ * Because the component get destroyed, all children outlet are destroyed.
2128
+ */
2129
+ onOutletDeactivated() {
2130
+ const contexts = this.contexts;
2131
+ this.contexts = new Map();
2132
+ return contexts;
2118
2133
  }
2119
- activateRoutes(futureNode, currNode, parentContexts) {
2120
- const future = futureNode.value;
2121
- const curr = currNode ? currNode.value : null;
2122
- advanceActivatedRoute(future);
2123
- // reusing the node
2124
- if (future === curr) {
2125
- if (future.component) {
2126
- // If we have a normal route, we need to go through an outlet.
2127
- const context = parentContexts.getOrCreateContext(future.outlet);
2128
- this.activateChildRoutes(futureNode, currNode, context.children);
2129
- }
2130
- else {
2131
- // if we have a componentless route, we recurse but keep the same outlet map.
2132
- this.activateChildRoutes(futureNode, currNode, parentContexts);
2133
- }
2134
- }
2135
- else {
2136
- if (future.component) {
2137
- // if we have a normal route, we need to place the component into the outlet and recurse.
2138
- const context = parentContexts.getOrCreateContext(future.outlet);
2139
- if (this.routeReuseStrategy.shouldAttach(future.snapshot)) {
2140
- const stored = this.routeReuseStrategy.retrieve(future.snapshot);
2141
- this.routeReuseStrategy.store(future.snapshot, null);
2142
- context.children.onOutletReAttached(stored.contexts);
2143
- context.attachRef = stored.componentRef;
2144
- context.route = stored.route.value;
2145
- if (context.outlet) {
2146
- // Attach right away when the outlet has already been instantiated
2147
- // Otherwise attach from `RouterOutlet.ngOnInit` when it is instantiated
2148
- context.outlet.attach(stored.componentRef, stored.route.value);
2149
- }
2150
- advanceActivatedRoute(stored.route.value);
2151
- this.activateChildRoutes(futureNode, null, context.children);
2152
- }
2153
- else {
2154
- const config = parentLoadedConfig(future.snapshot);
2155
- const cmpFactoryResolver = config ? config.module.componentFactoryResolver : null;
2156
- context.attachRef = null;
2157
- context.route = future;
2158
- context.resolver = cmpFactoryResolver;
2159
- if (context.outlet) {
2160
- // Activate the outlet when it has already been instantiated
2161
- // Otherwise it will get activated from its `ngOnInit` when instantiated
2162
- context.outlet.activateWith(future, cmpFactoryResolver);
2163
- }
2164
- this.activateChildRoutes(futureNode, null, context.children);
2165
- }
2166
- }
2167
- else {
2168
- // if we have a componentless route, we recurse but keep the same outlet map.
2169
- this.activateChildRoutes(futureNode, null, parentContexts);
2170
- }
2134
+ onOutletReAttached(contexts) {
2135
+ this.contexts = contexts;
2136
+ }
2137
+ getOrCreateContext(childName) {
2138
+ let context = this.getContext(childName);
2139
+ if (!context) {
2140
+ context = new OutletContext();
2141
+ this.contexts.set(childName, context);
2171
2142
  }
2143
+ return context;
2172
2144
  }
2173
- }
2174
- function parentLoadedConfig(snapshot) {
2175
- for (let s = snapshot.parent; s; s = s.parent) {
2176
- const route = s.routeConfig;
2177
- if (route && route._loadedConfig)
2178
- return route._loadedConfig;
2179
- if (route && route.component)
2180
- return null;
2145
+ getContext(childName) {
2146
+ return this.contexts.get(childName) || null;
2181
2147
  }
2182
- return null;
2183
2148
  }
2184
2149
 
2185
2150
  /**
@@ -2189,182 +2154,13 @@ function parentLoadedConfig(snapshot) {
2189
2154
  * Use of this source code is governed by an MIT-style license that can be
2190
2155
  * found in the LICENSE file at https://angular.io/license
2191
2156
  */
2192
- class LoadedRouterConfig {
2193
- constructor(routes, module) {
2194
- this.routes = routes;
2195
- this.module = module;
2196
- }
2197
- }
2198
-
2199
2157
  /**
2200
- * @license
2201
- * Copyright Google LLC All Rights Reserved.
2158
+ * @description
2202
2159
  *
2203
- * Use of this source code is governed by an MIT-style license that can be
2204
- * found in the LICENSE file at https://angular.io/license
2205
- */
2206
- /**
2207
- * Simple function check, but generic so type inference will flow. Example:
2160
+ * Acts as a placeholder that Angular dynamically fills based on the current router state.
2208
2161
  *
2209
- * function product(a: number, b: number) {
2210
- * return a * b;
2211
- * }
2212
- *
2213
- * if (isFunction<product>(fn)) {
2214
- * return fn(1, 2);
2215
- * } else {
2216
- * throw "Must provide the `product` function";
2217
- * }
2218
- */
2219
- function isFunction(v) {
2220
- return typeof v === 'function';
2221
- }
2222
- function isBoolean(v) {
2223
- return typeof v === 'boolean';
2224
- }
2225
- function isUrlTree(v) {
2226
- return v instanceof UrlTree;
2227
- }
2228
- function isCanLoad(guard) {
2229
- return guard && isFunction(guard.canLoad);
2230
- }
2231
- function isCanActivate(guard) {
2232
- return guard && isFunction(guard.canActivate);
2233
- }
2234
- function isCanActivateChild(guard) {
2235
- return guard && isFunction(guard.canActivateChild);
2236
- }
2237
- function isCanDeactivate(guard) {
2238
- return guard && isFunction(guard.canDeactivate);
2239
- }
2240
-
2241
- /**
2242
- * @license
2243
- * Copyright Google LLC All Rights Reserved.
2244
- *
2245
- * Use of this source code is governed by an MIT-style license that can be
2246
- * found in the LICENSE file at https://angular.io/license
2247
- */
2248
- const INITIAL_VALUE = Symbol('INITIAL_VALUE');
2249
- function prioritizedGuardValue() {
2250
- return switchMap(obs => {
2251
- return combineLatest(obs.map(o => o.pipe(take(1), startWith(INITIAL_VALUE))))
2252
- .pipe(scan((acc, list) => {
2253
- let isPending = false;
2254
- return list.reduce((innerAcc, val, i) => {
2255
- if (innerAcc !== INITIAL_VALUE)
2256
- return innerAcc;
2257
- // Toggle pending flag if any values haven't been set yet
2258
- if (val === INITIAL_VALUE)
2259
- isPending = true;
2260
- // Any other return values are only valid if we haven't yet hit a pending
2261
- // call. This guarantees that in the case of a guard at the bottom of the
2262
- // tree that returns a redirect, we will wait for the higher priority
2263
- // guard at the top to finish before performing the redirect.
2264
- if (!isPending) {
2265
- // Early return when we hit a `false` value as that should always
2266
- // cancel navigation
2267
- if (val === false)
2268
- return val;
2269
- if (i === list.length - 1 || isUrlTree(val)) {
2270
- return val;
2271
- }
2272
- }
2273
- return innerAcc;
2274
- }, acc);
2275
- }, INITIAL_VALUE), filter(item => item !== INITIAL_VALUE), map(item => isUrlTree(item) ? item : item === true), //
2276
- take(1));
2277
- });
2278
- }
2279
-
2280
- /**
2281
- * @license
2282
- * Copyright Google LLC All Rights Reserved.
2283
- *
2284
- * Use of this source code is governed by an MIT-style license that can be
2285
- * found in the LICENSE file at https://angular.io/license
2286
- */
2287
- /**
2288
- * Store contextual information about a `RouterOutlet`
2289
- *
2290
- * @publicApi
2291
- */
2292
- class OutletContext {
2293
- constructor() {
2294
- this.outlet = null;
2295
- this.route = null;
2296
- this.resolver = null;
2297
- this.children = new ChildrenOutletContexts();
2298
- this.attachRef = null;
2299
- }
2300
- }
2301
- /**
2302
- * Store contextual information about the children (= nested) `RouterOutlet`
2303
- *
2304
- * @publicApi
2305
- */
2306
- class ChildrenOutletContexts {
2307
- constructor() {
2308
- // contexts for child outlets, by name.
2309
- this.contexts = new Map();
2310
- }
2311
- /** Called when a `RouterOutlet` directive is instantiated */
2312
- onChildOutletCreated(childName, outlet) {
2313
- const context = this.getOrCreateContext(childName);
2314
- context.outlet = outlet;
2315
- this.contexts.set(childName, context);
2316
- }
2317
- /**
2318
- * Called when a `RouterOutlet` directive is destroyed.
2319
- * We need to keep the context as the outlet could be destroyed inside a NgIf and might be
2320
- * re-created later.
2321
- */
2322
- onChildOutletDestroyed(childName) {
2323
- const context = this.getContext(childName);
2324
- if (context) {
2325
- context.outlet = null;
2326
- context.attachRef = null;
2327
- }
2328
- }
2329
- /**
2330
- * Called when the corresponding route is deactivated during navigation.
2331
- * Because the component get destroyed, all children outlet are destroyed.
2332
- */
2333
- onOutletDeactivated() {
2334
- const contexts = this.contexts;
2335
- this.contexts = new Map();
2336
- return contexts;
2337
- }
2338
- onOutletReAttached(contexts) {
2339
- this.contexts = contexts;
2340
- }
2341
- getOrCreateContext(childName) {
2342
- let context = this.getContext(childName);
2343
- if (!context) {
2344
- context = new OutletContext();
2345
- this.contexts.set(childName, context);
2346
- }
2347
- return context;
2348
- }
2349
- getContext(childName) {
2350
- return this.contexts.get(childName) || null;
2351
- }
2352
- }
2353
-
2354
- /**
2355
- * @license
2356
- * Copyright Google LLC All Rights Reserved.
2357
- *
2358
- * Use of this source code is governed by an MIT-style license that can be
2359
- * found in the LICENSE file at https://angular.io/license
2360
- */
2361
- /**
2362
- * @description
2363
- *
2364
- * Acts as a placeholder that Angular dynamically fills based on the current router state.
2365
- *
2366
- * Each outlet can have a unique name, determined by the optional `name` attribute.
2367
- * The name cannot be set or changed dynamically. If not set, default value is "primary".
2162
+ * Each outlet can have a unique name, determined by the optional `name` attribute.
2163
+ * The name cannot be set or changed dynamically. If not set, default value is "primary".
2368
2164
  *
2369
2165
  * ```
2370
2166
  * <router-outlet></router-outlet>
@@ -2410,11 +2206,11 @@ class ChildrenOutletContexts {
2410
2206
  * @publicApi
2411
2207
  */
2412
2208
  class RouterOutlet {
2413
- constructor(parentContexts, location, resolver, name, changeDetector) {
2209
+ constructor(parentContexts, location, name, changeDetector, environmentInjector) {
2414
2210
  this.parentContexts = parentContexts;
2415
2211
  this.location = location;
2416
- this.resolver = resolver;
2417
2212
  this.changeDetector = changeDetector;
2213
+ this.environmentInjector = environmentInjector;
2418
2214
  this.activated = null;
2419
2215
  this._activatedRoute = null;
2420
2216
  this.activateEvents = new EventEmitter();
@@ -2449,7 +2245,7 @@ class RouterOutlet {
2449
2245
  }
2450
2246
  else {
2451
2247
  // otherwise the component defined in the configuration is created
2452
- this.activateWith(context.route, context.resolver || null);
2248
+ this.activateWith(context.route, context.injector);
2453
2249
  }
2454
2250
  }
2455
2251
  }
@@ -2508,33 +2304,39 @@ class RouterOutlet {
2508
2304
  this.deactivateEvents.emit(c);
2509
2305
  }
2510
2306
  }
2511
- activateWith(activatedRoute, resolver) {
2307
+ activateWith(activatedRoute, resolverOrInjector) {
2512
2308
  if (this.isActivated) {
2513
2309
  throw new Error('Cannot activate an already activated outlet');
2514
2310
  }
2515
2311
  this._activatedRoute = activatedRoute;
2312
+ const location = this.location;
2516
2313
  const snapshot = activatedRoute._futureSnapshot;
2517
- const component = snapshot.routeConfig.component;
2518
- resolver = resolver || this.resolver;
2519
- const factory = resolver.resolveComponentFactory(component);
2314
+ const component = snapshot.component;
2520
2315
  const childContexts = this.parentContexts.getOrCreateContext(this.name).children;
2521
- const injector = new OutletInjector(activatedRoute, childContexts, this.location.injector);
2522
- this.activated = this.location.createComponent(factory, this.location.length, injector);
2316
+ const injector = new OutletInjector(activatedRoute, childContexts, location.injector);
2317
+ if (resolverOrInjector && isComponentFactoryResolver(resolverOrInjector)) {
2318
+ const factory = resolverOrInjector.resolveComponentFactory(component);
2319
+ this.activated = location.createComponent(factory, location.length, injector);
2320
+ }
2321
+ else {
2322
+ const environmentInjector = resolverOrInjector ?? this.environmentInjector;
2323
+ this.activated = location.createComponent(component, { index: location.length, injector, environmentInjector });
2324
+ }
2523
2325
  // Calling `markForCheck` to make sure we will run the change detection when the
2524
2326
  // `RouterOutlet` is inside a `ChangeDetectionStrategy.OnPush` component.
2525
2327
  this.changeDetector.markForCheck();
2526
2328
  this.activateEvents.emit(this.activated.instance);
2527
2329
  }
2528
2330
  }
2529
- RouterOutlet.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterOutlet, deps: [{ token: ChildrenOutletContexts }, { token: i0.ViewContainerRef }, { token: i0.ComponentFactoryResolver }, { token: 'name', attribute: true }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
2530
- RouterOutlet.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: RouterOutlet, selector: "router-outlet", outputs: { activateEvents: "activate", deactivateEvents: "deactivate", attachEvents: "attach", detachEvents: "detach" }, exportAs: ["outlet"], ngImport: i0 });
2531
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterOutlet, decorators: [{
2331
+ RouterOutlet.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterOutlet, deps: [{ token: ChildrenOutletContexts }, { token: i0.ViewContainerRef }, { token: 'name', attribute: true }, { token: i0.ChangeDetectorRef }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Directive });
2332
+ RouterOutlet.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.0-rc.0", type: RouterOutlet, selector: "router-outlet", outputs: { activateEvents: "activate", deactivateEvents: "deactivate", attachEvents: "attach", detachEvents: "detach" }, exportAs: ["outlet"], ngImport: i0 });
2333
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterOutlet, decorators: [{
2532
2334
  type: Directive,
2533
2335
  args: [{ selector: 'router-outlet', exportAs: 'outlet' }]
2534
- }], ctorParameters: function () { return [{ type: ChildrenOutletContexts }, { type: i0.ViewContainerRef }, { type: i0.ComponentFactoryResolver }, { type: undefined, decorators: [{
2336
+ }], ctorParameters: function () { return [{ type: ChildrenOutletContexts }, { type: i0.ViewContainerRef }, { type: undefined, decorators: [{
2535
2337
  type: Attribute,
2536
2338
  args: ['name']
2537
- }] }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { activateEvents: [{
2339
+ }] }, { type: i0.ChangeDetectorRef }, { type: i0.EnvironmentInjector }]; }, propDecorators: { activateEvents: [{
2538
2340
  type: Output,
2539
2341
  args: ['activate']
2540
2342
  }], deactivateEvents: [{
@@ -2560,7 +2362,385 @@ class OutletInjector {
2560
2362
  if (token === ChildrenOutletContexts) {
2561
2363
  return this.childContexts;
2562
2364
  }
2563
- return this.parent.get(token, notFoundValue);
2365
+ return this.parent.get(token, notFoundValue);
2366
+ }
2367
+ }
2368
+ function isComponentFactoryResolver(item) {
2369
+ return !!item.resolveComponentFactory;
2370
+ }
2371
+
2372
+ /**
2373
+ * @license
2374
+ * Copyright Google LLC All Rights Reserved.
2375
+ *
2376
+ * Use of this source code is governed by an MIT-style license that can be
2377
+ * found in the LICENSE file at https://angular.io/license
2378
+ */
2379
+ /**
2380
+ * This component is used internally within the router to be a placeholder when an empty
2381
+ * router-outlet is needed. For example, with a config such as:
2382
+ *
2383
+ * `{path: 'parent', outlet: 'nav', children: [...]}`
2384
+ *
2385
+ * In order to render, there needs to be a component on this config, which will default
2386
+ * to this `EmptyOutletComponent`.
2387
+ */
2388
+ class ɵEmptyOutletComponent {
2389
+ }
2390
+ ɵEmptyOutletComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: ɵEmptyOutletComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2391
+ ɵEmptyOutletComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.0-rc.0", type: ɵEmptyOutletComponent, selector: "ng-component", ngImport: i0, template: `<router-outlet></router-outlet>`, isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
2392
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: ɵEmptyOutletComponent, decorators: [{
2393
+ type: Component,
2394
+ args: [{ template: `<router-outlet></router-outlet>` }]
2395
+ }] });
2396
+
2397
+ /**
2398
+ * @license
2399
+ * Copyright Google LLC All Rights Reserved.
2400
+ *
2401
+ * Use of this source code is governed by an MIT-style license that can be
2402
+ * found in the LICENSE file at https://angular.io/license
2403
+ */
2404
+ function getLoadedRoutes(route) {
2405
+ return route._loadedRoutes;
2406
+ }
2407
+ function getLoadedInjector(route) {
2408
+ return route._loadedInjector;
2409
+ }
2410
+ function getLoadedComponent(route) {
2411
+ return route._loadedComponent;
2412
+ }
2413
+ function getProvidersInjector(route) {
2414
+ return route._injector;
2415
+ }
2416
+ function validateConfig(config, parentPath = '', requireStandaloneComponents = false) {
2417
+ // forEach doesn't iterate undefined values
2418
+ for (let i = 0; i < config.length; i++) {
2419
+ const route = config[i];
2420
+ const fullPath = getFullPath(parentPath, route);
2421
+ validateNode(route, fullPath, requireStandaloneComponents);
2422
+ }
2423
+ }
2424
+ function assertStandalone(fullPath, component) {
2425
+ if (component && !ɵisStandalone(component)) {
2426
+ throw new Error(`Invalid configuration of route '${fullPath}'. The component must be standalone.`);
2427
+ }
2428
+ }
2429
+ function validateNode(route, fullPath, requireStandaloneComponents) {
2430
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
2431
+ if (!route) {
2432
+ throw new Error(`
2433
+ Invalid configuration of route '${fullPath}': Encountered undefined route.
2434
+ The reason might be an extra comma.
2435
+
2436
+ Example:
2437
+ const routes: Routes = [
2438
+ { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
2439
+ { path: 'dashboard', component: DashboardComponent },, << two commas
2440
+ { path: 'detail/:id', component: HeroDetailComponent }
2441
+ ];
2442
+ `);
2443
+ }
2444
+ if (Array.isArray(route)) {
2445
+ throw new Error(`Invalid configuration of route '${fullPath}': Array cannot be specified`);
2446
+ }
2447
+ if (!route.component && !route.loadComponent && !route.children && !route.loadChildren &&
2448
+ (route.outlet && route.outlet !== PRIMARY_OUTLET)) {
2449
+ throw new Error(`Invalid configuration of route '${fullPath}': a componentless route without children or loadChildren cannot have a named outlet set`);
2450
+ }
2451
+ if (route.redirectTo && route.children) {
2452
+ throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and children cannot be used together`);
2453
+ }
2454
+ if (route.redirectTo && route.loadChildren) {
2455
+ throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and loadChildren cannot be used together`);
2456
+ }
2457
+ if (route.children && route.loadChildren) {
2458
+ throw new Error(`Invalid configuration of route '${fullPath}': children and loadChildren cannot be used together`);
2459
+ }
2460
+ if (route.redirectTo && (route.component || route.loadComponent)) {
2461
+ throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and component/loadComponent cannot be used together`);
2462
+ }
2463
+ if (route.component && route.loadComponent) {
2464
+ throw new Error(`Invalid configuration of route '${fullPath}': component and loadComponent cannot be used together`);
2465
+ }
2466
+ if (route.redirectTo && route.canActivate) {
2467
+ throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and canActivate cannot be used together. Redirects happen before activation ` +
2468
+ `so canActivate will never be executed.`);
2469
+ }
2470
+ if (route.path && route.matcher) {
2471
+ throw new Error(`Invalid configuration of route '${fullPath}': path and matcher cannot be used together`);
2472
+ }
2473
+ if (route.redirectTo === void 0 && !route.component && !route.loadComponent &&
2474
+ !route.children && !route.loadChildren) {
2475
+ throw new Error(`Invalid configuration of route '${fullPath}'. One of the following must be provided: component, loadComponent, redirectTo, children or loadChildren`);
2476
+ }
2477
+ if (route.path === void 0 && route.matcher === void 0) {
2478
+ throw new Error(`Invalid configuration of route '${fullPath}': routes must have either a path or a matcher specified`);
2479
+ }
2480
+ if (typeof route.path === 'string' && route.path.charAt(0) === '/') {
2481
+ throw new Error(`Invalid configuration of route '${fullPath}': path cannot start with a slash`);
2482
+ }
2483
+ if (route.path === '' && route.redirectTo !== void 0 && route.pathMatch === void 0) {
2484
+ const exp = `The default value of 'pathMatch' is 'prefix', but often the intent is to use 'full'.`;
2485
+ throw new Error(`Invalid configuration of route '{path: "${fullPath}", redirectTo: "${route.redirectTo}"}': please provide 'pathMatch'. ${exp}`);
2486
+ }
2487
+ if (requireStandaloneComponents) {
2488
+ assertStandalone(fullPath, route.component);
2489
+ }
2490
+ }
2491
+ if (route.children) {
2492
+ validateConfig(route.children, fullPath, requireStandaloneComponents);
2493
+ }
2494
+ }
2495
+ function getFullPath(parentPath, currentRoute) {
2496
+ if (!currentRoute) {
2497
+ return parentPath;
2498
+ }
2499
+ if (!parentPath && !currentRoute.path) {
2500
+ return '';
2501
+ }
2502
+ else if (parentPath && !currentRoute.path) {
2503
+ return `${parentPath}/`;
2504
+ }
2505
+ else if (!parentPath && currentRoute.path) {
2506
+ return currentRoute.path;
2507
+ }
2508
+ else {
2509
+ return `${parentPath}/${currentRoute.path}`;
2510
+ }
2511
+ }
2512
+ /**
2513
+ * Makes a copy of the config and adds any default required properties.
2514
+ */
2515
+ function standardizeConfig(r) {
2516
+ const children = r.children && r.children.map(standardizeConfig);
2517
+ const c = children ? { ...r, children } : { ...r };
2518
+ if ((!c.component && !c.loadComponent) && (children || c.loadChildren) &&
2519
+ (c.outlet && c.outlet !== PRIMARY_OUTLET)) {
2520
+ c.component = ɵEmptyOutletComponent;
2521
+ }
2522
+ return c;
2523
+ }
2524
+ /** Returns the `route.outlet` or PRIMARY_OUTLET if none exists. */
2525
+ function getOutlet(route) {
2526
+ return route.outlet || PRIMARY_OUTLET;
2527
+ }
2528
+ /**
2529
+ * Sorts the `routes` such that the ones with an outlet matching `outletName` come first.
2530
+ * The order of the configs is otherwise preserved.
2531
+ */
2532
+ function sortByMatchingOutlets(routes, outletName) {
2533
+ const sortedConfig = routes.filter(r => getOutlet(r) === outletName);
2534
+ sortedConfig.push(...routes.filter(r => getOutlet(r) !== outletName));
2535
+ return sortedConfig;
2536
+ }
2537
+ /**
2538
+ * Gets the first injector in the snapshot's parent tree.
2539
+ *
2540
+ * If the `Route` has a static list of providers, the returned injector will be the one created from
2541
+ * those. If it does not exist, the returned injector may come from the parents, which may be from a
2542
+ * loaded config or their static providers.
2543
+ *
2544
+ * Returns `null` if there is neither this nor any parents have a stored injector.
2545
+ *
2546
+ * Generally used for retrieving the injector to use for getting tokens for guards/resolvers and
2547
+ * also used for getting the correct injector to use for creating components.
2548
+ */
2549
+ function getClosestRouteInjector(snapshot) {
2550
+ if (!snapshot)
2551
+ return null;
2552
+ // If the current route has its own injector, which is created from the static providers on the
2553
+ // route itself, we should use that. Otherwise, we start at the parent since we do not want to
2554
+ // include the lazy loaded injector from this route.
2555
+ if (snapshot.routeConfig?._injector) {
2556
+ return snapshot.routeConfig._injector;
2557
+ }
2558
+ for (let s = snapshot.parent; s; s = s.parent) {
2559
+ const route = s.routeConfig;
2560
+ // Note that the order here is important. `_loadedInjector` stored on the route with
2561
+ // `loadChildren: () => NgModule` so it applies to child routes with priority. The `_injector`
2562
+ // is created from the static providers on that parent route, so it applies to the children as
2563
+ // well, but only if there is no lazy loaded NgModuleRef injector.
2564
+ if (route?._loadedInjector)
2565
+ return route._loadedInjector;
2566
+ if (route?._injector)
2567
+ return route._injector;
2568
+ }
2569
+ return null;
2570
+ }
2571
+
2572
+ /**
2573
+ * @license
2574
+ * Copyright Google LLC All Rights Reserved.
2575
+ *
2576
+ * Use of this source code is governed by an MIT-style license that can be
2577
+ * found in the LICENSE file at https://angular.io/license
2578
+ */
2579
+ const activateRoutes = (rootContexts, routeReuseStrategy, forwardEvent) => map(t => {
2580
+ new ActivateRoutes(routeReuseStrategy, t.targetRouterState, t.currentRouterState, forwardEvent)
2581
+ .activate(rootContexts);
2582
+ return t;
2583
+ });
2584
+ class ActivateRoutes {
2585
+ constructor(routeReuseStrategy, futureState, currState, forwardEvent) {
2586
+ this.routeReuseStrategy = routeReuseStrategy;
2587
+ this.futureState = futureState;
2588
+ this.currState = currState;
2589
+ this.forwardEvent = forwardEvent;
2590
+ }
2591
+ activate(parentContexts) {
2592
+ const futureRoot = this.futureState._root;
2593
+ const currRoot = this.currState ? this.currState._root : null;
2594
+ this.deactivateChildRoutes(futureRoot, currRoot, parentContexts);
2595
+ advanceActivatedRoute(this.futureState.root);
2596
+ this.activateChildRoutes(futureRoot, currRoot, parentContexts);
2597
+ }
2598
+ // De-activate the child route that are not re-used for the future state
2599
+ deactivateChildRoutes(futureNode, currNode, contexts) {
2600
+ const children = nodeChildrenAsMap(currNode);
2601
+ // Recurse on the routes active in the future state to de-activate deeper children
2602
+ futureNode.children.forEach(futureChild => {
2603
+ const childOutletName = futureChild.value.outlet;
2604
+ this.deactivateRoutes(futureChild, children[childOutletName], contexts);
2605
+ delete children[childOutletName];
2606
+ });
2607
+ // De-activate the routes that will not be re-used
2608
+ forEach(children, (v, childName) => {
2609
+ this.deactivateRouteAndItsChildren(v, contexts);
2610
+ });
2611
+ }
2612
+ deactivateRoutes(futureNode, currNode, parentContext) {
2613
+ const future = futureNode.value;
2614
+ const curr = currNode ? currNode.value : null;
2615
+ if (future === curr) {
2616
+ // Reusing the node, check to see if the children need to be de-activated
2617
+ if (future.component) {
2618
+ // If we have a normal route, we need to go through an outlet.
2619
+ const context = parentContext.getContext(future.outlet);
2620
+ if (context) {
2621
+ this.deactivateChildRoutes(futureNode, currNode, context.children);
2622
+ }
2623
+ }
2624
+ else {
2625
+ // if we have a componentless route, we recurse but keep the same outlet map.
2626
+ this.deactivateChildRoutes(futureNode, currNode, parentContext);
2627
+ }
2628
+ }
2629
+ else {
2630
+ if (curr) {
2631
+ // Deactivate the current route which will not be re-used
2632
+ this.deactivateRouteAndItsChildren(currNode, parentContext);
2633
+ }
2634
+ }
2635
+ }
2636
+ deactivateRouteAndItsChildren(route, parentContexts) {
2637
+ // If there is no component, the Route is never attached to an outlet (because there is no
2638
+ // component to attach).
2639
+ if (route.value.component && this.routeReuseStrategy.shouldDetach(route.value.snapshot)) {
2640
+ this.detachAndStoreRouteSubtree(route, parentContexts);
2641
+ }
2642
+ else {
2643
+ this.deactivateRouteAndOutlet(route, parentContexts);
2644
+ }
2645
+ }
2646
+ detachAndStoreRouteSubtree(route, parentContexts) {
2647
+ const context = parentContexts.getContext(route.value.outlet);
2648
+ const contexts = context && route.value.component ? context.children : parentContexts;
2649
+ const children = nodeChildrenAsMap(route);
2650
+ for (const childOutlet of Object.keys(children)) {
2651
+ this.deactivateRouteAndItsChildren(children[childOutlet], contexts);
2652
+ }
2653
+ if (context && context.outlet) {
2654
+ const componentRef = context.outlet.detach();
2655
+ const contexts = context.children.onOutletDeactivated();
2656
+ this.routeReuseStrategy.store(route.value.snapshot, { componentRef, route, contexts });
2657
+ }
2658
+ }
2659
+ deactivateRouteAndOutlet(route, parentContexts) {
2660
+ const context = parentContexts.getContext(route.value.outlet);
2661
+ // The context could be `null` if we are on a componentless route but there may still be
2662
+ // children that need deactivating.
2663
+ const contexts = context && route.value.component ? context.children : parentContexts;
2664
+ const children = nodeChildrenAsMap(route);
2665
+ for (const childOutlet of Object.keys(children)) {
2666
+ this.deactivateRouteAndItsChildren(children[childOutlet], contexts);
2667
+ }
2668
+ if (context && context.outlet) {
2669
+ // Destroy the component
2670
+ context.outlet.deactivate();
2671
+ // Destroy the contexts for all the outlets that were in the component
2672
+ context.children.onOutletDeactivated();
2673
+ // Clear the information about the attached component on the context but keep the reference to
2674
+ // the outlet.
2675
+ context.attachRef = null;
2676
+ context.resolver = null;
2677
+ context.route = null;
2678
+ }
2679
+ }
2680
+ activateChildRoutes(futureNode, currNode, contexts) {
2681
+ const children = nodeChildrenAsMap(currNode);
2682
+ futureNode.children.forEach(c => {
2683
+ this.activateRoutes(c, children[c.value.outlet], contexts);
2684
+ this.forwardEvent(new ActivationEnd(c.value.snapshot));
2685
+ });
2686
+ if (futureNode.children.length) {
2687
+ this.forwardEvent(new ChildActivationEnd(futureNode.value.snapshot));
2688
+ }
2689
+ }
2690
+ activateRoutes(futureNode, currNode, parentContexts) {
2691
+ const future = futureNode.value;
2692
+ const curr = currNode ? currNode.value : null;
2693
+ advanceActivatedRoute(future);
2694
+ // reusing the node
2695
+ if (future === curr) {
2696
+ if (future.component) {
2697
+ // If we have a normal route, we need to go through an outlet.
2698
+ const context = parentContexts.getOrCreateContext(future.outlet);
2699
+ this.activateChildRoutes(futureNode, currNode, context.children);
2700
+ }
2701
+ else {
2702
+ // if we have a componentless route, we recurse but keep the same outlet map.
2703
+ this.activateChildRoutes(futureNode, currNode, parentContexts);
2704
+ }
2705
+ }
2706
+ else {
2707
+ if (future.component) {
2708
+ // if we have a normal route, we need to place the component into the outlet and recurse.
2709
+ const context = parentContexts.getOrCreateContext(future.outlet);
2710
+ if (this.routeReuseStrategy.shouldAttach(future.snapshot)) {
2711
+ const stored = this.routeReuseStrategy.retrieve(future.snapshot);
2712
+ this.routeReuseStrategy.store(future.snapshot, null);
2713
+ context.children.onOutletReAttached(stored.contexts);
2714
+ context.attachRef = stored.componentRef;
2715
+ context.route = stored.route.value;
2716
+ if (context.outlet) {
2717
+ // Attach right away when the outlet has already been instantiated
2718
+ // Otherwise attach from `RouterOutlet.ngOnInit` when it is instantiated
2719
+ context.outlet.attach(stored.componentRef, stored.route.value);
2720
+ }
2721
+ advanceActivatedRoute(stored.route.value);
2722
+ this.activateChildRoutes(futureNode, null, context.children);
2723
+ }
2724
+ else {
2725
+ const injector = getClosestRouteInjector(future.snapshot);
2726
+ const cmpFactoryResolver = injector?.get(ComponentFactoryResolver) ?? null;
2727
+ context.attachRef = null;
2728
+ context.route = future;
2729
+ context.resolver = cmpFactoryResolver;
2730
+ context.injector = injector;
2731
+ if (context.outlet) {
2732
+ // Activate the outlet when it has already been instantiated
2733
+ // Otherwise it will get activated from its `ngOnInit` when instantiated
2734
+ context.outlet.activateWith(future, context.injector);
2735
+ }
2736
+ this.activateChildRoutes(futureNode, null, context.children);
2737
+ }
2738
+ }
2739
+ else {
2740
+ // if we have a componentless route, we recurse but keep the same outlet map.
2741
+ this.activateChildRoutes(futureNode, null, parentContexts);
2742
+ }
2743
+ }
2564
2744
  }
2565
2745
  }
2566
2746
 
@@ -2572,22 +2752,39 @@ class OutletInjector {
2572
2752
  * found in the LICENSE file at https://angular.io/license
2573
2753
  */
2574
2754
  /**
2575
- * This component is used internally within the router to be a placeholder when an empty
2576
- * router-outlet is needed. For example, with a config such as:
2755
+ * Simple function check, but generic so type inference will flow. Example:
2577
2756
  *
2578
- * `{path: 'parent', outlet: 'nav', children: [...]}`
2757
+ * function product(a: number, b: number) {
2758
+ * return a * b;
2759
+ * }
2579
2760
  *
2580
- * In order to render, there needs to be a component on this config, which will default
2581
- * to this `EmptyOutletComponent`.
2761
+ * if (isFunction<product>(fn)) {
2762
+ * return fn(1, 2);
2763
+ * } else {
2764
+ * throw "Must provide the `product` function";
2765
+ * }
2582
2766
  */
2583
- class ɵEmptyOutletComponent {
2767
+ function isFunction(v) {
2768
+ return typeof v === 'function';
2769
+ }
2770
+ function isBoolean(v) {
2771
+ return typeof v === 'boolean';
2772
+ }
2773
+ function isUrlTree(v) {
2774
+ return v instanceof UrlTree;
2775
+ }
2776
+ function isCanLoad(guard) {
2777
+ return guard && isFunction(guard.canLoad);
2778
+ }
2779
+ function isCanActivate(guard) {
2780
+ return guard && isFunction(guard.canActivate);
2781
+ }
2782
+ function isCanActivateChild(guard) {
2783
+ return guard && isFunction(guard.canActivateChild);
2784
+ }
2785
+ function isCanDeactivate(guard) {
2786
+ return guard && isFunction(guard.canDeactivate);
2584
2787
  }
2585
- ɵEmptyOutletComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: ɵEmptyOutletComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2586
- ɵEmptyOutletComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "14.0.0-next.9", type: ɵEmptyOutletComponent, selector: "ng-component", ngImport: i0, template: `<router-outlet></router-outlet>`, isInline: true, directives: [{ type: RouterOutlet, selector: "router-outlet", outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
2587
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: ɵEmptyOutletComponent, decorators: [{
2588
- type: Component,
2589
- args: [{ template: `<router-outlet></router-outlet>` }]
2590
- }] });
2591
2788
 
2592
2789
  /**
2593
2790
  * @license
@@ -2596,113 +2793,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9",
2596
2793
  * Use of this source code is governed by an MIT-style license that can be
2597
2794
  * found in the LICENSE file at https://angular.io/license
2598
2795
  */
2599
- function validateConfig(config, parentPath = '') {
2600
- // forEach doesn't iterate undefined values
2601
- for (let i = 0; i < config.length; i++) {
2602
- const route = config[i];
2603
- const fullPath = getFullPath(parentPath, route);
2604
- validateNode(route, fullPath);
2605
- }
2606
- }
2607
- function validateNode(route, fullPath) {
2608
- if (typeof ngDevMode === 'undefined' || ngDevMode) {
2609
- if (!route) {
2610
- throw new Error(`
2611
- Invalid configuration of route '${fullPath}': Encountered undefined route.
2612
- The reason might be an extra comma.
2613
-
2614
- Example:
2615
- const routes: Routes = [
2616
- { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
2617
- { path: 'dashboard', component: DashboardComponent },, << two commas
2618
- { path: 'detail/:id', component: HeroDetailComponent }
2619
- ];
2620
- `);
2621
- }
2622
- if (Array.isArray(route)) {
2623
- throw new Error(`Invalid configuration of route '${fullPath}': Array cannot be specified`);
2624
- }
2625
- if (!route.component && !route.children && !route.loadChildren &&
2626
- (route.outlet && route.outlet !== PRIMARY_OUTLET)) {
2627
- throw new Error(`Invalid configuration of route '${fullPath}': a componentless route without children or loadChildren cannot have a named outlet set`);
2628
- }
2629
- if (route.redirectTo && route.children) {
2630
- throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and children cannot be used together`);
2631
- }
2632
- if (route.redirectTo && route.loadChildren) {
2633
- throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and loadChildren cannot be used together`);
2634
- }
2635
- if (route.children && route.loadChildren) {
2636
- throw new Error(`Invalid configuration of route '${fullPath}': children and loadChildren cannot be used together`);
2637
- }
2638
- if (route.redirectTo && route.component) {
2639
- throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and component cannot be used together`);
2640
- }
2641
- if (route.redirectTo && route.canActivate) {
2642
- throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and canActivate cannot be used together. Redirects happen before activation ` +
2643
- `so canActivate will never be executed.`);
2644
- }
2645
- if (route.path && route.matcher) {
2646
- throw new Error(`Invalid configuration of route '${fullPath}': path and matcher cannot be used together`);
2647
- }
2648
- if (route.redirectTo === void 0 && !route.component && !route.children && !route.loadChildren) {
2649
- throw new Error(`Invalid configuration of route '${fullPath}'. One of the following must be provided: component, redirectTo, children or loadChildren`);
2650
- }
2651
- if (route.path === void 0 && route.matcher === void 0) {
2652
- throw new Error(`Invalid configuration of route '${fullPath}': routes must have either a path or a matcher specified`);
2653
- }
2654
- if (typeof route.path === 'string' && route.path.charAt(0) === '/') {
2655
- throw new Error(`Invalid configuration of route '${fullPath}': path cannot start with a slash`);
2656
- }
2657
- if (route.path === '' && route.redirectTo !== void 0 && route.pathMatch === void 0) {
2658
- const exp = `The default value of 'pathMatch' is 'prefix', but often the intent is to use 'full'.`;
2659
- throw new Error(`Invalid configuration of route '{path: "${fullPath}", redirectTo: "${route.redirectTo}"}': please provide 'pathMatch'. ${exp}`);
2660
- }
2661
- }
2662
- if (route.children) {
2663
- validateConfig(route.children, fullPath);
2664
- }
2665
- }
2666
- function getFullPath(parentPath, currentRoute) {
2667
- if (!currentRoute) {
2668
- return parentPath;
2669
- }
2670
- if (!parentPath && !currentRoute.path) {
2671
- return '';
2672
- }
2673
- else if (parentPath && !currentRoute.path) {
2674
- return `${parentPath}/`;
2675
- }
2676
- else if (!parentPath && currentRoute.path) {
2677
- return currentRoute.path;
2678
- }
2679
- else {
2680
- return `${parentPath}/${currentRoute.path}`;
2681
- }
2682
- }
2683
- /**
2684
- * Makes a copy of the config and adds any default required properties.
2685
- */
2686
- function standardizeConfig(r) {
2687
- const children = r.children && r.children.map(standardizeConfig);
2688
- const c = children ? { ...r, children } : { ...r };
2689
- if (!c.component && (children || c.loadChildren) && (c.outlet && c.outlet !== PRIMARY_OUTLET)) {
2690
- c.component = ɵEmptyOutletComponent;
2691
- }
2692
- return c;
2693
- }
2694
- /** Returns the `route.outlet` or PRIMARY_OUTLET if none exists. */
2695
- function getOutlet(route) {
2696
- return route.outlet || PRIMARY_OUTLET;
2697
- }
2698
- /**
2699
- * Sorts the `routes` such that the ones with an outlet matching `outletName` come first.
2700
- * The order of the configs is otherwise preserved.
2701
- */
2702
- function sortByMatchingOutlets(routes, outletName) {
2703
- const sortedConfig = routes.filter(r => getOutlet(r) === outletName);
2704
- sortedConfig.push(...routes.filter(r => getOutlet(r) !== outletName));
2705
- return sortedConfig;
2796
+ const INITIAL_VALUE = Symbol('INITIAL_VALUE');
2797
+ function prioritizedGuardValue() {
2798
+ return switchMap(obs => {
2799
+ return combineLatest(obs.map(o => o.pipe(take(1), startWith(INITIAL_VALUE))))
2800
+ .pipe(scan((acc, list) => {
2801
+ let isPending = false;
2802
+ return list.reduce((innerAcc, val, i) => {
2803
+ if (innerAcc !== INITIAL_VALUE)
2804
+ return innerAcc;
2805
+ // Toggle pending flag if any values haven't been set yet
2806
+ if (val === INITIAL_VALUE)
2807
+ isPending = true;
2808
+ // Any other return values are only valid if we haven't yet hit a pending
2809
+ // call. This guarantees that in the case of a guard at the bottom of the
2810
+ // tree that returns a redirect, we will wait for the higher priority
2811
+ // guard at the top to finish before performing the redirect.
2812
+ if (!isPending) {
2813
+ // Early return when we hit a `false` value as that should always
2814
+ // cancel navigation
2815
+ if (val === false)
2816
+ return val;
2817
+ if (i === list.length - 1 || isUrlTree(val)) {
2818
+ return val;
2819
+ }
2820
+ }
2821
+ return innerAcc;
2822
+ }, acc);
2823
+ }, INITIAL_VALUE), filter(item => item !== INITIAL_VALUE), map(item => isUrlTree(item) ? item : item === true), //
2824
+ take(1));
2825
+ });
2706
2826
  }
2707
2827
 
2708
2828
  /**
@@ -2780,6 +2900,9 @@ function addEmptyPathsToChildrenIfNeeded(segmentGroup, consumedSegments, slicedS
2780
2900
  s._sourceSegment = segmentGroup;
2781
2901
  if (relativeLinkResolution === 'legacy') {
2782
2902
  s._segmentIndexShift = segmentGroup.segments.length;
2903
+ if (typeof ngDevMode === 'undefined' || !!ngDevMode) {
2904
+ s._segmentIndexShiftCorrected = consumedSegments.length;
2905
+ }
2783
2906
  }
2784
2907
  else {
2785
2908
  s._segmentIndexShift = consumedSegments.length;
@@ -2880,17 +3003,17 @@ function canLoadFails(route) {
2880
3003
  *
2881
3004
  * Lazy modules are loaded along the way.
2882
3005
  */
2883
- function applyRedirects$1(moduleInjector, configLoader, urlSerializer, urlTree, config) {
2884
- return new ApplyRedirects(moduleInjector, configLoader, urlSerializer, urlTree, config).apply();
3006
+ function applyRedirects$1(injector, configLoader, urlSerializer, urlTree, config) {
3007
+ return new ApplyRedirects(injector, configLoader, urlSerializer, urlTree, config).apply();
2885
3008
  }
2886
3009
  class ApplyRedirects {
2887
- constructor(moduleInjector, configLoader, urlSerializer, urlTree, config) {
3010
+ constructor(injector, configLoader, urlSerializer, urlTree, config) {
3011
+ this.injector = injector;
2888
3012
  this.configLoader = configLoader;
2889
3013
  this.urlSerializer = urlSerializer;
2890
3014
  this.urlTree = urlTree;
2891
3015
  this.config = config;
2892
3016
  this.allowRedirects = true;
2893
- this.ngModule = moduleInjector.get(NgModuleRef);
2894
3017
  }
2895
3018
  apply() {
2896
3019
  const splitGroup = split(this.urlTree.root, [], [], this.config).segmentGroup;
@@ -2901,7 +3024,7 @@ class ApplyRedirects {
2901
3024
  // them. We should be able to remove this logic as a "breaking change" but should do some more
2902
3025
  // investigation into the failures first.
2903
3026
  const rootSegmentGroup = new UrlSegmentGroup(splitGroup.segments, splitGroup.children);
2904
- const expanded$ = this.expandSegmentGroup(this.ngModule, this.config, rootSegmentGroup, PRIMARY_OUTLET);
3027
+ const expanded$ = this.expandSegmentGroup(this.injector, this.config, rootSegmentGroup, PRIMARY_OUTLET);
2905
3028
  const urlTrees$ = expanded$.pipe(map((rootSegmentGroup) => {
2906
3029
  return this.createUrlTree(squashSegmentGroup(rootSegmentGroup), this.urlTree.queryParams, this.urlTree.fragment);
2907
3030
  }));
@@ -2920,7 +3043,7 @@ class ApplyRedirects {
2920
3043
  }));
2921
3044
  }
2922
3045
  match(tree) {
2923
- const expanded$ = this.expandSegmentGroup(this.ngModule, this.config, tree.root, PRIMARY_OUTLET);
3046
+ const expanded$ = this.expandSegmentGroup(this.injector, this.config, tree.root, PRIMARY_OUTLET);
2924
3047
  const mapped$ = expanded$.pipe(map((rootSegmentGroup) => {
2925
3048
  return this.createUrlTree(squashSegmentGroup(rootSegmentGroup), tree.queryParams, tree.fragment);
2926
3049
  }));
@@ -2940,15 +3063,15 @@ class ApplyRedirects {
2940
3063
  rootCandidate;
2941
3064
  return new UrlTree(root, queryParams, fragment);
2942
3065
  }
2943
- expandSegmentGroup(ngModule, routes, segmentGroup, outlet) {
3066
+ expandSegmentGroup(injector, routes, segmentGroup, outlet) {
2944
3067
  if (segmentGroup.segments.length === 0 && segmentGroup.hasChildren()) {
2945
- return this.expandChildren(ngModule, routes, segmentGroup)
3068
+ return this.expandChildren(injector, routes, segmentGroup)
2946
3069
  .pipe(map((children) => new UrlSegmentGroup([], children)));
2947
3070
  }
2948
- return this.expandSegment(ngModule, segmentGroup, routes, segmentGroup.segments, outlet, true);
3071
+ return this.expandSegment(injector, segmentGroup, routes, segmentGroup.segments, outlet, true);
2949
3072
  }
2950
3073
  // Recursively expand segment groups for all the child outlets
2951
- expandChildren(ngModule, routes, segmentGroup) {
3074
+ expandChildren(injector, routes, segmentGroup) {
2952
3075
  // Expand outlets one at a time, starting with the primary outlet. We need to do it this way
2953
3076
  // because an absolute redirect from the primary outlet takes precedence.
2954
3077
  const childOutlets = [];
@@ -2967,16 +3090,25 @@ class ApplyRedirects {
2967
3090
  // first, followed by routes for other outlets, which might match if they have an
2968
3091
  // empty path.
2969
3092
  const sortedRoutes = sortByMatchingOutlets(routes, childOutlet);
2970
- return this.expandSegmentGroup(ngModule, sortedRoutes, child, childOutlet)
3093
+ return this.expandSegmentGroup(injector, sortedRoutes, child, childOutlet)
2971
3094
  .pipe(map(s => ({ segment: s, outlet: childOutlet })));
2972
3095
  }), scan((children, expandedChild) => {
2973
3096
  children[expandedChild.outlet] = expandedChild.segment;
2974
3097
  return children;
2975
3098
  }, {}), last$1());
2976
3099
  }
2977
- expandSegment(ngModule, segmentGroup, routes, segments, outlet, allowRedirects) {
2978
- return from(routes).pipe(concatMap((r) => {
2979
- const expanded$ = this.expandSegmentAgainstRoute(ngModule, segmentGroup, routes, r, segments, outlet, allowRedirects);
3100
+ expandSegment(injector, segmentGroup, routes, segments, outlet, allowRedirects) {
3101
+ return from(routes).pipe(concatMap(r => {
3102
+ if (r.providers && !r._injector) {
3103
+ r._injector = createEnvironmentInjector(r.providers, injector, `Route: ${r.path}`);
3104
+ }
3105
+ // We specifically _do not_ want to include the _loadedInjector here. The loaded injector
3106
+ // only applies to the route's children, not the route itself. Note that this distinction
3107
+ // only applies here to any tokens we try to retrieve during this phase. At the moment,
3108
+ // that only includes `canLoad`, which won't run again once the child module is loaded. As
3109
+ // a result, this makes no difference right now, but could in the future if there are more
3110
+ // actions here that need DI (for example, a canMatch guard).
3111
+ const expanded$ = this.expandSegmentAgainstRoute(r._injector ?? injector, segmentGroup, routes, r, segments, outlet, allowRedirects);
2980
3112
  return expanded$.pipe(catchError((e) => {
2981
3113
  if (e instanceof NoMatch$1) {
2982
3114
  return of(null);
@@ -2993,35 +3125,35 @@ class ApplyRedirects {
2993
3125
  throw e;
2994
3126
  }));
2995
3127
  }
2996
- expandSegmentAgainstRoute(ngModule, segmentGroup, routes, route, paths, outlet, allowRedirects) {
3128
+ expandSegmentAgainstRoute(injector, segmentGroup, routes, route, paths, outlet, allowRedirects) {
2997
3129
  if (!isImmediateMatch(route, segmentGroup, paths, outlet)) {
2998
3130
  return noMatch(segmentGroup);
2999
3131
  }
3000
3132
  if (route.redirectTo === undefined) {
3001
- return this.matchSegmentAgainstRoute(ngModule, segmentGroup, route, paths, outlet);
3133
+ return this.matchSegmentAgainstRoute(injector, segmentGroup, route, paths, outlet);
3002
3134
  }
3003
3135
  if (allowRedirects && this.allowRedirects) {
3004
- return this.expandSegmentAgainstRouteUsingRedirect(ngModule, segmentGroup, routes, route, paths, outlet);
3136
+ return this.expandSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, paths, outlet);
3005
3137
  }
3006
3138
  return noMatch(segmentGroup);
3007
3139
  }
3008
- expandSegmentAgainstRouteUsingRedirect(ngModule, segmentGroup, routes, route, segments, outlet) {
3140
+ expandSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet) {
3009
3141
  if (route.path === '**') {
3010
- return this.expandWildCardWithParamsAgainstRouteUsingRedirect(ngModule, routes, route, outlet);
3142
+ return this.expandWildCardWithParamsAgainstRouteUsingRedirect(injector, routes, route, outlet);
3011
3143
  }
3012
- return this.expandRegularSegmentAgainstRouteUsingRedirect(ngModule, segmentGroup, routes, route, segments, outlet);
3144
+ return this.expandRegularSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet);
3013
3145
  }
3014
- expandWildCardWithParamsAgainstRouteUsingRedirect(ngModule, routes, route, outlet) {
3146
+ expandWildCardWithParamsAgainstRouteUsingRedirect(injector, routes, route, outlet) {
3015
3147
  const newTree = this.applyRedirectCommands([], route.redirectTo, {});
3016
3148
  if (route.redirectTo.startsWith('/')) {
3017
3149
  return absoluteRedirect(newTree);
3018
3150
  }
3019
3151
  return this.lineralizeSegments(route, newTree).pipe(mergeMap((newSegments) => {
3020
3152
  const group = new UrlSegmentGroup(newSegments, {});
3021
- return this.expandSegment(ngModule, group, routes, newSegments, outlet, false);
3153
+ return this.expandSegment(injector, group, routes, newSegments, outlet, false);
3022
3154
  }));
3023
3155
  }
3024
- expandRegularSegmentAgainstRouteUsingRedirect(ngModule, segmentGroup, routes, route, segments, outlet) {
3156
+ expandRegularSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet) {
3025
3157
  const { matched, consumedSegments, remainingSegments, positionalParamSegments } = match(segmentGroup, route, segments);
3026
3158
  if (!matched)
3027
3159
  return noMatch(segmentGroup);
@@ -3030,16 +3162,18 @@ class ApplyRedirects {
3030
3162
  return absoluteRedirect(newTree);
3031
3163
  }
3032
3164
  return this.lineralizeSegments(route, newTree).pipe(mergeMap((newSegments) => {
3033
- return this.expandSegment(ngModule, segmentGroup, routes, newSegments.concat(remainingSegments), outlet, false);
3165
+ return this.expandSegment(injector, segmentGroup, routes, newSegments.concat(remainingSegments), outlet, false);
3034
3166
  }));
3035
3167
  }
3036
- matchSegmentAgainstRoute(ngModule, rawSegmentGroup, route, segments, outlet) {
3168
+ matchSegmentAgainstRoute(injector, rawSegmentGroup, route, segments, outlet) {
3037
3169
  if (route.path === '**') {
3038
3170
  if (route.loadChildren) {
3039
- const loaded$ = route._loadedConfig ? of(route._loadedConfig) :
3040
- this.configLoader.load(ngModule.injector, route);
3171
+ const loaded$ = route._loadedRoutes ?
3172
+ of({ routes: route._loadedRoutes, injector: route._loadedInjector }) :
3173
+ this.configLoader.loadChildren(injector, route);
3041
3174
  return loaded$.pipe(map((cfg) => {
3042
- route._loadedConfig = cfg;
3175
+ route._loadedRoutes = cfg.routes;
3176
+ route._loadedInjector = cfg.injector;
3043
3177
  return new UrlSegmentGroup(segments, {});
3044
3178
  }));
3045
3179
  }
@@ -3048,55 +3182,55 @@ class ApplyRedirects {
3048
3182
  const { matched, consumedSegments, remainingSegments } = match(rawSegmentGroup, route, segments);
3049
3183
  if (!matched)
3050
3184
  return noMatch(rawSegmentGroup);
3051
- const childConfig$ = this.getChildConfig(ngModule, route, segments);
3185
+ const childConfig$ = this.getChildConfig(injector, route, segments);
3052
3186
  return childConfig$.pipe(mergeMap((routerConfig) => {
3053
- const childModule = routerConfig.module;
3187
+ const childInjector = routerConfig.injector ?? injector;
3054
3188
  const childConfig = routerConfig.routes;
3055
3189
  const { segmentGroup: splitSegmentGroup, slicedSegments } = split(rawSegmentGroup, consumedSegments, remainingSegments, childConfig);
3056
3190
  // See comment on the other call to `split` about why this is necessary.
3057
3191
  const segmentGroup = new UrlSegmentGroup(splitSegmentGroup.segments, splitSegmentGroup.children);
3058
3192
  if (slicedSegments.length === 0 && segmentGroup.hasChildren()) {
3059
- const expanded$ = this.expandChildren(childModule, childConfig, segmentGroup);
3193
+ const expanded$ = this.expandChildren(childInjector, childConfig, segmentGroup);
3060
3194
  return expanded$.pipe(map((children) => new UrlSegmentGroup(consumedSegments, children)));
3061
3195
  }
3062
3196
  if (childConfig.length === 0 && slicedSegments.length === 0) {
3063
3197
  return of(new UrlSegmentGroup(consumedSegments, {}));
3064
3198
  }
3065
3199
  const matchedOnOutlet = getOutlet(route) === outlet;
3066
- const expanded$ = this.expandSegment(childModule, segmentGroup, childConfig, slicedSegments, matchedOnOutlet ? PRIMARY_OUTLET : outlet, true);
3200
+ const expanded$ = this.expandSegment(childInjector, segmentGroup, childConfig, slicedSegments, matchedOnOutlet ? PRIMARY_OUTLET : outlet, true);
3067
3201
  return expanded$.pipe(map((cs) => new UrlSegmentGroup(consumedSegments.concat(cs.segments), cs.children)));
3068
3202
  }));
3069
3203
  }
3070
- getChildConfig(ngModule, route, segments) {
3204
+ getChildConfig(injector, route, segments) {
3071
3205
  if (route.children) {
3072
3206
  // The children belong to the same module
3073
- return of(new LoadedRouterConfig(route.children, ngModule));
3207
+ return of({ routes: route.children, injector });
3074
3208
  }
3075
3209
  if (route.loadChildren) {
3076
3210
  // lazy children belong to the loaded module
3077
- if (route._loadedConfig !== undefined) {
3078
- return of(route._loadedConfig);
3211
+ if (route._loadedRoutes !== undefined) {
3212
+ return of({ routes: route._loadedRoutes, injector: route._loadedInjector });
3079
3213
  }
3080
- return this.runCanLoadGuards(ngModule.injector, route, segments)
3214
+ return this.runCanLoadGuards(injector, route, segments)
3081
3215
  .pipe(mergeMap((shouldLoadResult) => {
3082
3216
  if (shouldLoadResult) {
3083
- return this.configLoader.load(ngModule.injector, route)
3084
- .pipe(map((cfg) => {
3085
- route._loadedConfig = cfg;
3086
- return cfg;
3217
+ return this.configLoader.loadChildren(injector, route)
3218
+ .pipe(tap((cfg) => {
3219
+ route._loadedRoutes = cfg.routes;
3220
+ route._loadedInjector = cfg.injector;
3087
3221
  }));
3088
3222
  }
3089
3223
  return canLoadFails(route);
3090
3224
  }));
3091
3225
  }
3092
- return of(new LoadedRouterConfig([], ngModule));
3226
+ return of({ routes: [], injector });
3093
3227
  }
3094
- runCanLoadGuards(moduleInjector, route, segments) {
3228
+ runCanLoadGuards(injector, route, segments) {
3095
3229
  const canLoad = route.canLoad;
3096
3230
  if (!canLoad || canLoad.length === 0)
3097
3231
  return of(true);
3098
3232
  const canLoadObservables = canLoad.map((injectionToken) => {
3099
- const guard = moduleInjector.get(injectionToken);
3233
+ const guard = injector.get(injectionToken);
3100
3234
  let guardVal;
3101
3235
  if (isCanLoad(guard)) {
3102
3236
  guardVal = guard.canLoad(route, segments);
@@ -3224,8 +3358,8 @@ function squashSegmentGroup(segmentGroup) {
3224
3358
  * Use of this source code is governed by an MIT-style license that can be
3225
3359
  * found in the LICENSE file at https://angular.io/license
3226
3360
  */
3227
- function applyRedirects(moduleInjector, configLoader, urlSerializer, config) {
3228
- return switchMap(t => applyRedirects$1(moduleInjector, configLoader, urlSerializer, t.extractedUrl, config)
3361
+ function applyRedirects(environmentInjector, configLoader, urlSerializer, config) {
3362
+ return switchMap(t => applyRedirects$1(environmentInjector, configLoader, urlSerializer, t.extractedUrl, config)
3229
3363
  .pipe(map(urlAfterRedirects => ({ ...t, urlAfterRedirects }))));
3230
3364
  }
3231
3365
 
@@ -3259,21 +3393,11 @@ function getCanActivateChild(p) {
3259
3393
  return null;
3260
3394
  return { node: p, guards: canActivateChild };
3261
3395
  }
3262
- function getToken(token, snapshot, moduleInjector) {
3263
- const config = getClosestLoadedConfig(snapshot);
3264
- const injector = config ? config.module.injector : moduleInjector;
3396
+ function getToken(token, snapshot, fallbackInjector) {
3397
+ const routeInjector = getClosestRouteInjector(snapshot);
3398
+ const injector = routeInjector ?? fallbackInjector;
3265
3399
  return injector.get(token);
3266
3400
  }
3267
- function getClosestLoadedConfig(snapshot) {
3268
- if (!snapshot)
3269
- return null;
3270
- for (let s = snapshot.parent; s; s = s.parent) {
3271
- const route = s.routeConfig;
3272
- if (route && route._loadedConfig)
3273
- return route._loadedConfig;
3274
- }
3275
- return null;
3276
- }
3277
3401
  function getChildRouteGuards(futureNode, currNode, contexts, futurePath, checks = {
3278
3402
  canDeactivateChecks: [],
3279
3403
  canActivateChecks: []
@@ -3517,6 +3641,7 @@ function runCanDeactivate(component, currARS, currRSS, futureRSS, moduleInjector
3517
3641
  * Use of this source code is governed by an MIT-style license that can be
3518
3642
  * found in the LICENSE file at https://angular.io/license
3519
3643
  */
3644
+ const NG_DEV_MODE$2 = typeof ngDevMode === 'undefined' || !!ngDevMode;
3520
3645
  class NoMatch {
3521
3646
  }
3522
3647
  function newObservableError(e) {
@@ -3632,7 +3757,13 @@ class Recognizer {
3632
3757
  let remainingSegments = [];
3633
3758
  if (route.path === '**') {
3634
3759
  const params = segments.length > 0 ? last(segments).parameters : {};
3635
- snapshot = new ActivatedRouteSnapshot(segments, params, Object.freeze({ ...this.urlTree.queryParams }), this.urlTree.fragment, getData(route), getOutlet(route), route.component, route, getSourceSegmentGroup(rawSegment), getPathIndexShift(rawSegment) + segments.length, getResolve(route));
3760
+ const pathIndexShift = getPathIndexShift(rawSegment) + segments.length;
3761
+ snapshot = new ActivatedRouteSnapshot(segments, params, Object.freeze({ ...this.urlTree.queryParams }), this.urlTree.fragment, getData(route), getOutlet(route), route.component ?? route._loadedComponent ?? null, route, getSourceSegmentGroup(rawSegment), pathIndexShift, getResolve(route),
3762
+ // NG_DEV_MODE is used to prevent the getCorrectedPathIndexShift function from affecting
3763
+ // production bundle size. This value is intended only to surface a warning to users
3764
+ // depending on `relativeLinkResolution: 'legacy'` in dev mode.
3765
+ (NG_DEV_MODE$2 ? getCorrectedPathIndexShift(rawSegment) + segments.length :
3766
+ pathIndexShift));
3636
3767
  }
3637
3768
  else {
3638
3769
  const result = match(rawSegment, route, segments);
@@ -3641,7 +3772,9 @@ class Recognizer {
3641
3772
  }
3642
3773
  consumedSegments = result.consumedSegments;
3643
3774
  remainingSegments = result.remainingSegments;
3644
- snapshot = new ActivatedRouteSnapshot(consumedSegments, result.parameters, Object.freeze({ ...this.urlTree.queryParams }), this.urlTree.fragment, getData(route), getOutlet(route), route.component, route, getSourceSegmentGroup(rawSegment), getPathIndexShift(rawSegment) + consumedSegments.length, getResolve(route));
3775
+ const pathIndexShift = getPathIndexShift(rawSegment) + consumedSegments.length;
3776
+ snapshot = new ActivatedRouteSnapshot(consumedSegments, result.parameters, Object.freeze({ ...this.urlTree.queryParams }), this.urlTree.fragment, getData(route), getOutlet(route), route.component ?? route._loadedComponent ?? null, route, getSourceSegmentGroup(rawSegment), pathIndexShift, getResolve(route), (NG_DEV_MODE$2 ? getCorrectedPathIndexShift(rawSegment) + consumedSegments.length :
3777
+ pathIndexShift));
3645
3778
  }
3646
3779
  const childConfig = getChildConfig(route);
3647
3780
  const { segmentGroup, slicedSegments } = split(rawSegment, consumedSegments, remainingSegments,
@@ -3689,7 +3822,7 @@ function getChildConfig(route) {
3689
3822
  return route.children;
3690
3823
  }
3691
3824
  if (route.loadChildren) {
3692
- return route._loadedConfig.routes;
3825
+ return route._loadedRoutes;
3693
3826
  }
3694
3827
  return [];
3695
3828
  }
@@ -3751,10 +3884,19 @@ function getSourceSegmentGroup(segmentGroup) {
3751
3884
  }
3752
3885
  function getPathIndexShift(segmentGroup) {
3753
3886
  let s = segmentGroup;
3754
- let res = (s._segmentIndexShift ? s._segmentIndexShift : 0);
3887
+ let res = s._segmentIndexShift ?? 0;
3888
+ while (s._sourceSegment) {
3889
+ s = s._sourceSegment;
3890
+ res += s._segmentIndexShift ?? 0;
3891
+ }
3892
+ return res - 1;
3893
+ }
3894
+ function getCorrectedPathIndexShift(segmentGroup) {
3895
+ let s = segmentGroup;
3896
+ let res = s._segmentIndexShiftCorrected ?? s._segmentIndexShift ?? 0;
3755
3897
  while (s._sourceSegment) {
3756
3898
  s = s._sourceSegment;
3757
- res += (s._segmentIndexShift ? s._segmentIndexShift : 0);
3899
+ res += s._segmentIndexShiftCorrected ?? s._segmentIndexShift ?? 0;
3758
3900
  }
3759
3901
  return res - 1;
3760
3902
  }
@@ -3804,22 +3946,16 @@ function resolveData(paramsInheritanceStrategy, moduleInjector) {
3804
3946
  function runResolve(futureARS, futureRSS, paramsInheritanceStrategy, moduleInjector) {
3805
3947
  const config = futureARS.routeConfig;
3806
3948
  const resolve = futureARS._resolve;
3807
- const data = { ...futureARS.data };
3808
- if (config?.title !== undefined) {
3809
- if (typeof config.title === 'string' || config.title === null) {
3810
- data[RouteTitle] = config.title;
3811
- }
3812
- else {
3813
- resolve[RouteTitle] = config.title;
3814
- }
3949
+ if (config?.title !== undefined && !hasStaticTitle(config)) {
3950
+ resolve[RouteTitle] = config.title;
3815
3951
  }
3816
3952
  return resolveNode(resolve, futureARS, futureRSS, moduleInjector)
3817
3953
  .pipe(map((resolvedData) => {
3818
3954
  futureARS._resolvedData = resolvedData;
3819
- futureARS.data = {
3820
- ...data,
3821
- ...inheritedParamsDataResolve(futureARS, paramsInheritanceStrategy).resolve
3822
- };
3955
+ futureARS.data = inheritedParamsDataResolve(futureARS, paramsInheritanceStrategy).resolve;
3956
+ if (config && hasStaticTitle(config)) {
3957
+ futureARS.data[RouteTitle] = config.title;
3958
+ }
3823
3959
  return null;
3824
3960
  }));
3825
3961
  }
@@ -3830,16 +3966,9 @@ function resolveNode(resolve, futureARS, futureRSS, moduleInjector) {
3830
3966
  }
3831
3967
  const data = {};
3832
3968
  return from(keys).pipe(mergeMap(key => getResolver(resolve[key], futureARS, futureRSS, moduleInjector)
3833
- .pipe(take(1), tap((value) => {
3969
+ .pipe(first(), tap((value) => {
3834
3970
  data[key] = value;
3835
- }))), takeLast(1), mergeMap(() => {
3836
- // Ensure all resolvers returned values, otherwise don't emit any "next" and just complete
3837
- // the chain which will cancel navigation
3838
- if (getDataKeys(data).length === keys.length) {
3839
- return of(data);
3840
- }
3841
- return EMPTY;
3842
- }));
3971
+ }))), takeLast(1), mapTo(data), catchError((e) => e instanceof EmptyError ? EMPTY : throwError(e)));
3843
3972
  }
3844
3973
  function getDataKeys(obj) {
3845
3974
  return [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)];
@@ -3849,6 +3978,9 @@ function getResolver(injectionToken, futureARS, futureRSS, moduleInjector) {
3849
3978
  return resolver.resolve ? wrapIntoObservable(resolver.resolve(futureARS, futureRSS)) :
3850
3979
  wrapIntoObservable(resolver(futureARS, futureRSS));
3851
3980
  }
3981
+ function hasStaticTitle(config) {
3982
+ return typeof config.title === 'string' || config.title === null;
3983
+ }
3852
3984
 
3853
3985
  /**
3854
3986
  * @license
@@ -3945,6 +4077,7 @@ class DefaultRouteReuseStrategy extends BaseRouteReuseStrategy {
3945
4077
  * Use of this source code is governed by an MIT-style license that can be
3946
4078
  * found in the LICENSE file at https://angular.io/license
3947
4079
  */
4080
+ const NG_DEV_MODE$1 = typeof ngDevMode === 'undefined' || !!ngDevMode;
3948
4081
  /**
3949
4082
  * The [DI token](guide/glossary/#di-token) for a router configuration.
3950
4083
  *
@@ -3957,43 +4090,84 @@ class DefaultRouteReuseStrategy extends BaseRouteReuseStrategy {
3957
4090
  */
3958
4091
  const ROUTES = new InjectionToken('ROUTES');
3959
4092
  class RouterConfigLoader {
3960
- constructor(injector, compiler, onLoadStartListener, onLoadEndListener) {
4093
+ constructor(injector, compiler) {
3961
4094
  this.injector = injector;
3962
4095
  this.compiler = compiler;
3963
- this.onLoadStartListener = onLoadStartListener;
3964
- this.onLoadEndListener = onLoadEndListener;
4096
+ this.componentLoaders = new WeakMap();
4097
+ this.childrenLoaders = new WeakMap();
4098
+ }
4099
+ loadComponent(route) {
4100
+ if (this.componentLoaders.get(route)) {
4101
+ return this.componentLoaders.get(route);
4102
+ }
4103
+ else if (route._loadedComponent) {
4104
+ return of(route._loadedComponent);
4105
+ }
4106
+ if (this.onLoadStartListener) {
4107
+ this.onLoadStartListener(route);
4108
+ }
4109
+ const loadRunner = wrapIntoObservable(route.loadComponent())
4110
+ .pipe(tap(component => {
4111
+ if (this.onLoadEndListener) {
4112
+ this.onLoadEndListener(route);
4113
+ }
4114
+ NG_DEV_MODE$1 && assertStandalone(route.path ?? '', component);
4115
+ route._loadedComponent = component;
4116
+ }), finalize(() => {
4117
+ this.componentLoaders.delete(route);
4118
+ }));
4119
+ // Use custom ConnectableObservable as share in runners pipe increasing the bundle size too much
4120
+ const loader = new ConnectableObservable(loadRunner, () => new Subject()).pipe(refCount());
4121
+ this.componentLoaders.set(route, loader);
4122
+ return loader;
3965
4123
  }
3966
- load(parentInjector, route) {
3967
- if (route._loader$) {
3968
- return route._loader$;
4124
+ loadChildren(parentInjector, route) {
4125
+ if (this.childrenLoaders.get(route)) {
4126
+ return this.childrenLoaders.get(route);
4127
+ }
4128
+ else if (route._loadedRoutes) {
4129
+ return of({ routes: route._loadedRoutes, injector: route._loadedInjector });
3969
4130
  }
3970
4131
  if (this.onLoadStartListener) {
3971
4132
  this.onLoadStartListener(route);
3972
4133
  }
3973
- const moduleFactory$ = this.loadModuleFactory(route.loadChildren);
3974
- const loadRunner = moduleFactory$.pipe(map((factory) => {
4134
+ const moduleFactoryOrRoutes$ = this.loadModuleFactoryOrRoutes(route.loadChildren);
4135
+ const loadRunner = moduleFactoryOrRoutes$.pipe(map((factoryOrRoutes) => {
3975
4136
  if (this.onLoadEndListener) {
3976
4137
  this.onLoadEndListener(route);
3977
4138
  }
3978
- const module = factory.create(parentInjector);
3979
- // When loading a module that doesn't provide `RouterModule.forChild()` preloader
3980
- // will get stuck in an infinite loop. The child module's Injector will look to
3981
- // its parent `Injector` when it doesn't find any ROUTES so it will return routes
3982
- // for it's parent module instead.
3983
- return new LoadedRouterConfig(flatten(module.injector.get(ROUTES, undefined, InjectFlags.Self | InjectFlags.Optional))
3984
- .map(standardizeConfig), module);
3985
- }), catchError((err) => {
3986
- route._loader$ = undefined;
3987
- throw err;
4139
+ // This injector comes from the `NgModuleRef` when lazy loading an `NgModule`. There is no
4140
+ // injector associated with lazy loading a `Route` array.
4141
+ let injector;
4142
+ let rawRoutes;
4143
+ let requireStandaloneComponents = false;
4144
+ if (Array.isArray(factoryOrRoutes)) {
4145
+ rawRoutes = factoryOrRoutes;
4146
+ requireStandaloneComponents = true;
4147
+ }
4148
+ else {
4149
+ injector = factoryOrRoutes.create(parentInjector).injector;
4150
+ // When loading a module that doesn't provide `RouterModule.forChild()` preloader
4151
+ // will get stuck in an infinite loop. The child module's Injector will look to
4152
+ // its parent `Injector` when it doesn't find any ROUTES so it will return routes
4153
+ // for it's parent module instead.
4154
+ rawRoutes = flatten(injector.get(ROUTES, [], InjectFlags.Self | InjectFlags.Optional));
4155
+ }
4156
+ const routes = rawRoutes.map(standardizeConfig);
4157
+ NG_DEV_MODE$1 && validateConfig(routes, route.path, requireStandaloneComponents);
4158
+ return { routes, injector };
4159
+ }), finalize(() => {
4160
+ this.childrenLoaders.delete(route);
3988
4161
  }));
3989
4162
  // Use custom ConnectableObservable as share in runners pipe increasing the bundle size too much
3990
- route._loader$ = new ConnectableObservable(loadRunner, () => new Subject())
4163
+ const loader = new ConnectableObservable(loadRunner, () => new Subject())
3991
4164
  .pipe(refCount());
3992
- return route._loader$;
4165
+ this.childrenLoaders.set(route, loader);
4166
+ return loader;
3993
4167
  }
3994
- loadModuleFactory(loadChildren) {
4168
+ loadModuleFactoryOrRoutes(loadChildren) {
3995
4169
  return wrapIntoObservable(loadChildren()).pipe(mergeMap((t) => {
3996
- if (t instanceof NgModuleFactory) {
4170
+ if (t instanceof NgModuleFactory || Array.isArray(t)) {
3997
4171
  return of(t);
3998
4172
  }
3999
4173
  else {
@@ -4002,6 +4176,11 @@ class RouterConfigLoader {
4002
4176
  }));
4003
4177
  }
4004
4178
  }
4179
+ RouterConfigLoader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterConfigLoader, deps: [{ token: i0.Injector }, { token: i0.Compiler }], target: i0.ɵɵFactoryTarget.Injectable });
4180
+ RouterConfigLoader.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterConfigLoader });
4181
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterConfigLoader, decorators: [{
4182
+ type: Injectable
4183
+ }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i0.Compiler }]; } });
4005
4184
 
4006
4185
  /**
4007
4186
  * @license
@@ -4041,6 +4220,7 @@ class DefaultUrlHandlingStrategy {
4041
4220
  * Use of this source code is governed by an MIT-style license that can be
4042
4221
  * found in the LICENSE file at https://angular.io/license
4043
4222
  */
4223
+ const NG_DEV_MODE = typeof ngDevMode === 'undefined' || !!ngDevMode;
4044
4224
  function defaultErrorHandler(error) {
4045
4225
  throw error;
4046
4226
  }
@@ -4183,6 +4363,8 @@ class Router {
4183
4363
  /**
4184
4364
  * Enables a bug fix that corrects relative link resolution in components with empty paths.
4185
4365
  * @see `RouterModule`
4366
+ *
4367
+ * @deprecated
4186
4368
  */
4187
4369
  this.relativeLinkResolution = 'corrected';
4188
4370
  /**
@@ -4210,6 +4392,9 @@ class Router {
4210
4392
  this.canceledNavigationResolution = 'replace';
4211
4393
  const onLoadStart = (r) => this.triggerEvent(new RouteConfigLoadStart(r));
4212
4394
  const onLoadEnd = (r) => this.triggerEvent(new RouteConfigLoadEnd(r));
4395
+ this.configLoader = injector.get(RouterConfigLoader);
4396
+ this.configLoader.onLoadEndListener = onLoadEnd;
4397
+ this.configLoader.onLoadStartListener = onLoadStart;
4213
4398
  this.ngModule = injector.get(NgModuleRef);
4214
4399
  this.console = injector.get(ɵConsole);
4215
4400
  const ngZone = injector.get(NgZone);
@@ -4218,7 +4403,6 @@ class Router {
4218
4403
  this.currentUrlTree = createEmptyUrlTree();
4219
4404
  this.rawUrlTree = this.currentUrlTree;
4220
4405
  this.browserUrlTree = this.currentUrlTree;
4221
- this.configLoader = new RouterConfigLoader(injector, compiler, onLoadStart, onLoadEnd);
4222
4406
  this.routerState = createEmptyState(this.currentUrlTree, this.rootComponentType);
4223
4407
  this.transitions = new BehaviorSubject({
4224
4408
  id: 0,
@@ -4427,6 +4611,25 @@ class Router {
4427
4611
  skipLocationChange: !!skipLocationChange,
4428
4612
  replaceUrl: !!replaceUrl,
4429
4613
  });
4614
+ }),
4615
+ // --- LOAD COMPONENTS ---
4616
+ switchTap((t) => {
4617
+ const loadComponents = (route) => {
4618
+ const loaders = [];
4619
+ if (route.routeConfig?.loadComponent &&
4620
+ !route.routeConfig._loadedComponent) {
4621
+ loaders.push(this.configLoader.loadComponent(route.routeConfig)
4622
+ .pipe(tap(loadedComponent => {
4623
+ route.component = loadedComponent;
4624
+ }), map(() => void 0)));
4625
+ }
4626
+ for (const child of route.children) {
4627
+ loaders.push(...loadComponents(child));
4628
+ }
4629
+ return loaders;
4630
+ };
4631
+ return combineLatest(loadComponents(t.targetSnapshot.root))
4632
+ .pipe(defaultIfEmpty(), take(1));
4430
4633
  }), map((t) => {
4431
4634
  const targetRouterState = createRouterState(this.routeReuseStrategy, t.targetSnapshot, t.currentRouterState);
4432
4635
  return ({ ...t, targetRouterState });
@@ -4505,23 +4708,17 @@ class Router {
4505
4708
  t.resolve(false);
4506
4709
  }
4507
4710
  else {
4508
- // setTimeout is required so this navigation finishes with
4509
- // the return EMPTY below. If it isn't allowed to finish
4510
- // processing, there can be multiple navigations to the same
4511
- // URL.
4512
- setTimeout(() => {
4513
- const mergedTree = this.urlHandlingStrategy.merge(e.url, this.rawUrlTree);
4514
- const extras = {
4515
- skipLocationChange: t.extras.skipLocationChange,
4516
- // The URL is already updated at this point if we have 'eager' URL
4517
- // updates or if the navigation was triggered by the browser (back
4518
- // button, URL bar, etc). We want to replace that item in history if
4519
- // the navigation is rejected.
4520
- replaceUrl: this.urlUpdateStrategy === 'eager' ||
4521
- isBrowserTriggeredNavigation(t.source)
4522
- };
4523
- this.scheduleNavigation(mergedTree, 'imperative', null, extras, { resolve: t.resolve, reject: t.reject, promise: t.promise });
4524
- }, 0);
4711
+ const mergedTree = this.urlHandlingStrategy.merge(e.url, this.rawUrlTree);
4712
+ const extras = {
4713
+ skipLocationChange: t.extras.skipLocationChange,
4714
+ // The URL is already updated at this point if we have 'eager' URL
4715
+ // updates or if the navigation was triggered by the browser (back
4716
+ // button, URL bar, etc). We want to replace that item in history if
4717
+ // the navigation is rejected.
4718
+ replaceUrl: this.urlUpdateStrategy === 'eager' ||
4719
+ isBrowserTriggeredNavigation(t.source)
4720
+ };
4721
+ this.scheduleNavigation(mergedTree, 'imperative', null, extras, { resolve: t.resolve, reject: t.reject, promise: t.promise });
4525
4722
  }
4526
4723
  /* All other errors should reset to the router's internal URL reference to
4527
4724
  * the pre-error state. */
@@ -4631,7 +4828,7 @@ class Router {
4631
4828
  * ```
4632
4829
  */
4633
4830
  resetConfig(config) {
4634
- validateConfig(config);
4831
+ NG_DEV_MODE && validateConfig(config);
4635
4832
  this.config = config.map(standardizeConfig);
4636
4833
  this.navigated = false;
4637
4834
  this.lastSuccessfulId = -1;
@@ -4986,9 +5183,9 @@ class Router {
4986
5183
  return { navigationId };
4987
5184
  }
4988
5185
  }
4989
- Router.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: Router, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable });
4990
- Router.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: Router });
4991
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: Router, decorators: [{
5186
+ Router.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: Router, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable });
5187
+ Router.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: Router });
5188
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: Router, decorators: [{
4992
5189
  type: Injectable
4993
5190
  }], ctorParameters: function () { return [{ type: i0.Type }, { type: UrlSerializer }, { type: ChildrenOutletContexts }, { type: i3.Location }, { type: i0.Injector }, { type: i0.Compiler }, { type: undefined }]; } });
4994
5191
  function validateCommands(commands) {
@@ -5187,9 +5384,9 @@ class RouterLink {
5187
5384
  });
5188
5385
  }
5189
5386
  }
5190
- RouterLink.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterLink, deps: [{ token: Router }, { token: ActivatedRoute }, { token: 'tabindex', attribute: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
5191
- RouterLink.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: RouterLink, selector: ":not(a):not(area)[routerLink]", inputs: { queryParams: "queryParams", fragment: "fragment", queryParamsHandling: "queryParamsHandling", preserveFragment: "preserveFragment", skipLocationChange: "skipLocationChange", replaceUrl: "replaceUrl", state: "state", relativeTo: "relativeTo", routerLink: "routerLink" }, host: { listeners: { "click": "onClick()" } }, usesOnChanges: true, ngImport: i0 });
5192
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterLink, decorators: [{
5387
+ RouterLink.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterLink, deps: [{ token: Router }, { token: ActivatedRoute }, { token: 'tabindex', attribute: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
5388
+ RouterLink.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.0-rc.0", type: RouterLink, selector: ":not(a):not(area)[routerLink]", inputs: { queryParams: "queryParams", fragment: "fragment", queryParamsHandling: "queryParamsHandling", preserveFragment: "preserveFragment", skipLocationChange: "skipLocationChange", replaceUrl: "replaceUrl", state: "state", relativeTo: "relativeTo", routerLink: "routerLink" }, host: { listeners: { "click": "onClick()" } }, usesOnChanges: true, ngImport: i0 });
5389
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterLink, decorators: [{
5193
5390
  type: Directive,
5194
5391
  args: [{ selector: ':not(a):not(area)[routerLink]' }]
5195
5392
  }], ctorParameters: function () { return [{ type: Router }, { type: ActivatedRoute }, { type: undefined, decorators: [{
@@ -5306,9 +5503,9 @@ class RouterLinkWithHref {
5306
5503
  });
5307
5504
  }
5308
5505
  }
5309
- RouterLinkWithHref.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterLinkWithHref, deps: [{ token: Router }, { token: ActivatedRoute }, { token: i3.LocationStrategy }], target: i0.ɵɵFactoryTarget.Directive });
5310
- RouterLinkWithHref.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: RouterLinkWithHref, selector: "a[routerLink],area[routerLink]", inputs: { target: "target", queryParams: "queryParams", fragment: "fragment", queryParamsHandling: "queryParamsHandling", preserveFragment: "preserveFragment", skipLocationChange: "skipLocationChange", replaceUrl: "replaceUrl", state: "state", relativeTo: "relativeTo", routerLink: "routerLink" }, host: { listeners: { "click": "onClick($event.button,$event.ctrlKey,$event.shiftKey,$event.altKey,$event.metaKey)" }, properties: { "attr.target": "this.target", "attr.href": "this.href" } }, usesOnChanges: true, ngImport: i0 });
5311
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterLinkWithHref, decorators: [{
5506
+ RouterLinkWithHref.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterLinkWithHref, deps: [{ token: Router }, { token: ActivatedRoute }, { token: i3.LocationStrategy }], target: i0.ɵɵFactoryTarget.Directive });
5507
+ RouterLinkWithHref.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.0-rc.0", type: RouterLinkWithHref, selector: "a[routerLink],area[routerLink]", inputs: { target: "target", queryParams: "queryParams", fragment: "fragment", queryParamsHandling: "queryParamsHandling", preserveFragment: "preserveFragment", skipLocationChange: "skipLocationChange", replaceUrl: "replaceUrl", state: "state", relativeTo: "relativeTo", routerLink: "routerLink" }, host: { listeners: { "click": "onClick($event.button,$event.ctrlKey,$event.shiftKey,$event.altKey,$event.metaKey)" }, properties: { "attr.target": "this.target", "attr.href": "this.href" } }, usesOnChanges: true, ngImport: i0 });
5508
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterLinkWithHref, decorators: [{
5312
5509
  type: Directive,
5313
5510
  args: [{ selector: 'a[routerLink],area[routerLink]' }]
5314
5511
  }], ctorParameters: function () { return [{ type: Router }, { type: ActivatedRoute }, { type: i3.LocationStrategy }]; }, propDecorators: { target: [{
@@ -5405,6 +5602,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9",
5405
5602
  * </div>
5406
5603
  * ```
5407
5604
  *
5605
+ * The `RouterLinkActive` directive can also be used to set the aria-current attribute
5606
+ * to provide an alternative distinction for active elements to visually impaired users.
5607
+ *
5608
+ * For example, the following code adds the 'active' class to the Home Page link when it is
5609
+ * indeed active and in such case also sets its aria-current attribute to 'page':
5610
+ *
5611
+ * ```
5612
+ * <a routerLink="/" routerLinkActive="active" ariaCurrentWhenActive="page">Home Page</a>
5613
+ * ```
5614
+ *
5408
5615
  * @ngModule RouterModule
5409
5616
  *
5410
5617
  * @publicApi
@@ -5498,6 +5705,12 @@ class RouterLinkActive {
5498
5705
  this.renderer.removeClass(this.element.nativeElement, c);
5499
5706
  }
5500
5707
  });
5708
+ if (hasActiveLinks && this.ariaCurrentWhenActive !== undefined) {
5709
+ this.renderer.setAttribute(this.element.nativeElement, 'aria-current', this.ariaCurrentWhenActive.toString());
5710
+ }
5711
+ else {
5712
+ this.renderer.removeAttribute(this.element.nativeElement, 'aria-current');
5713
+ }
5501
5714
  // Emit on isActiveChange after classes are updated
5502
5715
  this.isActiveChange.emit(hasActiveLinks);
5503
5716
  }
@@ -5517,9 +5730,9 @@ class RouterLinkActive {
5517
5730
  this.links.some(isActiveCheckFn) || this.linksWithHrefs.some(isActiveCheckFn);
5518
5731
  }
5519
5732
  }
5520
- RouterLinkActive.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterLinkActive, deps: [{ token: Router }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: RouterLink, optional: true }, { token: RouterLinkWithHref, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
5521
- RouterLinkActive.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.9", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: { routerLinkActiveOptions: "routerLinkActiveOptions", routerLinkActive: "routerLinkActive" }, outputs: { isActiveChange: "isActiveChange" }, queries: [{ propertyName: "links", predicate: RouterLink, descendants: true }, { propertyName: "linksWithHrefs", predicate: RouterLinkWithHref, descendants: true }], exportAs: ["routerLinkActive"], usesOnChanges: true, ngImport: i0 });
5522
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterLinkActive, decorators: [{
5733
+ RouterLinkActive.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterLinkActive, deps: [{ token: Router }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: RouterLink, optional: true }, { token: RouterLinkWithHref, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
5734
+ RouterLinkActive.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.0.0-rc.0", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: { routerLinkActiveOptions: "routerLinkActiveOptions", ariaCurrentWhenActive: "ariaCurrentWhenActive", routerLinkActive: "routerLinkActive" }, outputs: { isActiveChange: "isActiveChange" }, queries: [{ propertyName: "links", predicate: RouterLink, descendants: true }, { propertyName: "linksWithHrefs", predicate: RouterLinkWithHref, descendants: true }], exportAs: ["routerLinkActive"], usesOnChanges: true, ngImport: i0 });
5735
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterLinkActive, decorators: [{
5523
5736
  type: Directive,
5524
5737
  args: [{
5525
5738
  selector: '[routerLinkActive]',
@@ -5537,6 +5750,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9",
5537
5750
  args: [RouterLinkWithHref, { descendants: true }]
5538
5751
  }], routerLinkActiveOptions: [{
5539
5752
  type: Input
5753
+ }], ariaCurrentWhenActive: [{
5754
+ type: Input
5540
5755
  }], isActiveChange: [{
5541
5756
  type: Output
5542
5757
  }], routerLinkActive: [{
@@ -5620,9 +5835,9 @@ class DefaultTitleStrategy extends TitleStrategy {
5620
5835
  }
5621
5836
  }
5622
5837
  }
5623
- DefaultTitleStrategy.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: DefaultTitleStrategy, deps: [{ token: i1.Title }], target: i0.ɵɵFactoryTarget.Injectable });
5624
- DefaultTitleStrategy.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: DefaultTitleStrategy, providedIn: 'root' });
5625
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: DefaultTitleStrategy, decorators: [{
5838
+ DefaultTitleStrategy.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: DefaultTitleStrategy, deps: [{ token: i1.Title }], target: i0.ɵɵFactoryTarget.Injectable });
5839
+ DefaultTitleStrategy.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: DefaultTitleStrategy, providedIn: 'root' });
5840
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: DefaultTitleStrategy, decorators: [{
5626
5841
  type: Injectable,
5627
5842
  args: [{ providedIn: 'root' }]
5628
5843
  }], ctorParameters: function () { return [{ type: i1.Title }]; } });
@@ -5686,13 +5901,11 @@ class NoPreloading {
5686
5901
  * @publicApi
5687
5902
  */
5688
5903
  class RouterPreloader {
5689
- constructor(router, compiler, injector, preloadingStrategy) {
5904
+ constructor(router, compiler, injector, preloadingStrategy, loader) {
5690
5905
  this.router = router;
5691
5906
  this.injector = injector;
5692
5907
  this.preloadingStrategy = preloadingStrategy;
5693
- const onStartLoad = (r) => router.triggerEvent(new RouteConfigLoadStart(r));
5694
- const onEndLoad = (r) => router.triggerEvent(new RouteConfigLoadEnd(r));
5695
- this.loader = new RouterConfigLoader(injector, compiler, onStartLoad, onEndLoad);
5908
+ this.loader = loader;
5696
5909
  }
5697
5910
  setUpPreloading() {
5698
5911
  this.subscription =
@@ -5701,8 +5914,7 @@ class RouterPreloader {
5701
5914
  .subscribe(() => { });
5702
5915
  }
5703
5916
  preload() {
5704
- const ngModule = this.injector.get(NgModuleRef);
5705
- return this.processRoutes(ngModule, this.router.config);
5917
+ return this.processRoutes(this.injector, this.router.config);
5706
5918
  }
5707
5919
  /** @nodoc */
5708
5920
  ngOnDestroy() {
@@ -5710,41 +5922,59 @@ class RouterPreloader {
5710
5922
  this.subscription.unsubscribe();
5711
5923
  }
5712
5924
  }
5713
- processRoutes(ngModule, routes) {
5925
+ processRoutes(injector, routes) {
5714
5926
  const res = [];
5715
5927
  for (const route of routes) {
5716
- // we already have the config loaded, just recurse
5717
- if (route.loadChildren && !route.canLoad && route._loadedConfig) {
5718
- const childConfig = route._loadedConfig;
5719
- res.push(this.processRoutes(childConfig.module, childConfig.routes));
5720
- // no config loaded, fetch the config
5928
+ if (route.providers && !route._injector) {
5929
+ route._injector =
5930
+ createEnvironmentInjector(route.providers, injector, `Route: ${route.path}`);
5721
5931
  }
5722
- else if (route.loadChildren && !route.canLoad) {
5723
- res.push(this.preloadConfig(ngModule, route));
5724
- // recurse into children
5932
+ const injectorForCurrentRoute = route._injector ?? injector;
5933
+ const injectorForChildren = route._loadedInjector ?? injectorForCurrentRoute;
5934
+ if ((route.loadChildren && !route._loadedRoutes) ||
5935
+ (route.loadComponent && !route._loadedComponent)) {
5936
+ res.push(this.preloadConfig(injectorForCurrentRoute, route));
5725
5937
  }
5726
- else if (route.children) {
5727
- res.push(this.processRoutes(ngModule, route.children));
5938
+ else if (route.children || route._loadedRoutes) {
5939
+ res.push(this.processRoutes(injectorForChildren, (route.children ?? route._loadedRoutes)));
5728
5940
  }
5729
5941
  }
5730
- return from(res).pipe(mergeAll(), map((_) => void 0));
5942
+ return from(res).pipe(mergeAll());
5731
5943
  }
5732
- preloadConfig(ngModule, route) {
5944
+ preloadConfig(injector, route) {
5733
5945
  return this.preloadingStrategy.preload(route, () => {
5734
- const loaded$ = route._loadedConfig ? of(route._loadedConfig) :
5735
- this.loader.load(ngModule.injector, route);
5736
- return loaded$.pipe(mergeMap((config) => {
5737
- route._loadedConfig = config;
5738
- return this.processRoutes(config.module, config.routes);
5946
+ let loadedChildren$;
5947
+ if (route.loadChildren && route.canLoad === undefined) {
5948
+ loadedChildren$ = this.loader.loadChildren(injector, route);
5949
+ }
5950
+ else {
5951
+ loadedChildren$ = of(null);
5952
+ }
5953
+ const recursiveLoadChildren$ = loadedChildren$.pipe(mergeMap((config) => {
5954
+ if (config === null) {
5955
+ return of(void 0);
5956
+ }
5957
+ route._loadedRoutes = config.routes;
5958
+ route._loadedInjector = config.injector;
5959
+ // If the loaded config was a module, use that as the module/module injector going
5960
+ // forward. Otherwise, continue using the current module/module injector.
5961
+ return this.processRoutes(config.injector ?? injector, config.routes);
5739
5962
  }));
5963
+ if (route.loadComponent && !route._loadedComponent) {
5964
+ const loadComponent$ = this.loader.loadComponent(route);
5965
+ return from([recursiveLoadChildren$, loadComponent$]).pipe(mergeAll());
5966
+ }
5967
+ else {
5968
+ return recursiveLoadChildren$;
5969
+ }
5740
5970
  });
5741
5971
  }
5742
5972
  }
5743
- RouterPreloader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterPreloader, deps: [{ token: Router }, { token: i0.Compiler }, { token: i0.Injector }, { token: PreloadingStrategy }], target: i0.ɵɵFactoryTarget.Injectable });
5744
- RouterPreloader.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterPreloader });
5745
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterPreloader, decorators: [{
5973
+ RouterPreloader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterPreloader, deps: [{ token: Router }, { token: i0.Compiler }, { token: i0.EnvironmentInjector }, { token: PreloadingStrategy }, { token: RouterConfigLoader }], target: i0.ɵɵFactoryTarget.Injectable });
5974
+ RouterPreloader.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterPreloader });
5975
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterPreloader, decorators: [{
5746
5976
  type: Injectable
5747
- }], ctorParameters: function () { return [{ type: Router }, { type: i0.Compiler }, { type: i0.Injector }, { type: PreloadingStrategy }]; } });
5977
+ }], ctorParameters: function () { return [{ type: Router }, { type: i0.Compiler }, { type: i0.EnvironmentInjector }, { type: PreloadingStrategy }, { type: RouterConfigLoader }]; } });
5748
5978
 
5749
5979
  /**
5750
5980
  * @license
@@ -5828,9 +6058,9 @@ class RouterScroller {
5828
6058
  }
5829
6059
  }
5830
6060
  }
5831
- RouterScroller.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterScroller, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable });
5832
- RouterScroller.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterScroller });
5833
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterScroller, decorators: [{
6061
+ RouterScroller.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterScroller, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable });
6062
+ RouterScroller.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterScroller });
6063
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterScroller, decorators: [{
5834
6064
  type: Injectable
5835
6065
  }], ctorParameters: function () { return [{ type: Router }, { type: i3.ViewportScroller }, { type: undefined }]; } });
5836
6066
 
@@ -5873,6 +6103,7 @@ const ROUTER_PROVIDERS = [
5873
6103
  NoPreloading,
5874
6104
  PreloadAllModules,
5875
6105
  { provide: ROUTER_CONFIGURATION, useValue: { enableTracing: false } },
6106
+ RouterConfigLoader,
5876
6107
  ];
5877
6108
  function routerNgProbeToken() {
5878
6109
  return new NgProbeToken('Router', Router);
@@ -5971,10 +6202,10 @@ class RouterModule {
5971
6202
  return { ngModule: RouterModule, providers: [provideRoutes(routes)] };
5972
6203
  }
5973
6204
  }
5974
- RouterModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterModule, deps: [{ token: ROUTER_FORROOT_GUARD, optional: true }, { token: Router, optional: true }], target: i0.ɵɵFactoryTarget.NgModule });
5975
- RouterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterModule, declarations: [RouterOutlet, RouterLink, RouterLinkWithHref, RouterLinkActive, ɵEmptyOutletComponent], exports: [RouterOutlet, RouterLink, RouterLinkWithHref, RouterLinkActive, ɵEmptyOutletComponent] });
5976
- RouterModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterModule });
5977
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterModule, decorators: [{
6205
+ RouterModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterModule, deps: [{ token: ROUTER_FORROOT_GUARD, optional: true }, { token: Router, optional: true }], target: i0.ɵɵFactoryTarget.NgModule });
6206
+ RouterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterModule, declarations: [RouterOutlet, RouterLink, RouterLinkWithHref, RouterLinkActive, ɵEmptyOutletComponent], exports: [RouterOutlet, RouterLink, RouterLinkWithHref, RouterLinkActive, ɵEmptyOutletComponent] });
6207
+ RouterModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterModule });
6208
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterModule, decorators: [{
5978
6209
  type: NgModule,
5979
6210
  args: [{
5980
6211
  declarations: ROUTER_DIRECTIVES,
@@ -6036,11 +6267,11 @@ function setupRouter(urlSerializer, contexts, location, injector, compiler, conf
6036
6267
  }
6037
6268
  router.titleStrategy = titleStrategy ?? defaultTitleStrategy;
6038
6269
  assignExtraOptionsToRouter(opts, router);
6039
- if (opts.enableTracing) {
6270
+ if ((typeof ngDevMode === 'undefined' || ngDevMode) && opts.enableTracing) {
6040
6271
  router.events.subscribe((e) => {
6041
6272
  // tslint:disable:no-console
6042
6273
  console.group?.(`Router Event: ${e.constructor.name}`);
6043
- console.log(e.toString());
6274
+ console.log(stringifyEvent(e));
6044
6275
  console.log(e);
6045
6276
  console.groupEnd?.();
6046
6277
  // tslint:enable:no-console
@@ -6107,9 +6338,7 @@ class RouterInitializer {
6107
6338
  router.setUpLocationChangeListener();
6108
6339
  resolve(true);
6109
6340
  }
6110
- else if (
6111
- // TODO: enabled is deprecated as of v11, can be removed in v13
6112
- opts.initialNavigation === 'enabled' || opts.initialNavigation === 'enabledBlocking') {
6341
+ else if (opts.initialNavigation === 'enabledBlocking') {
6113
6342
  router.hooks.afterPreactivation = () => {
6114
6343
  // only the initial navigation should be delayed
6115
6344
  if (!this.initNavigation) {
@@ -6153,9 +6382,9 @@ class RouterInitializer {
6153
6382
  this.destroyed = true;
6154
6383
  }
6155
6384
  }
6156
- RouterInitializer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterInitializer, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
6157
- RouterInitializer.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterInitializer });
6158
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: RouterInitializer, decorators: [{
6385
+ RouterInitializer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterInitializer, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
6386
+ RouterInitializer.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterInitializer });
6387
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-rc.0", ngImport: i0, type: RouterInitializer, decorators: [{
6159
6388
  type: Injectable
6160
6389
  }], ctorParameters: function () { return [{ type: i0.Injector }]; } });
6161
6390
  function getAppInitializer(r) {
@@ -6195,7 +6424,7 @@ function provideRouterInitializer() {
6195
6424
  /**
6196
6425
  * @publicApi
6197
6426
  */
6198
- const VERSION = new Version('14.0.0-next.9');
6427
+ const VERSION = new Version('14.0.0-rc.0');
6199
6428
 
6200
6429
  /**
6201
6430
  * @license