@angular/router 16.0.0-next.4 → 16.0.0-next.6

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 (94) hide show
  1. package/esm2022/src/apply_redirects.mjs +112 -0
  2. package/{esm2020 → esm2022}/src/components/empty_outlet.mjs +4 -4
  3. package/esm2022/src/create_url_tree.mjs +418 -0
  4. package/{esm2020 → esm2022}/src/directives/router_link.mjs +4 -4
  5. package/{esm2020 → esm2022}/src/directives/router_link_active.mjs +4 -4
  6. package/esm2022/src/directives/router_outlet.mjs +336 -0
  7. package/esm2022/src/index.mjs +30 -0
  8. package/esm2022/src/navigation_transition.mjs +397 -0
  9. package/esm2022/src/operators/activate_routes.mjs +192 -0
  10. package/{esm2020 → esm2022}/src/operators/check_guards.mjs +1 -1
  11. package/esm2022/src/operators/recognize.mjs +16 -0
  12. package/{esm2020 → esm2022}/src/page_title_strategy.mjs +7 -7
  13. package/esm2022/src/provide_router.mjs +507 -0
  14. package/esm2022/src/recognize.mjs +360 -0
  15. package/{esm2020 → esm2022}/src/route_reuse_strategy.mjs +7 -7
  16. package/esm2022/src/router.mjs +724 -0
  17. package/esm2022/src/router_config.mjs +18 -0
  18. package/esm2022/src/router_config_loader.mjs +132 -0
  19. package/esm2022/src/router_module.mjs +220 -0
  20. package/{esm2020 → esm2022}/src/router_outlet_context.mjs +4 -4
  21. package/esm2022/src/router_preloader.mjs +167 -0
  22. package/{esm2020 → esm2022}/src/router_scroller.mjs +4 -4
  23. package/esm2022/src/router_state.mjs +408 -0
  24. package/{esm2020 → esm2022}/src/url_handling_strategy.mjs +7 -7
  25. package/esm2022/src/url_tree.mjs +642 -0
  26. package/esm2022/src/utils/navigations.mjs +42 -0
  27. package/esm2022/src/utils/type_guards.mjs +54 -0
  28. package/{esm2020 → esm2022}/src/version.mjs +1 -1
  29. package/{esm2020 → esm2022}/testing/src/router_testing_harness.mjs +7 -7
  30. package/{esm2020 → esm2022}/testing/src/router_testing_module.mjs +10 -10
  31. package/{fesm2020 → fesm2022}/router.mjs +799 -787
  32. package/fesm2022/router.mjs.map +1 -0
  33. package/{fesm2020 → fesm2022}/testing.mjs +16 -16
  34. package/{fesm2020 → fesm2022}/testing.mjs.map +1 -1
  35. package/{fesm2020 → fesm2022}/upgrade.mjs +1 -1
  36. package/index.d.ts +92 -5
  37. package/package.json +14 -24
  38. package/testing/index.d.ts +1 -1
  39. package/upgrade/index.d.ts +1 -1
  40. package/esm2020/src/apply_redirects.mjs +0 -331
  41. package/esm2020/src/create_url_tree.mjs +0 -417
  42. package/esm2020/src/directives/router_outlet.mjs +0 -259
  43. package/esm2020/src/index.mjs +0 -30
  44. package/esm2020/src/navigation_transition.mjs +0 -399
  45. package/esm2020/src/operators/activate_routes.mjs +0 -177
  46. package/esm2020/src/operators/apply_redirects.mjs +0 -14
  47. package/esm2020/src/operators/recognize.mjs +0 -14
  48. package/esm2020/src/provide_router.mjs +0 -477
  49. package/esm2020/src/recognize.mjs +0 -270
  50. package/esm2020/src/router.mjs +0 -710
  51. package/esm2020/src/router_config.mjs +0 -19
  52. package/esm2020/src/router_config_loader.mjs +0 -131
  53. package/esm2020/src/router_module.mjs +0 -216
  54. package/esm2020/src/router_preloader.mjs +0 -167
  55. package/esm2020/src/router_state.mjs +0 -409
  56. package/esm2020/src/url_tree.mjs +0 -631
  57. package/esm2020/src/utils/navigations.mjs +0 -42
  58. package/esm2020/src/utils/type_guards.mjs +0 -54
  59. package/fesm2015/router.mjs +0 -7001
  60. package/fesm2015/router.mjs.map +0 -1
  61. package/fesm2015/testing.mjs +0 -270
  62. package/fesm2015/testing.mjs.map +0 -1
  63. package/fesm2015/upgrade.mjs +0 -146
  64. package/fesm2015/upgrade.mjs.map +0 -1
  65. package/fesm2020/router.mjs.map +0 -1
  66. /package/{esm2020 → esm2022}/index.mjs +0 -0
  67. /package/{esm2020 → esm2022}/public_api.mjs +0 -0
  68. /package/{esm2020 → esm2022}/router.mjs +0 -0
  69. /package/{esm2020 → esm2022}/src/create_router_state.mjs +0 -0
  70. /package/{esm2020 → esm2022}/src/errors.mjs +0 -0
  71. /package/{esm2020 → esm2022}/src/events.mjs +0 -0
  72. /package/{esm2020 → esm2022}/src/models.mjs +0 -0
  73. /package/{esm2020 → esm2022}/src/models_deprecated.mjs +0 -0
  74. /package/{esm2020 → esm2022}/src/navigation_canceling_error.mjs +0 -0
  75. /package/{esm2020 → esm2022}/src/operators/prioritized_guard_value.mjs +0 -0
  76. /package/{esm2020 → esm2022}/src/operators/resolve_data.mjs +0 -0
  77. /package/{esm2020 → esm2022}/src/operators/switch_tap.mjs +0 -0
  78. /package/{esm2020 → esm2022}/src/private_export.mjs +0 -0
  79. /package/{esm2020 → esm2022}/src/shared.mjs +0 -0
  80. /package/{esm2020 → esm2022}/src/utils/collection.mjs +0 -0
  81. /package/{esm2020 → esm2022}/src/utils/config.mjs +0 -0
  82. /package/{esm2020 → esm2022}/src/utils/config_matching.mjs +0 -0
  83. /package/{esm2020 → esm2022}/src/utils/functional_guards.mjs +0 -0
  84. /package/{esm2020 → esm2022}/src/utils/preactivation.mjs +0 -0
  85. /package/{esm2020 → esm2022}/src/utils/tree.mjs +0 -0
  86. /package/{esm2020 → esm2022}/testing/index.mjs +0 -0
  87. /package/{esm2020 → esm2022}/testing/public_api.mjs +0 -0
  88. /package/{esm2020 → esm2022}/testing/src/testing.mjs +0 -0
  89. /package/{esm2020 → esm2022}/testing/testing.mjs +0 -0
  90. /package/{esm2020 → esm2022}/upgrade/index.mjs +0 -0
  91. /package/{esm2020 → esm2022}/upgrade/public_api.mjs +0 -0
  92. /package/{esm2020 → esm2022}/upgrade/src/upgrade.mjs +0 -0
  93. /package/{esm2020 → esm2022}/upgrade/upgrade.mjs +0 -0
  94. /package/{fesm2020 → fesm2022}/upgrade.mjs.map +0 -0
@@ -1,15 +1,15 @@
1
1
  /**
2
- * @license Angular v16.0.0-next.4
2
+ * @license Angular v16.0.0-next.6
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
6
6
 
7
7
  import * as i0 from '@angular/core';
8
- import { ɵisPromise, ɵRuntimeError, Injectable, EventEmitter, inject, ViewContainerRef, ChangeDetectorRef, EnvironmentInjector, Directive, Input, Output, Component, createEnvironmentInjector, ɵisNgModule, isStandalone, ɵisInjectable, InjectionToken, Compiler, InjectFlags, NgModuleFactory, ɵConsole, NgZone, ɵcoerceToBoolean, ɵɵsanitizeUrlOrResourceUrl, Attribute, HostBinding, HostListener, Optional, ContentChildren, makeEnvironmentProviders, APP_BOOTSTRAP_LISTENER, ENVIRONMENT_INITIALIZER, Injector, ApplicationRef, APP_INITIALIZER, NgProbeToken, SkipSelf, NgModule, Inject, Version } from '@angular/core';
9
- import { isObservable, from, of, BehaviorSubject, EmptyError, combineLatest, concat, defer, pipe, throwError, Observable, EMPTY, ConnectableObservable, Subject } from 'rxjs';
8
+ import { ɵisPromise, ɵRuntimeError, Injectable, EventEmitter, inject, ViewContainerRef, ChangeDetectorRef, EnvironmentInjector, Directive, Input, Output, InjectionToken, reflectComponentType, Component, createEnvironmentInjector, ɵisNgModule, isStandalone, ɵisInjectable, Compiler, InjectFlags, NgModuleFactory, ɵConsole, ɵInitialRenderPendingTasks, NgZone, ɵcoerceToBoolean, ɵɵsanitizeUrlOrResourceUrl, Attribute, HostBinding, HostListener, Optional, ContentChildren, makeEnvironmentProviders, APP_BOOTSTRAP_LISTENER, ENVIRONMENT_INITIALIZER, Injector, ApplicationRef, APP_INITIALIZER, NgProbeToken, SkipSelf, NgModule, Inject, Version } from '@angular/core';
9
+ import { isObservable, from, of, BehaviorSubject, combineLatest, EmptyError, concat, defer, pipe, throwError, EMPTY, ConnectableObservable, Subject } from 'rxjs';
10
10
  import * as i3 from '@angular/common';
11
11
  import { Location, ViewportScroller, LOCATION_INITIALIZED, LocationStrategy, HashLocationStrategy, PathLocationStrategy } from '@angular/common';
12
- import { map, switchMap, take, startWith, filter, mergeMap, first, concatMap, tap, catchError, scan, last as last$1, takeWhile, defaultIfEmpty, takeLast, mapTo, finalize, refCount, mergeAll } from 'rxjs/operators';
12
+ import { map, switchMap, take, startWith, filter, mergeMap, first, concatMap, tap, catchError, scan, defaultIfEmpty, last as last$1, takeLast, mapTo, finalize, refCount, mergeAll } from 'rxjs/operators';
13
13
  import * as i1 from '@angular/platform-browser';
14
14
 
15
15
  /**
@@ -162,7 +162,6 @@ function wrapIntoObservable(value) {
162
162
  return of(value);
163
163
  }
164
164
 
165
- const NG_DEV_MODE$a = typeof ngDevMode === 'undefined' || ngDevMode;
166
165
  const pathCompareMap = {
167
166
  'exact': equalSegmentGroups,
168
167
  'subset': containsSegmentGroup,
@@ -287,7 +286,7 @@ class UrlTree {
287
286
  this.root = root;
288
287
  this.queryParams = queryParams;
289
288
  this.fragment = fragment;
290
- if (NG_DEV_MODE$a) {
289
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
291
290
  if (root.segments.length > 0) {
292
291
  throw new ɵRuntimeError(4015 /* RuntimeErrorCode.INVALID_ROOT_URL_SEGMENT */, 'The root `UrlSegmentGroup` should not contain `segments`. ' +
293
292
  'Instead, these segments belong in the `children` so they can be associated with a named outlet.');
@@ -420,10 +419,10 @@ function mapChildrenIntoArray(segment, fn) {
420
419
  * @publicApi
421
420
  */
422
421
  class UrlSerializer {
422
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: UrlSerializer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
423
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: UrlSerializer, providedIn: 'root', useFactory: () => new DefaultUrlSerializer() }); }
423
424
  }
424
- UrlSerializer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: UrlSerializer, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
425
- UrlSerializer.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: UrlSerializer, providedIn: 'root', useFactory: () => new DefaultUrlSerializer() });
426
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: UrlSerializer, decorators: [{
425
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: UrlSerializer, decorators: [{
427
426
  type: Injectable,
428
427
  args: [{ providedIn: 'root', useFactory: () => new DefaultUrlSerializer() }]
429
428
  }] });
