@angular/router 11.0.4 → 11.0.8

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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v11.0.4
2
+ * @license Angular v11.0.8
3
3
  * (c) 2010-2020 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -908,28 +908,6 @@
908
908
  }
909
909
  }
910
910
  }
911
- function waitForMap(obj, fn) {
912
- if (Object.keys(obj).length === 0) {
913
- return rxjs.of({});
914
- }
915
- var waitHead = [];
916
- var waitTail = [];
917
- var res = {};
918
- forEach(obj, function (a, k) {
919
- var mapped = fn(k, a).pipe(operators.map(function (r) { return res[k] = r; }));
920
- if (k === PRIMARY_OUTLET) {
921
- waitHead.push(mapped);
922
- }
923
- else {
924
- waitTail.push(mapped);
925
- }
926
- });
927
- // Closure compiler has problem with using spread operator here. So we use "Array.concat".
928
- // Note that we also need to cast the new promise because TypeScript cannot infer the type
929
- // when calling the "of" function through "Function.apply"
930
- return rxjs.of.apply(null, waitHead.concat(waitTail))
931
- .pipe(operators.concatAll(), operators.last(), operators.map(function () { return res; }));
932
- }
933
911
  function wrapIntoObservable(value) {
934
912
  if (core.ɵisObservable(value)) {
935
913
  return value;
@@ -1898,7 +1876,25 @@
1898
1876
  function ActivatedRouteSnapshot(
1899
1877
  /** The URL segments matched by this route */
1900
1878
  url,
1901
- /** The matrix parameters scoped to this route */
1879
+ /**
1880
+ * The matrix parameters scoped to this route.
1881
+ *
1882
+ * You can compute all params (or data) in the router state or to get params outside
1883
+ * of an activated component by traversing the `RouterState` tree as in the following
1884
+ * example:
1885
+ * ```
1886
+ * collectRouteParams(router: Router) {
1887
+ * let params = {};
1888
+ * let stack: ActivatedRouteSnapshot[] = [router.routerState.snapshot.root];
1889
+ * while (stack.length > 0) {
1890
+ * const route = stack.pop()!;
1891
+ * params = {...params, ...route.params};
1892
+ * stack.push(...route.children);
1893
+ * }
1894
+ * return params;
1895
+ * }
1896
+ * ```
1897
+ */
1902
1898
  params,
1903
1899
  /** The query parameters shared by all the routes */
1904
1900
  queryParams,
@@ -2432,13 +2428,6 @@
2432
2428
  return path == segment.path && shallowEqual(params, segment.parameters);
2433
2429
  }
2434
2430
 
2435
- /**
2436
- * @license
2437
- * Copyright Google LLC All Rights Reserved.
2438
- *
2439
- * Use of this source code is governed by an MIT-style license that can be
2440
- * found in the LICENSE file at https://angular.io/license
2441
- */
2442
2431
  var activateRoutes = function (rootContexts, routeReuseStrategy, forwardEvent) { return operators.map(function (t) {
2443
2432
  new ActivateRoutes(routeReuseStrategy, t.targetRouterState, t.currentRouterState, forwardEvent)
2444
2433
  .activate(rootContexts);
@@ -2514,18 +2503,30 @@
2514
2503
  }
2515
2504
  };
2516
2505
  ActivateRoutes.prototype.deactivateRouteAndOutlet = function (route, parentContexts) {
2517
- var _this = this;
2506
+ var e_1, _a;
2518
2507
  var context = parentContexts.getContext(route.value.outlet);
2519
- if (context) {
2520
- var children = nodeChildrenAsMap(route);
2521
- var contexts_1 = route.value.component ? context.children : parentContexts;
2522
- forEach(children, function (v, k) { return _this.deactivateRouteAndItsChildren(v, contexts_1); });
2523
- if (context.outlet) {
2524
- // Destroy the component
2525
- context.outlet.deactivate();
2526
- // Destroy the contexts for all the outlets that were in the component
2527
- context.children.onOutletDeactivated();
2508
+ // The context could be `null` if we are on a componentless route but there may still be
2509
+ // children that need deactivating.
2510
+ var contexts = context && route.value.component ? context.children : parentContexts;
2511
+ var children = nodeChildrenAsMap(route);
2512
+ try {
2513
+ for (var _b = __values(Object.keys(children)), _c = _b.next(); !_c.done; _c = _b.next()) {
2514
+ var childOutlet = _c.value;
2515
+ this.deactivateRouteAndItsChildren(children[childOutlet], contexts);
2516
+ }
2517
+ }
2518
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
2519
+ finally {
2520
+ try {
2521
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
2528
2522
  }
2523
+ finally { if (e_1) throw e_1.error; }
2524
+ }
2525
+ if (context && context.outlet) {
2526
+ // Destroy the component
2527
+ context.outlet.deactivate();
2528
+ // Destroy the contexts for all the outlets that were in the component
2529
+ context.children.onOutletDeactivated();
2529
2530
  }
2530
2531
  };
2531
2532
  ActivateRoutes.prototype.activateChildRoutes = function (futureNode, currNode, contexts) {
@@ -2722,13 +2723,6 @@
2722
2723
  { type: core.Component, args: [{ template: "<router-outlet></router-outlet>" },] }
2723
2724
  ];
2724
2725
 
2725
- /**
2726
- * @license
2727
- * Copyright Google LLC All Rights Reserved.
2728
- *
2729
- * Use of this source code is governed by an MIT-style license that can be
2730
- * found in the LICENSE file at https://angular.io/license
2731
- */
2732
2726
  function validateConfig(config, parentPath) {
2733
2727
  if (parentPath === void 0) { parentPath = ''; }
2734
2728
  // forEach doesn't iterate undefined values
@@ -2814,23 +2808,176 @@
2814
2808
  }
2815
2809
  return c;
2816
2810
  }
2817
- /** Returns of `Map` of outlet names to the `Route`s for that outlet. */
2818
- function groupRoutesByOutlet(routes) {
2819
- return routes.reduce(function (map, route) {
2820
- var routeOutlet = getOutlet(route);
2821
- if (map.has(routeOutlet)) {
2822
- map.get(routeOutlet).push(route);
2823
- }
2824
- else {
2825
- map.set(routeOutlet, [route]);
2826
- }
2827
- return map;
2828
- }, new Map());
2829
- }
2830
2811
  /** Returns the `route.outlet` or PRIMARY_OUTLET if none exists. */
2831
2812
  function getOutlet(route) {
2832
2813
  return route.outlet || PRIMARY_OUTLET;
2833
2814
  }
2815
+ /**
2816
+ * Sorts the `routes` such that the ones with an outlet matching `outletName` come first.
2817
+ * The order of the configs is otherwise preserved.
2818
+ */
2819
+ function sortByMatchingOutlets(routes, outletName) {
2820
+ var sortedConfig = routes.filter(function (r) { return getOutlet(r) === outletName; });
2821
+ sortedConfig.push.apply(sortedConfig, __spread(routes.filter(function (r) { return getOutlet(r) !== outletName; })));
2822
+ return sortedConfig;
2823
+ }
2824
+
2825
+ var noMatch = {
2826
+ matched: false,
2827
+ consumedSegments: [],
2828
+ lastChild: 0,
2829
+ parameters: {},
2830
+ positionalParamSegments: {}
2831
+ };
2832
+ function match(segmentGroup, route, segments) {
2833
+ var _a;
2834
+ if (route.path === '') {
2835
+ if (route.pathMatch === 'full' && (segmentGroup.hasChildren() || segments.length > 0)) {
2836
+ return Object.assign({}, noMatch);
2837
+ }
2838
+ return {
2839
+ matched: true,
2840
+ consumedSegments: [],
2841
+ lastChild: 0,
2842
+ parameters: {},
2843
+ positionalParamSegments: {}
2844
+ };
2845
+ }
2846
+ var matcher = route.matcher || defaultUrlMatcher;
2847
+ var res = matcher(segments, segmentGroup, route);
2848
+ if (!res)
2849
+ return Object.assign({}, noMatch);
2850
+ var posParams = {};
2851
+ forEach(res.posParams, function (v, k) {
2852
+ posParams[k] = v.path;
2853
+ });
2854
+ var parameters = res.consumed.length > 0 ? Object.assign(Object.assign({}, posParams), res.consumed[res.consumed.length - 1].parameters) :
2855
+ posParams;
2856
+ return {
2857
+ matched: true,
2858
+ consumedSegments: res.consumed,
2859
+ lastChild: res.consumed.length,
2860
+ // TODO(atscott): investigate combining parameters and positionalParamSegments
2861
+ parameters: parameters,
2862
+ positionalParamSegments: (_a = res.posParams) !== null && _a !== void 0 ? _a : {}
2863
+ };
2864
+ }
2865
+ function split(segmentGroup, consumedSegments, slicedSegments, config, relativeLinkResolution) {
2866
+ if (relativeLinkResolution === void 0) { relativeLinkResolution = 'corrected'; }
2867
+ if (slicedSegments.length > 0 &&
2868
+ containsEmptyPathMatchesWithNamedOutlets(segmentGroup, slicedSegments, config)) {
2869
+ var s_1 = new UrlSegmentGroup(consumedSegments, createChildrenForEmptyPaths(segmentGroup, consumedSegments, config, new UrlSegmentGroup(slicedSegments, segmentGroup.children)));
2870
+ s_1._sourceSegment = segmentGroup;
2871
+ s_1._segmentIndexShift = consumedSegments.length;
2872
+ return { segmentGroup: s_1, slicedSegments: [] };
2873
+ }
2874
+ if (slicedSegments.length === 0 &&
2875
+ containsEmptyPathMatches(segmentGroup, slicedSegments, config)) {
2876
+ var s_2 = new UrlSegmentGroup(segmentGroup.segments, addEmptyPathsToChildrenIfNeeded(segmentGroup, consumedSegments, slicedSegments, config, segmentGroup.children, relativeLinkResolution));
2877
+ s_2._sourceSegment = segmentGroup;
2878
+ s_2._segmentIndexShift = consumedSegments.length;
2879
+ return { segmentGroup: s_2, slicedSegments: slicedSegments };
2880
+ }
2881
+ var s = new UrlSegmentGroup(segmentGroup.segments, segmentGroup.children);
2882
+ s._sourceSegment = segmentGroup;
2883
+ s._segmentIndexShift = consumedSegments.length;
2884
+ return { segmentGroup: s, slicedSegments: slicedSegments };
2885
+ }
2886
+ function addEmptyPathsToChildrenIfNeeded(segmentGroup, consumedSegments, slicedSegments, routes, children, relativeLinkResolution) {
2887
+ var e_1, _b;
2888
+ var res = {};
2889
+ try {
2890
+ for (var routes_1 = __values(routes), routes_1_1 = routes_1.next(); !routes_1_1.done; routes_1_1 = routes_1.next()) {
2891
+ var r = routes_1_1.value;
2892
+ if (emptyPathMatch(segmentGroup, slicedSegments, r) && !children[getOutlet(r)]) {
2893
+ var s = new UrlSegmentGroup([], {});
2894
+ s._sourceSegment = segmentGroup;
2895
+ if (relativeLinkResolution === 'legacy') {
2896
+ s._segmentIndexShift = segmentGroup.segments.length;
2897
+ }
2898
+ else {
2899
+ s._segmentIndexShift = consumedSegments.length;
2900
+ }
2901
+ res[getOutlet(r)] = s;
2902
+ }
2903
+ }
2904
+ }
2905
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
2906
+ finally {
2907
+ try {
2908
+ if (routes_1_1 && !routes_1_1.done && (_b = routes_1.return)) _b.call(routes_1);
2909
+ }
2910
+ finally { if (e_1) throw e_1.error; }
2911
+ }
2912
+ return Object.assign(Object.assign({}, children), res);
2913
+ }
2914
+ function createChildrenForEmptyPaths(segmentGroup, consumedSegments, routes, primarySegment) {
2915
+ var e_2, _b;
2916
+ var res = {};
2917
+ res[PRIMARY_OUTLET] = primarySegment;
2918
+ primarySegment._sourceSegment = segmentGroup;
2919
+ primarySegment._segmentIndexShift = consumedSegments.length;
2920
+ try {
2921
+ for (var routes_2 = __values(routes), routes_2_1 = routes_2.next(); !routes_2_1.done; routes_2_1 = routes_2.next()) {
2922
+ var r = routes_2_1.value;
2923
+ if (r.path === '' && getOutlet(r) !== PRIMARY_OUTLET) {
2924
+ var s = new UrlSegmentGroup([], {});
2925
+ s._sourceSegment = segmentGroup;
2926
+ s._segmentIndexShift = consumedSegments.length;
2927
+ res[getOutlet(r)] = s;
2928
+ }
2929
+ }
2930
+ }
2931
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
2932
+ finally {
2933
+ try {
2934
+ if (routes_2_1 && !routes_2_1.done && (_b = routes_2.return)) _b.call(routes_2);
2935
+ }
2936
+ finally { if (e_2) throw e_2.error; }
2937
+ }
2938
+ return res;
2939
+ }
2940
+ function containsEmptyPathMatchesWithNamedOutlets(segmentGroup, slicedSegments, routes) {
2941
+ return routes.some(function (r) { return emptyPathMatch(segmentGroup, slicedSegments, r) && getOutlet(r) !== PRIMARY_OUTLET; });
2942
+ }
2943
+ function containsEmptyPathMatches(segmentGroup, slicedSegments, routes) {
2944
+ return routes.some(function (r) { return emptyPathMatch(segmentGroup, slicedSegments, r); });
2945
+ }
2946
+ function emptyPathMatch(segmentGroup, slicedSegments, r) {
2947
+ if ((segmentGroup.hasChildren() || slicedSegments.length > 0) && r.pathMatch === 'full') {
2948
+ return false;
2949
+ }
2950
+ return r.path === '';
2951
+ }
2952
+ /**
2953
+ * Determines if `route` is a path match for the `rawSegment`, `segments`, and `outlet` without
2954
+ * verifying that its children are a full match for the remainder of the `rawSegment` children as
2955
+ * well.
2956
+ */
2957
+ function isImmediateMatch(route, rawSegment, segments, outlet) {
2958
+ // We allow matches to empty paths when the outlets differ so we can match a url like `/(b:b)` to
2959
+ // a config like
2960
+ // * `{path: '', children: [{path: 'b', outlet: 'b'}]}`
2961
+ // or even
2962
+ // * `{path: '', outlet: 'a', children: [{path: 'b', outlet: 'b'}]`
2963
+ //
2964
+ // The exception here is when the segment outlet is for the primary outlet. This would
2965
+ // result in a match inside the named outlet because all children there are written as primary
2966
+ // outlets. So we need to prevent child named outlet matches in a url like `/b` in a config like
2967
+ // * `{path: '', outlet: 'x' children: [{path: 'b'}]}`
2968
+ // This should only match if the url is `/(x:b)`.
2969
+ if (getOutlet(route) !== outlet &&
2970
+ (outlet === PRIMARY_OUTLET || !emptyPathMatch(rawSegment, segments, route))) {
2971
+ return false;
2972
+ }
2973
+ if (route.path === '**') {
2974
+ return true;
2975
+ }
2976
+ return match(rawSegment, route, segments).matched;
2977
+ }
2978
+ function noLeftoversInUrl(segmentGroup, segments, outlet) {
2979
+ return segments.length === 0 && !segmentGroup.children[outlet];
2980
+ }
2834
2981
 
2835
2982
  var NoMatch = /** @class */ (function () {
2836
2983
  function NoMatch(segmentGroup) {
@@ -2844,7 +2991,7 @@
2844
2991
  }
2845
2992
  return AbsoluteRedirect;
2846
2993
  }());
2847
- function noMatch(segmentGroup) {
2994
+ function noMatch$1(segmentGroup) {
2848
2995
  return new rxjs.Observable(function (obs) { return obs.error(new NoMatch(segmentGroup)); });
2849
2996
  }
2850
2997
  function absoluteRedirect(newTree) {
@@ -2875,8 +3022,18 @@
2875
3022
  }
2876
3023
  ApplyRedirects.prototype.apply = function () {
2877
3024
  var _this = this;
2878
- var expanded$ = this.expandSegmentGroup(this.ngModule, this.config, this.urlTree.root, PRIMARY_OUTLET);
2879
- var urlTrees$ = expanded$.pipe(operators.map(function (rootSegmentGroup) { return _this.createUrlTree(rootSegmentGroup, _this.urlTree.queryParams, _this.urlTree.fragment); }));
3025
+ var splitGroup = split(this.urlTree.root, [], [], this.config).segmentGroup;
3026
+ // TODO(atscott): creating a new segment removes the _sourceSegment _segmentIndexShift, which is
3027
+ // only necessary to prevent failures in tests which assert exact object matches. The `split` is
3028
+ // now shared between `applyRedirects` and `recognize` but only the `recognize` step needs these
3029
+ // properties. Before the implementations were merged, the `applyRedirects` would not assign
3030
+ // them. We should be able to remove this logic as a "breaking change" but should do some more
3031
+ // investigation into the failures first.
3032
+ var rootSegmentGroup = new UrlSegmentGroup(splitGroup.segments, splitGroup.children);
3033
+ var expanded$ = this.expandSegmentGroup(this.ngModule, this.config, rootSegmentGroup, PRIMARY_OUTLET);
3034
+ var urlTrees$ = expanded$.pipe(operators.map(function (rootSegmentGroup) {
3035
+ return _this.createUrlTree(squashSegmentGroup(rootSegmentGroup), _this.urlTree.queryParams, _this.urlTree.fragment);
3036
+ }));
2880
3037
  return urlTrees$.pipe(operators.catchError(function (e) {
2881
3038
  if (e instanceof AbsoluteRedirect) {
2882
3039
  // after an absolute redirect we do not apply any more redirects!
@@ -2893,7 +3050,9 @@
2893
3050
  ApplyRedirects.prototype.match = function (tree) {
2894
3051
  var _this = this;
2895
3052
  var expanded$ = this.expandSegmentGroup(this.ngModule, this.config, tree.root, PRIMARY_OUTLET);
2896
- var mapped$ = expanded$.pipe(operators.map(function (rootSegmentGroup) { return _this.createUrlTree(rootSegmentGroup, tree.queryParams, tree.fragment); }));
3053
+ var mapped$ = expanded$.pipe(operators.map(function (rootSegmentGroup) {
3054
+ return _this.createUrlTree(squashSegmentGroup(rootSegmentGroup), tree.queryParams, tree.fragment);
3055
+ }));
2897
3056
  return mapped$.pipe(operators.catchError(function (e) {
2898
3057
  if (e instanceof NoMatch) {
2899
3058
  throw _this.noMatchError(e);
@@ -2920,65 +3079,74 @@
2920
3079
  };
2921
3080
  // Recursively expand segment groups for all the child outlets
2922
3081
  ApplyRedirects.prototype.expandChildren = function (ngModule, routes, segmentGroup) {
3082
+ var e_1, _a;
2923
3083
  var _this = this;
2924
- return waitForMap(segmentGroup.children, function (childOutlet, child) { return _this.expandSegmentGroup(ngModule, routes, child, childOutlet); });
3084
+ // Expand outlets one at a time, starting with the primary outlet. We need to do it this way
3085
+ // because an absolute redirect from the primary outlet takes precedence.
3086
+ var childOutlets = [];
3087
+ try {
3088
+ for (var _b = __values(Object.keys(segmentGroup.children)), _c = _b.next(); !_c.done; _c = _b.next()) {
3089
+ var child = _c.value;
3090
+ if (child === 'primary') {
3091
+ childOutlets.unshift(child);
3092
+ }
3093
+ else {
3094
+ childOutlets.push(child);
3095
+ }
3096
+ }
3097
+ }
3098
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
3099
+ finally {
3100
+ try {
3101
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
3102
+ }
3103
+ finally { if (e_1) throw e_1.error; }
3104
+ }
3105
+ return rxjs.from(childOutlets)
3106
+ .pipe(operators.concatMap(function (childOutlet) {
3107
+ var child = segmentGroup.children[childOutlet];
3108
+ // Sort the routes so routes with outlets that match the the segment appear
3109
+ // first, followed by routes for other outlets, which might match if they have an
3110
+ // empty path.
3111
+ var sortedRoutes = sortByMatchingOutlets(routes, childOutlet);
3112
+ return _this.expandSegmentGroup(ngModule, sortedRoutes, child, childOutlet)
3113
+ .pipe(operators.map(function (s) { return ({ segment: s, outlet: childOutlet }); }));
3114
+ }), operators.scan(function (children, expandedChild) {
3115
+ children[expandedChild.outlet] = expandedChild.segment;
3116
+ return children;
3117
+ }, {}), operators.last());
2925
3118
  };
2926
3119
  ApplyRedirects.prototype.expandSegment = function (ngModule, segmentGroup, routes, segments, outlet, allowRedirects) {
2927
3120
  var _this = this;
2928
- // We need to expand each outlet group independently to ensure that we not only load modules
2929
- // for routes matching the given `outlet`, but also those which will be activated because
2930
- // their path is empty string. This can result in multiple outlets being activated at once.
2931
- var routesByOutlet = groupRoutesByOutlet(routes);
2932
- if (!routesByOutlet.has(outlet)) {
2933
- routesByOutlet.set(outlet, []);
2934
- }
2935
- var expandRoutes = function (routes) {
2936
- return rxjs.from(routes).pipe(operators.concatMap(function (r) {
2937
- var expanded$ = _this.expandSegmentAgainstRoute(ngModule, segmentGroup, routes, r, segments, outlet, allowRedirects);
2938
- return expanded$.pipe(operators.catchError(function (e) {
2939
- if (e instanceof NoMatch) {
2940
- return rxjs.of(null);
2941
- }
2942
- throw e;
2943
- }));
2944
- }), operators.first(function (s) { return s !== null; }), operators.catchError(function (e) {
2945
- if (e instanceof rxjs.EmptyError || e.name === 'EmptyError') {
2946
- if (_this.noLeftoversInUrl(segmentGroup, segments, outlet)) {
2947
- return rxjs.of(new UrlSegmentGroup([], {}));
2948
- }
2949
- throw new NoMatch(segmentGroup);
3121
+ return rxjs.from(routes).pipe(operators.concatMap(function (r) {
3122
+ var expanded$ = _this.expandSegmentAgainstRoute(ngModule, segmentGroup, routes, r, segments, outlet, allowRedirects);
3123
+ return expanded$.pipe(operators.catchError(function (e) {
3124
+ if (e instanceof NoMatch) {
3125
+ return rxjs.of(null);
2950
3126
  }
2951
3127
  throw e;
2952
3128
  }));
2953
- };
2954
- var expansions = Array.from(routesByOutlet.entries()).map(function (_a) {
2955
- var _b = __read(_a, 2), routeOutlet = _b[0], routes = _b[1];
2956
- var expanded = expandRoutes(routes);
2957
- // Map all results from outlets we aren't activating to `null` so they can be ignored later
2958
- return routeOutlet === outlet ? expanded :
2959
- expanded.pipe(operators.map(function () { return null; }), operators.catchError(function () { return rxjs.of(null); }));
2960
- });
2961
- return rxjs.from(expansions)
2962
- .pipe(operators.combineAll(), operators.first(),
2963
- // Return only the expansion for the route outlet we are trying to activate.
2964
- operators.map(function (results) { return results.find(function (result) { return result !== null; }); }));
2965
- };
2966
- ApplyRedirects.prototype.noLeftoversInUrl = function (segmentGroup, segments, outlet) {
2967
- return segments.length === 0 && !segmentGroup.children[outlet];
3129
+ }), operators.first(function (s) { return !!s; }), operators.catchError(function (e, _) {
3130
+ if (e instanceof rxjs.EmptyError || e.name === 'EmptyError') {
3131
+ if (noLeftoversInUrl(segmentGroup, segments, outlet)) {
3132
+ return rxjs.of(new UrlSegmentGroup([], {}));
3133
+ }
3134
+ throw new NoMatch(segmentGroup);
3135
+ }
3136
+ throw e;
3137
+ }));
2968
3138
  };
2969
3139
  ApplyRedirects.prototype.expandSegmentAgainstRoute = function (ngModule, segmentGroup, routes, route, paths, outlet, allowRedirects) {
2970
- // Empty string segments are special because multiple outlets can match a single path, i.e.
2971
- // `[{path: '', component: B}, {path: '', loadChildren: () => {}, outlet: "about"}]`
2972
- if (getOutlet(route) !== outlet && route.path !== '') {
2973
- return noMatch(segmentGroup);
3140
+ if (!isImmediateMatch(route, segmentGroup, paths, outlet)) {
3141
+ return noMatch$1(segmentGroup);
2974
3142
  }
2975
3143
  if (route.redirectTo === undefined) {
2976
- return this.matchSegmentAgainstRoute(ngModule, segmentGroup, route, paths);
3144
+ return this.matchSegmentAgainstRoute(ngModule, segmentGroup, route, paths, outlet);
2977
3145
  }
2978
3146
  if (allowRedirects && this.allowRedirects) {
2979
3147
  return this.expandSegmentAgainstRouteUsingRedirect(ngModule, segmentGroup, routes, route, paths, outlet);
2980
3148
  }
2981
- return noMatch(segmentGroup);
3149
+ return noMatch$1(segmentGroup);
2982
3150
  };
2983
3151
  ApplyRedirects.prototype.expandSegmentAgainstRouteUsingRedirect = function (ngModule, segmentGroup, routes, route, segments, outlet) {
2984
3152
  if (route.path === '**') {
@@ -3001,7 +3169,7 @@
3001
3169
  var _this = this;
3002
3170
  var _a = match(segmentGroup, route, segments), matched = _a.matched, consumedSegments = _a.consumedSegments, lastChild = _a.lastChild, positionalParamSegments = _a.positionalParamSegments;
3003
3171
  if (!matched)
3004
- return noMatch(segmentGroup);
3172
+ return noMatch$1(segmentGroup);
3005
3173
  var newTree = this.applyRedirectCommands(consumedSegments, route.redirectTo, positionalParamSegments);
3006
3174
  if (route.redirectTo.startsWith('/')) {
3007
3175
  return absoluteRedirect(newTree);
@@ -3010,7 +3178,7 @@
3010
3178
  return _this.expandSegment(ngModule, segmentGroup, routes, newSegments.concat(segments.slice(lastChild)), outlet, false);
3011
3179
  }));
3012
3180
  };
3013
- ApplyRedirects.prototype.matchSegmentAgainstRoute = function (ngModule, rawSegmentGroup, route, segments) {
3181
+ ApplyRedirects.prototype.matchSegmentAgainstRoute = function (ngModule, rawSegmentGroup, route, segments, outlet) {
3014
3182
  var _this = this;
3015
3183
  if (route.path === '**') {
3016
3184
  if (route.loadChildren) {
@@ -3024,13 +3192,15 @@
3024
3192
  }
3025
3193
  var _a = match(rawSegmentGroup, route, segments), matched = _a.matched, consumedSegments = _a.consumedSegments, lastChild = _a.lastChild;
3026
3194
  if (!matched)
3027
- return noMatch(rawSegmentGroup);
3195
+ return noMatch$1(rawSegmentGroup);
3028
3196
  var rawSlicedSegments = segments.slice(lastChild);
3029
3197
  var childConfig$ = this.getChildConfig(ngModule, route, segments);
3030
3198
  return childConfig$.pipe(operators.mergeMap(function (routerConfig) {
3031
3199
  var childModule = routerConfig.module;
3032
3200
  var childConfig = routerConfig.routes;
3033
- var _a = split(rawSegmentGroup, consumedSegments, rawSlicedSegments, childConfig), segmentGroup = _a.segmentGroup, slicedSegments = _a.slicedSegments;
3201
+ var _a = split(rawSegmentGroup, consumedSegments, rawSlicedSegments, childConfig), splitSegmentGroup = _a.segmentGroup, slicedSegments = _a.slicedSegments;
3202
+ // See comment on the other call to `split` about why this is necessary.
3203
+ var segmentGroup = new UrlSegmentGroup(splitSegmentGroup.segments, splitSegmentGroup.children);
3034
3204
  if (slicedSegments.length === 0 && segmentGroup.hasChildren()) {
3035
3205
  var expanded$_1 = _this.expandChildren(childModule, childConfig, segmentGroup);
3036
3206
  return expanded$_1.pipe(operators.map(function (children) { return new UrlSegmentGroup(consumedSegments, children); }));
@@ -3038,7 +3208,8 @@
3038
3208
  if (childConfig.length === 0 && slicedSegments.length === 0) {
3039
3209
  return rxjs.of(new UrlSegmentGroup(consumedSegments, {}));
3040
3210
  }
3041
- var expanded$ = _this.expandSegment(childModule, segmentGroup, childConfig, slicedSegments, PRIMARY_OUTLET, true);
3211
+ var matchedOnOutlet = getOutlet(route) === outlet;
3212
+ var expanded$ = _this.expandSegment(childModule, segmentGroup, childConfig, slicedSegments, matchedOnOutlet ? PRIMARY_OUTLET : outlet, true);
3042
3213
  return expanded$.pipe(operators.map(function (cs) { return new UrlSegmentGroup(consumedSegments.concat(cs.segments), cs.children); }));
3043
3214
  }));
3044
3215
  };
@@ -3151,7 +3322,7 @@
3151
3322
  return pos;
3152
3323
  };
3153
3324
  ApplyRedirects.prototype.findOrReturn = function (redirectToUrlSegment, actualSegments) {
3154
- var e_1, _a;
3325
+ var e_2, _a;
3155
3326
  var idx = 0;
3156
3327
  try {
3157
3328
  for (var actualSegments_1 = __values(actualSegments), actualSegments_1_1 = actualSegments_1.next(); !actualSegments_1_1.done; actualSegments_1_1 = actualSegments_1.next()) {
@@ -3163,54 +3334,25 @@
3163
3334
  idx++;
3164
3335
  }
3165
3336
  }
3166
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
3337
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
3167
3338
  finally {
3168
3339
  try {
3169
3340
  if (actualSegments_1_1 && !actualSegments_1_1.done && (_a = actualSegments_1.return)) _a.call(actualSegments_1);
3170
3341
  }
3171
- finally { if (e_1) throw e_1.error; }
3342
+ finally { if (e_2) throw e_2.error; }
3172
3343
  }
3173
3344
  return redirectToUrlSegment;
3174
3345
  };
3175
3346
  return ApplyRedirects;
3176
3347
  }());
3177
- function match(segmentGroup, route, segments) {
3178
- if (route.path === '') {
3179
- if ((route.pathMatch === 'full') && (segmentGroup.hasChildren() || segments.length > 0)) {
3180
- return { matched: false, consumedSegments: [], lastChild: 0, positionalParamSegments: {} };
3181
- }
3182
- return { matched: true, consumedSegments: [], lastChild: 0, positionalParamSegments: {} };
3183
- }
3184
- var matcher = route.matcher || defaultUrlMatcher;
3185
- var res = matcher(segments, segmentGroup, route);
3186
- if (!res) {
3187
- return {
3188
- matched: false,
3189
- consumedSegments: [],
3190
- lastChild: 0,
3191
- positionalParamSegments: {},
3192
- };
3193
- }
3194
- return {
3195
- matched: true,
3196
- consumedSegments: res.consumed,
3197
- lastChild: res.consumed.length,
3198
- positionalParamSegments: res.posParams,
3199
- };
3200
- }
3201
- function split(segmentGroup, consumedSegments, slicedSegments, config) {
3202
- if (slicedSegments.length > 0 &&
3203
- containsEmptyPathRedirectsWithNamedOutlets(segmentGroup, slicedSegments, config)) {
3204
- var s = new UrlSegmentGroup(consumedSegments, createChildrenForEmptySegments(config, new UrlSegmentGroup(slicedSegments, segmentGroup.children)));
3205
- return { segmentGroup: mergeTrivialChildren(s), slicedSegments: [] };
3206
- }
3207
- if (slicedSegments.length === 0 &&
3208
- containsEmptyPathRedirects(segmentGroup, slicedSegments, config)) {
3209
- var s = new UrlSegmentGroup(segmentGroup.segments, addEmptySegmentsToChildrenIfNeeded(segmentGroup, slicedSegments, config, segmentGroup.children));
3210
- return { segmentGroup: mergeTrivialChildren(s), slicedSegments: slicedSegments };
3211
- }
3212
- return { segmentGroup: segmentGroup, slicedSegments: slicedSegments };
3213
- }
3348
+ /**
3349
+ * When possible, merges the primary outlet child into the parent `UrlSegmentGroup`.
3350
+ *
3351
+ * When a segment group has only one child which is a primary outlet, merges that child into the
3352
+ * parent. That is, the child segment group's segments are merged into the `s` and the child's
3353
+ * children become the children of `s`. Think of this like a 'squash', merging the child segment
3354
+ * group into the parent.
3355
+ */
3214
3356
  function mergeTrivialChildren(s) {
3215
3357
  if (s.numberOfChildren === 1 && s.children[PRIMARY_OUTLET]) {
3216
3358
  var c = s.children[PRIMARY_OUTLET];
@@ -3218,58 +3360,34 @@
3218
3360
  }
3219
3361
  return s;
3220
3362
  }
3221
- function addEmptySegmentsToChildrenIfNeeded(segmentGroup, slicedSegments, routes, children) {
3222
- var e_2, _a;
3223
- var res = {};
3224
- try {
3225
- for (var routes_1 = __values(routes), routes_1_1 = routes_1.next(); !routes_1_1.done; routes_1_1 = routes_1.next()) {
3226
- var r = routes_1_1.value;
3227
- if (isEmptyPathRedirect(segmentGroup, slicedSegments, r) && !children[getOutlet(r)]) {
3228
- res[getOutlet(r)] = new UrlSegmentGroup([], {});
3229
- }
3230
- }
3231
- }
3232
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
3233
- finally {
3234
- try {
3235
- if (routes_1_1 && !routes_1_1.done && (_a = routes_1.return)) _a.call(routes_1);
3236
- }
3237
- finally { if (e_2) throw e_2.error; }
3238
- }
3239
- return Object.assign(Object.assign({}, children), res);
3240
- }
3241
- function createChildrenForEmptySegments(routes, primarySegmentGroup) {
3363
+ /**
3364
+ * Recursively merges primary segment children into their parents and also drops empty children
3365
+ * (those which have no segments and no children themselves). The latter prevents serializing a
3366
+ * group into something like `/a(aux:)`, where `aux` is an empty child segment.
3367
+ */
3368
+ function squashSegmentGroup(segmentGroup) {
3242
3369
  var e_3, _a;
3243
- var res = {};
3244
- res[PRIMARY_OUTLET] = primarySegmentGroup;
3370
+ var newChildren = {};
3245
3371
  try {
3246
- for (var routes_2 = __values(routes), routes_2_1 = routes_2.next(); !routes_2_1.done; routes_2_1 = routes_2.next()) {
3247
- var r = routes_2_1.value;
3248
- if (r.path === '' && getOutlet(r) !== PRIMARY_OUTLET) {
3249
- res[getOutlet(r)] = new UrlSegmentGroup([], {});
3372
+ for (var _b = __values(Object.keys(segmentGroup.children)), _c = _b.next(); !_c.done; _c = _b.next()) {
3373
+ var childOutlet = _c.value;
3374
+ var child = segmentGroup.children[childOutlet];
3375
+ var childCandidate = squashSegmentGroup(child);
3376
+ // don't add empty children
3377
+ if (childCandidate.segments.length > 0 || childCandidate.hasChildren()) {
3378
+ newChildren[childOutlet] = childCandidate;
3250
3379
  }
3251
3380
  }
3252
3381
  }
3253
3382
  catch (e_3_1) { e_3 = { error: e_3_1 }; }
3254
3383
  finally {
3255
3384
  try {
3256
- if (routes_2_1 && !routes_2_1.done && (_a = routes_2.return)) _a.call(routes_2);
3385
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
3257
3386
  }
3258
3387
  finally { if (e_3) throw e_3.error; }
3259
3388
  }
3260
- return res;
3261
- }
3262
- function containsEmptyPathRedirectsWithNamedOutlets(segmentGroup, segments, routes) {
3263
- return routes.some(function (r) { return isEmptyPathRedirect(segmentGroup, segments, r) && getOutlet(r) !== PRIMARY_OUTLET; });
3264
- }
3265
- function containsEmptyPathRedirects(segmentGroup, segments, routes) {
3266
- return routes.some(function (r) { return isEmptyPathRedirect(segmentGroup, segments, r); });
3267
- }
3268
- function isEmptyPathRedirect(segmentGroup, segments, r) {
3269
- if ((segmentGroup.hasChildren() || segments.length > 0) && r.pathMatch === 'full') {
3270
- return false;
3271
- }
3272
- return r.path === '' && r.redirectTo !== undefined;
3389
+ var s = new UrlSegmentGroup(segmentGroup.segments, newChildren);
3390
+ return mergeTrivialChildren(s);
3273
3391
  }
3274
3392
 
3275
3393
  /**
@@ -3586,11 +3704,28 @@
3586
3704
  }
3587
3705
  return NoMatch;
3588
3706
  }());
3707
+ function newObservableError(e) {
3708
+ // TODO(atscott): This pattern is used throughout the router code and can be `throwError` instead.
3709
+ return new rxjs.Observable(function (obs) { return obs.error(e); });
3710
+ }
3589
3711
  function recognize(rootComponentType, config, urlTree, url, paramsInheritanceStrategy, relativeLinkResolution) {
3590
3712
  if (paramsInheritanceStrategy === void 0) { paramsInheritanceStrategy = 'emptyOnly'; }
3591
3713
  if (relativeLinkResolution === void 0) { relativeLinkResolution = 'legacy'; }
3592
- return new Recognizer(rootComponentType, config, urlTree, url, paramsInheritanceStrategy, relativeLinkResolution)
3593
- .recognize();
3714
+ try {
3715
+ var result = new Recognizer(rootComponentType, config, urlTree, url, paramsInheritanceStrategy, relativeLinkResolution)
3716
+ .recognize();
3717
+ if (result === null) {
3718
+ return newObservableError(new NoMatch$1());
3719
+ }
3720
+ else {
3721
+ return rxjs.of(result);
3722
+ }
3723
+ }
3724
+ catch (e) {
3725
+ // Catch the potential error from recognize due to duplicate outlet matches and return as an
3726
+ // `Observable` error instead.
3727
+ return newObservableError(e);
3728
+ }
3594
3729
  }
3595
3730
  var Recognizer = /** @class */ (function () {
3596
3731
  function Recognizer(rootComponentType, config, urlTree, url, paramsInheritanceStrategy, relativeLinkResolution) {
@@ -3602,18 +3737,19 @@
3602
3737
  this.relativeLinkResolution = relativeLinkResolution;
3603
3738
  }
3604
3739
  Recognizer.prototype.recognize = function () {
3605
- try {
3606
- var rootSegmentGroup = split$1(this.urlTree.root, [], [], this.config, this.relativeLinkResolution).segmentGroup;
3607
- var children = this.processSegmentGroup(this.config, rootSegmentGroup, PRIMARY_OUTLET);
3608
- var root = new ActivatedRouteSnapshot([], Object.freeze({}), Object.freeze(Object.assign({}, this.urlTree.queryParams)), this.urlTree.fragment, {}, PRIMARY_OUTLET, this.rootComponentType, null, this.urlTree.root, -1, {});
3609
- var rootNode = new TreeNode(root, children);
3610
- var routeState = new RouterStateSnapshot(this.url, rootNode);
3611
- this.inheritParamsAndData(routeState._root);
3612
- return rxjs.of(routeState);
3613
- }
3614
- catch (e) {
3615
- return new rxjs.Observable(function (obs) { return obs.error(e); });
3740
+ var rootSegmentGroup = split(this.urlTree.root, [], [], this.config.filter(function (c) { return c.redirectTo === undefined; }), this.relativeLinkResolution)
3741
+ .segmentGroup;
3742
+ var children = this.processSegmentGroup(this.config, rootSegmentGroup, PRIMARY_OUTLET);
3743
+ if (children === null) {
3744
+ return null;
3616
3745
  }
3746
+ // Use Object.freeze to prevent readers of the Router state from modifying it outside of a
3747
+ // navigation, resulting in the router being out of sync with the browser.
3748
+ var root = new ActivatedRouteSnapshot([], Object.freeze({}), Object.freeze(Object.assign({}, this.urlTree.queryParams)), this.urlTree.fragment, {}, PRIMARY_OUTLET, this.rootComponentType, null, this.urlTree.root, -1, {});
3749
+ var rootNode = new TreeNode(root, children);
3750
+ var routeState = new RouterStateSnapshot(this.url, rootNode);
3751
+ this.inheritParamsAndData(routeState._root);
3752
+ return routeState;
3617
3753
  };
3618
3754
  Recognizer.prototype.inheritParamsAndData = function (routeNode) {
3619
3755
  var _this = this;
@@ -3629,70 +3765,123 @@
3629
3765
  }
3630
3766
  return this.processSegment(config, segmentGroup, segmentGroup.segments, outlet);
3631
3767
  };
3768
+ /**
3769
+ * Matches every child outlet in the `segmentGroup` to a `Route` in the config. Returns `null` if
3770
+ * we cannot find a match for _any_ of the children.
3771
+ *
3772
+ * @param config - The `Routes` to match against
3773
+ * @param segmentGroup - The `UrlSegmentGroup` whose children need to be matched against the
3774
+ * config.
3775
+ */
3632
3776
  Recognizer.prototype.processChildren = function (config, segmentGroup) {
3633
- var _this = this;
3634
- var children = mapChildrenIntoArray(segmentGroup, function (child, childOutlet) { return _this.processSegmentGroup(config, child, childOutlet); });
3635
- checkOutletNameUniqueness(children);
3636
- sortActivatedRouteSnapshots(children);
3637
- return children;
3777
+ var e_1, _a;
3778
+ var children = [];
3779
+ try {
3780
+ for (var _b = __values(Object.keys(segmentGroup.children)), _c = _b.next(); !_c.done; _c = _b.next()) {
3781
+ var childOutlet = _c.value;
3782
+ var child = segmentGroup.children[childOutlet];
3783
+ // Sort the config so that routes with outlets that match the one being activated appear
3784
+ // first, followed by routes for other outlets, which might match if they have an empty path.
3785
+ var sortedConfig = sortByMatchingOutlets(config, childOutlet);
3786
+ var outletChildren = this.processSegmentGroup(sortedConfig, child, childOutlet);
3787
+ if (outletChildren === null) {
3788
+ // Configs must match all segment children so because we did not find a match for this
3789
+ // outlet, return `null`.
3790
+ return null;
3791
+ }
3792
+ children.push.apply(children, __spread(outletChildren));
3793
+ }
3794
+ }
3795
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
3796
+ finally {
3797
+ try {
3798
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
3799
+ }
3800
+ finally { if (e_1) throw e_1.error; }
3801
+ }
3802
+ // Because we may have matched two outlets to the same empty path segment, we can have multiple
3803
+ // activated results for the same outlet. We should merge the children of these results so the
3804
+ // final return value is only one `TreeNode` per outlet.
3805
+ var mergedChildren = mergeEmptyPathMatches(children);
3806
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
3807
+ // This should really never happen - we are only taking the first match for each outlet and
3808
+ // merge the empty path matches.
3809
+ checkOutletNameUniqueness(mergedChildren);
3810
+ }
3811
+ sortActivatedRouteSnapshots(mergedChildren);
3812
+ return mergedChildren;
3638
3813
  };
3639
3814
  Recognizer.prototype.processSegment = function (config, segmentGroup, segments, outlet) {
3640
- var e_1, _a;
3815
+ var e_2, _a;
3641
3816
  try {
3642
3817
  for (var config_1 = __values(config), config_1_1 = config_1.next(); !config_1_1.done; config_1_1 = config_1.next()) {
3643
3818
  var r = config_1_1.value;
3644
- try {
3645
- return this.processSegmentAgainstRoute(r, segmentGroup, segments, outlet);
3646
- }
3647
- catch (e) {
3648
- if (!(e instanceof NoMatch$1))
3649
- throw e;
3819
+ var children = this.processSegmentAgainstRoute(r, segmentGroup, segments, outlet);
3820
+ if (children !== null) {
3821
+ return children;
3650
3822
  }
3651
3823
  }
3652
3824
  }
3653
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
3825
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
3654
3826
  finally {
3655
3827
  try {
3656
3828
  if (config_1_1 && !config_1_1.done && (_a = config_1.return)) _a.call(config_1);
3657
3829
  }
3658
- finally { if (e_1) throw e_1.error; }
3830
+ finally { if (e_2) throw e_2.error; }
3659
3831
  }
3660
- if (this.noLeftoversInUrl(segmentGroup, segments, outlet)) {
3832
+ if (noLeftoversInUrl(segmentGroup, segments, outlet)) {
3661
3833
  return [];
3662
3834
  }
3663
- throw new NoMatch$1();
3664
- };
3665
- Recognizer.prototype.noLeftoversInUrl = function (segmentGroup, segments, outlet) {
3666
- return segments.length === 0 && !segmentGroup.children[outlet];
3835
+ return null;
3667
3836
  };
3668
3837
  Recognizer.prototype.processSegmentAgainstRoute = function (route, rawSegment, segments, outlet) {
3669
- if (route.redirectTo)
3670
- throw new NoMatch$1();
3671
- if ((route.outlet || PRIMARY_OUTLET) !== outlet)
3672
- throw new NoMatch$1();
3838
+ if (route.redirectTo || !isImmediateMatch(route, rawSegment, segments, outlet))
3839
+ return null;
3673
3840
  var snapshot;
3674
3841
  var consumedSegments = [];
3675
3842
  var rawSlicedSegments = [];
3676
3843
  if (route.path === '**') {
3677
3844
  var params = segments.length > 0 ? last(segments).parameters : {};
3678
- snapshot = new ActivatedRouteSnapshot(segments, params, Object.freeze(Object.assign({}, this.urlTree.queryParams)), this.urlTree.fragment, getData(route), outlet, route.component, route, getSourceSegmentGroup(rawSegment), getPathIndexShift(rawSegment) + segments.length, getResolve(route));
3845
+ snapshot = new ActivatedRouteSnapshot(segments, params, Object.freeze(Object.assign({}, this.urlTree.queryParams)), this.urlTree.fragment, getData(route), getOutlet(route), route.component, route, getSourceSegmentGroup(rawSegment), getPathIndexShift(rawSegment) + segments.length, getResolve(route));
3679
3846
  }
3680
3847
  else {
3681
- var result = match$1(rawSegment, route, segments);
3848
+ var result = match(rawSegment, route, segments);
3849
+ if (!result.matched) {
3850
+ return null;
3851
+ }
3682
3852
  consumedSegments = result.consumedSegments;
3683
3853
  rawSlicedSegments = segments.slice(result.lastChild);
3684
- snapshot = new ActivatedRouteSnapshot(consumedSegments, result.parameters, Object.freeze(Object.assign({}, this.urlTree.queryParams)), this.urlTree.fragment, getData(route), outlet, route.component, route, getSourceSegmentGroup(rawSegment), getPathIndexShift(rawSegment) + consumedSegments.length, getResolve(route));
3854
+ snapshot = new ActivatedRouteSnapshot(consumedSegments, result.parameters, Object.freeze(Object.assign({}, this.urlTree.queryParams)), this.urlTree.fragment, getData(route), getOutlet(route), route.component, route, getSourceSegmentGroup(rawSegment), getPathIndexShift(rawSegment) + consumedSegments.length, getResolve(route));
3685
3855
  }
3686
3856
  var childConfig = getChildConfig(route);
3687
- var _a = split$1(rawSegment, consumedSegments, rawSlicedSegments, childConfig, this.relativeLinkResolution), segmentGroup = _a.segmentGroup, slicedSegments = _a.slicedSegments;
3857
+ var _a = split(rawSegment, consumedSegments, rawSlicedSegments,
3858
+ // Filter out routes with redirectTo because we are trying to create activated route
3859
+ // snapshots and don't handle redirects here. That should have been done in
3860
+ // `applyRedirects`.
3861
+ childConfig.filter(function (c) { return c.redirectTo === undefined; }), this.relativeLinkResolution), segmentGroup = _a.segmentGroup, slicedSegments = _a.slicedSegments;
3688
3862
  if (slicedSegments.length === 0 && segmentGroup.hasChildren()) {
3689
3863
  var children_1 = this.processChildren(childConfig, segmentGroup);
3864
+ if (children_1 === null) {
3865
+ return null;
3866
+ }
3690
3867
  return [new TreeNode(snapshot, children_1)];
3691
3868
  }
3692
3869
  if (childConfig.length === 0 && slicedSegments.length === 0) {
3693
3870
  return [new TreeNode(snapshot, [])];
3694
3871
  }
3695
- var children = this.processSegment(childConfig, segmentGroup, slicedSegments, PRIMARY_OUTLET);
3872
+ var matchedOnOutlet = getOutlet(route) === outlet;
3873
+ // If we matched a config due to empty path match on a different outlet, we need to continue
3874
+ // passing the current outlet for the segment rather than switch to PRIMARY.
3875
+ // Note that we switch to primary when we have a match because outlet configs look like this:
3876
+ // {path: 'a', outlet: 'a', children: [
3877
+ // {path: 'b', component: B},
3878
+ // {path: 'c', component: C},
3879
+ // ]}
3880
+ // Notice that the children of the named outlet are configured with the primary outlet
3881
+ var children = this.processSegment(childConfig, segmentGroup, slicedSegments, matchedOnOutlet ? PRIMARY_OUTLET : outlet);
3882
+ if (children === null) {
3883
+ return null;
3884
+ }
3696
3885
  return [new TreeNode(snapshot, children)];
3697
3886
  };
3698
3887
  return Recognizer;
@@ -3715,24 +3904,46 @@
3715
3904
  }
3716
3905
  return [];
3717
3906
  }
3718
- function match$1(segmentGroup, route, segments) {
3719
- if (route.path === '') {
3720
- if (route.pathMatch === 'full' && (segmentGroup.hasChildren() || segments.length > 0)) {
3721
- throw new NoMatch$1();
3907
+ function hasEmptyPathConfig(node) {
3908
+ var config = node.value.routeConfig;
3909
+ return config && config.path === '' && config.redirectTo === undefined;
3910
+ }
3911
+ /**
3912
+ * Finds `TreeNode`s with matching empty path route configs and merges them into `TreeNode` with the
3913
+ * children from each duplicate. This is necessary because different outlets can match a single
3914
+ * empty path route config and the results need to then be merged.
3915
+ */
3916
+ function mergeEmptyPathMatches(nodes) {
3917
+ var e_3, _a;
3918
+ var result = [];
3919
+ var _loop_1 = function (node) {
3920
+ var _a;
3921
+ if (!hasEmptyPathConfig(node)) {
3922
+ result.push(node);
3923
+ return "continue";
3924
+ }
3925
+ var duplicateEmptyPathNode = result.find(function (resultNode) { return node.value.routeConfig === resultNode.value.routeConfig; });
3926
+ if (duplicateEmptyPathNode !== undefined) {
3927
+ (_a = duplicateEmptyPathNode.children).push.apply(_a, __spread(node.children));
3928
+ }
3929
+ else {
3930
+ result.push(node);
3931
+ }
3932
+ };
3933
+ try {
3934
+ for (var nodes_1 = __values(nodes), nodes_1_1 = nodes_1.next(); !nodes_1_1.done; nodes_1_1 = nodes_1.next()) {
3935
+ var node = nodes_1_1.value;
3936
+ _loop_1(node);
3722
3937
  }
3723
- return { consumedSegments: [], lastChild: 0, parameters: {} };
3724
3938
  }
3725
- var matcher = route.matcher || defaultUrlMatcher;
3726
- var res = matcher(segments, segmentGroup, route);
3727
- if (!res)
3728
- throw new NoMatch$1();
3729
- var posParams = {};
3730
- forEach(res.posParams, function (v, k) {
3731
- posParams[k] = v.path;
3732
- });
3733
- var parameters = res.consumed.length > 0 ? Object.assign(Object.assign({}, posParams), res.consumed[res.consumed.length - 1].parameters) :
3734
- posParams;
3735
- return { consumedSegments: res.consumed, lastChild: res.consumed.length, parameters: parameters };
3939
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
3940
+ finally {
3941
+ try {
3942
+ if (nodes_1_1 && !nodes_1_1.done && (_a = nodes_1.return)) _a.call(nodes_1);
3943
+ }
3944
+ finally { if (e_3) throw e_3.error; }
3945
+ }
3946
+ return result;
3736
3947
  }
3737
3948
  function checkOutletNameUniqueness(nodes) {
3738
3949
  var names = {};
@@ -3762,92 +3973,6 @@
3762
3973
  }
3763
3974
  return res - 1;
3764
3975
  }
3765
- function split$1(segmentGroup, consumedSegments, slicedSegments, config, relativeLinkResolution) {
3766
- if (slicedSegments.length > 0 &&
3767
- containsEmptyPathMatchesWithNamedOutlets(segmentGroup, slicedSegments, config)) {
3768
- var s_1 = new UrlSegmentGroup(consumedSegments, createChildrenForEmptyPaths(segmentGroup, consumedSegments, config, new UrlSegmentGroup(slicedSegments, segmentGroup.children)));
3769
- s_1._sourceSegment = segmentGroup;
3770
- s_1._segmentIndexShift = consumedSegments.length;
3771
- return { segmentGroup: s_1, slicedSegments: [] };
3772
- }
3773
- if (slicedSegments.length === 0 &&
3774
- containsEmptyPathMatches(segmentGroup, slicedSegments, config)) {
3775
- var s_2 = new UrlSegmentGroup(segmentGroup.segments, addEmptyPathsToChildrenIfNeeded(segmentGroup, consumedSegments, slicedSegments, config, segmentGroup.children, relativeLinkResolution));
3776
- s_2._sourceSegment = segmentGroup;
3777
- s_2._segmentIndexShift = consumedSegments.length;
3778
- return { segmentGroup: s_2, slicedSegments: slicedSegments };
3779
- }
3780
- var s = new UrlSegmentGroup(segmentGroup.segments, segmentGroup.children);
3781
- s._sourceSegment = segmentGroup;
3782
- s._segmentIndexShift = consumedSegments.length;
3783
- return { segmentGroup: s, slicedSegments: slicedSegments };
3784
- }
3785
- function addEmptyPathsToChildrenIfNeeded(segmentGroup, consumedSegments, slicedSegments, routes, children, relativeLinkResolution) {
3786
- var e_2, _a;
3787
- var res = {};
3788
- try {
3789
- for (var routes_1 = __values(routes), routes_1_1 = routes_1.next(); !routes_1_1.done; routes_1_1 = routes_1.next()) {
3790
- var r = routes_1_1.value;
3791
- if (emptyPathMatch(segmentGroup, slicedSegments, r) && !children[getOutlet(r)]) {
3792
- var s = new UrlSegmentGroup([], {});
3793
- s._sourceSegment = segmentGroup;
3794
- if (relativeLinkResolution === 'legacy') {
3795
- s._segmentIndexShift = segmentGroup.segments.length;
3796
- }
3797
- else {
3798
- s._segmentIndexShift = consumedSegments.length;
3799
- }
3800
- res[getOutlet(r)] = s;
3801
- }
3802
- }
3803
- }
3804
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
3805
- finally {
3806
- try {
3807
- if (routes_1_1 && !routes_1_1.done && (_a = routes_1.return)) _a.call(routes_1);
3808
- }
3809
- finally { if (e_2) throw e_2.error; }
3810
- }
3811
- return Object.assign(Object.assign({}, children), res);
3812
- }
3813
- function createChildrenForEmptyPaths(segmentGroup, consumedSegments, routes, primarySegment) {
3814
- var e_3, _a;
3815
- var res = {};
3816
- res[PRIMARY_OUTLET] = primarySegment;
3817
- primarySegment._sourceSegment = segmentGroup;
3818
- primarySegment._segmentIndexShift = consumedSegments.length;
3819
- try {
3820
- for (var routes_2 = __values(routes), routes_2_1 = routes_2.next(); !routes_2_1.done; routes_2_1 = routes_2.next()) {
3821
- var r = routes_2_1.value;
3822
- if (r.path === '' && getOutlet(r) !== PRIMARY_OUTLET) {
3823
- var s = new UrlSegmentGroup([], {});
3824
- s._sourceSegment = segmentGroup;
3825
- s._segmentIndexShift = consumedSegments.length;
3826
- res[getOutlet(r)] = s;
3827
- }
3828
- }
3829
- }
3830
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
3831
- finally {
3832
- try {
3833
- if (routes_2_1 && !routes_2_1.done && (_a = routes_2.return)) _a.call(routes_2);
3834
- }
3835
- finally { if (e_3) throw e_3.error; }
3836
- }
3837
- return res;
3838
- }
3839
- function containsEmptyPathMatchesWithNamedOutlets(segmentGroup, slicedSegments, routes) {
3840
- return routes.some(function (r) { return emptyPathMatch(segmentGroup, slicedSegments, r) && getOutlet(r) !== PRIMARY_OUTLET; });
3841
- }
3842
- function containsEmptyPathMatches(segmentGroup, slicedSegments, routes) {
3843
- return routes.some(function (r) { return emptyPathMatch(segmentGroup, slicedSegments, r); });
3844
- }
3845
- function emptyPathMatch(segmentGroup, slicedSegments, r) {
3846
- if ((segmentGroup.hasChildren() || slicedSegments.length > 0) && r.pathMatch === 'full') {
3847
- return false;
3848
- }
3849
- return r.path === '' && r.redirectTo === undefined;
3850
- }
3851
3976
  function getData(route) {
3852
3977
  return route.data || {};
3853
3978
  }
@@ -4542,7 +4667,7 @@
4542
4667
  // navigation completes, there will be nothing in
4543
4668
  // history.state.navigationId. This can cause sync problems with AngularJS
4544
4669
  // sync code which looks for a value here in order to determine whether or
4545
- // not to handle a given popstate event or to leave it to the Angualr
4670
+ // not to handle a given popstate event or to leave it to the Angular
4546
4671
  // router.
4547
4672
  _this.resetUrlToCurrentUrlTree();
4548
4673
  var navCancel = new NavigationCancel(t.id, _this.serializeUrl(t.extractedUrl), "Navigation ID " + t.id + " is not equal to the current navigation id " + _this.navigationId);
@@ -6297,7 +6422,7 @@
6297
6422
  /**
6298
6423
  * @publicApi
6299
6424
  */
6300
- var VERSION = new core.Version('11.0.4');
6425
+ var VERSION = new core.Version('11.0.8');
6301
6426
 
6302
6427
  /**
6303
6428
  * @license