@@ -635,7 +634,8 @@ class UrlParser {
635
634
  parseSegment() {
636
635
  const path = matchSegments(this.remaining);
637
636
  if (path === '' && this.peekStartsWith(';')) {
638
- throw new ɵRuntimeError(4009 /* RuntimeErrorCode.EMPTY_PATH_WITH_PARAMS */, NG_DEV_MODE$a && `Empty path url segment cannot have parameters: '${this.remaining}'.`);
637
+ throw new ɵRuntimeError(4009 /* RuntimeErrorCode.EMPTY_PATH_WITH_PARAMS */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
638
+ `Empty path url segment cannot have parameters: '${this.remaining}'.`);
639
639
  }
640
640
  this.capture(path);
641
641
  return new UrlSegment(decode(path), this.parseMatrixParams());
@@ -704,7 +704,7 @@ class UrlParser {
704
704
  // if is is not one of these characters, then the segment was unescaped
705
705
  // or the group was not closed
706
706
  if (next !== '/' && next !== ')' && next !== ';') {
707
- throw new ɵRuntimeError(4010 /* RuntimeErrorCode.UNPARSABLE_URL */, NG_DEV_MODE$a && `Cannot parse url '${this.url}'`);
707
+ throw new ɵRuntimeError(4010 /* RuntimeErrorCode.UNPARSABLE_URL */, (typeof ngDevMode === 'undefined' || ngDevMode) && `Cannot parse url '${this.url}'`);
708
708
  }
709
709
  let outletName = undefined;
710
710
  if (path.indexOf(':') > -1) {
@@ -735,7 +735,7 @@ class UrlParser {
735
735
  }
736
736
  capture(str) {
737
737
  if (!this.consumeOptional(str)) {
738
- throw new ɵRuntimeError(4011 /* RuntimeErrorCode.UNEXPECTED_VALUE_IN_URL */, NG_DEV_MODE$a && `Expected "${str}".`);
738
+ throw new ɵRuntimeError(4011 /* RuntimeErrorCode.UNEXPECTED_VALUE_IN_URL */, (typeof ngDevMode === 'undefined' || ngDevMode) && `Expected "${str}".`);
739
739
  }
740
740
  }
741
741
  }
@@ -745,17 +745,28 @@ function createRoot(rootCandidate) {
745
745
  rootCandidate;
746
746
  }
747
747
  /**
748
- * Recursively merges primary segment children into their parents and also drops empty children
749
- * (those which have no segments and no children themselves). The latter prevents serializing a
750
- * group into something like `/a(aux:)`, where `aux` is an empty child segment.
748
+ * Recursively
749
+ * - merges primary segment children into their parents
750
+ * - drops empty children (those which have no segments and no children themselves). This latter
751
+ * prevents serializing a group into something like `/a(aux:)`, where `aux` is an empty child
752
+ * segment.
753
+ * - merges named outlets without a primary segment sibling into the children. This prevents
754
+ * serializing a URL like `//(a:a)(b:b) instead of `/(a:a//b:b)` when the aux b route lives on the
755
+ * root but the `a` route lives under an empty path primary route.
751
756
  */
752
757
  function squashSegmentGroup(segmentGroup) {
753
758
  const newChildren = {};
754
759
  for (const childOutlet of Object.keys(segmentGroup.children)) {
755
760
  const child = segmentGroup.children[childOutlet];
756
761
  const childCandidate = squashSegmentGroup(child);
757
- // don't add empty children
758
- if (childCandidate.segments.length > 0 || childCandidate.hasChildren()) {
762
+ // moves named children in an empty path primary child into this group
763
+ if (childOutlet === PRIMARY_OUTLET && childCandidate.segments.length === 0 &&
764
+ childCandidate.hasChildren()) {
765
+ for (const [grandChildOutlet, grandChild] of Object.entries(childCandidate.children)) {
766
+ newChildren[grandChildOutlet] = grandChild;
767
+ }
768
+ } // don't add empty children
769
+ else if (childCandidate.segments.length > 0 || childCandidate.hasChildren()) {
759
770
  newChildren[childOutlet] = childCandidate;
760
771
  }
761
772
  }
@@ -781,7 +792,6 @@ function isUrlTree(v) {
781
792
  return v instanceof UrlTree;
782
793
  }
783
794
 
784
- const NG_DEV_MODE$9 = typeof ngDevMode === 'undefined' || ngDevMode;
785
795
  /**
786
796
  * Creates a `UrlTree` relative to an `ActivatedRouteSnapshot`.
787
797
  *
@@ -928,11 +938,13 @@ class Navigation {
928
938
  this.numberOfDoubleDots = numberOfDoubleDots;
929
939
  this.commands = commands;
930
940
  if (isAbsolute && commands.length > 0 && isMatrixParams(commands[0])) {
931
- throw new ɵRuntimeError(4003 /* RuntimeErrorCode.ROOT_SEGMENT_MATRIX_PARAMS */, NG_DEV_MODE$9 && 'Root segment cannot have matrix parameters');
941
+ throw new ɵRuntimeError(4003 /* RuntimeErrorCode.ROOT_SEGMENT_MATRIX_PARAMS */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
942
+ 'Root segment cannot have matrix parameters');
932
943
  }
933
944
  const cmdWithOutlet = commands.find(isCommandWithOutlets);
934
945
  if (cmdWithOutlet && cmdWithOutlet !== last(commands)) {
935
- throw new ɵRuntimeError(4004 /* RuntimeErrorCode.MISPLACED_OUTLETS_COMMAND */, NG_DEV_MODE$9 && '{outlets:{}} has to be the last command');
946
+ throw new ɵRuntimeError(4004 /* RuntimeErrorCode.MISPLACED_OUTLETS_COMMAND */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
947
+ '{outlets:{}} has to be the last command');
936
948
  }
937
949
  }
938
950
  toRoot() {
@@ -1016,7 +1028,7 @@ function createPositionApplyingDoubleDots(group, index, numberOfDoubleDots) {
1016
1028
  dd -= ci;
1017
1029
  g = g.parent;
1018
1030
  if (!g) {
1019
- throw new ɵRuntimeError(4005 /* RuntimeErrorCode.INVALID_DOUBLE_DOTS */, NG_DEV_MODE$9 && 'Invalid number of \'../\'');
1031
+ throw new ɵRuntimeError(4005 /* RuntimeErrorCode.INVALID_DOUBLE_DOTS */, (typeof ngDevMode === 'undefined' || ngDevMode) && 'Invalid number of \'../\'');
1020
1032
  }
1021
1033
  ci = g.segments.length;
1022
1034
  }
@@ -1688,6 +1700,79 @@ function stringifyEvent(routerEvent) {
1688
1700
  }
1689
1701
  }
1690
1702
 
1703
+ /**
1704
+ * Store contextual information about a `RouterOutlet`
1705
+ *
1706
+ * @publicApi
1707
+ */
1708
+ class OutletContext {
1709
+ constructor() {
1710
+ this.outlet = null;
1711
+ this.route = null;
1712
+ this.injector = null;
1713
+ this.children = new ChildrenOutletContexts();
1714
+ this.attachRef = null;
1715
+ }
1716
+ }
1717
+ /**
1718
+ * Store contextual information about the children (= nested) `RouterOutlet`
1719
+ *
1720
+ * @publicApi
1721
+ */
1722
+ class ChildrenOutletContexts {
1723
+ constructor() {
1724
+ // contexts for child outlets, by name.
1725
+ this.contexts = new Map();
1726
+ }
1727
+ /** Called when a `RouterOutlet` directive is instantiated */
1728
+ onChildOutletCreated(childName, outlet) {
1729
+ const context = this.getOrCreateContext(childName);
1730
+ context.outlet = outlet;
1731
+ this.contexts.set(childName, context);
1732
+ }
1733
+ /**
1734
+ * Called when a `RouterOutlet` directive is destroyed.
1735
+ * We need to keep the context as the outlet could be destroyed inside a NgIf and might be
1736
+ * re-created later.
1737
+ */
1738
+ onChildOutletDestroyed(childName) {
1739
+ const context = this.getContext(childName);
1740
+ if (context) {
1741
+ context.outlet = null;
1742
+ context.attachRef = null;
1743
+ }
1744
+ }
1745
+ /**
1746
+ * Called when the corresponding route is deactivated during navigation.
1747
+ * Because the component get destroyed, all children outlet are destroyed.
1748
+ */
1749
+ onOutletDeactivated() {
1750
+ const contexts = this.contexts;
1751
+ this.contexts = new Map();
1752
+ return contexts;
1753
+ }
1754
+ onOutletReAttached(contexts) {
1755
+ this.contexts = contexts;
1756
+ }
1757
+ getOrCreateContext(childName) {
1758
+ let context = this.getContext(childName);
1759
+ if (!context) {
1760
+ context = new OutletContext();
1761
+ this.contexts.set(childName, context);
1762
+ }
1763
+ return context;
1764
+ }
1765
+ getContext(childName) {
1766
+ return this.contexts.get(childName) || null;
1767
+ }
1768
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: ChildrenOutletContexts, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1769
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: ChildrenOutletContexts, providedIn: 'root' }); }
1770
+ }
1771
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: ChildrenOutletContexts, decorators: [{
1772
+ type: Injectable,
1773
+ args: [{ providedIn: 'root' }]
1774
+ }] });
1775
+
1691
1776
  class Tree {
1692
1777
  constructor(root) {
1693
1778
  this._root = root;
@@ -1881,9 +1966,8 @@ class ActivatedRoute {
1881
1966
  this.data = data;
1882
1967
  this.outlet = outlet;
1883
1968
  this.component = component;
1884
- /** An Observable of the resolved route title */
1885
- this.title = this.data?.pipe(map((d) => d[RouteTitleKey])) ?? of(undefined);
1886
1969
  this._futureSnapshot = futureSnapshot;
1970
+ this.title = this.data?.pipe(map((d) => d[RouteTitleKey])) ?? of(undefined);
1887
1971
  }
1888
1972
  /** The configuration used to match this route. */
1889
1973
  get routeConfig() {
@@ -2171,146 +2255,6 @@ function equalParamsAndUrlSegments(a, b) {
2171
2255
  (!a.parent || equalParamsAndUrlSegments(a.parent, b.parent));
2172
2256
  }
2173
2257
 
2174
- function createRouterState(routeReuseStrategy, curr, prevState) {
2175
- const root = createNode(routeReuseStrategy, curr._root, prevState ? prevState._root : undefined);
2176
- return new RouterState(root, curr);
2177
- }
2178
- function createNode(routeReuseStrategy, curr, prevState) {
2179
- // reuse an activated route that is currently displayed on the screen
2180
- if (prevState && routeReuseStrategy.shouldReuseRoute(curr.value, prevState.value.snapshot)) {
2181
- const value = prevState.value;
2182
- value._futureSnapshot = curr.value;
2183
- const children = createOrReuseChildren(routeReuseStrategy, curr, prevState);
2184
- return new TreeNode(value, children);
2185
- }
2186
- else {
2187
- if (routeReuseStrategy.shouldAttach(curr.value)) {
2188
- // retrieve an activated route that is used to be displayed, but is not currently displayed
2189
- const detachedRouteHandle = routeReuseStrategy.retrieve(curr.value);
2190
- if (detachedRouteHandle !== null) {
2191
- const tree = detachedRouteHandle.route;
2192
- tree.value._futureSnapshot = curr.value;
2193
- tree.children = curr.children.map(c => createNode(routeReuseStrategy, c));
2194
- return tree;
2195
- }
2196
- }
2197
- const value = createActivatedRoute(curr.value);
2198
- const children = curr.children.map(c => createNode(routeReuseStrategy, c));
2199
- return new TreeNode(value, children);
2200
- }
2201
- }
2202
- function createOrReuseChildren(routeReuseStrategy, curr, prevState) {
2203
- return curr.children.map(child => {
2204
- for (const p of prevState.children) {
2205
- if (routeReuseStrategy.shouldReuseRoute(child.value, p.value.snapshot)) {
2206
- return createNode(routeReuseStrategy, child, p);
2207
- }
2208
- }
2209
- return createNode(routeReuseStrategy, child);
2210
- });
2211
- }
2212
- function createActivatedRoute(c) {
2213
- return new ActivatedRoute(new BehaviorSubject(c.url), new BehaviorSubject(c.params), new BehaviorSubject(c.queryParams), new BehaviorSubject(c.fragment), new BehaviorSubject(c.data), c.outlet, c.component, c);
2214
- }
2215
-
2216
- const NAVIGATION_CANCELING_ERROR = 'ngNavigationCancelingError';
2217
- function redirectingNavigationError(urlSerializer, redirect) {
2218
- const { redirectTo, navigationBehaviorOptions } = isUrlTree(redirect) ? { redirectTo: redirect, navigationBehaviorOptions: undefined } : redirect;
2219
- const error = navigationCancelingError(ngDevMode && `Redirecting to "${urlSerializer.serialize(redirectTo)}"`, 0 /* NavigationCancellationCode.Redirect */, redirect);
2220
- error.url = redirectTo;
2221
- error.navigationBehaviorOptions = navigationBehaviorOptions;
2222
- return error;
2223
- }
2224
- function navigationCancelingError(message, code, redirectUrl) {
2225
- const error = new Error('NavigationCancelingError: ' + (message || ''));
2226
- error[NAVIGATION_CANCELING_ERROR] = true;
2227
- error.cancellationCode = code;
2228
- if (redirectUrl) {
2229
- error.url = redirectUrl;
2230
- }
2231
- return error;
2232
- }
2233
- function isRedirectingNavigationCancelingError$1(error) {
2234
- return isNavigationCancelingError$1(error) && isUrlTree(error.url);
2235
- }
2236
- function isNavigationCancelingError$1(error) {
2237
- return error && error[NAVIGATION_CANCELING_ERROR];
2238
- }
2239
-
2240
- /**
2241
- * Store contextual information about a `RouterOutlet`
2242
- *
2243
- * @publicApi
2244
- */
2245
- class OutletContext {
2246
- constructor() {
2247
- this.outlet = null;
2248
- this.route = null;
2249
- this.injector = null;
2250
- this.children = new ChildrenOutletContexts();
2251
- this.attachRef = null;
2252
- }
2253
- }
2254
- /**
2255
- * Store contextual information about the children (= nested) `RouterOutlet`
2256
- *
2257
- * @publicApi
2258
- */
2259
- class ChildrenOutletContexts {
2260
- constructor() {
2261
- // contexts for child outlets, by name.
2262
- this.contexts = new Map();
2263
- }
2264
- /** Called when a `RouterOutlet` directive is instantiated */
2265
- onChildOutletCreated(childName, outlet) {
2266
- const context = this.getOrCreateContext(childName);
2267
- context.outlet = outlet;
2268
- this.contexts.set(childName, context);
2269
- }
2270
- /**
2271
- * Called when a `RouterOutlet` directive is destroyed.
2272
- * We need to keep the context as the outlet could be destroyed inside a NgIf and might be
2273
- * re-created later.
2274
- */
2275
- onChildOutletDestroyed(childName) {
2276
- const context = this.getContext(childName);
2277
- if (context) {
2278
- context.outlet = null;
2279
- context.attachRef = null;
2280
- }
2281
- }
2282
- /**
2283
- * Called when the corresponding route is deactivated during navigation.
2284
- * Because the component get destroyed, all children outlet are destroyed.
2285
- */
2286
- onOutletDeactivated() {
2287
- const contexts = this.contexts;
2288
- this.contexts = new Map();
2289
- return contexts;
2290
- }
2291
- onOutletReAttached(contexts) {
2292
- this.contexts = contexts;
2293
- }
2294
- getOrCreateContext(childName) {
2295
- let context = this.getContext(childName);
2296
- if (!context) {
2297
- context = new OutletContext();
2298
- this.contexts.set(childName, context);
2299
- }
2300
- return context;
2301
- }
2302
- getContext(childName) {
2303
- return this.contexts.get(childName) || null;
2304
- }
2305
- }
2306
- ChildrenOutletContexts.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: ChildrenOutletContexts, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2307
- ChildrenOutletContexts.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: ChildrenOutletContexts, providedIn: 'root' });
2308
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: ChildrenOutletContexts, decorators: [{
2309
- type: Injectable,
2310
- args: [{ providedIn: 'root' }]
2311
- }] });
2312
-
2313
- const NG_DEV_MODE$8 = typeof ngDevMode === 'undefined' || ngDevMode;
2314
2258
  /**
2315
2259
  * @description
2316
2260
  *
@@ -2388,6 +2332,13 @@ class RouterOutlet {
2388
2332
  this.location = inject(ViewContainerRef);
2389
2333
  this.changeDetector = inject(ChangeDetectorRef);
2390
2334
  this.environmentInjector = inject(EnvironmentInjector);
2335
+ this.inputBinder = inject(INPUT_BINDER, { optional: true });
2336
+ /** @nodoc */
2337
+ this.supportsBindingToComponentInputs = true;
2338
+ }
2339
+ /** @internal */
2340
+ get activatedComponentRef() {
2341
+ return this.activated;
2391
2342
  }
2392
2343
  /** @nodoc */
2393
2344
  ngOnChanges(changes) {
@@ -2413,6 +2364,7 @@ class RouterOutlet {
2413
2364
  if (this.isTrackedInParentContexts(this.name)) {
2414
2365
  this.parentContexts.onChildOutletDestroyed(this.name);
2415
2366
  }
2367
+ this.inputBinder?.unsubscribeFromRouteData(this);
2416
2368
  }
2417
2369
  isTrackedInParentContexts(outletName) {
2418
2370
  return this.parentContexts.getContext(outletName)?.outlet === this;
@@ -2449,12 +2401,12 @@ class RouterOutlet {
2449
2401
  */
2450
2402
  get component() {
2451
2403
  if (!this.activated)
2452
- throw new ɵRuntimeError(4012 /* RuntimeErrorCode.OUTLET_NOT_ACTIVATED */, NG_DEV_MODE$8 && 'Outlet is not activated');
2404
+ throw new ɵRuntimeError(4012 /* RuntimeErrorCode.OUTLET_NOT_ACTIVATED */, (typeof ngDevMode === 'undefined' || ngDevMode) && 'Outlet is not activated');
2453
2405
  return this.activated.instance;
2454
2406
  }
2455
2407
  get activatedRoute() {
2456
2408
  if (!this.activated)
2457
- throw new ɵRuntimeError(4012 /* RuntimeErrorCode.OUTLET_NOT_ACTIVATED */, NG_DEV_MODE$8 && 'Outlet is not activated');
2409
+ throw new ɵRuntimeError(4012 /* RuntimeErrorCode.OUTLET_NOT_ACTIVATED */, (typeof ngDevMode === 'undefined' || ngDevMode) && 'Outlet is not activated');
2458
2410
  return this._activatedRoute;
2459
2411
  }
2460
2412
  get activatedRouteData() {
@@ -2468,7 +2420,7 @@ class RouterOutlet {
2468
2420
  */
2469
2421
  detach() {
2470
2422
  if (!this.activated)
2471
- throw new ɵRuntimeError(4012 /* RuntimeErrorCode.OUTLET_NOT_ACTIVATED */, NG_DEV_MODE$8 && 'Outlet is not activated');
2423
+ throw new ɵRuntimeError(4012 /* RuntimeErrorCode.OUTLET_NOT_ACTIVATED */, (typeof ngDevMode === 'undefined' || ngDevMode) && 'Outlet is not activated');
2472
2424
  this.location.detach();
2473
2425
  const cmp = this.activated;
2474
2426
  this.activated = null;
@@ -2483,6 +2435,7 @@ class RouterOutlet {
2483
2435
  this.activated = ref;
2484
2436
  this._activatedRoute = activatedRoute;
2485
2437
  this.location.insert(ref.hostView);
2438
+ this.inputBinder?.bindActivatedRouteToOutletComponent(this);
2486
2439
  this.attachEvents.emit(ref.instance);
2487
2440
  }
2488
2441
  deactivate() {
@@ -2496,7 +2449,8 @@ class RouterOutlet {
2496
2449
  }
2497
2450
  activateWith(activatedRoute, environmentInjector) {
2498
2451
  if (this.isActivated) {
2499
- throw new ɵRuntimeError(4013 /* RuntimeErrorCode.OUTLET_ALREADY_ACTIVATED */, NG_DEV_MODE$8 && 'Cannot activate an already activated outlet');
2452
+ throw new ɵRuntimeError(4013 /* RuntimeErrorCode.OUTLET_ALREADY_ACTIVATED */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
2453
+ 'Cannot activate an already activated outlet');
2500
2454
  }
2501
2455
  this._activatedRoute = activatedRoute;
2502
2456
  const location = this.location;
@@ -2512,12 +2466,13 @@ class RouterOutlet {
2512
2466
  // Calling `markForCheck` to make sure we will run the change detection when the
2513
2467
  // `RouterOutlet` is inside a `ChangeDetectionStrategy.OnPush` component.
2514
2468
  this.changeDetector.markForCheck();
2469
+ this.inputBinder?.bindActivatedRouteToOutletComponent(this);
2515
2470
  this.activateEvents.emit(this.activated.instance);
2516
2471
  }
2472
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterOutlet, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2473
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0-next.6", type: RouterOutlet, isStandalone: true, selector: "router-outlet", inputs: { name: "name" }, outputs: { activateEvents: "activate", deactivateEvents: "deactivate", attachEvents: "attach", detachEvents: "detach" }, exportAs: ["outlet"], usesOnChanges: true, ngImport: i0 }); }
2517
2474
  }
2518
- RouterOutlet.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterOutlet, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2519
- RouterOutlet.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0-next.4", type: RouterOutlet, isStandalone: true, selector: "router-outlet", inputs: { name: "name" }, outputs: { activateEvents: "activate", deactivateEvents: "deactivate", attachEvents: "attach", detachEvents: "detach" }, exportAs: ["outlet"], usesOnChanges: true, ngImport: i0 });
2520
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterOutlet, decorators: [{
2475
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterOutlet, decorators: [{
2521
2476
  type: Directive,
2522
2477
  args: [{
2523
2478
  selector: 'router-outlet',
@@ -2555,48 +2510,178 @@ class OutletInjector {
2555
2510
  return this.parent.get(token, notFoundValue);
2556
2511
  }
2557
2512
  }
2558
-
2513
+ const INPUT_BINDER = new InjectionToken('');
2559
2514
  /**
2560
- * This component is used internally within the router to be a placeholder when an empty
2561
- * router-outlet is needed. For example, with a config such as:
2562
- *
2563
- * `{path: 'parent', outlet: 'nav', children: [...]}`
2564
- *
2565
- * In order to render, there needs to be a component on this config, which will default
2566
- * to this `EmptyOutletComponent`.
2515
+ * Injectable used as a tree-shakable provider for opting in to binding router data to component
2516
+ * inputs.
2517
+ *
2518
+ * The RouterOutlet registers itself with this service when an `ActivatedRoute` is attached or
2519
+ * activated. When this happens, the service subscribes to the `ActivatedRoute` observables (params,
2520
+ * queryParams, data) and sets the inputs of the component using `ComponentRef.setInput`.
2521
+ * Importantly, when an input does not have an item in the route data with a matching key, this
2522
+ * input is set to `undefined`. If it were not done this way, the previous information would be
2523
+ * retained if the data got removed from the route (i.e. if a query parameter is removed).
2524
+ *
2525
+ * The `RouterOutlet` should unregister itself when destroyed via `unsubscribeFromRouteData` so that
2526
+ * the subscriptions are cleaned up.
2567
2527
  */
2568
- class ɵEmptyOutletComponent {
2528
+ class RoutedComponentInputBinder {
2529
+ constructor() {
2530
+ this.outletDataSubscriptions = new Map;
2531
+ }
2532
+ bindActivatedRouteToOutletComponent(outlet) {
2533
+ this.unsubscribeFromRouteData(outlet);
2534
+ this.subscribeToRouteData(outlet);
2535
+ }
2536
+ unsubscribeFromRouteData(outlet) {
2537
+ this.outletDataSubscriptions.get(outlet)?.unsubscribe();
2538
+ this.outletDataSubscriptions.delete(outlet);
2539
+ }
2540
+ subscribeToRouteData(outlet) {
2541
+ const { activatedRoute } = outlet;
2542
+ const dataSubscription = combineLatest([
2543
+ activatedRoute.queryParams,
2544
+ activatedRoute.params,
2545
+ activatedRoute.data,
2546
+ ])
2547
+ .pipe(switchMap(([queryParams, params, data]) => {
2548
+ // Promise.resolve is used to avoid synchronously writing the wrong data when two of
2549
+ // the Observables in the `combineLatest` stream emit one after another.
2550
+ return Promise.resolve({ ...queryParams, ...params, ...data });
2551
+ }))
2552
+ .subscribe(data => {
2553
+ // Outlet may have been deactivated or changed names to be associated with a different
2554
+ // route
2555
+ if (!outlet.isActivated || !outlet.activatedComponentRef ||
2556
+ outlet.activatedRoute !== activatedRoute || activatedRoute.component === null) {
2557
+ this.unsubscribeFromRouteData(outlet);
2558
+ return;
2559
+ }
2560
+ const mirror = reflectComponentType(activatedRoute.component);
2561
+ if (!mirror) {
2562
+ this.unsubscribeFromRouteData(outlet);
2563
+ return;
2564
+ }
2565
+ for (const { templateName } of mirror.inputs) {
2566
+ outlet.activatedComponentRef.setInput(templateName, data[templateName]);
2567
+ }
2568
+ });
2569
+ this.outletDataSubscriptions.set(outlet, dataSubscription);
2570
+ }
2571
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RoutedComponentInputBinder, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2572
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RoutedComponentInputBinder }); }
2569
2573
  }
2570
- ɵEmptyOutletComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: ɵEmptyOutletComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2571
- ɵEmptyOutletComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.0-next.4", type: ɵEmptyOutletComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: `<router-outlet></router-outlet>`, isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
2572
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: ɵEmptyOutletComponent, decorators: [{
2573
- type: Component,
2574
- args: [{
2575
- template: `<router-outlet></router-outlet>`,
2576
- imports: [RouterOutlet],
2577
- standalone: true,
2578
- }]
2574
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RoutedComponentInputBinder, decorators: [{
2575
+ type: Injectable
2579
2576
  }] });
2580
2577
 
2581
- /**
2582
- * Creates an `EnvironmentInjector` if the `Route` has providers and one does not already exist
2583
- * and returns the injector. Otherwise, if the `Route` does not have `providers`, returns the
2584
- * `currentInjector`.
2585
- *
2586
- * @param route The route that might have providers
2587
- * @param currentInjector The parent injector of the `Route`
2588
- */
2589
- function getOrCreateRouteInjectorIfNeeded(route, currentInjector) {
2590
- if (route.providers && !route._injector) {
2591
- route._injector =
2592
- createEnvironmentInjector(route.providers, currentInjector, `Route: ${route.path}`);
2593
- }
2594
- return route._injector ?? currentInjector;
2595
- }
2596
- function getLoadedRoutes(route) {
2597
- return route._loadedRoutes;
2578
+ function createRouterState(routeReuseStrategy, curr, prevState) {
2579
+ const root = createNode(routeReuseStrategy, curr._root, prevState ? prevState._root : undefined);
2580
+ return new RouterState(root, curr);
2598
2581
  }
2599
- function getLoadedInjector(route) {
2582
+ function createNode(routeReuseStrategy, curr, prevState) {
2583
+ // reuse an activated route that is currently displayed on the screen
2584
+ if (prevState && routeReuseStrategy.shouldReuseRoute(curr.value, prevState.value.snapshot)) {
2585
+ const value = prevState.value;
2586
+ value._futureSnapshot = curr.value;
2587
+ const children = createOrReuseChildren(routeReuseStrategy, curr, prevState);
2588
+ return new TreeNode(value, children);
2589
+ }
2590
+ else {
2591
+ if (routeReuseStrategy.shouldAttach(curr.value)) {
2592
+ // retrieve an activated route that is used to be displayed, but is not currently displayed
2593
+ const detachedRouteHandle = routeReuseStrategy.retrieve(curr.value);
2594
+ if (detachedRouteHandle !== null) {
2595
+ const tree = detachedRouteHandle.route;
2596
+ tree.value._futureSnapshot = curr.value;
2597
+ tree.children = curr.children.map(c => createNode(routeReuseStrategy, c));
2598
+ return tree;
2599
+ }
2600
+ }
2601
+ const value = createActivatedRoute(curr.value);
2602
+ const children = curr.children.map(c => createNode(routeReuseStrategy, c));
2603
+ return new TreeNode(value, children);
2604
+ }
2605
+ }
2606
+ function createOrReuseChildren(routeReuseStrategy, curr, prevState) {
2607
+ return curr.children.map(child => {
2608
+ for (const p of prevState.children) {
2609
+ if (routeReuseStrategy.shouldReuseRoute(child.value, p.value.snapshot)) {
2610
+ return createNode(routeReuseStrategy, child, p);
2611
+ }
2612
+ }
2613
+ return createNode(routeReuseStrategy, child);
2614
+ });
2615
+ }
2616
+ function createActivatedRoute(c) {
2617
+ return new ActivatedRoute(new BehaviorSubject(c.url), new BehaviorSubject(c.params), new BehaviorSubject(c.queryParams), new BehaviorSubject(c.fragment), new BehaviorSubject(c.data), c.outlet, c.component, c);
2618
+ }
2619
+
2620
+ const NAVIGATION_CANCELING_ERROR = 'ngNavigationCancelingError';
2621
+ function redirectingNavigationError(urlSerializer, redirect) {
2622
+ const { redirectTo, navigationBehaviorOptions } = isUrlTree(redirect) ? { redirectTo: redirect, navigationBehaviorOptions: undefined } : redirect;
2623
+ const error = navigationCancelingError(ngDevMode && `Redirecting to "${urlSerializer.serialize(redirectTo)}"`, 0 /* NavigationCancellationCode.Redirect */, redirect);
2624
+ error.url = redirectTo;
2625
+ error.navigationBehaviorOptions = navigationBehaviorOptions;
2626
+ return error;
2627
+ }
2628
+ function navigationCancelingError(message, code, redirectUrl) {
2629
+ const error = new Error('NavigationCancelingError: ' + (message || ''));
2630
+ error[NAVIGATION_CANCELING_ERROR] = true;
2631
+ error.cancellationCode = code;
2632
+ if (redirectUrl) {
2633
+ error.url = redirectUrl;
2634
+ }
2635
+ return error;
2636
+ }
2637
+ function isRedirectingNavigationCancelingError$1(error) {
2638
+ return isNavigationCancelingError$1(error) && isUrlTree(error.url);
2639
+ }
2640
+ function isNavigationCancelingError$1(error) {
2641
+ return error && error[NAVIGATION_CANCELING_ERROR];
2642
+ }
2643
+
2644
+ /**
2645
+ * This component is used internally within the router to be a placeholder when an empty
2646
+ * router-outlet is needed. For example, with a config such as:
2647
+ *
2648
+ * `{path: 'parent', outlet: 'nav', children: [...]}`
2649
+ *
2650
+ * In order to render, there needs to be a component on this config, which will default
2651
+ * to this `EmptyOutletComponent`.
2652
+ */
2653
+ class ɵEmptyOutletComponent {
2654
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: ɵEmptyOutletComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2655
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.0-next.6", type: ɵEmptyOutletComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: `<router-outlet></router-outlet>`, isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] }); }
2656
+ }
2657
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: ɵEmptyOutletComponent, decorators: [{
2658
+ type: Component,
2659
+ args: [{
2660
+ template: `<router-outlet></router-outlet>`,
2661
+ imports: [RouterOutlet],
2662
+ standalone: true,
2663
+ }]
2664
+ }] });
2665
+
2666
+ /**
2667
+ * Creates an `EnvironmentInjector` if the `Route` has providers and one does not already exist
2668
+ * and returns the injector. Otherwise, if the `Route` does not have `providers`, returns the
2669
+ * `currentInjector`.
2670
+ *
2671
+ * @param route The route that might have providers
2672
+ * @param currentInjector The parent injector of the `Route`
2673
+ */
2674
+ function getOrCreateRouteInjectorIfNeeded(route, currentInjector) {
2675
+ if (route.providers && !route._injector) {
2676
+ route._injector =
2677
+ createEnvironmentInjector(route.providers, currentInjector, `Route: ${route.path}`);
2678
+ }
2679
+ return route._injector ?? currentInjector;
2680
+ }
2681
+ function getLoadedRoutes(route) {
2682
+ return route._loadedRoutes;
2683
+ }
2684
+ function getLoadedInjector(route) {
2600
2685
  return route._loadedInjector;
2601
2686
  }
2602
2687
  function getLoadedComponent(route) {
@@ -2765,17 +2850,19 @@ function getClosestRouteInjector(snapshot) {
2765
2850
  return null;
2766
2851
  }
2767
2852
 
2768
- const activateRoutes = (rootContexts, routeReuseStrategy, forwardEvent) => map(t => {
2769
- new ActivateRoutes(routeReuseStrategy, t.targetRouterState, t.currentRouterState, forwardEvent)
2853
+ let warnedAboutUnsupportedInputBinding = false;
2854
+ const activateRoutes = (rootContexts, routeReuseStrategy, forwardEvent, inputBindingEnabled) => map(t => {
2855
+ new ActivateRoutes(routeReuseStrategy, t.targetRouterState, t.currentRouterState, forwardEvent, inputBindingEnabled)
2770
2856
  .activate(rootContexts);
2771
2857
  return t;
2772
2858
  });
2773
2859
  class ActivateRoutes {
2774
- constructor(routeReuseStrategy, futureState, currState, forwardEvent) {
2860
+ constructor(routeReuseStrategy, futureState, currState, forwardEvent, inputBindingEnabled) {
2775
2861
  this.routeReuseStrategy = routeReuseStrategy;
2776
2862
  this.futureState = futureState;
2777
2863
  this.currState = currState;
2778
2864
  this.forwardEvent = forwardEvent;
2865
+ this.inputBindingEnabled = inputBindingEnabled;
2779
2866
  }
2780
2867
  activate(parentContexts) {
2781
2868
  const futureRoot = this.futureState._root;
@@ -2854,13 +2941,16 @@ class ActivateRoutes {
2854
2941
  for (const childOutlet of Object.keys(children)) {
2855
2942
  this.deactivateRouteAndItsChildren(children[childOutlet], contexts);
2856
2943
  }
2857
- if (context && context.outlet) {
2858
- // Destroy the component
2859
- context.outlet.deactivate();
2860
- // Destroy the contexts for all the outlets that were in the component
2861
- context.children.onOutletDeactivated();
2944
+ if (context) {
2945
+ if (context.outlet) {
2946
+ // Destroy the component
2947
+ context.outlet.deactivate();
2948
+ // Destroy the contexts for all the outlets that were in the component
2949
+ context.children.onOutletDeactivated();
2950
+ }
2862
2951
  // Clear the information about the attached component on the context but keep the reference to
2863
- // the outlet.
2952
+ // the outlet. Clear even if outlet was not yet activated to avoid activating later with old
2953
+ // info
2864
2954
  context.attachRef = null;
2865
2955
  context.route = null;
2866
2956
  }
@@ -2927,6 +3017,16 @@ class ActivateRoutes {
2927
3017
  this.activateChildRoutes(futureNode, null, parentContexts);
2928
3018
  }
2929
3019
  }
3020
+ if ((typeof ngDevMode === 'undefined' || ngDevMode)) {
3021
+ const context = parentContexts.getOrCreateContext(future.outlet);
3022
+ const outlet = context.outlet;
3023
+ if (outlet && this.inputBindingEnabled && !outlet.supportsBindingToComponentInputs &&
3024
+ !warnedAboutUnsupportedInputBinding) {
3025
+ console.warn(`'withComponentInputBinding' feature is enabled but ` +
3026
+ `this application is using an outlet that may not support binding to component inputs.`);
3027
+ warnedAboutUnsupportedInputBinding = true;
3028
+ }
3029
+ }
2930
3030
  }
2931
3031
  }
2932
3032
 
@@ -3287,136 +3387,7 @@ function runCanMatchGuards(injector, route, segments, urlSerializer) {
3287
3387
  .pipe(prioritizedGuardValue(), redirectIfUrlTree(urlSerializer));
3288
3388
  }
3289
3389
 
3290
- const noMatch$1 = {
3291
- matched: false,
3292
- consumedSegments: [],
3293
- remainingSegments: [],
3294
- parameters: {},
3295
- positionalParamSegments: {}
3296
- };
3297
- function matchWithChecks(segmentGroup, route, segments, injector, urlSerializer) {
3298
- const result = match(segmentGroup, route, segments);
3299
- if (!result.matched) {
3300
- return of(result);
3301
- }
3302
- // Only create the Route's `EnvironmentInjector` if it matches the attempted
3303
- // navigation
3304
- injector = getOrCreateRouteInjectorIfNeeded(route, injector);
3305
- return runCanMatchGuards(injector, route, segments, urlSerializer)
3306
- .pipe(map((v) => v === true ? result : { ...noMatch$1 }));
3307
- }
3308
- function match(segmentGroup, route, segments) {
3309
- if (route.path === '') {
3310
- if (route.pathMatch === 'full' && (segmentGroup.hasChildren() || segments.length > 0)) {
3311
- return { ...noMatch$1 };
3312
- }
3313
- return {
3314
- matched: true,
3315
- consumedSegments: [],
3316
- remainingSegments: segments,
3317
- parameters: {},
3318
- positionalParamSegments: {}
3319
- };
3320
- }
3321
- const matcher = route.matcher || defaultUrlMatcher;
3322
- const res = matcher(segments, segmentGroup, route);
3323
- if (!res)
3324
- return { ...noMatch$1 };
3325
- const posParams = {};
3326
- Object.entries(res.posParams ?? {}).forEach(([k, v]) => {
3327
- posParams[k] = v.path;
3328
- });
3329
- const parameters = res.consumed.length > 0 ?
3330
- { ...posParams, ...res.consumed[res.consumed.length - 1].parameters } :
3331
- posParams;
3332
- return {
3333
- matched: true,
3334
- consumedSegments: res.consumed,
3335
- remainingSegments: segments.slice(res.consumed.length),
3336
- // TODO(atscott): investigate combining parameters and positionalParamSegments
3337
- parameters,
3338
- positionalParamSegments: res.posParams ?? {}
3339
- };
3340
- }
3341
- function split(segmentGroup, consumedSegments, slicedSegments, config) {
3342
- if (slicedSegments.length > 0 &&
3343
- containsEmptyPathMatchesWithNamedOutlets(segmentGroup, slicedSegments, config)) {
3344
- const s = new UrlSegmentGroup(consumedSegments, createChildrenForEmptyPaths(config, new UrlSegmentGroup(slicedSegments, segmentGroup.children)));
3345
- return { segmentGroup: s, slicedSegments: [] };
3346
- }
3347
- if (slicedSegments.length === 0 &&
3348
- containsEmptyPathMatches(segmentGroup, slicedSegments, config)) {
3349
- const s = new UrlSegmentGroup(segmentGroup.segments, addEmptyPathsToChildrenIfNeeded(segmentGroup, consumedSegments, slicedSegments, config, segmentGroup.children));
3350
- return { segmentGroup: s, slicedSegments };
3351
- }
3352
- const s = new UrlSegmentGroup(segmentGroup.segments, segmentGroup.children);
3353
- return { segmentGroup: s, slicedSegments };
3354
- }
3355
- function addEmptyPathsToChildrenIfNeeded(segmentGroup, consumedSegments, slicedSegments, routes, children) {
3356
- const res = {};
3357
- for (const r of routes) {
3358
- if (emptyPathMatch(segmentGroup, slicedSegments, r) && !children[getOutlet(r)]) {
3359
- const s = new UrlSegmentGroup([], {});
3360
- res[getOutlet(r)] = s;
3361
- }
3362
- }
3363
- return { ...children, ...res };
3364
- }
3365
- function createChildrenForEmptyPaths(routes, primarySegment) {
3366
- const res = {};
3367
- res[PRIMARY_OUTLET] = primarySegment;
3368
- for (const r of routes) {
3369
- if (r.path === '' && getOutlet(r) !== PRIMARY_OUTLET) {
3370
- const s = new UrlSegmentGroup([], {});
3371
- res[getOutlet(r)] = s;
3372
- }
3373
- }
3374
- return res;
3375
- }
3376
- function containsEmptyPathMatchesWithNamedOutlets(segmentGroup, slicedSegments, routes) {
3377
- return routes.some(r => emptyPathMatch(segmentGroup, slicedSegments, r) && getOutlet(r) !== PRIMARY_OUTLET);
3378
- }
3379
- function containsEmptyPathMatches(segmentGroup, slicedSegments, routes) {
3380
- return routes.some(r => emptyPathMatch(segmentGroup, slicedSegments, r));
3381
- }
3382
- function emptyPathMatch(segmentGroup, slicedSegments, r) {
3383
- if ((segmentGroup.hasChildren() || slicedSegments.length > 0) && r.pathMatch === 'full') {
3384
- return false;
3385
- }
3386
- return r.path === '';
3387
- }
3388
- /**
3389
- * Determines if `route` is a path match for the `rawSegment`, `segments`, and `outlet` without
3390
- * verifying that its children are a full match for the remainder of the `rawSegment` children as
3391
- * well.
3392
- */
3393
- function isImmediateMatch(route, rawSegment, segments, outlet) {
3394
- // We allow matches to empty paths when the outlets differ so we can match a url like `/(b:b)` to
3395
- // a config like
3396
- // * `{path: '', children: [{path: 'b', outlet: 'b'}]}`
3397
- // or even
3398
- // * `{path: '', outlet: 'a', children: [{path: 'b', outlet: 'b'}]`
3399
- //
3400
- // The exception here is when the segment outlet is for the primary outlet. This would
3401
- // result in a match inside the named outlet because all children there are written as primary
3402
- // outlets. So we need to prevent child named outlet matches in a url like `/b` in a config like
3403
- // * `{path: '', outlet: 'x' children: [{path: 'b'}]}`
3404
- // This should only match if the url is `/(x:b)`.
3405
- if (getOutlet(route) !== outlet &&
3406
- (outlet === PRIMARY_OUTLET || !emptyPathMatch(rawSegment, segments, route))) {
3407
- return false;
3408
- }
3409
- if (route.path === '**') {
3410
- return true;
3411
- }
3412
- return match(rawSegment, route, segments).matched;
3413
- }
3414
- function noLeftoversInUrl(segmentGroup, segments, outlet) {
3415
- return segments.length === 0 && !segmentGroup.children[outlet];
3416
- }
3417
-
3418
- const NG_DEV_MODE$7 = typeof ngDevMode === 'undefined' || ngDevMode;
3419
- class NoMatch$1 {
3390
+ class NoMatch {
3420
3391
  constructor(segmentGroup) {
3421
3392
  this.segmentGroup = segmentGroup || null;
3422
3393
  }
@@ -3426,241 +3397,28 @@ class AbsoluteRedirect {
3426
3397
  this.urlTree = urlTree;
3427
3398
  }
3428
3399
  }
3429
- function noMatch(segmentGroup) {
3430
- return throwError(new NoMatch$1(segmentGroup));
3400
+ function noMatch$1(segmentGroup) {
3401
+ return throwError(new NoMatch(segmentGroup));
3431
3402
  }
3432
3403
  function absoluteRedirect(newTree) {
3433
3404
  return throwError(new AbsoluteRedirect(newTree));
3434
3405
  }
3435
3406
  function namedOutletsRedirect(redirectTo) {
3436
- return throwError(new ɵRuntimeError(4000 /* RuntimeErrorCode.NAMED_OUTLET_REDIRECT */, NG_DEV_MODE$7 &&
3407
+ return throwError(new ɵRuntimeError(4000 /* RuntimeErrorCode.NAMED_OUTLET_REDIRECT */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
3437
3408
  `Only absolute redirects can have named outlets. redirectTo: '${redirectTo}'`));
3438
3409
  }
3439
3410
  function canLoadFails(route) {
3440
- return throwError(navigationCancelingError(NG_DEV_MODE$7 &&
3411
+ return throwError(navigationCancelingError((typeof ngDevMode === 'undefined' || ngDevMode) &&
3441
3412
  `Cannot load children because the guard of the route "path: '${route.path}'" returned false`, 3 /* NavigationCancellationCode.GuardRejected */));
3442
3413
  }
3443
- /**
3444
- * Returns the `UrlTree` with the redirection applied.
3445
- *
3446
- * Lazy modules are loaded along the way.
3447
- */
3448
- function applyRedirects$1(injector, configLoader, urlSerializer, urlTree, config) {
3449
- return new ApplyRedirects(injector, configLoader, urlSerializer, urlTree, config).apply();
3450
- }
3451
3414
  class ApplyRedirects {
3452
- constructor(injector, configLoader, urlSerializer, urlTree, config) {
3453
- this.injector = injector;
3454
- this.configLoader = configLoader;
3415
+ constructor(urlSerializer, urlTree) {
3455
3416
  this.urlSerializer = urlSerializer;
3456
3417
  this.urlTree = urlTree;
3457
- this.config = config;
3458
- this.allowRedirects = true;
3459
- }
3460
- apply() {
3461
- const splitGroup = split(this.urlTree.root, [], [], this.config).segmentGroup;
3462
- // TODO(atscott): creating a new segment removes the _sourceSegment _segmentIndexShift, which is
3463
- // only necessary to prevent failures in tests which assert exact object matches. The `split` is
3464
- // now shared between `applyRedirects` and `recognize` but only the `recognize` step needs these
3465
- // properties. Before the implementations were merged, the `applyRedirects` would not assign
3466
- // them. We should be able to remove this logic as a "breaking change" but should do some more
3467
- // investigation into the failures first.
3468
- const rootSegmentGroup = new UrlSegmentGroup(splitGroup.segments, splitGroup.children);
3469
- const expanded$ = this.expandSegmentGroup(this.injector, this.config, rootSegmentGroup, PRIMARY_OUTLET);
3470
- const urlTrees$ = expanded$.pipe(map((rootSegmentGroup) => {
3471
- return this.createUrlTree(squashSegmentGroup(rootSegmentGroup), this.urlTree.queryParams, this.urlTree.fragment);
3472
- }));
3473
- return urlTrees$.pipe(catchError((e) => {
3474
- if (e instanceof AbsoluteRedirect) {
3475
- // After an absolute redirect we do not apply any more redirects!
3476
- // If this implementation changes, update the documentation note in `redirectTo`.
3477
- this.allowRedirects = false;
3478
- // we need to run matching, so we can fetch all lazy-loaded modules
3479
- return this.match(e.urlTree);
3480
- }
3481
- if (e instanceof NoMatch$1) {
3482
- throw this.noMatchError(e);
3483
- }
3484
- throw e;
3485
- }));
3486
- }
3487
- match(tree) {
3488
- const expanded$ = this.expandSegmentGroup(this.injector, this.config, tree.root, PRIMARY_OUTLET);
3489
- const mapped$ = expanded$.pipe(map((rootSegmentGroup) => {
3490
- return this.createUrlTree(squashSegmentGroup(rootSegmentGroup), tree.queryParams, tree.fragment);
3491
- }));
3492
- return mapped$.pipe(catchError((e) => {
3493
- if (e instanceof NoMatch$1) {
3494
- throw this.noMatchError(e);
3495
- }
3496
- throw e;
3497
- }));
3498
3418
  }
3499
3419
  noMatchError(e) {
3500
- return new ɵRuntimeError(4002 /* RuntimeErrorCode.NO_MATCH */, NG_DEV_MODE$7 && `Cannot match any routes. URL Segment: '${e.segmentGroup}'`);
3501
- }
3502
- createUrlTree(rootCandidate, queryParams, fragment) {
3503
- const root = createRoot(rootCandidate);
3504
- return new UrlTree(root, queryParams, fragment);
3505
- }
3506
- expandSegmentGroup(injector, routes, segmentGroup, outlet) {
3507
- if (segmentGroup.segments.length === 0 && segmentGroup.hasChildren()) {
3508
- return this.expandChildren(injector, routes, segmentGroup)
3509
- .pipe(map((children) => new UrlSegmentGroup([], children)));
3510
- }
3511
- return this.expandSegment(injector, segmentGroup, routes, segmentGroup.segments, outlet, true);
3512
- }
3513
- // Recursively expand segment groups for all the child outlets
3514
- expandChildren(injector, routes, segmentGroup) {
3515
- // Expand outlets one at a time, starting with the primary outlet. We need to do it this way
3516
- // because an absolute redirect from the primary outlet takes precedence.
3517
- const childOutlets = [];
3518
- for (const child of Object.keys(segmentGroup.children)) {
3519
- if (child === 'primary') {
3520
- childOutlets.unshift(child);
3521
- }
3522
- else {
3523
- childOutlets.push(child);
3524
- }
3525
- }
3526
- return from(childOutlets)
3527
- .pipe(concatMap(childOutlet => {
3528
- const child = segmentGroup.children[childOutlet];
3529
- // Sort the routes so routes with outlets that match the segment appear
3530
- // first, followed by routes for other outlets, which might match if they have an
3531
- // empty path.
3532
- const sortedRoutes = sortByMatchingOutlets(routes, childOutlet);
3533
- return this.expandSegmentGroup(injector, sortedRoutes, child, childOutlet)
3534
- .pipe(map(s => ({ segment: s, outlet: childOutlet })));
3535
- }), scan((children, expandedChild) => {
3536
- children[expandedChild.outlet] = expandedChild.segment;
3537
- return children;
3538
- }, {}), last$1());
3539
- }
3540
- expandSegment(injector, segmentGroup, routes, segments, outlet, allowRedirects) {
3541
- return from(routes).pipe(concatMap(r => {
3542
- const expanded$ = this.expandSegmentAgainstRoute(injector, segmentGroup, routes, r, segments, outlet, allowRedirects);
3543
- return expanded$.pipe(catchError((e) => {
3544
- if (e instanceof NoMatch$1) {
3545
- return of(null);
3546
- }
3547
- throw e;
3548
- }));
3549
- }), first((s) => !!s), catchError((e, _) => {
3550
- if (isEmptyError(e)) {
3551
- if (noLeftoversInUrl(segmentGroup, segments, outlet)) {
3552
- return of(new UrlSegmentGroup([], {}));
3553
- }
3554
- return noMatch(segmentGroup);
3555
- }
3556
- throw e;
3557
- }));
3558
- }
3559
- expandSegmentAgainstRoute(injector, segmentGroup, routes, route, paths, outlet, allowRedirects) {
3560
- if (!isImmediateMatch(route, segmentGroup, paths, outlet)) {
3561
- return noMatch(segmentGroup);
3562
- }
3563
- if (route.redirectTo === undefined) {
3564
- return this.matchSegmentAgainstRoute(injector, segmentGroup, route, paths, outlet);
3565
- }
3566
- if (allowRedirects && this.allowRedirects) {
3567
- return this.expandSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, paths, outlet);
3568
- }
3569
- return noMatch(segmentGroup);
3570
- }
3571
- expandSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet) {
3572
- if (route.path === '**') {
3573
- return this.expandWildCardWithParamsAgainstRouteUsingRedirect(injector, routes, route, outlet);
3574
- }
3575
- return this.expandRegularSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet);
3576
- }
3577
- expandWildCardWithParamsAgainstRouteUsingRedirect(injector, routes, route, outlet) {
3578
- const newTree = this.applyRedirectCommands([], route.redirectTo, {});
3579
- if (route.redirectTo.startsWith('/')) {
3580
- return absoluteRedirect(newTree);
3581
- }
3582
- return this.lineralizeSegments(route, newTree).pipe(mergeMap((newSegments) => {
3583
- const group = new UrlSegmentGroup(newSegments, {});
3584
- return this.expandSegment(injector, group, routes, newSegments, outlet, false);
3585
- }));
3586
- }
3587
- expandRegularSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet) {
3588
- const { matched, consumedSegments, remainingSegments, positionalParamSegments } = match(segmentGroup, route, segments);
3589
- if (!matched)
3590
- return noMatch(segmentGroup);
3591
- const newTree = this.applyRedirectCommands(consumedSegments, route.redirectTo, positionalParamSegments);
3592
- if (route.redirectTo.startsWith('/')) {
3593
- return absoluteRedirect(newTree);
3594
- }
3595
- return this.lineralizeSegments(route, newTree).pipe(mergeMap((newSegments) => {
3596
- return this.expandSegment(injector, segmentGroup, routes, newSegments.concat(remainingSegments), outlet, false);
3597
- }));
3598
- }
3599
- matchSegmentAgainstRoute(injector, rawSegmentGroup, route, segments, outlet) {
3600
- if (route.path === '**') {
3601
- // Only create the Route's `EnvironmentInjector` if it matches the attempted navigation
3602
- injector = getOrCreateRouteInjectorIfNeeded(route, injector);
3603
- if (route.loadChildren) {
3604
- const loaded$ = route._loadedRoutes ?
3605
- of({ routes: route._loadedRoutes, injector: route._loadedInjector }) :
3606
- this.configLoader.loadChildren(injector, route);
3607
- return loaded$.pipe(map((cfg) => {
3608
- route._loadedRoutes = cfg.routes;
3609
- route._loadedInjector = cfg.injector;
3610
- return new UrlSegmentGroup(segments, {});
3611
- }));
3612
- }
3613
- return of(new UrlSegmentGroup(segments, {}));
3614
- }
3615
- return matchWithChecks(rawSegmentGroup, route, segments, injector, this.urlSerializer)
3616
- .pipe(switchMap(({ matched, consumedSegments, remainingSegments }) => {
3617
- if (!matched)
3618
- return noMatch(rawSegmentGroup);
3619
- // If the route has an injector created from providers, we should start using that.
3620
- injector = route._injector ?? injector;
3621
- const childConfig$ = this.getChildConfig(injector, route, segments);
3622
- return childConfig$.pipe(mergeMap((routerConfig) => {
3623
- const childInjector = routerConfig.injector ?? injector;
3624
- const childConfig = routerConfig.routes;
3625
- const { segmentGroup: splitSegmentGroup, slicedSegments } = split(rawSegmentGroup, consumedSegments, remainingSegments, childConfig);
3626
- // See comment on the other call to `split` about why this is necessary.
3627
- const segmentGroup = new UrlSegmentGroup(splitSegmentGroup.segments, splitSegmentGroup.children);
3628
- if (slicedSegments.length === 0 && segmentGroup.hasChildren()) {
3629
- const expanded$ = this.expandChildren(childInjector, childConfig, segmentGroup);
3630
- return expanded$.pipe(map((children) => new UrlSegmentGroup(consumedSegments, children)));
3631
- }
3632
- if (childConfig.length === 0 && slicedSegments.length === 0) {
3633
- return of(new UrlSegmentGroup(consumedSegments, {}));
3634
- }
3635
- const matchedOnOutlet = getOutlet(route) === outlet;
3636
- const expanded$ = this.expandSegment(childInjector, segmentGroup, childConfig, slicedSegments, matchedOnOutlet ? PRIMARY_OUTLET : outlet, true);
3637
- return expanded$.pipe(map((cs) => new UrlSegmentGroup(consumedSegments.concat(cs.segments), cs.children)));
3638
- }));
3639
- }));
3640
- }
3641
- getChildConfig(injector, route, segments) {
3642
- if (route.children) {
3643
- // The children belong to the same module
3644
- return of({ routes: route.children, injector });
3645
- }
3646
- if (route.loadChildren) {
3647
- // lazy children belong to the loaded module
3648
- if (route._loadedRoutes !== undefined) {
3649
- return of({ routes: route._loadedRoutes, injector: route._loadedInjector });
3650
- }
3651
- return runCanLoadGuards(injector, route, segments, this.urlSerializer)
3652
- .pipe(mergeMap((shouldLoadResult) => {
3653
- if (shouldLoadResult) {
3654
- return this.configLoader.loadChildren(injector, route)
3655
- .pipe(tap((cfg) => {
3656
- route._loadedRoutes = cfg.routes;
3657
- route._loadedInjector = cfg.injector;
3658
- }));
3659
- }
3660
- return canLoadFails(route);
3661
- }));
3662
- }
3663
- return of({ routes: [], injector });
3420
+ return new ɵRuntimeError(4002 /* RuntimeErrorCode.NO_MATCH */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
3421
+ `Cannot match any routes. URL Segment: '${e.segmentGroup}'`);
3664
3422
  }
3665
3423
  lineralizeSegments(route, urlTree) {
3666
3424
  let res = [];
@@ -3712,7 +3470,7 @@ class ApplyRedirects {
3712
3470
  findPosParam(redirectTo, redirectToUrlSegment, posParams) {
3713
3471
  const pos = posParams[redirectToUrlSegment.path.substring(1)];
3714
3472
  if (!pos)
3715
- throw new ɵRuntimeError(4001 /* RuntimeErrorCode.MISSING_REDIRECT */, NG_DEV_MODE$7 &&
3473
+ throw new ɵRuntimeError(4001 /* RuntimeErrorCode.MISSING_REDIRECT */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
3716
3474
  `Cannot redirect to '${redirectTo}'. Cannot find '${redirectToUrlSegment.path}'.`);
3717
3475
  return pos;
3718
3476
  }
@@ -3725,59 +3483,196 @@ class ApplyRedirects {
3725
3483
  }
3726
3484
  idx++;
3727
3485
  }
3728
- return redirectToUrlSegment;
3486
+ return redirectToUrlSegment;
3487
+ }
3488
+ }
3489
+
3490
+ const noMatch = {
3491
+ matched: false,
3492
+ consumedSegments: [],
3493
+ remainingSegments: [],
3494
+ parameters: {},
3495
+ positionalParamSegments: {}
3496
+ };
3497
+ function matchWithChecks(segmentGroup, route, segments, injector, urlSerializer) {
3498
+ const result = match(segmentGroup, route, segments);
3499
+ if (!result.matched) {
3500
+ return of(result);
3501
+ }
3502
+ // Only create the Route's `EnvironmentInjector` if it matches the attempted
3503
+ // navigation
3504
+ injector = getOrCreateRouteInjectorIfNeeded(route, injector);
3505
+ return runCanMatchGuards(injector, route, segments, urlSerializer)
3506
+ .pipe(map((v) => v === true ? result : { ...noMatch }));
3507
+ }
3508
+ function match(segmentGroup, route, segments) {
3509
+ if (route.path === '') {
3510
+ if (route.pathMatch === 'full' && (segmentGroup.hasChildren() || segments.length > 0)) {
3511
+ return { ...noMatch };
3512
+ }
3513
+ return {
3514
+ matched: true,
3515
+ consumedSegments: [],
3516
+ remainingSegments: segments,
3517
+ parameters: {},
3518
+ positionalParamSegments: {}
3519
+ };
3520
+ }
3521
+ const matcher = route.matcher || defaultUrlMatcher;
3522
+ const res = matcher(segments, segmentGroup, route);
3523
+ if (!res)
3524
+ return { ...noMatch };
3525
+ const posParams = {};
3526
+ Object.entries(res.posParams ?? {}).forEach(([k, v]) => {
3527
+ posParams[k] = v.path;
3528
+ });
3529
+ const parameters = res.consumed.length > 0 ?
3530
+ { ...posParams, ...res.consumed[res.consumed.length - 1].parameters } :
3531
+ posParams;
3532
+ return {
3533
+ matched: true,
3534
+ consumedSegments: res.consumed,
3535
+ remainingSegments: segments.slice(res.consumed.length),
3536
+ // TODO(atscott): investigate combining parameters and positionalParamSegments
3537
+ parameters,
3538
+ positionalParamSegments: res.posParams ?? {}
3539
+ };
3540
+ }
3541
+ function split(segmentGroup, consumedSegments, slicedSegments, config) {
3542
+ if (slicedSegments.length > 0 &&
3543
+ containsEmptyPathMatchesWithNamedOutlets(segmentGroup, slicedSegments, config)) {
3544
+ const s = new UrlSegmentGroup(consumedSegments, createChildrenForEmptyPaths(config, new UrlSegmentGroup(slicedSegments, segmentGroup.children)));
3545
+ return { segmentGroup: s, slicedSegments: [] };
3546
+ }
3547
+ if (slicedSegments.length === 0 &&
3548
+ containsEmptyPathMatches(segmentGroup, slicedSegments, config)) {
3549
+ const s = new UrlSegmentGroup(segmentGroup.segments, addEmptyPathsToChildrenIfNeeded(segmentGroup, consumedSegments, slicedSegments, config, segmentGroup.children));
3550
+ return { segmentGroup: s, slicedSegments };
3551
+ }
3552
+ const s = new UrlSegmentGroup(segmentGroup.segments, segmentGroup.children);
3553
+ return { segmentGroup: s, slicedSegments };
3554
+ }
3555
+ function addEmptyPathsToChildrenIfNeeded(segmentGroup, consumedSegments, slicedSegments, routes, children) {
3556
+ const res = {};
3557
+ for (const r of routes) {
3558
+ if (emptyPathMatch(segmentGroup, slicedSegments, r) && !children[getOutlet(r)]) {
3559
+ const s = new UrlSegmentGroup([], {});
3560
+ res[getOutlet(r)] = s;
3561
+ }
3562
+ }
3563
+ return { ...children, ...res };
3564
+ }
3565
+ function createChildrenForEmptyPaths(routes, primarySegment) {
3566
+ const res = {};
3567
+ res[PRIMARY_OUTLET] = primarySegment;
3568
+ for (const r of routes) {
3569
+ if (r.path === '' && getOutlet(r) !== PRIMARY_OUTLET) {
3570
+ const s = new UrlSegmentGroup([], {});
3571
+ res[getOutlet(r)] = s;
3572
+ }
3729
3573
  }
3574
+ return res;
3730
3575
  }
3731
-
3732
- function applyRedirects(environmentInjector, configLoader, urlSerializer, config) {
3733
- return switchMap(t => applyRedirects$1(environmentInjector, configLoader, urlSerializer, t.extractedUrl, config)
3734
- .pipe(map(urlAfterRedirects => ({ ...t, urlAfterRedirects }))));
3576
+ function containsEmptyPathMatchesWithNamedOutlets(segmentGroup, slicedSegments, routes) {
3577
+ return routes.some(r => emptyPathMatch(segmentGroup, slicedSegments, r) && getOutlet(r) !== PRIMARY_OUTLET);
3735
3578
  }
3736
-
3737
- const NG_DEV_MODE$6 = typeof ngDevMode === 'undefined' || !!ngDevMode;
3738
- class NoMatch {
3579
+ function containsEmptyPathMatches(segmentGroup, slicedSegments, routes) {
3580
+ return routes.some(r => emptyPathMatch(segmentGroup, slicedSegments, r));
3739
3581
  }
3740
- function newObservableError(e) {
3741
- // TODO(atscott): This pattern is used throughout the router code and can be `throwError` instead.
3742
- return new Observable((obs) => obs.error(e));
3582
+ function emptyPathMatch(segmentGroup, slicedSegments, r) {
3583
+ if ((segmentGroup.hasChildren() || slicedSegments.length > 0) && r.pathMatch === 'full') {
3584
+ return false;
3585
+ }
3586
+ return r.path === '';
3743
3587
  }
3744
- function recognize$1(injector, rootComponentType, config, urlTree, url, urlSerializer, paramsInheritanceStrategy = 'emptyOnly') {
3745
- return new Recognizer(injector, rootComponentType, config, urlTree, url, paramsInheritanceStrategy, urlSerializer)
3746
- .recognize()
3747
- .pipe(switchMap(result => {
3748
- if (result === null) {
3749
- return newObservableError(new NoMatch());
3750
- }
3751
- else {
3752
- return of(result);
3753
- }
3754
- }));
3588
+ /**
3589
+ * Determines if `route` is a path match for the `rawSegment`, `segments`, and `outlet` without
3590
+ * verifying that its children are a full match for the remainder of the `rawSegment` children as
3591
+ * well.
3592
+ */
3593
+ function isImmediateMatch(route, rawSegment, segments, outlet) {
3594
+ // We allow matches to empty paths when the outlets differ so we can match a url like `/(b:b)` to
3595
+ // a config like
3596
+ // * `{path: '', children: [{path: 'b', outlet: 'b'}]}`
3597
+ // or even
3598
+ // * `{path: '', outlet: 'a', children: [{path: 'b', outlet: 'b'}]`
3599
+ //
3600
+ // The exception here is when the segment outlet is for the primary outlet. This would
3601
+ // result in a match inside the named outlet because all children there are written as primary
3602
+ // outlets. So we need to prevent child named outlet matches in a url like `/b` in a config like
3603
+ // * `{path: '', outlet: 'x' children: [{path: 'b'}]}`
3604
+ // This should only match if the url is `/(x:b)`.
3605
+ if (getOutlet(route) !== outlet &&
3606
+ (outlet === PRIMARY_OUTLET || !emptyPathMatch(rawSegment, segments, route))) {
3607
+ return false;
3608
+ }
3609
+ if (route.path === '**') {
3610
+ return true;
3611
+ }
3612
+ return match(rawSegment, route, segments).matched;
3613
+ }
3614
+ function noLeftoversInUrl(segmentGroup, segments, outlet) {
3615
+ return segments.length === 0 && !segmentGroup.children[outlet];
3616
+ }
3617
+
3618
+ function recognize$1(injector, configLoader, rootComponentType, config, urlTree, urlSerializer, paramsInheritanceStrategy = 'emptyOnly') {
3619
+ return new Recognizer(injector, configLoader, rootComponentType, config, urlTree, paramsInheritanceStrategy, urlSerializer)
3620
+ .recognize();
3755
3621
  }
3756
3622
  class Recognizer {
3757
- constructor(injector, rootComponentType, config, urlTree, url, paramsInheritanceStrategy, urlSerializer) {
3623
+ constructor(injector, configLoader, rootComponentType, config, urlTree, paramsInheritanceStrategy, urlSerializer) {
3758
3624
  this.injector = injector;
3625
+ this.configLoader = configLoader;
3759
3626
  this.rootComponentType = rootComponentType;
3760
3627
  this.config = config;
3761
3628
  this.urlTree = urlTree;
3762
- this.url = url;
3763
3629
  this.paramsInheritanceStrategy = paramsInheritanceStrategy;
3764
3630
  this.urlSerializer = urlSerializer;
3631
+ this.allowRedirects = true;
3632
+ this.applyRedirects = new ApplyRedirects(this.urlSerializer, this.urlTree);
3633
+ }
3634
+ noMatchError(e) {
3635
+ return new ɵRuntimeError(4002 /* RuntimeErrorCode.NO_MATCH */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
3636
+ `Cannot match any routes. URL Segment: '${e.segmentGroup}'`);
3765
3637
  }
3766
3638
  recognize() {
3767
- const rootSegmentGroup = split(this.urlTree.root, [], [], this.config.filter(c => c.redirectTo === undefined))
3768
- .segmentGroup;
3639
+ const rootSegmentGroup = split(this.urlTree.root, [], [], this.config).segmentGroup;
3769
3640
  return this.processSegmentGroup(this.injector, this.config, rootSegmentGroup, PRIMARY_OUTLET)
3770
- .pipe(map(children => {
3771
- if (children === null) {
3772
- return null;
3641
+ .pipe(catchError((e) => {
3642
+ if (e instanceof AbsoluteRedirect) {
3643
+ // After an absolute redirect we do not apply any more redirects!
3644
+ // If this implementation changes, update the documentation note in `redirectTo`.
3645
+ this.allowRedirects = false;
3646
+ this.urlTree = e.urlTree;
3647
+ return this.match(e.urlTree);
3648
+ }
3649
+ if (e instanceof NoMatch) {
3650
+ throw this.noMatchError(e);
3773
3651
  }
3774
- // Use Object.freeze to prevent readers of the Router state from modifying it outside of a
3775
- // navigation, resulting in the router being out of sync with the browser.
3652
+ throw e;
3653
+ }), map(children => {
3654
+ // Use Object.freeze to prevent readers of the Router state from modifying it outside
3655
+ // of a navigation, resulting in the router being out of sync with the browser.
3776
3656
  const root = new ActivatedRouteSnapshot([], Object.freeze({}), Object.freeze({ ...this.urlTree.queryParams }), this.urlTree.fragment, {}, PRIMARY_OUTLET, this.rootComponentType, null, {});
3777
3657
  const rootNode = new TreeNode(root, children);
3778
- const routeState = new RouterStateSnapshot(this.url, rootNode);
3658
+ const routeState = new RouterStateSnapshot('', rootNode);
3659
+ const tree = createUrlTreeFromSnapshot(root, [], this.urlTree.queryParams, this.urlTree.fragment);
3660
+ // https://github.com/angular/angular/issues/47307
3661
+ // Creating the tree stringifies the query params
3662
+ // We don't want to do this here so reassign them to the original.
3663
+ tree.queryParams = this.urlTree.queryParams;
3664
+ routeState.url = this.urlSerializer.serialize(tree);
3779
3665
  this.inheritParamsAndData(routeState._root);
3780
- return routeState;
3666
+ return { state: routeState, tree };
3667
+ }));
3668
+ }
3669
+ match(tree) {
3670
+ const expanded$ = this.processSegmentGroup(this.injector, this.config, tree.root, PRIMARY_OUTLET);
3671
+ return expanded$.pipe(catchError((e) => {
3672
+ if (e instanceof NoMatch) {
3673
+ throw this.noMatchError(e);
3674
+ }
3675
+ throw e;
3781
3676
  }));
3782
3677
  }
3783
3678
  inheritParamsAndData(routeNode) {
@@ -3791,7 +3686,7 @@ class Recognizer {
3791
3686
  if (segmentGroup.segments.length === 0 && segmentGroup.hasChildren()) {
3792
3687
  return this.processChildren(injector, config, segmentGroup);
3793
3688
  }
3794
- return this.processSegment(injector, config, segmentGroup, segmentGroup.segments, outlet);
3689
+ return this.processSegment(injector, config, segmentGroup, segmentGroup.segments, outlet, true);
3795
3690
  }
3796
3691
  /**
3797
3692
  * Matches every child outlet in the `segmentGroup` to a `Route` in the config. Returns `null` if
@@ -3802,7 +3697,18 @@ class Recognizer {
3802
3697
  * config.
3803
3698
  */
3804
3699
  processChildren(injector, config, segmentGroup) {
3805
- return from(Object.keys(segmentGroup.children))
3700
+ // Expand outlets one at a time, starting with the primary outlet. We need to do it this way
3701
+ // because an absolute redirect from the primary outlet takes precedence.
3702
+ const childOutlets = [];
3703
+ for (const child of Object.keys(segmentGroup.children)) {
3704
+ if (child === 'primary') {
3705
+ childOutlets.unshift(child);
3706
+ }
3707
+ else {
3708
+ childOutlets.push(child);
3709
+ }
3710
+ }
3711
+ return from(childOutlets)
3806
3712
  .pipe(concatMap(childOutlet => {
3807
3713
  const child = segmentGroup.children[childOutlet];
3808
3714
  // Sort the config so that routes with outlets that match the one being activated
@@ -3811,42 +3717,86 @@ class Recognizer {
3811
3717
  const sortedConfig = sortByMatchingOutlets(config, childOutlet);
3812
3718
  return this.processSegmentGroup(injector, sortedConfig, child, childOutlet);
3813
3719
  }), scan((children, outletChildren) => {
3814
- if (!children || !outletChildren)
3815
- return null;
3816
3720
  children.push(...outletChildren);
3817
3721
  return children;
3818
- }), takeWhile(children => children !== null), defaultIfEmpty(null), last$1(), map(children => {
3722
+ }), defaultIfEmpty(null), last$1(), mergeMap(children => {
3819
3723
  if (children === null)
3820
- return null;
3724
+ return noMatch$1(segmentGroup);
3821
3725
  // Because we may have matched two outlets to the same empty path segment, we can have
3822
3726
  // multiple activated results for the same outlet. We should merge the children of
3823
3727
  // these results so the final return value is only one `TreeNode` per outlet.
3824
3728
  const mergedChildren = mergeEmptyPathMatches(children);
3825
- if (NG_DEV_MODE$6) {
3729
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
3826
3730
  // This should really never happen - we are only taking the first match for each
3827
3731
  // outlet and merge the empty path matches.
3828
3732
  checkOutletNameUniqueness(mergedChildren);
3829
3733
  }
3830
3734
  sortActivatedRouteSnapshots(mergedChildren);
3831
- return mergedChildren;
3735
+ return of(mergedChildren);
3832
3736
  }));
3833
3737
  }
3834
- processSegment(injector, routes, segmentGroup, segments, outlet) {
3738
+ processSegment(injector, routes, segmentGroup, segments, outlet, allowRedirects) {
3835
3739
  return from(routes).pipe(concatMap(r => {
3836
- return this.processSegmentAgainstRoute(r._injector ?? injector, r, segmentGroup, segments, outlet);
3740
+ return this
3741
+ .processSegmentAgainstRoute(r._injector ?? injector, routes, r, segmentGroup, segments, outlet, allowRedirects)
3742
+ .pipe(catchError((e) => {
3743
+ if (e instanceof NoMatch) {
3744
+ return of(null);
3745
+ }
3746
+ throw e;
3747
+ }));
3837
3748
  }), first((x) => !!x), catchError(e => {
3838
3749
  if (isEmptyError(e)) {
3839
3750
  if (noLeftoversInUrl(segmentGroup, segments, outlet)) {
3840
3751
  return of([]);
3841
3752
  }
3842
- return of(null);
3753
+ return noMatch$1(segmentGroup);
3843
3754
  }
3844
3755
  throw e;
3845
3756
  }));
3846
3757
  }
3847
- processSegmentAgainstRoute(injector, route, rawSegment, segments, outlet) {
3848
- if (route.redirectTo || !isImmediateMatch(route, rawSegment, segments, outlet))
3849
- return of(null);
3758
+ processSegmentAgainstRoute(injector, routes, route, rawSegment, segments, outlet, allowRedirects) {
3759
+ if (!isImmediateMatch(route, rawSegment, segments, outlet))
3760
+ return noMatch$1(rawSegment);
3761
+ if (route.redirectTo === undefined) {
3762
+ return this.matchSegmentAgainstRoute(injector, rawSegment, route, segments, outlet, allowRedirects);
3763
+ }
3764
+ if (allowRedirects && this.allowRedirects) {
3765
+ return this.expandSegmentAgainstRouteUsingRedirect(injector, rawSegment, routes, route, segments, outlet);
3766
+ }
3767
+ return noMatch$1(rawSegment);
3768
+ }
3769
+ expandSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet) {
3770
+ if (route.path === '**') {
3771
+ return this.expandWildCardWithParamsAgainstRouteUsingRedirect(injector, routes, route, outlet);
3772
+ }
3773
+ return this.expandRegularSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet);
3774
+ }
3775
+ expandWildCardWithParamsAgainstRouteUsingRedirect(injector, routes, route, outlet) {
3776
+ const newTree = this.applyRedirects.applyRedirectCommands([], route.redirectTo, {});
3777
+ if (route.redirectTo.startsWith('/')) {
3778
+ return absoluteRedirect(newTree);
3779
+ }
3780
+ return this.applyRedirects.lineralizeSegments(route, newTree)
3781
+ .pipe(mergeMap((newSegments) => {
3782
+ const group = new UrlSegmentGroup(newSegments, {});
3783
+ return this.processSegment(injector, routes, group, newSegments, outlet, false);
3784
+ }));
3785
+ }
3786
+ expandRegularSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet) {
3787
+ const { matched, consumedSegments, remainingSegments, positionalParamSegments } = match(segmentGroup, route, segments);
3788
+ if (!matched)
3789
+ return noMatch$1(segmentGroup);
3790
+ const newTree = this.applyRedirects.applyRedirectCommands(consumedSegments, route.redirectTo, positionalParamSegments);
3791
+ if (route.redirectTo.startsWith('/')) {
3792
+ return absoluteRedirect(newTree);
3793
+ }
3794
+ return this.applyRedirects.lineralizeSegments(route, newTree)
3795
+ .pipe(mergeMap((newSegments) => {
3796
+ return this.processSegment(injector, routes, segmentGroup, newSegments.concat(remainingSegments), outlet, false);
3797
+ }));
3798
+ }
3799
+ matchSegmentAgainstRoute(injector, rawSegment, route, segments, outlet, allowRedirects) {
3850
3800
  let matchResult;
3851
3801
  if (route.path === '**') {
3852
3802
  const params = segments.length > 0 ? last(segments).parameters : {};
@@ -3856,6 +3806,11 @@ class Recognizer {
3856
3806
  consumedSegments: [],
3857
3807
  remainingSegments: [],
3858
3808
  });
3809
+ // Prior versions of the route matching algorithm would stop matching at the wildcard route.
3810
+ // We should investigate a better strategy for any existing children. Otherwise, these
3811
+ // child segments are silently dropped from the navigation.
3812
+ // https://github.com/angular/angular/issues/40089
3813
+ rawSegment.children = {};
3859
3814
  }
3860
3815
  else {
3861
3816
  matchResult =
@@ -3870,47 +3825,67 @@ class Recognizer {
3870
3825
  }
3871
3826
  return matchResult.pipe(switchMap((result) => {
3872
3827
  if (result === null) {
3873
- return of(null);
3828
+ return noMatch$1(rawSegment);
3874
3829
  }
3875
- const { snapshot, consumedSegments, remainingSegments } = result;
3876
3830
  // If the route has an injector created from providers, we should start using that.
3877
3831
  injector = route._injector ?? injector;
3878
- const childInjector = route._loadedInjector ?? injector;
3879
- const childConfig = getChildConfig(route);
3880
- const { segmentGroup, slicedSegments } = split(rawSegment, consumedSegments, remainingSegments,
3881
- // Filter out routes with redirectTo because we are trying to create activated route
3882
- // snapshots and don't handle redirects here. That should have been done in
3883
- // `applyRedirects`.
3884
- childConfig.filter(c => c.redirectTo === undefined));
3885
- if (slicedSegments.length === 0 && segmentGroup.hasChildren()) {
3886
- return this.processChildren(childInjector, childConfig, segmentGroup).pipe(map(children => {
3887
- if (children === null) {
3888
- return null;
3889
- }
3832
+ return this.getChildConfig(injector, route, segments)
3833
+ .pipe(switchMap(({ routes: childConfig }) => {
3834
+ const childInjector = route._loadedInjector ?? injector;
3835
+ const { snapshot, consumedSegments, remainingSegments } = result;
3836
+ const { segmentGroup, slicedSegments } = split(rawSegment, consumedSegments, remainingSegments, childConfig);
3837
+ if (slicedSegments.length === 0 && segmentGroup.hasChildren()) {
3838
+ return this.processChildren(childInjector, childConfig, segmentGroup)
3839
+ .pipe(map(children => {
3840
+ if (children === null) {
3841
+ return null;
3842
+ }
3843
+ return [new TreeNode(snapshot, children)];
3844
+ }));
3845
+ }
3846
+ if (childConfig.length === 0 && slicedSegments.length === 0) {
3847
+ return of([new TreeNode(snapshot, [])]);
3848
+ }
3849
+ const matchedOnOutlet = getOutlet(route) === outlet;
3850
+ // If we matched a config due to empty path match on a different outlet, we need to
3851
+ // continue passing the current outlet for the segment rather than switch to PRIMARY.
3852
+ // Note that we switch to primary when we have a match because outlet configs look like
3853
+ // this: {path: 'a', outlet: 'a', children: [
3854
+ // {path: 'b', component: B},
3855
+ // {path: 'c', component: C},
3856
+ // ]}
3857
+ // Notice that the children of the named outlet are configured with the primary outlet
3858
+ return this
3859
+ .processSegment(childInjector, childConfig, segmentGroup, slicedSegments, matchedOnOutlet ? PRIMARY_OUTLET : outlet, true)
3860
+ .pipe(map(children => {
3890
3861
  return [new TreeNode(snapshot, children)];
3891
3862
  }));
3863
+ }));
3864
+ }));
3865
+ }
3866
+ getChildConfig(injector, route, segments) {
3867
+ if (route.children) {
3868
+ // The children belong to the same module
3869
+ return of({ routes: route.children, injector });
3870
+ }
3871
+ if (route.loadChildren) {
3872
+ // lazy children belong to the loaded module
3873
+ if (route._loadedRoutes !== undefined) {
3874
+ return of({ routes: route._loadedRoutes, injector: route._loadedInjector });
3892
3875
  }
3893
- if (childConfig.length === 0 && slicedSegments.length === 0) {
3894
- return of([new TreeNode(snapshot, [])]);
3895
- }
3896
- const matchedOnOutlet = getOutlet(route) === outlet;
3897
- // If we matched a config due to empty path match on a different outlet, we need to
3898
- // continue passing the current outlet for the segment rather than switch to PRIMARY.
3899
- // Note that we switch to primary when we have a match because outlet configs look like
3900
- // this: {path: 'a', outlet: 'a', children: [
3901
- // {path: 'b', component: B},
3902
- // {path: 'c', component: C},
3903
- // ]}
3904
- // Notice that the children of the named outlet are configured with the primary outlet
3905
- return this
3906
- .processSegment(childInjector, childConfig, segmentGroup, slicedSegments, matchedOnOutlet ? PRIMARY_OUTLET : outlet)
3907
- .pipe(map(children => {
3908
- if (children === null) {
3909
- return null;
3876
+ return runCanLoadGuards(injector, route, segments, this.urlSerializer)
3877
+ .pipe(mergeMap((shouldLoadResult) => {
3878
+ if (shouldLoadResult) {
3879
+ return this.configLoader.loadChildren(injector, route)
3880
+ .pipe(tap((cfg) => {
3881
+ route._loadedRoutes = cfg.routes;
3882
+ route._loadedInjector = cfg.injector;
3883
+ }));
3910
3884
  }
3911
- return [new TreeNode(snapshot, children)];
3885
+ return canLoadFails(route);
3912
3886
  }));
3913
- }));
3887
+ }
3888
+ return of({ routes: [], injector });
3914
3889
  }
3915
3890
  }
3916
3891
  function sortActivatedRouteSnapshots(nodes) {
@@ -3922,18 +3897,9 @@ function sortActivatedRouteSnapshots(nodes) {
3922
3897
  return a.value.outlet.localeCompare(b.value.outlet);
3923
3898
  });
3924
3899
  }
3925
- function getChildConfig(route) {
3926
- if (route.children) {
3927
- return route.children;
3928
- }
3929
- if (route.loadChildren) {
3930
- return route._loadedRoutes;
3931
- }
3932
- return [];
3933
- }
3934
3900
  function hasEmptyPathConfig(node) {
3935
3901
  const config = node.value.routeConfig;
3936
- return config && config.path === '' && config.redirectTo === undefined;
3902
+ return config && config.path === '';
3937
3903
  }
3938
3904
  /**
3939
3905
  * Finds `TreeNode`s with matching empty path route configs and merges them into `TreeNode` with
@@ -3975,7 +3941,8 @@ function checkOutletNameUniqueness(nodes) {
3975
3941
  if (routeWithSameOutletName) {
3976
3942
  const p = routeWithSameOutletName.url.map(s => s.toString()).join('/');
3977
3943
  const c = n.value.url.map(s => s.toString()).join('/');
3978
- throw new ɵRuntimeError(4006 /* RuntimeErrorCode.TWO_SEGMENTS_WITH_SAME_OUTLET */, NG_DEV_MODE$6 && `Two segments cannot have the same outlet name: '${p}' and '${c}'.`);
3944
+ throw new ɵRuntimeError(4006 /* RuntimeErrorCode.TWO_SEGMENTS_WITH_SAME_OUTLET */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
3945
+ `Two segments cannot have the same outlet name: '${p}' and '${c}'.`);
3979
3946
  }
3980
3947
  names[n.value.outlet] = n.value;
3981
3948
  });
@@ -3987,9 +3954,11 @@ function getResolve(route) {
3987
3954
  return route.resolve || {};
3988
3955
  }
3989
3956
 
3990
- function recognize(injector, rootComponentType, config, serializer, paramsInheritanceStrategy) {
3991
- return mergeMap(t => recognize$1(injector, rootComponentType, config, t.urlAfterRedirects, serializer.serialize(t.urlAfterRedirects), serializer, paramsInheritanceStrategy)
3992
- .pipe(map(targetSnapshot => ({ ...t, targetSnapshot }))));
3957
+ function recognize(injector, configLoader, rootComponentType, config, serializer, paramsInheritanceStrategy) {
3958
+ return mergeMap(t => recognize$1(injector, configLoader, rootComponentType, config, t.extractedUrl, serializer, paramsInheritanceStrategy)
3959
+ .pipe(map(({ state: targetSnapshot, tree: urlAfterRedirects }) => {
3960
+ return { ...t, targetSnapshot, urlAfterRedirects };
3961
+ })));
3993
3962
  }
3994
3963
 
3995
3964
  function resolveData(paramsInheritanceStrategy, injector) {
@@ -4060,7 +4029,6 @@ function switchTap(next) {
4060
4029
  });
4061
4030
  }
4062
4031
 
4063
- const NG_DEV_MODE$5 = typeof ngDevMode === 'undefined' || !!ngDevMode;
4064
4032
  /**
4065
4033
  * The [DI token](guide/glossary/#di-token) for a router configuration.
4066
4034
  *
@@ -4093,7 +4061,8 @@ class RouterConfigLoader {
4093
4061
  if (this.onLoadEndListener) {
4094
4062
  this.onLoadEndListener(route);
4095
4063
  }
4096
- NG_DEV_MODE$5 && assertStandalone(route.path ?? '', component);
4064
+ (typeof ngDevMode === 'undefined' || ngDevMode) &&
4065
+ assertStandalone(route.path ?? '', component);
4097
4066
  route._loadedComponent = component;
4098
4067
  }), finalize(() => {
4099
4068
  this.componentLoaders.delete(route);
@@ -4136,7 +4105,8 @@ class RouterConfigLoader {
4136
4105
  rawRoutes = injector.get(ROUTES, [], InjectFlags.Self | InjectFlags.Optional).flat();
4137
4106
  }
4138
4107
  const routes = rawRoutes.map(standardizeConfig);
4139
- NG_DEV_MODE$5 && validateConfig(routes, route.path, requireStandaloneComponents);
4108
+ (typeof ngDevMode === 'undefined' || ngDevMode) &&
4109
+ validateConfig(routes, route.path, requireStandaloneComponents);
4140
4110
  return { routes, injector };
4141
4111
  }), finalize(() => {
4142
4112
  this.childrenLoaders.delete(route);
@@ -4158,10 +4128,10 @@ class RouterConfigLoader {
4158
4128
  }
4159
4129
  }));
4160
4130
  }
4131
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterConfigLoader, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4132
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterConfigLoader, providedIn: 'root' }); }
4161
4133
  }
4162
- RouterConfigLoader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterConfigLoader, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4163
- RouterConfigLoader.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterConfigLoader, providedIn: 'root' });
4164
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterConfigLoader, decorators: [{
4134
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterConfigLoader, decorators: [{
4165
4135
  type: Injectable,
4166
4136
  args: [{ providedIn: 'root' }]
4167
4137
  }] });
@@ -4177,7 +4147,6 @@ function maybeUnwrapDefaultExport(input) {
4177
4147
  return isWrappedDefaultExport(input) ? input['default'] : input;
4178
4148
  }
4179
4149
 
4180
- const NG_DEV_MODE$4 = typeof ngDevMode === 'undefined' || !!ngDevMode;
4181
4150
  class NavigationTransitions {
4182
4151
  get hasRequestedNavigation() {
4183
4152
  return this.navigationId !== 0;
@@ -4190,6 +4159,7 @@ class NavigationTransitions {
4190
4159
  this.environmentInjector = inject(EnvironmentInjector);
4191
4160
  this.urlSerializer = inject(UrlSerializer);
4192
4161
  this.rootContexts = inject(ChildrenOutletContexts);
4162
+ this.inputBindingEnabled = inject(INPUT_BINDER, { optional: true }) !== null;
4193
4163
  this.navigationId = 0;
4194
4164
  /**
4195
4165
  * Hook that enables you to pause navigation after the preactivation phase.
@@ -4267,7 +4237,7 @@ class NavigationTransitions {
4267
4237
  browserUrlTree !== router.currentUrlTree.toString();
4268
4238
  const onSameUrlNavigation = t.extras.onSameUrlNavigation ?? router.onSameUrlNavigation;
4269
4239
  if (!urlTransition && onSameUrlNavigation !== 'reload') {
4270
- const reason = NG_DEV_MODE$4 ?
4240
+ const reason = (typeof ngDevMode === 'undefined' || ngDevMode) ?
4271
4241
  `Navigation to ${t.rawUrl} was ignored because it is the same as the current Router URL.` :
4272
4242
  '';
4273
4243
  this.events.next(new NavigationSkipped(t.id, router.serializeUrl(overallTransitionState.rawUrl), reason, 0 /* NavigationSkippedCode.IgnoredSameUrlNavigation */));
@@ -4293,22 +4263,16 @@ class NavigationTransitions {
4293
4263
  // navigation to always be async
4294
4264
  return Promise.resolve(t);
4295
4265
  }),
4296
- // ApplyRedirects
4297
- applyRedirects(this.environmentInjector, this.configLoader, this.urlSerializer, router.config),
4298
- // Update the currentNavigation
4299
- // `urlAfterRedirects` is guaranteed to be set after this point
4266
+ // Recognize
4267
+ recognize(this.environmentInjector, this.configLoader, this.rootComponentType, router.config, this.urlSerializer, router.paramsInheritanceStrategy),
4268
+ // Update URL if in `eager` update mode
4300
4269
  tap(t => {
4270
+ overallTransitionState.targetSnapshot = t.targetSnapshot;
4271
+ overallTransitionState.urlAfterRedirects = t.urlAfterRedirects;
4301
4272
  this.currentNavigation = {
4302
4273
  ...this.currentNavigation,
4303
4274
  finalUrl: t.urlAfterRedirects
4304
4275
  };
4305
- overallTransitionState.urlAfterRedirects = t.urlAfterRedirects;
4306
- }),
4307
- // Recognize
4308
- recognize(this.environmentInjector, this.rootComponentType, router.config, this.urlSerializer, router.paramsInheritanceStrategy),
4309
- // Update URL if in `eager` update mode
4310
- tap(t => {
4311
- overallTransitionState.targetSnapshot = t.targetSnapshot;
4312
4276
  if (router.urlUpdateStrategy === 'eager') {
4313
4277
  if (!t.extras.skipLocationChange) {
4314
4278
  const rawUrl = router.urlHandlingStrategy.merge(t.urlAfterRedirects, t.rawUrl);
@@ -4344,7 +4308,7 @@ class NavigationTransitions {
4344
4308
  * current "settled" URL. This way the next navigation will be coming
4345
4309
  * from the current URL in the browser.
4346
4310
  */
4347
- const reason = NG_DEV_MODE$4 ?
4311
+ const reason = (typeof ngDevMode === 'undefined' || ngDevMode) ?
4348
4312
  `Navigation was ignored because the UrlHandlingStrategy` +
4349
4313
  ` indicated neither the current URL ${router.rawUrlTree} nor target URL ${t.rawUrl} should be processed.` :
4350
4314
  '';
@@ -4392,7 +4356,7 @@ class NavigationTransitions {
4392
4356
  complete: () => {
4393
4357
  if (!dataResolved) {
4394
4358
  router.restoreHistory(t);
4395
- this.cancelNavigationTransition(t, NG_DEV_MODE$4 ?
4359
+ this.cancelNavigationTransition(t, (typeof ngDevMode === 'undefined' || ngDevMode) ?
4396
4360
  `At least one route resolver didn't emit any value.` :
4397
4361
  '', 2 /* NavigationCancellationCode.NoDataFromResolver */);
4398
4362
  }
@@ -4445,7 +4409,11 @@ class NavigationTransitions {
4445
4409
  }
4446
4410
  router.browserUrlTree = t.urlAfterRedirects;
4447
4411
  }
4448
- }), activateRoutes(this.rootContexts, router.routeReuseStrategy, (evt) => this.events.next(evt)), tap({
4412
+ }), activateRoutes(this.rootContexts, router.routeReuseStrategy, (evt) => this.events.next(evt), this.inputBindingEnabled),
4413
+ // Ensure that if some observable used to drive the transition doesn't
4414
+ // complete, the navigation still finalizes This should never happen, but
4415
+ // this is done as a safety measure to avoid surfacing this error (#49567).
4416
+ take(1), tap({
4449
4417
  next: (t) => {
4450
4418
  completed = true;
4451
4419
  this.lastSuccessfulNavigation = this.currentNavigation;
@@ -4465,7 +4433,7 @@ class NavigationTransitions {
4465
4433
  * catch-all to make sure the NavigationCancel event is fired when a
4466
4434
  * navigation gets cancelled but not caught by other means. */
4467
4435
  if (!completed && !errored) {
4468
- const cancelationReason = NG_DEV_MODE$4 ?
4436
+ const cancelationReason = (typeof ngDevMode === 'undefined' || ngDevMode) ?
4469
4437
  `Navigation ID ${overallTransitionState
4470
4438
  .id} is not equal to the current navigation id ${this.navigationId}` :
4471
4439
  '';
@@ -4539,10 +4507,10 @@ class NavigationTransitions {
4539
4507
  this.events.next(navCancel);
4540
4508
  t.resolve(false);
4541
4509
  }
4510
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: NavigationTransitions, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4511
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: NavigationTransitions, providedIn: 'root' }); }
4542
4512
  }
4543
- NavigationTransitions.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: NavigationTransitions, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4544
- NavigationTransitions.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: NavigationTransitions, providedIn: 'root' });
4545
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: NavigationTransitions, decorators: [{
4513
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: NavigationTransitions, decorators: [{
4546
4514
  type: Injectable,
4547
4515
  args: [{ providedIn: 'root' }]
4548
4516
  }], ctorParameters: function () { return []; } });
@@ -4593,10 +4561,10 @@ class TitleStrategy {
4593
4561
  getResolvedTitleForRoute(snapshot) {
4594
4562
  return snapshot.data[RouteTitleKey];
4595
4563
  }
4564
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: TitleStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4565
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: TitleStrategy, providedIn: 'root', useFactory: () => inject(DefaultTitleStrategy) }); }
4596
4566
  }
4597
- TitleStrategy.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: TitleStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4598
- TitleStrategy.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: TitleStrategy, providedIn: 'root', useFactory: () => inject(DefaultTitleStrategy) });
4599
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: TitleStrategy, decorators: [{
4567
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: TitleStrategy, decorators: [{
4600
4568
  type: Injectable,
4601
4569
  args: [{ providedIn: 'root', useFactory: () => inject(DefaultTitleStrategy) }]
4602
4570
  }] });
@@ -4619,10 +4587,10 @@ class DefaultTitleStrategy extends TitleStrategy {
4619
4587
  this.title.setTitle(title);
4620
4588
  }
4621
4589
  }
4590
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: DefaultTitleStrategy, deps: [{ token: i1.Title }], target: i0.ɵɵFactoryTarget.Injectable }); }
4591
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: DefaultTitleStrategy, providedIn: 'root' }); }
4622
4592
  }
4623
- DefaultTitleStrategy.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: DefaultTitleStrategy, deps: [{ token: i1.Title }], target: i0.ɵɵFactoryTarget.Injectable });
4624
- DefaultTitleStrategy.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: DefaultTitleStrategy, providedIn: 'root' });
4625
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: DefaultTitleStrategy, decorators: [{
4593
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: DefaultTitleStrategy, decorators: [{
4626
4594
  type: Injectable,
4627
4595
  args: [{ providedIn: 'root' }]
4628
4596
  }], ctorParameters: function () { return [{ type: i1.Title }]; } });
@@ -4635,10 +4603,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4",
4635
4603
  * @publicApi
4636
4604
  */
4637
4605
  class RouteReuseStrategy {
4606
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouteReuseStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4607
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouteReuseStrategy, providedIn: 'root', useFactory: () => inject(DefaultRouteReuseStrategy) }); }
4638
4608
  }
4639
- RouteReuseStrategy.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouteReuseStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4640
- RouteReuseStrategy.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouteReuseStrategy, providedIn: 'root', useFactory: () => inject(DefaultRouteReuseStrategy) });
4641
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouteReuseStrategy, decorators: [{
4609
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouteReuseStrategy, decorators: [{
4642
4610
  type: Injectable,
4643
4611
  args: [{ providedIn: 'root', useFactory: () => inject(DefaultRouteReuseStrategy) }]
4644
4612
  }] });
@@ -4689,21 +4657,20 @@ class BaseRouteReuseStrategy {
4689
4657
  }
4690
4658
  }
4691
4659
  class DefaultRouteReuseStrategy extends BaseRouteReuseStrategy {
4660
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: DefaultRouteReuseStrategy, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
4661
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: DefaultRouteReuseStrategy, providedIn: 'root' }); }
4692
4662
  }
4693
- DefaultRouteReuseStrategy.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: DefaultRouteReuseStrategy, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
4694
- DefaultRouteReuseStrategy.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: DefaultRouteReuseStrategy, providedIn: 'root' });
4695
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: DefaultRouteReuseStrategy, decorators: [{
4663
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: DefaultRouteReuseStrategy, decorators: [{
4696
4664
  type: Injectable,
4697
4665
  args: [{ providedIn: 'root' }]
4698
4666
  }] });
4699
4667
 
4700
- const NG_DEV_MODE$3 = typeof ngDevMode === 'undefined' || !!ngDevMode;
4701
4668
  /**
4702
4669
  * A [DI token](guide/glossary/#di-token) for the router service.
4703
4670
  *
4704
4671
  * @publicApi
4705
4672
  */
4706
- const ROUTER_CONFIGURATION = new InjectionToken(NG_DEV_MODE$3 ? 'router config' : '', {
4673
+ const ROUTER_CONFIGURATION = new InjectionToken((typeof ngDevMode === 'undefined' || ngDevMode) ? 'router config' : '', {
4707
4674
  providedIn: 'root',
4708
4675
  factory: () => ({}),
4709
4676
  });
@@ -4716,10 +4683,10 @@ const ROUTER_CONFIGURATION = new InjectionToken(NG_DEV_MODE$3 ? 'router config'
4716
4683
  * @publicApi
4717
4684
  */
4718
4685
  class UrlHandlingStrategy {
4686
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: UrlHandlingStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4687
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: UrlHandlingStrategy, providedIn: 'root', useFactory: () => inject(DefaultUrlHandlingStrategy) }); }
4719
4688
  }
4720
- UrlHandlingStrategy.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: UrlHandlingStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4721
- UrlHandlingStrategy.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: UrlHandlingStrategy, providedIn: 'root', useFactory: () => inject(DefaultUrlHandlingStrategy) });
4722
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: UrlHandlingStrategy, decorators: [{
4689
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: UrlHandlingStrategy, decorators: [{
4723
4690
  type: Injectable,
4724
4691
  args: [{ providedIn: 'root', useFactory: () => inject(DefaultUrlHandlingStrategy) }]
4725
4692
  }] });
@@ -4736,15 +4703,47 @@ class DefaultUrlHandlingStrategy {
4736
4703
  merge(newUrlPart, wholeUrl) {
4737
4704
  return newUrlPart;
4738
4705
  }
4706
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: DefaultUrlHandlingStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4707
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: DefaultUrlHandlingStrategy, providedIn: 'root' }); }
4739
4708
  }
4740
- DefaultUrlHandlingStrategy.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: DefaultUrlHandlingStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4741
- DefaultUrlHandlingStrategy.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: DefaultUrlHandlingStrategy, providedIn: 'root' });
4742
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: DefaultUrlHandlingStrategy, decorators: [{
4709
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: DefaultUrlHandlingStrategy, decorators: [{
4743
4710
  type: Injectable,
4744
4711
  args: [{ providedIn: 'root' }]
4745
4712
  }] });
4746
4713
 
4747
- const NG_DEV_MODE$2 = typeof ngDevMode === 'undefined' || !!ngDevMode;
4714
+ var NavigationResult;
4715
+ (function (NavigationResult) {
4716
+ NavigationResult[NavigationResult["COMPLETE"] = 0] = "COMPLETE";
4717
+ NavigationResult[NavigationResult["FAILED"] = 1] = "FAILED";
4718
+ NavigationResult[NavigationResult["REDIRECTING"] = 2] = "REDIRECTING";
4719
+ })(NavigationResult || (NavigationResult = {}));
4720
+ /**
4721
+ * Performs the given action once the router finishes its next/current navigation.
4722
+ *
4723
+ * The navigation is considered complete under the following conditions:
4724
+ * - `NavigationCancel` event emits and the code is not `NavigationCancellationCode.Redirect` or
4725
+ * `NavigationCancellationCode.SupersededByNewNavigation`. In these cases, the
4726
+ * redirecting/superseding navigation must finish.
4727
+ * - `NavigationError`, `NavigationEnd`, or `NavigationSkipped` event emits
4728
+ */
4729
+ function afterNextNavigation(router, action) {
4730
+ router.events
4731
+ .pipe(filter((e) => e instanceof NavigationEnd || e instanceof NavigationCancel ||
4732
+ e instanceof NavigationError || e instanceof NavigationSkipped), map(e => {
4733
+ if (e instanceof NavigationEnd || e instanceof NavigationSkipped) {
4734
+ return NavigationResult.COMPLETE;
4735
+ }
4736
+ const redirecting = e instanceof NavigationCancel ?
4737
+ (e.code === 0 /* NavigationCancellationCode.Redirect */ ||
4738
+ e.code === 1 /* NavigationCancellationCode.SupersededByNewNavigation */) :
4739
+ false;
4740
+ return redirecting ? NavigationResult.REDIRECTING : NavigationResult.FAILED;
4741
+ }), filter((result) => result !== NavigationResult.REDIRECTING), take(1))
4742
+ .subscribe(() => {
4743
+ action();
4744
+ });
4745
+ }
4746
+
4748
4747
  function defaultErrorHandler(error) {
4749
4748
  throw error;
4750
4749
  }
@@ -4821,6 +4820,7 @@ class Router {
4821
4820
  this.console = inject(ɵConsole);
4822
4821
  this.isNgZoneEnabled = false;
4823
4822
  this.options = inject(ROUTER_CONFIGURATION, { optional: true }) || {};
4823
+ this.pendingTasks = inject(ɵInitialRenderPendingTasks);
4824
4824
  /**
4825
4825
  * A handler for navigation errors in this NgModule.
4826
4826
  *
@@ -4937,6 +4937,13 @@ class Router {
4937
4937
  this.navigationTransitions = inject(NavigationTransitions);
4938
4938
  this.urlSerializer = inject(UrlSerializer);
4939
4939
  this.location = inject(Location);
4940
+ /**
4941
+ * Indicates whether the the application has opted in to binding Router data to component inputs.
4942
+ *
4943
+ * This option is enabled by the `withComponentInputBinding` feature of `provideRouter` or
4944
+ * `bindToComponentInputs` in the `ExtraOptions` of `RouterModule.forRoot`.
4945
+ */
4946
+ this.componentInputBindingEnabled = !!inject(INPUT_BINDER, { optional: true });
4940
4947
  this.isNgZoneEnabled = inject(NgZone) instanceof NgZone && NgZone.isInAngularZone();
4941
4948
  this.resetConfig(this.config);
4942
4949
  this.currentUrlTree = new UrlTree();
@@ -5054,7 +5061,7 @@ class Router {
5054
5061
  * ```
5055
5062
  */
5056
5063
  resetConfig(config) {
5057
- NG_DEV_MODE$2 && validateConfig(config);
5064
+ (typeof ngDevMode === 'undefined' || ngDevMode) && validateConfig(config);
5058
5065
  this.config = config.map(standardizeConfig);
5059
5066
  this.navigated = false;
5060
5067
  this.lastSuccessfulId = -1;
@@ -5189,13 +5196,10 @@ class Router {
5189
5196
  navigateByUrl(url, extras = {
5190
5197
  skipLocationChange: false
5191
5198
  }) {
5192
- if (NG_DEV_MODE$2) {
5199
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
5193
5200
  if (this.isNgZoneEnabled && !NgZone.isInAngularZone()) {
5194
5201
  this.console.warn(`Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'?`);
5195
5202
  }
5196
- if (url instanceof UrlTree && url._warnIfUsedForNavigation) {
5197
- this.console.warn(url._warnIfUsedForNavigation);
5198
- }
5199
5203
  }
5200
5204
  const urlTree = isUrlTree(url) ? url : this.parseUrl(url);
5201
5205
  const mergedTree = this.urlHandlingStrategy.merge(urlTree, this.rawUrlTree);
@@ -5318,6 +5322,13 @@ class Router {
5318
5322
  // This is unused when `canceledNavigationResolution` is not computed.
5319
5323
  targetPageId = 0;
5320
5324
  }
5325
+ // Indicate that the navigation is happening.
5326
+ const taskId = this.pendingTasks.add();
5327
+ afterNextNavigation(this, () => {
5328
+ // Remove pending task in a microtask to allow for cancelled
5329
+ // initial navigations and redirects within the same task.
5330
+ Promise.resolve().then(() => this.pendingTasks.remove(taskId));
5331
+ });
5321
5332
  this.navigationTransitions.handleNavigationRequest({
5322
5333
  targetPageId,
5323
5334
  source,
@@ -5416,10 +5427,10 @@ class Router {
5416
5427
  }
5417
5428
  return { navigationId };
5418
5429
  }
5430
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: Router, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
5431
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: Router, providedIn: 'root' }); }
5419
5432
  }
5420
- Router.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: Router, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
5421
- Router.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: Router, providedIn: 'root' });
5422
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: Router, decorators: [{
5433
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: Router, decorators: [{
5423
5434
  type: Injectable,
5424
5435
  args: [{ providedIn: 'root' }]
5425
5436
  }], ctorParameters: function () { return []; } });
@@ -5427,7 +5438,8 @@ function validateCommands(commands) {
5427
5438
  for (let i = 0; i < commands.length; i++) {
5428
5439
  const cmd = commands[i];
5429
5440
  if (cmd == null) {
5430
- throw new ɵRuntimeError(4008 /* RuntimeErrorCode.NULLISH_COMMAND */, NG_DEV_MODE$2 && `The requested path contains ${cmd} segment at index ${i}`);
5441
+ throw new ɵRuntimeError(4008 /* RuntimeErrorCode.NULLISH_COMMAND */, (typeof ngDevMode === 'undefined' || ngDevMode) &&
5442
+ `The requested path contains ${cmd} segment at index ${i}`);
5431
5443
  }
5432
5444
  }
5433
5445
  }
@@ -5704,10 +5716,10 @@ class RouterLink {
5704
5716
  preserveFragment: this.preserveFragment,
5705
5717
  });
5706
5718
  }
5719
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterLink, deps: [{ token: Router }, { token: ActivatedRoute }, { token: 'tabindex', attribute: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i3.LocationStrategy }], target: i0.ɵɵFactoryTarget.Directive }); }
5720
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0-next.6", type: RouterLink, isStandalone: true, selector: "[routerLink]", inputs: { target: "target", queryParams: "queryParams", fragment: "fragment", queryParamsHandling: "queryParamsHandling", state: "state", relativeTo: "relativeTo", preserveFragment: "preserveFragment", skipLocationChange: "skipLocationChange", replaceUrl: "replaceUrl", routerLink: "routerLink" }, host: { listeners: { "click": "onClick($event.button,$event.ctrlKey,$event.shiftKey,$event.altKey,$event.metaKey)" }, properties: { "attr.target": "this.target" } }, usesOnChanges: true, ngImport: i0 }); }
5707
5721
  }
5708
- RouterLink.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterLink, deps: [{ token: Router }, { token: ActivatedRoute }, { token: 'tabindex', attribute: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i3.LocationStrategy }], target: i0.ɵɵFactoryTarget.Directive });
5709
- RouterLink.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0-next.4", type: RouterLink, isStandalone: true, selector: "[routerLink]", inputs: { target: "target", queryParams: "queryParams", fragment: "fragment", queryParamsHandling: "queryParamsHandling", state: "state", relativeTo: "relativeTo", preserveFragment: "preserveFragment", skipLocationChange: "skipLocationChange", replaceUrl: "replaceUrl", routerLink: "routerLink" }, host: { listeners: { "click": "onClick($event.button,$event.ctrlKey,$event.shiftKey,$event.altKey,$event.metaKey)" }, properties: { "attr.target": "this.target" } }, usesOnChanges: true, ngImport: i0 });
5710
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterLink, decorators: [{
5722
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterLink, decorators: [{
5711
5723
  type: Directive,
5712
5724
  args: [{
5713
5725
  selector: '[routerLink]',
@@ -5927,10 +5939,10 @@ class RouterLinkActive {
5927
5939
  const isActiveCheckFn = this.isLinkActive(this.router);
5928
5940
  return this.link && isActiveCheckFn(this.link) || this.links.some(isActiveCheckFn);
5929
5941
  }
5942
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterLinkActive, deps: [{ token: Router }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: RouterLink, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
5943
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0-next.6", type: RouterLinkActive, isStandalone: true, selector: "[routerLinkActive]", inputs: { routerLinkActiveOptions: "routerLinkActiveOptions", ariaCurrentWhenActive: "ariaCurrentWhenActive", routerLinkActive: "routerLinkActive" }, outputs: { isActiveChange: "isActiveChange" }, queries: [{ propertyName: "links", predicate: RouterLink, descendants: true }], exportAs: ["routerLinkActive"], usesOnChanges: true, ngImport: i0 }); }
5930
5944
  }
5931
- RouterLinkActive.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterLinkActive, deps: [{ token: Router }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: RouterLink, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
5932
- RouterLinkActive.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0-next.4", type: RouterLinkActive, isStandalone: true, selector: "[routerLinkActive]", inputs: { routerLinkActiveOptions: "routerLinkActiveOptions", ariaCurrentWhenActive: "ariaCurrentWhenActive", routerLinkActive: "routerLinkActive" }, outputs: { isActiveChange: "isActiveChange" }, queries: [{ propertyName: "links", predicate: RouterLink, descendants: true }], exportAs: ["routerLinkActive"], usesOnChanges: true, ngImport: i0 });
5933
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterLinkActive, decorators: [{
5945
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterLinkActive, decorators: [{
5934
5946
  type: Directive,
5935
5947
  args: [{
5936
5948
  selector: '[routerLinkActive]',
@@ -5982,10 +5994,10 @@ class PreloadAllModules {
5982
5994
  preload(route, fn) {
5983
5995
  return fn().pipe(catchError(() => of(null)));
5984
5996
  }
5997
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: PreloadAllModules, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
5998
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: PreloadAllModules, providedIn: 'root' }); }
5985
5999
  }
5986
- PreloadAllModules.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: PreloadAllModules, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
5987
- PreloadAllModules.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: PreloadAllModules, providedIn: 'root' });
5988
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: PreloadAllModules, decorators: [{
6000
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: PreloadAllModules, decorators: [{
5989
6001
  type: Injectable,
5990
6002
  args: [{ providedIn: 'root' }]
5991
6003
  }] });
@@ -6002,10 +6014,10 @@ class NoPreloading {
6002
6014
  preload(route, fn) {
6003
6015
  return of(null);
6004
6016
  }
6017
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: NoPreloading, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
6018
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: NoPreloading, providedIn: 'root' }); }
6005
6019
  }
6006
- NoPreloading.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: NoPreloading, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
6007
- NoPreloading.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: NoPreloading, providedIn: 'root' });
6008
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: NoPreloading, decorators: [{
6020
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: NoPreloading, decorators: [{
6009
6021
  type: Injectable,
6010
6022
  args: [{ providedIn: 'root' }]
6011
6023
  }] });
@@ -6064,7 +6076,7 @@ class RouterPreloader {
6064
6076
  (route.loadComponent && !route._loadedComponent)) {
6065
6077
  res.push(this.preloadConfig(injectorForCurrentRoute, route));
6066
6078
  }
6067
- else if (route.children || route._loadedRoutes) {
6079
+ if (route.children || route._loadedRoutes) {
6068
6080
  res.push(this.processRoutes(injectorForChildren, (route.children ?? route._loadedRoutes)));
6069
6081
  }
6070
6082
  }
@@ -6098,10 +6110,10 @@ class RouterPreloader {
6098
6110
  }
6099
6111
  });
6100
6112
  }
6113
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterPreloader, deps: [{ token: Router }, { token: i0.Compiler }, { token: i0.EnvironmentInjector }, { token: PreloadingStrategy }, { token: RouterConfigLoader }], target: i0.ɵɵFactoryTarget.Injectable }); }
6114
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterPreloader, providedIn: 'root' }); }
6101
6115
  }
6102
- RouterPreloader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterPreloader, deps: [{ token: Router }, { token: i0.Compiler }, { token: i0.EnvironmentInjector }, { token: PreloadingStrategy }, { token: RouterConfigLoader }], target: i0.ɵɵFactoryTarget.Injectable });
6103
- RouterPreloader.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterPreloader, providedIn: 'root' });
6104
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterPreloader, decorators: [{
6116
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterPreloader, decorators: [{
6105
6117
  type: Injectable,
6106
6118
  args: [{ providedIn: 'root' }]
6107
6119
  }], ctorParameters: function () { return [{ type: Router }, { type: i0.Compiler }, { type: i0.EnvironmentInjector }, { type: PreloadingStrategy }, { type: RouterConfigLoader }]; } });
@@ -6194,47 +6206,13 @@ class RouterScroller {
6194
6206
  this.routerEventsSubscription?.unsubscribe();
6195
6207
  this.scrollEventsSubscription?.unsubscribe();
6196
6208
  }
6209
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterScroller, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable }); }
6210
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterScroller }); }
6197
6211
  }
6198
- RouterScroller.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterScroller, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable });
6199
- RouterScroller.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterScroller });
6200
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterScroller, decorators: [{
6212
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterScroller, decorators: [{
6201
6213
  type: Injectable
6202
6214
  }], ctorParameters: function () { return [{ type: UrlSerializer }, { type: NavigationTransitions }, { type: i3.ViewportScroller }, { type: i0.NgZone }, { type: undefined }]; } });
6203
6215
 
6204
- var NavigationResult;
6205
- (function (NavigationResult) {
6206
- NavigationResult[NavigationResult["COMPLETE"] = 0] = "COMPLETE";
6207
- NavigationResult[NavigationResult["FAILED"] = 1] = "FAILED";
6208
- NavigationResult[NavigationResult["REDIRECTING"] = 2] = "REDIRECTING";
6209
- })(NavigationResult || (NavigationResult = {}));
6210
- /**
6211
- * Performs the given action once the router finishes its next/current navigation.
6212
- *
6213
- * The navigation is considered complete under the following conditions:
6214
- * - `NavigationCancel` event emits and the code is not `NavigationCancellationCode.Redirect` or
6215
- * `NavigationCancellationCode.SupersededByNewNavigation`. In these cases, the
6216
- * redirecting/superseding navigation must finish.
6217
- * - `NavigationError`, `NavigationEnd`, or `NavigationSkipped` event emits
6218
- */
6219
- function afterNextNavigation(router, action) {
6220
- router.events
6221
- .pipe(filter((e) => e instanceof NavigationEnd || e instanceof NavigationCancel ||
6222
- e instanceof NavigationError || e instanceof NavigationSkipped), map(e => {
6223
- if (e instanceof NavigationEnd || e instanceof NavigationSkipped) {
6224
- return NavigationResult.COMPLETE;
6225
- }
6226
- const redirecting = e instanceof NavigationCancel ?
6227
- (e.code === 0 /* NavigationCancellationCode.Redirect */ ||
6228
- e.code === 1 /* NavigationCancellationCode.SupersededByNewNavigation */) :
6229
- false;
6230
- return redirecting ? NavigationResult.REDIRECTING : NavigationResult.FAILED;
6231
- }), filter((result) => result !== NavigationResult.REDIRECTING), take(1))
6232
- .subscribe(() => {
6233
- action();
6234
- });
6235
- }
6236
-
6237
- const NG_DEV_MODE$1 = typeof ngDevMode === 'undefined' || ngDevMode;
6238
6216
  /**
6239
6217
  * Sets up providers necessary to enable `Router` functionality for the application.
6240
6218
  * Allows to configure a set of routes as well as extra features that should be enabled.
@@ -6274,7 +6252,9 @@ const NG_DEV_MODE$1 = typeof ngDevMode === 'undefined' || ngDevMode;
6274
6252
  function provideRouter(routes, ...features) {
6275
6253
  return makeEnvironmentProviders([
6276
6254
  { provide: ROUTES, multi: true, useValue: routes },
6277
- NG_DEV_MODE$1 ? { provide: ROUTER_IS_PROVIDED, useValue: true } : [],
6255
+ (typeof ngDevMode === 'undefined' || ngDevMode) ?
6256
+ { provide: ROUTER_IS_PROVIDED, useValue: true } :
6257
+ [],
6278
6258
  { provide: ActivatedRoute, useFactory: rootRoute, deps: [Router] },
6279
6259
  { provide: APP_BOOTSTRAP_LISTENER, multi: true, useFactory: getBootstrapListener },
6280
6260
  features.map(feature => feature.ɵproviders),
@@ -6326,7 +6306,7 @@ const routerIsProvidedDevModeCheck = {
6326
6306
  function provideRoutes(routes) {
6327
6307
  return [
6328
6308
  { provide: ROUTES, multi: true, useValue: routes },
6329
- NG_DEV_MODE$1 ? routerIsProvidedDevModeCheck : [],
6309
+ (typeof ngDevMode === 'undefined' || ngDevMode) ? routerIsProvidedDevModeCheck : [],
6330
6310
  ];
6331
6311
  }
6332
6312
  /**
@@ -6384,6 +6364,7 @@ function getBootstrapListener() {
6384
6364
  router.resetRootComponentType(ref.componentTypes[0]);
6385
6365
  if (!bootstrapDone.closed) {
6386
6366
  bootstrapDone.next();
6367
+ bootstrapDone.complete();
6387
6368
  bootstrapDone.unsubscribe();
6388
6369
  }
6389
6370
  };
@@ -6393,12 +6374,12 @@ function getBootstrapListener() {
6393
6374
  * `enabledBlocking`, the first navigation waits until bootstrapping is finished before continuing
6394
6375
  * to the activation phase.
6395
6376
  */
6396
- const BOOTSTRAP_DONE = new InjectionToken(NG_DEV_MODE$1 ? 'bootstrap done indicator' : '', {
6377
+ const BOOTSTRAP_DONE = new InjectionToken((typeof ngDevMode === 'undefined' || ngDevMode) ? 'bootstrap done indicator' : '', {
6397
6378
  factory: () => {
6398
6379
  return new Subject();
6399
6380
  }
6400
6381
  });
6401
- const INITIAL_NAVIGATION = new InjectionToken(NG_DEV_MODE$1 ? 'initial navigation' : '', { providedIn: 'root', factory: () => 1 /* InitialNavigation.EnabledNonBlocking */ });
6382
+ const INITIAL_NAVIGATION = new InjectionToken((typeof ngDevMode === 'undefined' || ngDevMode) ? 'initial navigation' : '', { providedIn: 'root', factory: () => 1 /* InitialNavigation.EnabledNonBlocking */ });
6402
6383
  /**
6403
6384
  * Configures initial navigation to start before the root component is created.
6404
6385
  *
@@ -6527,7 +6508,7 @@ function withDisabledInitialNavigation() {
6527
6508
  */
6528
6509
  function withDebugTracing() {
6529
6510
  let providers = [];
6530
- if (NG_DEV_MODE$1) {
6511
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
6531
6512
  providers = [{
6532
6513
  provide: ENVIRONMENT_INITIALIZER,
6533
6514
  multi: true,
@@ -6549,7 +6530,7 @@ function withDebugTracing() {
6549
6530
  }
6550
6531
  return routerFeature(1 /* RouterFeatureKind.DebugTracingFeature */, providers);
6551
6532
  }
6552
- const ROUTER_PRELOADER = new InjectionToken(NG_DEV_MODE$1 ? 'router preloader' : '');
6533
+ const ROUTER_PRELOADER = new InjectionToken((typeof ngDevMode === 'undefined' || ngDevMode) ? 'router preloader' : '');
6553
6534
  /**
6554
6535
  * Allows to configure a preloading strategy to use. The strategy is configured by providing a
6555
6536
  * reference to a class that implements a `PreloadingStrategy`.
@@ -6690,8 +6671,34 @@ function withNavigationErrorHandler(fn) {
6690
6671
  }];
6691
6672
  return routerFeature(7 /* RouterFeatureKind.NavigationErrorHandlerFeature */, providers);
6692
6673
  }
6674
+ /**
6675
+ * Enables binding information from the `Router` state directly to the inputs of the component in
6676
+ * `Route` configurations.
6677
+ *
6678
+ * @usageNotes
6679
+ *
6680
+ * Basic example of how you can enable the feature:
6681
+ * ```
6682
+ * const appRoutes: Routes = [];
6683
+ * bootstrapApplication(AppComponent,
6684
+ * {
6685
+ * providers: [
6686
+ * provideRouter(appRoutes, withComponentInputBinding())
6687
+ * ]
6688
+ * }
6689
+ * );
6690
+ * ```
6691
+ *
6692
+ * @returns A set of providers for use with `provideRouter`.
6693
+ */
6694
+ function withComponentInputBinding() {
6695
+ const providers = [
6696
+ RoutedComponentInputBinder,
6697
+ { provide: INPUT_BINDER, useExisting: RoutedComponentInputBinder },
6698
+ ];
6699
+ return routerFeature(8 /* RouterFeatureKind.ComponentInputBindingFeature */, providers);
6700
+ }
6693
6701
 
6694
- const NG_DEV_MODE = typeof ngDevMode === 'undefined' || ngDevMode;
6695
6702
  /**
6696
6703
  * The directives defined in the `RouterModule`.
6697
6704
  */
@@ -6699,7 +6706,8 @@ const ROUTER_DIRECTIVES = [RouterOutlet, RouterLink, RouterLinkActive, ɵEmptyOu
6699
6706
  /**
6700
6707
  * @docsNotRequired
6701
6708
  */
6702
- const ROUTER_FORROOT_GUARD = new InjectionToken(NG_DEV_MODE ? 'router duplicate forRoot guard' : 'ROUTER_FORROOT_GUARD');
6709
+ const ROUTER_FORROOT_GUARD = new InjectionToken((typeof ngDevMode === 'undefined' || ngDevMode) ? 'router duplicate forRoot guard' :
6710
+ 'ROUTER_FORROOT_GUARD');
6703
6711
  // TODO(atscott): All of these except `ActivatedRoute` are `providedIn: 'root'`. They are only kept
6704
6712
  // here to avoid a breaking change whereby the provider order matters based on where the
6705
6713
  // `RouterModule`/`RouterTestingModule` is imported. These can/should be removed as a "breaking"
@@ -6713,7 +6721,8 @@ const ROUTER_PROVIDERS = [
6713
6721
  RouterConfigLoader,
6714
6722
  // Only used to warn when `provideRoutes` is used without `RouterModule` or `provideRouter`. Can
6715
6723
  // be removed when `provideRoutes` is removed.
6716
- NG_DEV_MODE ? { provide: ROUTER_IS_PROVIDED, useValue: true } : [],
6724
+ (typeof ngDevMode === 'undefined' || ngDevMode) ? { provide: ROUTER_IS_PROVIDED, useValue: true } :
6725
+ [],
6717
6726
  ];
6718
6727
  function routerNgProbeToken() {
6719
6728
  return new NgProbeToken('Router', Router);
@@ -6764,7 +6773,9 @@ class RouterModule {
6764
6773
  ngModule: RouterModule,
6765
6774
  providers: [
6766
6775
  ROUTER_PROVIDERS,
6767
- NG_DEV_MODE ? (config?.enableTracing ? withDebugTracing().ɵproviders : []) : [],
6776
+ (typeof ngDevMode === 'undefined' || ngDevMode) ?
6777
+ (config?.enableTracing ? withDebugTracing().ɵproviders : []) :
6778
+ [],
6768
6779
  { provide: ROUTES, multi: true, useValue: routes },
6769
6780
  {
6770
6781
  provide: ROUTER_FORROOT_GUARD,
@@ -6777,6 +6788,7 @@ class RouterModule {
6777
6788
  config?.preloadingStrategy ? withPreloading(config.preloadingStrategy).ɵproviders : [],
6778
6789
  { provide: NgProbeToken, multi: true, useFactory: routerNgProbeToken },
6779
6790
  config?.initialNavigation ? provideInitialNavigation(config) : [],
6791
+ config?.bindToComponentInputs ? withComponentInputBinding().ɵproviders : [],
6780
6792
  provideRouterInitializer(),
6781
6793
  ],
6782
6794
  };
@@ -6803,11 +6815,11 @@ class RouterModule {
6803
6815
  providers: [{ provide: ROUTES, multi: true, useValue: routes }],
6804
6816
  };
6805
6817
  }
6818
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterModule, deps: [{ token: ROUTER_FORROOT_GUARD, optional: true }], target: i0.ɵɵFactoryTarget.NgModule }); }
6819
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterModule, imports: [RouterOutlet, RouterLink, RouterLinkActive, ɵEmptyOutletComponent], exports: [RouterOutlet, RouterLink, RouterLinkActive, ɵEmptyOutletComponent] }); }
6820
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterModule, imports: [ɵEmptyOutletComponent] }); }
6806
6821
  }
6807
- RouterModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterModule, deps: [{ token: ROUTER_FORROOT_GUARD, optional: true }], target: i0.ɵɵFactoryTarget.NgModule });
6808
- RouterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterModule, imports: [RouterOutlet, RouterLink, RouterLinkActive, ɵEmptyOutletComponent], exports: [RouterOutlet, RouterLink, RouterLinkActive, ɵEmptyOutletComponent] });
6809
- RouterModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterModule, imports: [ɵEmptyOutletComponent] });
6810
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.4", ngImport: i0, type: RouterModule, decorators: [{
6822
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0-next.6", ngImport: i0, type: RouterModule, decorators: [{
6811
6823
  type: NgModule,
6812
6824
  args: [{
6813
6825
  imports: ROUTER_DIRECTIVES,
@@ -6850,7 +6862,7 @@ function providePathLocationStrategy() {
6850
6862
  return { provide: LocationStrategy, useClass: PathLocationStrategy };
6851
6863
  }
6852
6864
  function provideForRootGuard(router) {
6853
- if (NG_DEV_MODE && router) {
6865
+ if ((typeof ngDevMode === 'undefined' || ngDevMode) && router) {
6854
6866
  throw new ɵRuntimeError(4007 /* RuntimeErrorCode.FOR_ROOT_CALLED_TWICE */, `The Router was provided more than once. This can happen if 'forRoot' is used outside of the root injector.` +
6855
6867
  ` Lazy loaded modules should use RouterModule.forChild() instead.`);
6856
6868
  }
@@ -6873,7 +6885,7 @@ function provideInitialNavigation(config) {
6873
6885
  *
6874
6886
  * @publicApi
6875
6887
  */
6876
- const ROUTER_INITIALIZER = new InjectionToken(NG_DEV_MODE ? 'Router Initializer' : '');
6888
+ const ROUTER_INITIALIZER = new InjectionToken((typeof ngDevMode === 'undefined' || ngDevMode) ? 'Router Initializer' : '');
6877
6889
  function provideRouterInitializer() {
6878
6890
  return [
6879
6891
  // ROUTER_INITIALIZER token should be removed. It's public API but shouldn't be. We can just
@@ -6952,7 +6964,7 @@ function mapToResolve(provider) {
6952
6964
  /**
6953
6965
  * @publicApi
6954
6966
  */
6955
- const VERSION = new Version('16.0.0-next.4');
6967
+ const VERSION = new Version('16.0.0-next.6');
6956
6968
 
6957
6969
  /**
6958
6970
  * @module
@@ -6967,5 +6979,5 @@ const VERSION = new Version('16.0.0-next.4');
6967
6979
  * Generated bundle index. Do not edit.
6968
6980
  */
6969
6981
 
6970
- export { ActivatedRoute, ActivatedRouteSnapshot, ActivationEnd, ActivationStart, BaseRouteReuseStrategy, ChildActivationEnd, ChildActivationStart, ChildrenOutletContexts, DefaultTitleStrategy, DefaultUrlSerializer, GuardsCheckEnd, GuardsCheckStart, NavigationCancel, NavigationEnd, NavigationError, NavigationSkipped, NavigationStart, NoPreloading, OutletContext, PRIMARY_OUTLET, PreloadAllModules, PreloadingStrategy, ROUTER_CONFIGURATION, ROUTER_INITIALIZER, ROUTES, ResolveEnd, ResolveStart, RouteConfigLoadEnd, RouteConfigLoadStart, RouteReuseStrategy, Router, RouterEvent, RouterLink, RouterLinkActive, RouterLink as RouterLinkWithHref, RouterModule, RouterOutlet, RouterPreloader, RouterState, RouterStateSnapshot, RoutesRecognized, Scroll, TitleStrategy, UrlHandlingStrategy, UrlSegment, UrlSegmentGroup, UrlSerializer, UrlTree, VERSION, convertToParamMap, createUrlTreeFromSnapshot, defaultUrlMatcher, mapToCanActivate, mapToCanActivateChild, mapToCanDeactivate, mapToCanMatch, mapToResolve, provideRouter, provideRoutes, withDebugTracing, withDisabledInitialNavigation, withEnabledBlockingInitialNavigation, withHashLocation, withInMemoryScrolling, withNavigationErrorHandler, withPreloading, withRouterConfig, ɵEmptyOutletComponent, ROUTER_PROVIDERS as ɵROUTER_PROVIDERS, afterNextNavigation as ɵafterNextNavigation, withPreloading as ɵwithPreloading };
6982
+ export { ActivatedRoute, ActivatedRouteSnapshot, ActivationEnd, ActivationStart, BaseRouteReuseStrategy, ChildActivationEnd, ChildActivationStart, ChildrenOutletContexts, DefaultTitleStrategy, DefaultUrlSerializer, GuardsCheckEnd, GuardsCheckStart, NavigationCancel, NavigationEnd, NavigationError, NavigationSkipped, NavigationStart, NoPreloading, OutletContext, PRIMARY_OUTLET, PreloadAllModules, PreloadingStrategy, ROUTER_CONFIGURATION, ROUTER_INITIALIZER, ROUTES, ResolveEnd, ResolveStart, RouteConfigLoadEnd, RouteConfigLoadStart, RouteReuseStrategy, Router, RouterEvent, RouterLink, RouterLinkActive, RouterLink as RouterLinkWithHref, RouterModule, RouterOutlet, RouterPreloader, RouterState, RouterStateSnapshot, RoutesRecognized, Scroll, TitleStrategy, UrlHandlingStrategy, UrlSegment, UrlSegmentGroup, UrlSerializer, UrlTree, VERSION, convertToParamMap, createUrlTreeFromSnapshot, defaultUrlMatcher, mapToCanActivate, mapToCanActivateChild, mapToCanDeactivate, mapToCanMatch, mapToResolve, provideRouter, provideRoutes, withComponentInputBinding, withDebugTracing, withDisabledInitialNavigation, withEnabledBlockingInitialNavigation, withHashLocation, withInMemoryScrolling, withNavigationErrorHandler, withPreloading, withRouterConfig, ɵEmptyOutletComponent, ROUTER_PROVIDERS as ɵROUTER_PROVIDERS, afterNextNavigation as ɵafterNextNavigation, withPreloading as ɵwithPreloading };
6971
6983
  //# sourceMappingURL=router.mjs.map