NewTube/.angular/cache/20.2.2/app/vite/deps/@angular_router.js

6106 lines
213 KiB
JavaScript

import {
Title
} from "./chunk-DYWB3JMR.js";
import "./chunk-5DRVFSXL.js";
import {
HashLocationStrategy,
LOCATION_INITIALIZED,
Location,
LocationStrategy,
PathLocationStrategy,
ViewportScroller
} from "./chunk-H4LQPAO2.js";
import "./chunk-OUSM42MY.js";
import {
APP_BOOTSTRAP_LISTENER,
ApplicationRef,
Attribute,
ChangeDetectorRef,
Compiler,
Component,
Console,
ContentChildren,
DOCUMENT,
DestroyRef,
Directive,
ENVIRONMENT_INITIALIZER,
ElementRef,
EnvironmentInjector,
EventEmitter,
HostAttributeToken,
HostBinding,
HostListener,
INTERNAL_APPLICATION_ERROR_HANDLER,
IS_ENABLED_BLOCKING_INITIAL_NAVIGATION,
Injectable,
InjectionToken,
Injector,
Input,
NgModule,
NgModuleFactory$1,
NgZone,
Optional,
Output,
PendingTasksInternal,
Renderer2,
RuntimeError,
SkipSelf,
Version,
ViewContainerRef,
afterNextRender,
booleanAttribute,
createEnvironmentInjector,
inject,
input,
isInjectable,
isNgModule,
isPromise,
isStandalone,
makeEnvironmentProviders,
performanceMarkFeature,
provideAppInitializer,
reflectComponentType,
runInInjectionContext,
setClassMetadata,
signal,
untracked,
ɵɵNgOnChangesFeature,
ɵɵattribute,
ɵɵcontentQuery,
ɵɵdefineComponent,
ɵɵdefineDirective,
ɵɵdefineInjectable,
ɵɵdefineInjector,
ɵɵdefineNgModule,
ɵɵdirectiveInject,
ɵɵelement,
ɵɵgetInheritedFactory,
ɵɵinject,
ɵɵinjectAttribute,
ɵɵinvalidFactory,
ɵɵlistener,
ɵɵloadQuery,
ɵɵqueryRefresh,
ɵɵsanitizeUrlOrResourceUrl
} from "./chunk-FVA7C6JK.js";
import "./chunk-JRFR6BLO.js";
import {
defer,
isObservable
} from "./chunk-HWYXSU2G.js";
import {
BehaviorSubject,
ConnectableObservable,
EMPTY,
EmptyError,
Observable,
Subject,
Subscription,
catchError,
combineLatest,
concat,
concatMap,
defaultIfEmpty,
filter,
finalize,
first,
from,
last,
map,
mergeAll,
mergeMap,
of,
pipe,
refCount,
scan,
startWith,
switchMap,
take,
takeLast,
takeUntil,
tap,
throwError
} from "./chunk-MARUHEWW.js";
import {
__spreadProps,
__spreadValues
} from "./chunk-GOMI4DH3.js";
// node_modules/@angular/router/fesm2022/router2.mjs
var PRIMARY_OUTLET = "primary";
var RouteTitleKey = Symbol("RouteTitle");
var ParamsAsMap = class {
params;
constructor(params) {
this.params = params || {};
}
has(name) {
return Object.prototype.hasOwnProperty.call(this.params, name);
}
get(name) {
if (this.has(name)) {
const v = this.params[name];
return Array.isArray(v) ? v[0] : v;
}
return null;
}
getAll(name) {
if (this.has(name)) {
const v = this.params[name];
return Array.isArray(v) ? v : [v];
}
return [];
}
get keys() {
return Object.keys(this.params);
}
};
function convertToParamMap(params) {
return new ParamsAsMap(params);
}
function defaultUrlMatcher(segments, segmentGroup, route) {
const parts = route.path.split("/");
if (parts.length > segments.length) {
return null;
}
if (route.pathMatch === "full" && (segmentGroup.hasChildren() || parts.length < segments.length)) {
return null;
}
const posParams = {};
for (let index = 0; index < parts.length; index++) {
const part = parts[index];
const segment = segments[index];
const isParameter = part[0] === ":";
if (isParameter) {
posParams[part.substring(1)] = segment;
} else if (part !== segment.path) {
return null;
}
}
return {
consumed: segments.slice(0, parts.length),
posParams
};
}
function shallowEqualArrays(a, b) {
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; ++i) {
if (!shallowEqual(a[i], b[i])) return false;
}
return true;
}
function shallowEqual(a, b) {
const k1 = a ? getDataKeys(a) : void 0;
const k2 = b ? getDataKeys(b) : void 0;
if (!k1 || !k2 || k1.length != k2.length) {
return false;
}
let key;
for (let i = 0; i < k1.length; i++) {
key = k1[i];
if (!equalArraysOrString(a[key], b[key])) {
return false;
}
}
return true;
}
function getDataKeys(obj) {
return [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)];
}
function equalArraysOrString(a, b) {
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) return false;
const aSorted = [...a].sort();
const bSorted = [...b].sort();
return aSorted.every((val, index) => bSorted[index] === val);
} else {
return a === b;
}
}
function last2(a) {
return a.length > 0 ? a[a.length - 1] : null;
}
function wrapIntoObservable(value) {
if (isObservable(value)) {
return value;
}
if (isPromise(value)) {
return from(Promise.resolve(value));
}
return of(value);
}
var pathCompareMap = {
"exact": equalSegmentGroups,
"subset": containsSegmentGroup
};
var paramCompareMap = {
"exact": equalParams,
"subset": containsParams,
"ignored": () => true
};
function containsTree(container, containee, options) {
return pathCompareMap[options.paths](container.root, containee.root, options.matrixParams) && paramCompareMap[options.queryParams](container.queryParams, containee.queryParams) && !(options.fragment === "exact" && container.fragment !== containee.fragment);
}
function equalParams(container, containee) {
return shallowEqual(container, containee);
}
function equalSegmentGroups(container, containee, matrixParams) {
if (!equalPath(container.segments, containee.segments)) return false;
if (!matrixParamsMatch(container.segments, containee.segments, matrixParams)) {
return false;
}
if (container.numberOfChildren !== containee.numberOfChildren) return false;
for (const c in containee.children) {
if (!container.children[c]) return false;
if (!equalSegmentGroups(container.children[c], containee.children[c], matrixParams)) return false;
}
return true;
}
function containsParams(container, containee) {
return Object.keys(containee).length <= Object.keys(container).length && Object.keys(containee).every((key) => equalArraysOrString(container[key], containee[key]));
}
function containsSegmentGroup(container, containee, matrixParams) {
return containsSegmentGroupHelper(container, containee, containee.segments, matrixParams);
}
function containsSegmentGroupHelper(container, containee, containeePaths, matrixParams) {
if (container.segments.length > containeePaths.length) {
const current = container.segments.slice(0, containeePaths.length);
if (!equalPath(current, containeePaths)) return false;
if (containee.hasChildren()) return false;
if (!matrixParamsMatch(current, containeePaths, matrixParams)) return false;
return true;
} else if (container.segments.length === containeePaths.length) {
if (!equalPath(container.segments, containeePaths)) return false;
if (!matrixParamsMatch(container.segments, containeePaths, matrixParams)) return false;
for (const c in containee.children) {
if (!container.children[c]) return false;
if (!containsSegmentGroup(container.children[c], containee.children[c], matrixParams)) {
return false;
}
}
return true;
} else {
const current = containeePaths.slice(0, container.segments.length);
const next = containeePaths.slice(container.segments.length);
if (!equalPath(container.segments, current)) return false;
if (!matrixParamsMatch(container.segments, current, matrixParams)) return false;
if (!container.children[PRIMARY_OUTLET]) return false;
return containsSegmentGroupHelper(container.children[PRIMARY_OUTLET], containee, next, matrixParams);
}
}
function matrixParamsMatch(containerPaths, containeePaths, options) {
return containeePaths.every((containeeSegment, i) => {
return paramCompareMap[options](containerPaths[i].parameters, containeeSegment.parameters);
});
}
var UrlTree = class {
root;
queryParams;
fragment;
/** @internal */
_queryParamMap;
constructor(root = new UrlSegmentGroup([], {}), queryParams = {}, fragment = null) {
this.root = root;
this.queryParams = queryParams;
this.fragment = fragment;
if (typeof ngDevMode === "undefined" || ngDevMode) {
if (root.segments.length > 0) {
throw new RuntimeError(4015, "The root `UrlSegmentGroup` should not contain `segments`. Instead, these segments belong in the `children` so they can be associated with a named outlet.");
}
}
}
get queryParamMap() {
this._queryParamMap ??= convertToParamMap(this.queryParams);
return this._queryParamMap;
}
/** @docsNotRequired */
toString() {
return DEFAULT_SERIALIZER.serialize(this);
}
};
var UrlSegmentGroup = class {
segments;
children;
/** The parent node in the url tree */
parent = null;
constructor(segments, children) {
this.segments = segments;
this.children = children;
Object.values(children).forEach((v) => v.parent = this);
}
/** Whether the segment has child segments */
hasChildren() {
return this.numberOfChildren > 0;
}
/** Number of child segments */
get numberOfChildren() {
return Object.keys(this.children).length;
}
/** @docsNotRequired */
toString() {
return serializePaths(this);
}
};
var UrlSegment = class {
path;
parameters;
/** @internal */
_parameterMap;
constructor(path, parameters) {
this.path = path;
this.parameters = parameters;
}
get parameterMap() {
this._parameterMap ??= convertToParamMap(this.parameters);
return this._parameterMap;
}
/** @docsNotRequired */
toString() {
return serializePath(this);
}
};
function equalSegments(as, bs) {
return equalPath(as, bs) && as.every((a, i) => shallowEqual(a.parameters, bs[i].parameters));
}
function equalPath(as, bs) {
if (as.length !== bs.length) return false;
return as.every((a, i) => a.path === bs[i].path);
}
function mapChildrenIntoArray(segment, fn) {
let res = [];
Object.entries(segment.children).forEach(([childOutlet, child]) => {
if (childOutlet === PRIMARY_OUTLET) {
res = res.concat(fn(child, childOutlet));
}
});
Object.entries(segment.children).forEach(([childOutlet, child]) => {
if (childOutlet !== PRIMARY_OUTLET) {
res = res.concat(fn(child, childOutlet));
}
});
return res;
}
var UrlSerializer = class _UrlSerializer {
static ɵfac = function UrlSerializer_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _UrlSerializer)();
};
static ɵprov = ɵɵdefineInjectable({
token: _UrlSerializer,
factory: () => (() => new DefaultUrlSerializer())(),
providedIn: "root"
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(UrlSerializer, [{
type: Injectable,
args: [{
providedIn: "root",
useFactory: () => new DefaultUrlSerializer()
}]
}], null, null);
})();
var DefaultUrlSerializer = class {
/** Parses a url into a `UrlTree` */
parse(url) {
const p = new UrlParser(url);
return new UrlTree(p.parseRootSegment(), p.parseQueryParams(), p.parseFragment());
}
/** Converts a `UrlTree` into a url */
serialize(tree2) {
const segment = `/${serializeSegment(tree2.root, true)}`;
const query = serializeQueryParams(tree2.queryParams);
const fragment = typeof tree2.fragment === `string` ? `#${encodeUriFragment(tree2.fragment)}` : "";
return `${segment}${query}${fragment}`;
}
};
var DEFAULT_SERIALIZER = new DefaultUrlSerializer();
function serializePaths(segment) {
return segment.segments.map((p) => serializePath(p)).join("/");
}
function serializeSegment(segment, root) {
if (!segment.hasChildren()) {
return serializePaths(segment);
}
if (root) {
const primary = segment.children[PRIMARY_OUTLET] ? serializeSegment(segment.children[PRIMARY_OUTLET], false) : "";
const children = [];
Object.entries(segment.children).forEach(([k, v]) => {
if (k !== PRIMARY_OUTLET) {
children.push(`${k}:${serializeSegment(v, false)}`);
}
});
return children.length > 0 ? `${primary}(${children.join("//")})` : primary;
} else {
const children = mapChildrenIntoArray(segment, (v, k) => {
if (k === PRIMARY_OUTLET) {
return [serializeSegment(segment.children[PRIMARY_OUTLET], false)];
}
return [`${k}:${serializeSegment(v, false)}`];
});
if (Object.keys(segment.children).length === 1 && segment.children[PRIMARY_OUTLET] != null) {
return `${serializePaths(segment)}/${children[0]}`;
}
return `${serializePaths(segment)}/(${children.join("//")})`;
}
}
function encodeUriString(s) {
return encodeURIComponent(s).replace(/%40/g, "@").replace(/%3A/gi, ":").replace(/%24/g, "$").replace(/%2C/gi, ",");
}
function encodeUriQuery(s) {
return encodeUriString(s).replace(/%3B/gi, ";");
}
function encodeUriFragment(s) {
return encodeURI(s);
}
function encodeUriSegment(s) {
return encodeUriString(s).replace(/\(/g, "%28").replace(/\)/g, "%29").replace(/%26/gi, "&");
}
function decode(s) {
return decodeURIComponent(s);
}
function decodeQuery(s) {
return decode(s.replace(/\+/g, "%20"));
}
function serializePath(path) {
return `${encodeUriSegment(path.path)}${serializeMatrixParams(path.parameters)}`;
}
function serializeMatrixParams(params) {
return Object.entries(params).map(([key, value]) => `;${encodeUriSegment(key)}=${encodeUriSegment(value)}`).join("");
}
function serializeQueryParams(params) {
const strParams = Object.entries(params).map(([name, value]) => {
return Array.isArray(value) ? value.map((v) => `${encodeUriQuery(name)}=${encodeUriQuery(v)}`).join("&") : `${encodeUriQuery(name)}=${encodeUriQuery(value)}`;
}).filter((s) => s);
return strParams.length ? `?${strParams.join("&")}` : "";
}
var SEGMENT_RE = /^[^\/()?;#]+/;
function matchSegments(str) {
const match2 = str.match(SEGMENT_RE);
return match2 ? match2[0] : "";
}
var MATRIX_PARAM_SEGMENT_RE = /^[^\/()?;=#]+/;
function matchMatrixKeySegments(str) {
const match2 = str.match(MATRIX_PARAM_SEGMENT_RE);
return match2 ? match2[0] : "";
}
var QUERY_PARAM_RE = /^[^=?&#]+/;
function matchQueryParams(str) {
const match2 = str.match(QUERY_PARAM_RE);
return match2 ? match2[0] : "";
}
var QUERY_PARAM_VALUE_RE = /^[^&#]+/;
function matchUrlQueryParamValue(str) {
const match2 = str.match(QUERY_PARAM_VALUE_RE);
return match2 ? match2[0] : "";
}
var UrlParser = class {
url;
remaining;
constructor(url) {
this.url = url;
this.remaining = url;
}
parseRootSegment() {
this.consumeOptional("/");
if (this.remaining === "" || this.peekStartsWith("?") || this.peekStartsWith("#")) {
return new UrlSegmentGroup([], {});
}
return new UrlSegmentGroup([], this.parseChildren());
}
parseQueryParams() {
const params = {};
if (this.consumeOptional("?")) {
do {
this.parseQueryParam(params);
} while (this.consumeOptional("&"));
}
return params;
}
parseFragment() {
return this.consumeOptional("#") ? decodeURIComponent(this.remaining) : null;
}
parseChildren() {
if (this.remaining === "") {
return {};
}
this.consumeOptional("/");
const segments = [];
if (!this.peekStartsWith("(")) {
segments.push(this.parseSegment());
}
while (this.peekStartsWith("/") && !this.peekStartsWith("//") && !this.peekStartsWith("/(")) {
this.capture("/");
segments.push(this.parseSegment());
}
let children = {};
if (this.peekStartsWith("/(")) {
this.capture("/");
children = this.parseParens(true);
}
let res = {};
if (this.peekStartsWith("(")) {
res = this.parseParens(false);
}
if (segments.length > 0 || Object.keys(children).length > 0) {
res[PRIMARY_OUTLET] = new UrlSegmentGroup(segments, children);
}
return res;
}
// parse a segment with its matrix parameters
// ie `name;k1=v1;k2`
parseSegment() {
const path = matchSegments(this.remaining);
if (path === "" && this.peekStartsWith(";")) {
throw new RuntimeError(4009, (typeof ngDevMode === "undefined" || ngDevMode) && `Empty path url segment cannot have parameters: '${this.remaining}'.`);
}
this.capture(path);
return new UrlSegment(decode(path), this.parseMatrixParams());
}
parseMatrixParams() {
const params = {};
while (this.consumeOptional(";")) {
this.parseParam(params);
}
return params;
}
parseParam(params) {
const key = matchMatrixKeySegments(this.remaining);
if (!key) {
return;
}
this.capture(key);
let value = "";
if (this.consumeOptional("=")) {
const valueMatch = matchSegments(this.remaining);
if (valueMatch) {
value = valueMatch;
this.capture(value);
}
}
params[decode(key)] = decode(value);
}
// Parse a single query parameter `name[=value]`
parseQueryParam(params) {
const key = matchQueryParams(this.remaining);
if (!key) {
return;
}
this.capture(key);
let value = "";
if (this.consumeOptional("=")) {
const valueMatch = matchUrlQueryParamValue(this.remaining);
if (valueMatch) {
value = valueMatch;
this.capture(value);
}
}
const decodedKey = decodeQuery(key);
const decodedVal = decodeQuery(value);
if (params.hasOwnProperty(decodedKey)) {
let currentVal = params[decodedKey];
if (!Array.isArray(currentVal)) {
currentVal = [currentVal];
params[decodedKey] = currentVal;
}
currentVal.push(decodedVal);
} else {
params[decodedKey] = decodedVal;
}
}
// parse `(a/b//outlet_name:c/d)`
parseParens(allowPrimary) {
const segments = {};
this.capture("(");
while (!this.consumeOptional(")") && this.remaining.length > 0) {
const path = matchSegments(this.remaining);
const next = this.remaining[path.length];
if (next !== "/" && next !== ")" && next !== ";") {
throw new RuntimeError(4010, (typeof ngDevMode === "undefined" || ngDevMode) && `Cannot parse url '${this.url}'`);
}
let outletName = void 0;
if (path.indexOf(":") > -1) {
outletName = path.slice(0, path.indexOf(":"));
this.capture(outletName);
this.capture(":");
} else if (allowPrimary) {
outletName = PRIMARY_OUTLET;
}
const children = this.parseChildren();
segments[outletName] = Object.keys(children).length === 1 ? children[PRIMARY_OUTLET] : new UrlSegmentGroup([], children);
this.consumeOptional("//");
}
return segments;
}
peekStartsWith(str) {
return this.remaining.startsWith(str);
}
// Consumes the prefix when it is present and returns whether it has been consumed
consumeOptional(str) {
if (this.peekStartsWith(str)) {
this.remaining = this.remaining.substring(str.length);
return true;
}
return false;
}
capture(str) {
if (!this.consumeOptional(str)) {
throw new RuntimeError(4011, (typeof ngDevMode === "undefined" || ngDevMode) && `Expected "${str}".`);
}
}
};
function createRoot(rootCandidate) {
return rootCandidate.segments.length > 0 ? new UrlSegmentGroup([], {
[PRIMARY_OUTLET]: rootCandidate
}) : rootCandidate;
}
function squashSegmentGroup(segmentGroup) {
const newChildren = {};
for (const [childOutlet, child] of Object.entries(segmentGroup.children)) {
const childCandidate = squashSegmentGroup(child);
if (childOutlet === PRIMARY_OUTLET && childCandidate.segments.length === 0 && childCandidate.hasChildren()) {
for (const [grandChildOutlet, grandChild] of Object.entries(childCandidate.children)) {
newChildren[grandChildOutlet] = grandChild;
}
} else if (childCandidate.segments.length > 0 || childCandidate.hasChildren()) {
newChildren[childOutlet] = childCandidate;
}
}
const s = new UrlSegmentGroup(segmentGroup.segments, newChildren);
return mergeTrivialChildren(s);
}
function mergeTrivialChildren(s) {
if (s.numberOfChildren === 1 && s.children[PRIMARY_OUTLET]) {
const c = s.children[PRIMARY_OUTLET];
return new UrlSegmentGroup(s.segments.concat(c.segments), c.children);
}
return s;
}
function isUrlTree(v) {
return v instanceof UrlTree;
}
function createUrlTreeFromSnapshot(relativeTo, commands, queryParams = null, fragment = null) {
const relativeToUrlSegmentGroup = createSegmentGroupFromRoute(relativeTo);
return createUrlTreeFromSegmentGroup(relativeToUrlSegmentGroup, commands, queryParams, fragment);
}
function createSegmentGroupFromRoute(route) {
let targetGroup;
function createSegmentGroupFromRouteRecursive(currentRoute) {
const childOutlets = {};
for (const childSnapshot of currentRoute.children) {
const root = createSegmentGroupFromRouteRecursive(childSnapshot);
childOutlets[childSnapshot.outlet] = root;
}
const segmentGroup = new UrlSegmentGroup(currentRoute.url, childOutlets);
if (currentRoute === route) {
targetGroup = segmentGroup;
}
return segmentGroup;
}
const rootCandidate = createSegmentGroupFromRouteRecursive(route.root);
const rootSegmentGroup = createRoot(rootCandidate);
return targetGroup ?? rootSegmentGroup;
}
function createUrlTreeFromSegmentGroup(relativeTo, commands, queryParams, fragment) {
let root = relativeTo;
while (root.parent) {
root = root.parent;
}
if (commands.length === 0) {
return tree(root, root, root, queryParams, fragment);
}
const nav = computeNavigation(commands);
if (nav.toRoot()) {
return tree(root, root, new UrlSegmentGroup([], {}), queryParams, fragment);
}
const position = findStartingPositionForTargetGroup(nav, root, relativeTo);
const newSegmentGroup = position.processChildren ? updateSegmentGroupChildren(position.segmentGroup, position.index, nav.commands) : updateSegmentGroup(position.segmentGroup, position.index, nav.commands);
return tree(root, position.segmentGroup, newSegmentGroup, queryParams, fragment);
}
function isMatrixParams(command) {
return typeof command === "object" && command != null && !command.outlets && !command.segmentPath;
}
function isCommandWithOutlets(command) {
return typeof command === "object" && command != null && command.outlets;
}
function tree(oldRoot, oldSegmentGroup, newSegmentGroup, queryParams, fragment) {
let qp = {};
if (queryParams) {
Object.entries(queryParams).forEach(([name, value]) => {
qp[name] = Array.isArray(value) ? value.map((v) => `${v}`) : `${value}`;
});
}
let rootCandidate;
if (oldRoot === oldSegmentGroup) {
rootCandidate = newSegmentGroup;
} else {
rootCandidate = replaceSegment(oldRoot, oldSegmentGroup, newSegmentGroup);
}
const newRoot = createRoot(squashSegmentGroup(rootCandidate));
return new UrlTree(newRoot, qp, fragment);
}
function replaceSegment(current, oldSegment, newSegment) {
const children = {};
Object.entries(current.children).forEach(([outletName, c]) => {
if (c === oldSegment) {
children[outletName] = newSegment;
} else {
children[outletName] = replaceSegment(c, oldSegment, newSegment);
}
});
return new UrlSegmentGroup(current.segments, children);
}
var Navigation = class {
isAbsolute;
numberOfDoubleDots;
commands;
constructor(isAbsolute, numberOfDoubleDots, commands) {
this.isAbsolute = isAbsolute;
this.numberOfDoubleDots = numberOfDoubleDots;
this.commands = commands;
if (isAbsolute && commands.length > 0 && isMatrixParams(commands[0])) {
throw new RuntimeError(4003, (typeof ngDevMode === "undefined" || ngDevMode) && "Root segment cannot have matrix parameters");
}
const cmdWithOutlet = commands.find(isCommandWithOutlets);
if (cmdWithOutlet && cmdWithOutlet !== last2(commands)) {
throw new RuntimeError(4004, (typeof ngDevMode === "undefined" || ngDevMode) && "{outlets:{}} has to be the last command");
}
}
toRoot() {
return this.isAbsolute && this.commands.length === 1 && this.commands[0] == "/";
}
};
function computeNavigation(commands) {
if (typeof commands[0] === "string" && commands.length === 1 && commands[0] === "/") {
return new Navigation(true, 0, commands);
}
let numberOfDoubleDots = 0;
let isAbsolute = false;
const res = commands.reduce((res2, cmd, cmdIdx) => {
if (typeof cmd === "object" && cmd != null) {
if (cmd.outlets) {
const outlets = {};
Object.entries(cmd.outlets).forEach(([name, commands2]) => {
outlets[name] = typeof commands2 === "string" ? commands2.split("/") : commands2;
});
return [...res2, {
outlets
}];
}
if (cmd.segmentPath) {
return [...res2, cmd.segmentPath];
}
}
if (!(typeof cmd === "string")) {
return [...res2, cmd];
}
if (cmdIdx === 0) {
cmd.split("/").forEach((urlPart, partIndex) => {
if (partIndex == 0 && urlPart === ".") ;
else if (partIndex == 0 && urlPart === "") {
isAbsolute = true;
} else if (urlPart === "..") {
numberOfDoubleDots++;
} else if (urlPart != "") {
res2.push(urlPart);
}
});
return res2;
}
return [...res2, cmd];
}, []);
return new Navigation(isAbsolute, numberOfDoubleDots, res);
}
var Position = class {
segmentGroup;
processChildren;
index;
constructor(segmentGroup, processChildren, index) {
this.segmentGroup = segmentGroup;
this.processChildren = processChildren;
this.index = index;
}
};
function findStartingPositionForTargetGroup(nav, root, target) {
if (nav.isAbsolute) {
return new Position(root, true, 0);
}
if (!target) {
return new Position(root, false, NaN);
}
if (target.parent === null) {
return new Position(target, true, 0);
}
const modifier = isMatrixParams(nav.commands[0]) ? 0 : 1;
const index = target.segments.length - 1 + modifier;
return createPositionApplyingDoubleDots(target, index, nav.numberOfDoubleDots);
}
function createPositionApplyingDoubleDots(group, index, numberOfDoubleDots) {
let g = group;
let ci = index;
let dd = numberOfDoubleDots;
while (dd > ci) {
dd -= ci;
g = g.parent;
if (!g) {
throw new RuntimeError(4005, (typeof ngDevMode === "undefined" || ngDevMode) && "Invalid number of '../'");
}
ci = g.segments.length;
}
return new Position(g, false, ci - dd);
}
function getOutlets(commands) {
if (isCommandWithOutlets(commands[0])) {
return commands[0].outlets;
}
return {
[PRIMARY_OUTLET]: commands
};
}
function updateSegmentGroup(segmentGroup, startIndex, commands) {
segmentGroup ??= new UrlSegmentGroup([], {});
if (segmentGroup.segments.length === 0 && segmentGroup.hasChildren()) {
return updateSegmentGroupChildren(segmentGroup, startIndex, commands);
}
const m = prefixedWith(segmentGroup, startIndex, commands);
const slicedCommands = commands.slice(m.commandIndex);
if (m.match && m.pathIndex < segmentGroup.segments.length) {
const g = new UrlSegmentGroup(segmentGroup.segments.slice(0, m.pathIndex), {});
g.children[PRIMARY_OUTLET] = new UrlSegmentGroup(segmentGroup.segments.slice(m.pathIndex), segmentGroup.children);
return updateSegmentGroupChildren(g, 0, slicedCommands);
} else if (m.match && slicedCommands.length === 0) {
return new UrlSegmentGroup(segmentGroup.segments, {});
} else if (m.match && !segmentGroup.hasChildren()) {
return createNewSegmentGroup(segmentGroup, startIndex, commands);
} else if (m.match) {
return updateSegmentGroupChildren(segmentGroup, 0, slicedCommands);
} else {
return createNewSegmentGroup(segmentGroup, startIndex, commands);
}
}
function updateSegmentGroupChildren(segmentGroup, startIndex, commands) {
if (commands.length === 0) {
return new UrlSegmentGroup(segmentGroup.segments, {});
} else {
const outlets = getOutlets(commands);
const children = {};
if (Object.keys(outlets).some((o) => o !== PRIMARY_OUTLET) && segmentGroup.children[PRIMARY_OUTLET] && segmentGroup.numberOfChildren === 1 && segmentGroup.children[PRIMARY_OUTLET].segments.length === 0) {
const childrenOfEmptyChild = updateSegmentGroupChildren(segmentGroup.children[PRIMARY_OUTLET], startIndex, commands);
return new UrlSegmentGroup(segmentGroup.segments, childrenOfEmptyChild.children);
}
Object.entries(outlets).forEach(([outlet, commands2]) => {
if (typeof commands2 === "string") {
commands2 = [commands2];
}
if (commands2 !== null) {
children[outlet] = updateSegmentGroup(segmentGroup.children[outlet], startIndex, commands2);
}
});
Object.entries(segmentGroup.children).forEach(([childOutlet, child]) => {
if (outlets[childOutlet] === void 0) {
children[childOutlet] = child;
}
});
return new UrlSegmentGroup(segmentGroup.segments, children);
}
}
function prefixedWith(segmentGroup, startIndex, commands) {
let currentCommandIndex = 0;
let currentPathIndex = startIndex;
const noMatch2 = {
match: false,
pathIndex: 0,
commandIndex: 0
};
while (currentPathIndex < segmentGroup.segments.length) {
if (currentCommandIndex >= commands.length) return noMatch2;
const path = segmentGroup.segments[currentPathIndex];
const command = commands[currentCommandIndex];
if (isCommandWithOutlets(command)) {
break;
}
const curr = `${command}`;
const next = currentCommandIndex < commands.length - 1 ? commands[currentCommandIndex + 1] : null;
if (currentPathIndex > 0 && curr === void 0) break;
if (curr && next && typeof next === "object" && next.outlets === void 0) {
if (!compare(curr, next, path)) return noMatch2;
currentCommandIndex += 2;
} else {
if (!compare(curr, {}, path)) return noMatch2;
currentCommandIndex++;
}
currentPathIndex++;
}
return {
match: true,
pathIndex: currentPathIndex,
commandIndex: currentCommandIndex
};
}
function createNewSegmentGroup(segmentGroup, startIndex, commands) {
const paths = segmentGroup.segments.slice(0, startIndex);
let i = 0;
while (i < commands.length) {
const command = commands[i];
if (isCommandWithOutlets(command)) {
const children = createNewSegmentChildren(command.outlets);
return new UrlSegmentGroup(paths, children);
}
if (i === 0 && isMatrixParams(commands[0])) {
const p = segmentGroup.segments[startIndex];
paths.push(new UrlSegment(p.path, stringify(commands[0])));
i++;
continue;
}
const curr = isCommandWithOutlets(command) ? command.outlets[PRIMARY_OUTLET] : `${command}`;
const next = i < commands.length - 1 ? commands[i + 1] : null;
if (curr && next && isMatrixParams(next)) {
paths.push(new UrlSegment(curr, stringify(next)));
i += 2;
} else {
paths.push(new UrlSegment(curr, {}));
i++;
}
}
return new UrlSegmentGroup(paths, {});
}
function createNewSegmentChildren(outlets) {
const children = {};
Object.entries(outlets).forEach(([outlet, commands]) => {
if (typeof commands === "string") {
commands = [commands];
}
if (commands !== null) {
children[outlet] = createNewSegmentGroup(new UrlSegmentGroup([], {}), 0, commands);
}
});
return children;
}
function stringify(params) {
const res = {};
Object.entries(params).forEach(([k, v]) => res[k] = `${v}`);
return res;
}
function compare(path, params, segment) {
return path == segment.path && shallowEqual(params, segment.parameters);
}
var IMPERATIVE_NAVIGATION = "imperative";
var EventType;
(function(EventType2) {
EventType2[EventType2["NavigationStart"] = 0] = "NavigationStart";
EventType2[EventType2["NavigationEnd"] = 1] = "NavigationEnd";
EventType2[EventType2["NavigationCancel"] = 2] = "NavigationCancel";
EventType2[EventType2["NavigationError"] = 3] = "NavigationError";
EventType2[EventType2["RoutesRecognized"] = 4] = "RoutesRecognized";
EventType2[EventType2["ResolveStart"] = 5] = "ResolveStart";
EventType2[EventType2["ResolveEnd"] = 6] = "ResolveEnd";
EventType2[EventType2["GuardsCheckStart"] = 7] = "GuardsCheckStart";
EventType2[EventType2["GuardsCheckEnd"] = 8] = "GuardsCheckEnd";
EventType2[EventType2["RouteConfigLoadStart"] = 9] = "RouteConfigLoadStart";
EventType2[EventType2["RouteConfigLoadEnd"] = 10] = "RouteConfigLoadEnd";
EventType2[EventType2["ChildActivationStart"] = 11] = "ChildActivationStart";
EventType2[EventType2["ChildActivationEnd"] = 12] = "ChildActivationEnd";
EventType2[EventType2["ActivationStart"] = 13] = "ActivationStart";
EventType2[EventType2["ActivationEnd"] = 14] = "ActivationEnd";
EventType2[EventType2["Scroll"] = 15] = "Scroll";
EventType2[EventType2["NavigationSkipped"] = 16] = "NavigationSkipped";
})(EventType || (EventType = {}));
var RouterEvent = class {
id;
url;
constructor(id, url) {
this.id = id;
this.url = url;
}
};
var NavigationStart = class extends RouterEvent {
type = EventType.NavigationStart;
/**
* Identifies the call or event that triggered the navigation.
* An `imperative` trigger is a call to `router.navigateByUrl()` or `router.navigate()`.
*
* @see {@link NavigationEnd}
* @see {@link NavigationCancel}
* @see {@link NavigationError}
*/
navigationTrigger;
/**
* The navigation state that was previously supplied to the `pushState` call,
* when the navigation is triggered by a `popstate` event. Otherwise null.
*
* The state object is defined by `NavigationExtras`, and contains any
* developer-defined state value, as well as a unique ID that
* the router assigns to every router transition/navigation.
*
* From the perspective of the router, the router never "goes back".
* When the user clicks on the back button in the browser,
* a new navigation ID is created.
*
* Use the ID in this previous-state object to differentiate between a newly created
* state and one returned to by a `popstate` event, so that you can restore some
* remembered state, such as scroll position.
*
*/
restoredState;
constructor(id, url, navigationTrigger = "imperative", restoredState = null) {
super(id, url);
this.navigationTrigger = navigationTrigger;
this.restoredState = restoredState;
}
/** @docsNotRequired */
toString() {
return `NavigationStart(id: ${this.id}, url: '${this.url}')`;
}
};
var NavigationEnd = class extends RouterEvent {
urlAfterRedirects;
type = EventType.NavigationEnd;
constructor(id, url, urlAfterRedirects) {
super(id, url);
this.urlAfterRedirects = urlAfterRedirects;
}
/** @docsNotRequired */
toString() {
return `NavigationEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}')`;
}
};
var NavigationCancellationCode;
(function(NavigationCancellationCode2) {
NavigationCancellationCode2[NavigationCancellationCode2["Redirect"] = 0] = "Redirect";
NavigationCancellationCode2[NavigationCancellationCode2["SupersededByNewNavigation"] = 1] = "SupersededByNewNavigation";
NavigationCancellationCode2[NavigationCancellationCode2["NoDataFromResolver"] = 2] = "NoDataFromResolver";
NavigationCancellationCode2[NavigationCancellationCode2["GuardRejected"] = 3] = "GuardRejected";
NavigationCancellationCode2[NavigationCancellationCode2["Aborted"] = 4] = "Aborted";
})(NavigationCancellationCode || (NavigationCancellationCode = {}));
var NavigationSkippedCode;
(function(NavigationSkippedCode2) {
NavigationSkippedCode2[NavigationSkippedCode2["IgnoredSameUrlNavigation"] = 0] = "IgnoredSameUrlNavigation";
NavigationSkippedCode2[NavigationSkippedCode2["IgnoredByUrlHandlingStrategy"] = 1] = "IgnoredByUrlHandlingStrategy";
})(NavigationSkippedCode || (NavigationSkippedCode = {}));
var NavigationCancel = class extends RouterEvent {
reason;
code;
type = EventType.NavigationCancel;
constructor(id, url, reason, code) {
super(id, url);
this.reason = reason;
this.code = code;
}
/** @docsNotRequired */
toString() {
return `NavigationCancel(id: ${this.id}, url: '${this.url}')`;
}
};
var NavigationSkipped = class extends RouterEvent {
reason;
code;
type = EventType.NavigationSkipped;
constructor(id, url, reason, code) {
super(id, url);
this.reason = reason;
this.code = code;
}
};
var NavigationError = class extends RouterEvent {
error;
target;
type = EventType.NavigationError;
constructor(id, url, error, target) {
super(id, url);
this.error = error;
this.target = target;
}
/** @docsNotRequired */
toString() {
return `NavigationError(id: ${this.id}, url: '${this.url}', error: ${this.error})`;
}
};
var RoutesRecognized = class extends RouterEvent {
urlAfterRedirects;
state;
type = EventType.RoutesRecognized;
constructor(id, url, urlAfterRedirects, state) {
super(id, url);
this.urlAfterRedirects = urlAfterRedirects;
this.state = state;
}
/** @docsNotRequired */
toString() {
return `RoutesRecognized(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
}
};
var GuardsCheckStart = class extends RouterEvent {
urlAfterRedirects;
state;
type = EventType.GuardsCheckStart;
constructor(id, url, urlAfterRedirects, state) {
super(id, url);
this.urlAfterRedirects = urlAfterRedirects;
this.state = state;
}
toString() {
return `GuardsCheckStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
}
};
var GuardsCheckEnd = class extends RouterEvent {
urlAfterRedirects;
state;
shouldActivate;
type = EventType.GuardsCheckEnd;
constructor(id, url, urlAfterRedirects, state, shouldActivate) {
super(id, url);
this.urlAfterRedirects = urlAfterRedirects;
this.state = state;
this.shouldActivate = shouldActivate;
}
toString() {
return `GuardsCheckEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state}, shouldActivate: ${this.shouldActivate})`;
}
};
var ResolveStart = class extends RouterEvent {
urlAfterRedirects;
state;
type = EventType.ResolveStart;
constructor(id, url, urlAfterRedirects, state) {
super(id, url);
this.urlAfterRedirects = urlAfterRedirects;
this.state = state;
}
toString() {
return `ResolveStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
}
};
var ResolveEnd = class extends RouterEvent {
urlAfterRedirects;
state;
type = EventType.ResolveEnd;
constructor(id, url, urlAfterRedirects, state) {
super(id, url);
this.urlAfterRedirects = urlAfterRedirects;
this.state = state;
}
toString() {
return `ResolveEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
}
};
var RouteConfigLoadStart = class {
route;
type = EventType.RouteConfigLoadStart;
constructor(route) {
this.route = route;
}
toString() {
return `RouteConfigLoadStart(path: ${this.route.path})`;
}
};
var RouteConfigLoadEnd = class {
route;
type = EventType.RouteConfigLoadEnd;
constructor(route) {
this.route = route;
}
toString() {
return `RouteConfigLoadEnd(path: ${this.route.path})`;
}
};
var ChildActivationStart = class {
snapshot;
type = EventType.ChildActivationStart;
constructor(snapshot) {
this.snapshot = snapshot;
}
toString() {
const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || "";
return `ChildActivationStart(path: '${path}')`;
}
};
var ChildActivationEnd = class {
snapshot;
type = EventType.ChildActivationEnd;
constructor(snapshot) {
this.snapshot = snapshot;
}
toString() {
const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || "";
return `ChildActivationEnd(path: '${path}')`;
}
};
var ActivationStart = class {
snapshot;
type = EventType.ActivationStart;
constructor(snapshot) {
this.snapshot = snapshot;
}
toString() {
const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || "";
return `ActivationStart(path: '${path}')`;
}
};
var ActivationEnd = class {
snapshot;
type = EventType.ActivationEnd;
constructor(snapshot) {
this.snapshot = snapshot;
}
toString() {
const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || "";
return `ActivationEnd(path: '${path}')`;
}
};
var Scroll = class {
routerEvent;
position;
anchor;
type = EventType.Scroll;
constructor(routerEvent, position, anchor) {
this.routerEvent = routerEvent;
this.position = position;
this.anchor = anchor;
}
toString() {
const pos = this.position ? `${this.position[0]}, ${this.position[1]}` : null;
return `Scroll(anchor: '${this.anchor}', position: '${pos}')`;
}
};
var BeforeActivateRoutes = class {
};
var RedirectRequest = class {
url;
navigationBehaviorOptions;
constructor(url, navigationBehaviorOptions) {
this.url = url;
this.navigationBehaviorOptions = navigationBehaviorOptions;
}
};
function isPublicRouterEvent(e) {
return !(e instanceof BeforeActivateRoutes) && !(e instanceof RedirectRequest);
}
function stringifyEvent(routerEvent) {
switch (routerEvent.type) {
case EventType.ActivationEnd:
return `ActivationEnd(path: '${routerEvent.snapshot.routeConfig?.path || ""}')`;
case EventType.ActivationStart:
return `ActivationStart(path: '${routerEvent.snapshot.routeConfig?.path || ""}')`;
case EventType.ChildActivationEnd:
return `ChildActivationEnd(path: '${routerEvent.snapshot.routeConfig?.path || ""}')`;
case EventType.ChildActivationStart:
return `ChildActivationStart(path: '${routerEvent.snapshot.routeConfig?.path || ""}')`;
case EventType.GuardsCheckEnd:
return `GuardsCheckEnd(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state}, shouldActivate: ${routerEvent.shouldActivate})`;
case EventType.GuardsCheckStart:
return `GuardsCheckStart(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state})`;
case EventType.NavigationCancel:
return `NavigationCancel(id: ${routerEvent.id}, url: '${routerEvent.url}')`;
case EventType.NavigationSkipped:
return `NavigationSkipped(id: ${routerEvent.id}, url: '${routerEvent.url}')`;
case EventType.NavigationEnd:
return `NavigationEnd(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}')`;
case EventType.NavigationError:
return `NavigationError(id: ${routerEvent.id}, url: '${routerEvent.url}', error: ${routerEvent.error})`;
case EventType.NavigationStart:
return `NavigationStart(id: ${routerEvent.id}, url: '${routerEvent.url}')`;
case EventType.ResolveEnd:
return `ResolveEnd(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state})`;
case EventType.ResolveStart:
return `ResolveStart(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state})`;
case EventType.RouteConfigLoadEnd:
return `RouteConfigLoadEnd(path: ${routerEvent.route.path})`;
case EventType.RouteConfigLoadStart:
return `RouteConfigLoadStart(path: ${routerEvent.route.path})`;
case EventType.RoutesRecognized:
return `RoutesRecognized(id: ${routerEvent.id}, url: '${routerEvent.url}', urlAfterRedirects: '${routerEvent.urlAfterRedirects}', state: ${routerEvent.state})`;
case EventType.Scroll:
const pos = routerEvent.position ? `${routerEvent.position[0]}, ${routerEvent.position[1]}` : null;
return `Scroll(anchor: '${routerEvent.anchor}', position: '${pos}')`;
}
}
function getOrCreateRouteInjectorIfNeeded(route, currentInjector) {
if (route.providers && !route._injector) {
route._injector = createEnvironmentInjector(route.providers, currentInjector, `Route: ${route.path}`);
}
return route._injector ?? currentInjector;
}
function validateConfig(config, parentPath = "", requireStandaloneComponents = false) {
for (let i = 0; i < config.length; i++) {
const route = config[i];
const fullPath = getFullPath(parentPath, route);
validateNode(route, fullPath, requireStandaloneComponents);
}
}
function assertStandalone(fullPath, component) {
if (component && isNgModule(component)) {
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}'. You are using 'loadComponent' with a module, but it must be used with standalone components. Use 'loadChildren' instead.`);
} else if (component && !isStandalone(component)) {
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}'. The component must be standalone.`);
}
}
function validateNode(route, fullPath, requireStandaloneComponents) {
if (typeof ngDevMode === "undefined" || ngDevMode) {
if (!route) {
throw new RuntimeError(4014, `
Invalid configuration of route '${fullPath}': Encountered undefined route.
The reason might be an extra comma.
Example:
const routes: Routes = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: 'dashboard', component: DashboardComponent },, << two commas
{ path: 'detail/:id', component: HeroDetailComponent }
];
`);
}
if (Array.isArray(route)) {
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': Array cannot be specified`);
}
if (!route.redirectTo && !route.component && !route.loadComponent && !route.children && !route.loadChildren && route.outlet && route.outlet !== PRIMARY_OUTLET) {
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': a componentless route without children or loadChildren cannot have a named outlet set`);
}
if (route.redirectTo && route.children) {
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': redirectTo and children cannot be used together`);
}
if (route.redirectTo && route.loadChildren) {
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': redirectTo and loadChildren cannot be used together`);
}
if (route.children && route.loadChildren) {
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': children and loadChildren cannot be used together`);
}
if (route.component && route.loadComponent) {
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': component and loadComponent cannot be used together`);
}
if (route.redirectTo) {
if (route.component || route.loadComponent) {
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': redirectTo and component/loadComponent cannot be used together`);
}
if (route.canMatch || route.canActivate) {
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': redirectTo and ${route.canMatch ? "canMatch" : "canActivate"} cannot be used together.Redirects happen before guards are executed.`);
}
}
if (route.path && route.matcher) {
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': path and matcher cannot be used together`);
}
if (route.redirectTo === void 0 && !route.component && !route.loadComponent && !route.children && !route.loadChildren) {
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}'. One of the following must be provided: component, loadComponent, redirectTo, children or loadChildren`);
}
if (route.path === void 0 && route.matcher === void 0) {
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': routes must have either a path or a matcher specified`);
}
if (typeof route.path === "string" && route.path.charAt(0) === "/") {
throw new RuntimeError(4014, `Invalid configuration of route '${fullPath}': path cannot start with a slash`);
}
if (route.path === "" && route.redirectTo !== void 0 && route.pathMatch === void 0) {
const exp = `The default value of 'pathMatch' is 'prefix', but often the intent is to use 'full'.`;
throw new RuntimeError(4014, `Invalid configuration of route '{path: "${fullPath}", redirectTo: "${route.redirectTo}"}': please provide 'pathMatch'. ${exp}`);
}
if (requireStandaloneComponents) {
assertStandalone(fullPath, route.component);
}
}
if (route.children) {
validateConfig(route.children, fullPath, requireStandaloneComponents);
}
}
function getFullPath(parentPath, currentRoute) {
if (!currentRoute) {
return parentPath;
}
if (!parentPath && !currentRoute.path) {
return "";
} else if (parentPath && !currentRoute.path) {
return `${parentPath}/`;
} else if (!parentPath && currentRoute.path) {
return currentRoute.path;
} else {
return `${parentPath}/${currentRoute.path}`;
}
}
function getOutlet(route) {
return route.outlet || PRIMARY_OUTLET;
}
function sortByMatchingOutlets(routes, outletName) {
const sortedConfig = routes.filter((r) => getOutlet(r) === outletName);
sortedConfig.push(...routes.filter((r) => getOutlet(r) !== outletName));
return sortedConfig;
}
function getClosestRouteInjector(snapshot) {
if (!snapshot) return null;
if (snapshot.routeConfig?._injector) {
return snapshot.routeConfig._injector;
}
for (let s = snapshot.parent; s; s = s.parent) {
const route = s.routeConfig;
if (route?._loadedInjector) return route._loadedInjector;
if (route?._injector) return route._injector;
}
return null;
}
var OutletContext = class {
rootInjector;
outlet = null;
route = null;
children;
attachRef = null;
get injector() {
return getClosestRouteInjector(this.route?.snapshot) ?? this.rootInjector;
}
constructor(rootInjector) {
this.rootInjector = rootInjector;
this.children = new ChildrenOutletContexts(this.rootInjector);
}
};
var ChildrenOutletContexts = class _ChildrenOutletContexts {
rootInjector;
// contexts for child outlets, by name.
contexts = /* @__PURE__ */ new Map();
/** @docs-private */
constructor(rootInjector) {
this.rootInjector = rootInjector;
}
/** Called when a `RouterOutlet` directive is instantiated */
onChildOutletCreated(childName, outlet) {
const context = this.getOrCreateContext(childName);
context.outlet = outlet;
this.contexts.set(childName, context);
}
/**
* Called when a `RouterOutlet` directive is destroyed.
* We need to keep the context as the outlet could be destroyed inside a NgIf and might be
* re-created later.
*/
onChildOutletDestroyed(childName) {
const context = this.getContext(childName);
if (context) {
context.outlet = null;
context.attachRef = null;
}
}
/**
* Called when the corresponding route is deactivated during navigation.
* Because the component get destroyed, all children outlet are destroyed.
*/
onOutletDeactivated() {
const contexts = this.contexts;
this.contexts = /* @__PURE__ */ new Map();
return contexts;
}
onOutletReAttached(contexts) {
this.contexts = contexts;
}
getOrCreateContext(childName) {
let context = this.getContext(childName);
if (!context) {
context = new OutletContext(this.rootInjector);
this.contexts.set(childName, context);
}
return context;
}
getContext(childName) {
return this.contexts.get(childName) || null;
}
static ɵfac = function ChildrenOutletContexts_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _ChildrenOutletContexts)(ɵɵinject(EnvironmentInjector));
};
static ɵprov = ɵɵdefineInjectable({
token: _ChildrenOutletContexts,
factory: _ChildrenOutletContexts.ɵfac,
providedIn: "root"
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ChildrenOutletContexts, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], () => [{
type: EnvironmentInjector
}], null);
})();
var Tree = class {
/** @internal */
_root;
constructor(root) {
this._root = root;
}
get root() {
return this._root.value;
}
/**
* @internal
*/
parent(t) {
const p = this.pathFromRoot(t);
return p.length > 1 ? p[p.length - 2] : null;
}
/**
* @internal
*/
children(t) {
const n = findNode(t, this._root);
return n ? n.children.map((t2) => t2.value) : [];
}
/**
* @internal
*/
firstChild(t) {
const n = findNode(t, this._root);
return n && n.children.length > 0 ? n.children[0].value : null;
}
/**
* @internal
*/
siblings(t) {
const p = findPath(t, this._root);
if (p.length < 2) return [];
const c = p[p.length - 2].children.map((c2) => c2.value);
return c.filter((cc) => cc !== t);
}
/**
* @internal
*/
pathFromRoot(t) {
return findPath(t, this._root).map((s) => s.value);
}
};
function findNode(value, node) {
if (value === node.value) return node;
for (const child of node.children) {
const node2 = findNode(value, child);
if (node2) return node2;
}
return null;
}
function findPath(value, node) {
if (value === node.value) return [node];
for (const child of node.children) {
const path = findPath(value, child);
if (path.length) {
path.unshift(node);
return path;
}
}
return [];
}
var TreeNode = class {
value;
children;
constructor(value, children) {
this.value = value;
this.children = children;
}
toString() {
return `TreeNode(${this.value})`;
}
};
function nodeChildrenAsMap(node) {
const map2 = {};
if (node) {
node.children.forEach((child) => map2[child.value.outlet] = child);
}
return map2;
}
var RouterState = class extends Tree {
snapshot;
/** @internal */
constructor(root, snapshot) {
super(root);
this.snapshot = snapshot;
setRouterState(this, root);
}
toString() {
return this.snapshot.toString();
}
};
function createEmptyState(rootComponent) {
const snapshot = createEmptyStateSnapshot(rootComponent);
const emptyUrl = new BehaviorSubject([new UrlSegment("", {})]);
const emptyParams = new BehaviorSubject({});
const emptyData = new BehaviorSubject({});
const emptyQueryParams = new BehaviorSubject({});
const fragment = new BehaviorSubject("");
const activated = new ActivatedRoute(emptyUrl, emptyParams, emptyQueryParams, fragment, emptyData, PRIMARY_OUTLET, rootComponent, snapshot.root);
activated.snapshot = snapshot.root;
return new RouterState(new TreeNode(activated, []), snapshot);
}
function createEmptyStateSnapshot(rootComponent) {
const emptyParams = {};
const emptyData = {};
const emptyQueryParams = {};
const fragment = "";
const activated = new ActivatedRouteSnapshot([], emptyParams, emptyQueryParams, fragment, emptyData, PRIMARY_OUTLET, rootComponent, null, {});
return new RouterStateSnapshot("", new TreeNode(activated, []));
}
var ActivatedRoute = class {
urlSubject;
paramsSubject;
queryParamsSubject;
fragmentSubject;
dataSubject;
outlet;
component;
/** The current snapshot of this route */
snapshot;
/** @internal */
_futureSnapshot;
/** @internal */
_routerState;
/** @internal */
_paramMap;
/** @internal */
_queryParamMap;
/** An Observable of the resolved route title */
title;
/** An observable of the URL segments matched by this route. */
url;
/** An observable of the matrix parameters scoped to this route. */
params;
/** An observable of the query parameters shared by all the routes. */
queryParams;
/** An observable of the URL fragment shared by all the routes. */
fragment;
/** An observable of the static and resolved data of this route. */
data;
/** @internal */
constructor(urlSubject, paramsSubject, queryParamsSubject, fragmentSubject, dataSubject, outlet, component, futureSnapshot) {
this.urlSubject = urlSubject;
this.paramsSubject = paramsSubject;
this.queryParamsSubject = queryParamsSubject;
this.fragmentSubject = fragmentSubject;
this.dataSubject = dataSubject;
this.outlet = outlet;
this.component = component;
this._futureSnapshot = futureSnapshot;
this.title = this.dataSubject?.pipe(map((d) => d[RouteTitleKey])) ?? of(void 0);
this.url = urlSubject;
this.params = paramsSubject;
this.queryParams = queryParamsSubject;
this.fragment = fragmentSubject;
this.data = dataSubject;
}
/** The configuration used to match this route. */
get routeConfig() {
return this._futureSnapshot.routeConfig;
}
/** The root of the router state. */
get root() {
return this._routerState.root;
}
/** The parent of this route in the router state tree. */
get parent() {
return this._routerState.parent(this);
}
/** The first child of this route in the router state tree. */
get firstChild() {
return this._routerState.firstChild(this);
}
/** The children of this route in the router state tree. */
get children() {
return this._routerState.children(this);
}
/** The path from the root of the router state tree to this route. */
get pathFromRoot() {
return this._routerState.pathFromRoot(this);
}
/**
* An Observable that contains a map of the required and optional parameters
* specific to the route.
* The map supports retrieving single and multiple values from the same parameter.
*/
get paramMap() {
this._paramMap ??= this.params.pipe(map((p) => convertToParamMap(p)));
return this._paramMap;
}
/**
* An Observable that contains a map of the query parameters available to all routes.
* The map supports retrieving single and multiple values from the query parameter.
*/
get queryParamMap() {
this._queryParamMap ??= this.queryParams.pipe(map((p) => convertToParamMap(p)));
return this._queryParamMap;
}
toString() {
return this.snapshot ? this.snapshot.toString() : `Future(${this._futureSnapshot})`;
}
};
function getInherited(route, parent, paramsInheritanceStrategy = "emptyOnly") {
let inherited;
const {
routeConfig
} = route;
if (parent !== null && (paramsInheritanceStrategy === "always" || // inherit parent data if route is empty path
routeConfig?.path === "" || // inherit parent data if parent was componentless
!parent.component && !parent.routeConfig?.loadComponent)) {
inherited = {
params: __spreadValues(__spreadValues({}, parent.params), route.params),
data: __spreadValues(__spreadValues({}, parent.data), route.data),
resolve: __spreadValues(__spreadValues(__spreadValues(__spreadValues({}, route.data), parent.data), routeConfig?.data), route._resolvedData)
};
} else {
inherited = {
params: __spreadValues({}, route.params),
data: __spreadValues({}, route.data),
resolve: __spreadValues(__spreadValues({}, route.data), route._resolvedData ?? {})
};
}
if (routeConfig && hasStaticTitle(routeConfig)) {
inherited.resolve[RouteTitleKey] = routeConfig.title;
}
return inherited;
}
var ActivatedRouteSnapshot = class {
url;
params;
queryParams;
fragment;
data;
outlet;
component;
/** The configuration used to match this route **/
routeConfig;
/** @internal */
_resolve;
/** @internal */
_resolvedData;
/** @internal */
_routerState;
/** @internal */
_paramMap;
/** @internal */
_queryParamMap;
/** The resolved route title */
get title() {
return this.data?.[RouteTitleKey];
}
/** @internal */
constructor(url, params, queryParams, fragment, data, outlet, component, routeConfig, resolve) {
this.url = url;
this.params = params;
this.queryParams = queryParams;
this.fragment = fragment;
this.data = data;
this.outlet = outlet;
this.component = component;
this.routeConfig = routeConfig;
this._resolve = resolve;
}
/** The root of the router state */
get root() {
return this._routerState.root;
}
/** The parent of this route in the router state tree */
get parent() {
return this._routerState.parent(this);
}
/** The first child of this route in the router state tree */
get firstChild() {
return this._routerState.firstChild(this);
}
/** The children of this route in the router state tree */
get children() {
return this._routerState.children(this);
}
/** The path from the root of the router state tree to this route */
get pathFromRoot() {
return this._routerState.pathFromRoot(this);
}
get paramMap() {
this._paramMap ??= convertToParamMap(this.params);
return this._paramMap;
}
get queryParamMap() {
this._queryParamMap ??= convertToParamMap(this.queryParams);
return this._queryParamMap;
}
toString() {
const url = this.url.map((segment) => segment.toString()).join("/");
const matched = this.routeConfig ? this.routeConfig.path : "";
return `Route(url:'${url}', path:'${matched}')`;
}
};
var RouterStateSnapshot = class extends Tree {
url;
/** @internal */
constructor(url, root) {
super(root);
this.url = url;
setRouterState(this, root);
}
toString() {
return serializeNode(this._root);
}
};
function setRouterState(state, node) {
node.value._routerState = state;
node.children.forEach((c) => setRouterState(state, c));
}
function serializeNode(node) {
const c = node.children.length > 0 ? ` { ${node.children.map(serializeNode).join(", ")} } ` : "";
return `${node.value}${c}`;
}
function advanceActivatedRoute(route) {
if (route.snapshot) {
const currentSnapshot = route.snapshot;
const nextSnapshot = route._futureSnapshot;
route.snapshot = nextSnapshot;
if (!shallowEqual(currentSnapshot.queryParams, nextSnapshot.queryParams)) {
route.queryParamsSubject.next(nextSnapshot.queryParams);
}
if (currentSnapshot.fragment !== nextSnapshot.fragment) {
route.fragmentSubject.next(nextSnapshot.fragment);
}
if (!shallowEqual(currentSnapshot.params, nextSnapshot.params)) {
route.paramsSubject.next(nextSnapshot.params);
}
if (!shallowEqualArrays(currentSnapshot.url, nextSnapshot.url)) {
route.urlSubject.next(nextSnapshot.url);
}
if (!shallowEqual(currentSnapshot.data, nextSnapshot.data)) {
route.dataSubject.next(nextSnapshot.data);
}
} else {
route.snapshot = route._futureSnapshot;
route.dataSubject.next(route._futureSnapshot.data);
}
}
function equalParamsAndUrlSegments(a, b) {
const equalUrlParams = shallowEqual(a.params, b.params) && equalSegments(a.url, b.url);
const parentsMismatch = !a.parent !== !b.parent;
return equalUrlParams && !parentsMismatch && (!a.parent || equalParamsAndUrlSegments(a.parent, b.parent));
}
function hasStaticTitle(config) {
return typeof config.title === "string" || config.title === null;
}
var ROUTER_OUTLET_DATA = new InjectionToken(ngDevMode ? "RouterOutlet data" : "");
var RouterOutlet = class _RouterOutlet {
activated = null;
/** @internal */
get activatedComponentRef() {
return this.activated;
}
_activatedRoute = null;
/**
* The name of the outlet
*
*/
name = PRIMARY_OUTLET;
activateEvents = new EventEmitter();
deactivateEvents = new EventEmitter();
/**
* Emits an attached component instance when the `RouteReuseStrategy` instructs to re-attach a
* previously detached subtree.
**/
attachEvents = new EventEmitter();
/**
* Emits a detached component instance when the `RouteReuseStrategy` instructs to detach the
* subtree.
*/
detachEvents = new EventEmitter();
/**
* Data that will be provided to the child injector through the `ROUTER_OUTLET_DATA` token.
*
* When unset, the value of the token is `undefined` by default.
*/
routerOutletData = input(void 0, ...ngDevMode ? [{
debugName: "routerOutletData"
}] : []);
parentContexts = inject(ChildrenOutletContexts);
location = inject(ViewContainerRef);
changeDetector = inject(ChangeDetectorRef);
inputBinder = inject(INPUT_BINDER, {
optional: true
});
/** @docs-private */
supportsBindingToComponentInputs = true;
/** @docs-private */
ngOnChanges(changes) {
if (changes["name"]) {
const {
firstChange,
previousValue
} = changes["name"];
if (firstChange) {
return;
}
if (this.isTrackedInParentContexts(previousValue)) {
this.deactivate();
this.parentContexts.onChildOutletDestroyed(previousValue);
}
this.initializeOutletWithName();
}
}
/** @docs-private */
ngOnDestroy() {
if (this.isTrackedInParentContexts(this.name)) {
this.parentContexts.onChildOutletDestroyed(this.name);
}
this.inputBinder?.unsubscribeFromRouteData(this);
}
isTrackedInParentContexts(outletName) {
return this.parentContexts.getContext(outletName)?.outlet === this;
}
/** @docs-private */
ngOnInit() {
this.initializeOutletWithName();
}
initializeOutletWithName() {
this.parentContexts.onChildOutletCreated(this.name, this);
if (this.activated) {
return;
}
const context = this.parentContexts.getContext(this.name);
if (context?.route) {
if (context.attachRef) {
this.attach(context.attachRef, context.route);
} else {
this.activateWith(context.route, context.injector);
}
}
}
get isActivated() {
return !!this.activated;
}
/**
* @returns The currently activated component instance.
* @throws An error if the outlet is not activated.
*/
get component() {
if (!this.activated) throw new RuntimeError(4012, (typeof ngDevMode === "undefined" || ngDevMode) && "Outlet is not activated");
return this.activated.instance;
}
get activatedRoute() {
if (!this.activated) throw new RuntimeError(4012, (typeof ngDevMode === "undefined" || ngDevMode) && "Outlet is not activated");
return this._activatedRoute;
}
get activatedRouteData() {
if (this._activatedRoute) {
return this._activatedRoute.snapshot.data;
}
return {};
}
/**
* Called when the `RouteReuseStrategy` instructs to detach the subtree
*/
detach() {
if (!this.activated) throw new RuntimeError(4012, (typeof ngDevMode === "undefined" || ngDevMode) && "Outlet is not activated");
this.location.detach();
const cmp = this.activated;
this.activated = null;
this._activatedRoute = null;
this.detachEvents.emit(cmp.instance);
return cmp;
}
/**
* Called when the `RouteReuseStrategy` instructs to re-attach a previously detached subtree
*/
attach(ref, activatedRoute) {
this.activated = ref;
this._activatedRoute = activatedRoute;
this.location.insert(ref.hostView);
this.inputBinder?.bindActivatedRouteToOutletComponent(this);
this.attachEvents.emit(ref.instance);
}
deactivate() {
if (this.activated) {
const c = this.component;
this.activated.destroy();
this.activated = null;
this._activatedRoute = null;
this.deactivateEvents.emit(c);
}
}
activateWith(activatedRoute, environmentInjector) {
if (this.isActivated) {
throw new RuntimeError(4013, (typeof ngDevMode === "undefined" || ngDevMode) && "Cannot activate an already activated outlet");
}
this._activatedRoute = activatedRoute;
const location = this.location;
const snapshot = activatedRoute.snapshot;
const component = snapshot.component;
const childContexts = this.parentContexts.getOrCreateContext(this.name).children;
const injector = new OutletInjector(activatedRoute, childContexts, location.injector, this.routerOutletData);
this.activated = location.createComponent(component, {
index: location.length,
injector,
environmentInjector
});
this.changeDetector.markForCheck();
this.inputBinder?.bindActivatedRouteToOutletComponent(this);
this.activateEvents.emit(this.activated.instance);
}
static ɵfac = function RouterOutlet_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _RouterOutlet)();
};
static ɵdir = ɵɵdefineDirective({
type: _RouterOutlet,
selectors: [["router-outlet"]],
inputs: {
name: "name",
routerOutletData: [1, "routerOutletData"]
},
outputs: {
activateEvents: "activate",
deactivateEvents: "deactivate",
attachEvents: "attach",
detachEvents: "detach"
},
exportAs: ["outlet"],
features: [ɵɵNgOnChangesFeature]
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RouterOutlet, [{
type: Directive,
args: [{
selector: "router-outlet",
exportAs: "outlet"
}]
}], null, {
name: [{
type: Input
}],
activateEvents: [{
type: Output,
args: ["activate"]
}],
deactivateEvents: [{
type: Output,
args: ["deactivate"]
}],
attachEvents: [{
type: Output,
args: ["attach"]
}],
detachEvents: [{
type: Output,
args: ["detach"]
}]
});
})();
var OutletInjector = class {
route;
childContexts;
parent;
outletData;
constructor(route, childContexts, parent, outletData) {
this.route = route;
this.childContexts = childContexts;
this.parent = parent;
this.outletData = outletData;
}
get(token, notFoundValue) {
if (token === ActivatedRoute) {
return this.route;
}
if (token === ChildrenOutletContexts) {
return this.childContexts;
}
if (token === ROUTER_OUTLET_DATA) {
return this.outletData;
}
return this.parent.get(token, notFoundValue);
}
};
var INPUT_BINDER = new InjectionToken("");
var RoutedComponentInputBinder = class _RoutedComponentInputBinder {
outletDataSubscriptions = /* @__PURE__ */ new Map();
bindActivatedRouteToOutletComponent(outlet) {
this.unsubscribeFromRouteData(outlet);
this.subscribeToRouteData(outlet);
}
unsubscribeFromRouteData(outlet) {
this.outletDataSubscriptions.get(outlet)?.unsubscribe();
this.outletDataSubscriptions.delete(outlet);
}
subscribeToRouteData(outlet) {
const {
activatedRoute
} = outlet;
const dataSubscription = combineLatest([activatedRoute.queryParams, activatedRoute.params, activatedRoute.data]).pipe(switchMap(([queryParams, params, data], index) => {
data = __spreadValues(__spreadValues(__spreadValues({}, queryParams), params), data);
if (index === 0) {
return of(data);
}
return Promise.resolve(data);
})).subscribe((data) => {
if (!outlet.isActivated || !outlet.activatedComponentRef || outlet.activatedRoute !== activatedRoute || activatedRoute.component === null) {
this.unsubscribeFromRouteData(outlet);
return;
}
const mirror = reflectComponentType(activatedRoute.component);
if (!mirror) {
this.unsubscribeFromRouteData(outlet);
return;
}
for (const {
templateName
} of mirror.inputs) {
outlet.activatedComponentRef.setInput(templateName, data[templateName]);
}
});
this.outletDataSubscriptions.set(outlet, dataSubscription);
}
static ɵfac = function RoutedComponentInputBinder_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _RoutedComponentInputBinder)();
};
static ɵprov = ɵɵdefineInjectable({
token: _RoutedComponentInputBinder,
factory: _RoutedComponentInputBinder.ɵfac
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RoutedComponentInputBinder, [{
type: Injectable
}], null, null);
})();
var ɵEmptyOutletComponent = class _ɵEmptyOutletComponent {
static ɵfac = function ɵEmptyOutletComponent_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _ɵEmptyOutletComponent)();
};
static ɵcmp = ɵɵdefineComponent({
type: _ɵEmptyOutletComponent,
selectors: [["ng-component"]],
exportAs: ["emptyRouterOutlet"],
decls: 1,
vars: 0,
template: function _EmptyOutletComponent_Template(rf, ctx) {
if (rf & 1) {
ɵɵelement(0, "router-outlet");
}
},
dependencies: [RouterOutlet],
encapsulation: 2
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ɵEmptyOutletComponent, [{
type: Component,
args: [{
template: `<router-outlet/>`,
imports: [RouterOutlet],
// Used to avoid component ID collisions with user code.
exportAs: "emptyRouterOutlet"
}]
}], null, null);
})();
function standardizeConfig(r) {
const children = r.children && r.children.map(standardizeConfig);
const c = children ? __spreadProps(__spreadValues({}, r), {
children
}) : __spreadValues({}, r);
if (!c.component && !c.loadComponent && (children || c.loadChildren) && c.outlet && c.outlet !== PRIMARY_OUTLET) {
c.component = ɵEmptyOutletComponent;
}
return c;
}
function createRouterState(routeReuseStrategy, curr, prevState) {
const root = createNode(routeReuseStrategy, curr._root, prevState ? prevState._root : void 0);
return new RouterState(root, curr);
}
function createNode(routeReuseStrategy, curr, prevState) {
if (prevState && routeReuseStrategy.shouldReuseRoute(curr.value, prevState.value.snapshot)) {
const value = prevState.value;
value._futureSnapshot = curr.value;
const children = createOrReuseChildren(routeReuseStrategy, curr, prevState);
return new TreeNode(value, children);
} else {
if (routeReuseStrategy.shouldAttach(curr.value)) {
const detachedRouteHandle = routeReuseStrategy.retrieve(curr.value);
if (detachedRouteHandle !== null) {
const tree2 = detachedRouteHandle.route;
tree2.value._futureSnapshot = curr.value;
tree2.children = curr.children.map((c) => createNode(routeReuseStrategy, c));
return tree2;
}
}
const value = createActivatedRoute(curr.value);
const children = curr.children.map((c) => createNode(routeReuseStrategy, c));
return new TreeNode(value, children);
}
}
function createOrReuseChildren(routeReuseStrategy, curr, prevState) {
return curr.children.map((child) => {
for (const p of prevState.children) {
if (routeReuseStrategy.shouldReuseRoute(child.value, p.value.snapshot)) {
return createNode(routeReuseStrategy, child, p);
}
}
return createNode(routeReuseStrategy, child);
});
}
function createActivatedRoute(c) {
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);
}
var RedirectCommand = class {
redirectTo;
navigationBehaviorOptions;
constructor(redirectTo, navigationBehaviorOptions) {
this.redirectTo = redirectTo;
this.navigationBehaviorOptions = navigationBehaviorOptions;
}
};
var NAVIGATION_CANCELING_ERROR = "ngNavigationCancelingError";
function redirectingNavigationError(urlSerializer, redirect) {
const {
redirectTo,
navigationBehaviorOptions
} = isUrlTree(redirect) ? {
redirectTo: redirect,
navigationBehaviorOptions: void 0
} : redirect;
const error = navigationCancelingError(ngDevMode && `Redirecting to "${urlSerializer.serialize(redirectTo)}"`, NavigationCancellationCode.Redirect);
error.url = redirectTo;
error.navigationBehaviorOptions = navigationBehaviorOptions;
return error;
}
function navigationCancelingError(message, code) {
const error = new Error(`NavigationCancelingError: ${message || ""}`);
error[NAVIGATION_CANCELING_ERROR] = true;
error.cancellationCode = code;
return error;
}
function isRedirectingNavigationCancelingError(error) {
return isNavigationCancelingError(error) && isUrlTree(error.url);
}
function isNavigationCancelingError(error) {
return !!error && error[NAVIGATION_CANCELING_ERROR];
}
var warnedAboutUnsupportedInputBinding = false;
var activateRoutes = (rootContexts, routeReuseStrategy, forwardEvent, inputBindingEnabled) => map((t) => {
new ActivateRoutes(routeReuseStrategy, t.targetRouterState, t.currentRouterState, forwardEvent, inputBindingEnabled).activate(rootContexts);
return t;
});
var ActivateRoutes = class {
routeReuseStrategy;
futureState;
currState;
forwardEvent;
inputBindingEnabled;
constructor(routeReuseStrategy, futureState, currState, forwardEvent, inputBindingEnabled) {
this.routeReuseStrategy = routeReuseStrategy;
this.futureState = futureState;
this.currState = currState;
this.forwardEvent = forwardEvent;
this.inputBindingEnabled = inputBindingEnabled;
}
activate(parentContexts) {
const futureRoot = this.futureState._root;
const currRoot = this.currState ? this.currState._root : null;
this.deactivateChildRoutes(futureRoot, currRoot, parentContexts);
advanceActivatedRoute(this.futureState.root);
this.activateChildRoutes(futureRoot, currRoot, parentContexts);
}
// De-activate the child route that are not re-used for the future state
deactivateChildRoutes(futureNode, currNode, contexts) {
const children = nodeChildrenAsMap(currNode);
futureNode.children.forEach((futureChild) => {
const childOutletName = futureChild.value.outlet;
this.deactivateRoutes(futureChild, children[childOutletName], contexts);
delete children[childOutletName];
});
Object.values(children).forEach((v) => {
this.deactivateRouteAndItsChildren(v, contexts);
});
}
deactivateRoutes(futureNode, currNode, parentContext) {
const future = futureNode.value;
const curr = currNode ? currNode.value : null;
if (future === curr) {
if (future.component) {
const context = parentContext.getContext(future.outlet);
if (context) {
this.deactivateChildRoutes(futureNode, currNode, context.children);
}
} else {
this.deactivateChildRoutes(futureNode, currNode, parentContext);
}
} else {
if (curr) {
this.deactivateRouteAndItsChildren(currNode, parentContext);
}
}
}
deactivateRouteAndItsChildren(route, parentContexts) {
if (route.value.component && this.routeReuseStrategy.shouldDetach(route.value.snapshot)) {
this.detachAndStoreRouteSubtree(route, parentContexts);
} else {
this.deactivateRouteAndOutlet(route, parentContexts);
}
}
detachAndStoreRouteSubtree(route, parentContexts) {
const context = parentContexts.getContext(route.value.outlet);
const contexts = context && route.value.component ? context.children : parentContexts;
const children = nodeChildrenAsMap(route);
for (const treeNode of Object.values(children)) {
this.deactivateRouteAndItsChildren(treeNode, contexts);
}
if (context && context.outlet) {
const componentRef = context.outlet.detach();
const contexts2 = context.children.onOutletDeactivated();
this.routeReuseStrategy.store(route.value.snapshot, {
componentRef,
route,
contexts: contexts2
});
}
}
deactivateRouteAndOutlet(route, parentContexts) {
const context = parentContexts.getContext(route.value.outlet);
const contexts = context && route.value.component ? context.children : parentContexts;
const children = nodeChildrenAsMap(route);
for (const treeNode of Object.values(children)) {
this.deactivateRouteAndItsChildren(treeNode, contexts);
}
if (context) {
if (context.outlet) {
context.outlet.deactivate();
context.children.onOutletDeactivated();
}
context.attachRef = null;
context.route = null;
}
}
activateChildRoutes(futureNode, currNode, contexts) {
const children = nodeChildrenAsMap(currNode);
futureNode.children.forEach((c) => {
this.activateRoutes(c, children[c.value.outlet], contexts);
this.forwardEvent(new ActivationEnd(c.value.snapshot));
});
if (futureNode.children.length) {
this.forwardEvent(new ChildActivationEnd(futureNode.value.snapshot));
}
}
activateRoutes(futureNode, currNode, parentContexts) {
const future = futureNode.value;
const curr = currNode ? currNode.value : null;
advanceActivatedRoute(future);
if (future === curr) {
if (future.component) {
const context = parentContexts.getOrCreateContext(future.outlet);
this.activateChildRoutes(futureNode, currNode, context.children);
} else {
this.activateChildRoutes(futureNode, currNode, parentContexts);
}
} else {
if (future.component) {
const context = parentContexts.getOrCreateContext(future.outlet);
if (this.routeReuseStrategy.shouldAttach(future.snapshot)) {
const stored = this.routeReuseStrategy.retrieve(future.snapshot);
this.routeReuseStrategy.store(future.snapshot, null);
context.children.onOutletReAttached(stored.contexts);
context.attachRef = stored.componentRef;
context.route = stored.route.value;
if (context.outlet) {
context.outlet.attach(stored.componentRef, stored.route.value);
}
advanceActivatedRoute(stored.route.value);
this.activateChildRoutes(futureNode, null, context.children);
} else {
context.attachRef = null;
context.route = future;
if (context.outlet) {
context.outlet.activateWith(future, context.injector);
}
this.activateChildRoutes(futureNode, null, context.children);
}
} else {
this.activateChildRoutes(futureNode, null, parentContexts);
}
}
if (typeof ngDevMode === "undefined" || ngDevMode) {
const context = parentContexts.getOrCreateContext(future.outlet);
const outlet = context.outlet;
if (outlet && this.inputBindingEnabled && !outlet.supportsBindingToComponentInputs && !warnedAboutUnsupportedInputBinding) {
console.warn(`'withComponentInputBinding' feature is enabled but this application is using an outlet that may not support binding to component inputs.`);
warnedAboutUnsupportedInputBinding = true;
}
}
}
};
var CanActivate = class {
path;
route;
constructor(path) {
this.path = path;
this.route = this.path[this.path.length - 1];
}
};
var CanDeactivate = class {
component;
route;
constructor(component, route) {
this.component = component;
this.route = route;
}
};
function getAllRouteGuards(future, curr, parentContexts) {
const futureRoot = future._root;
const currRoot = curr ? curr._root : null;
return getChildRouteGuards(futureRoot, currRoot, parentContexts, [futureRoot.value]);
}
function getCanActivateChild(p) {
const canActivateChild = p.routeConfig ? p.routeConfig.canActivateChild : null;
if (!canActivateChild || canActivateChild.length === 0) return null;
return {
node: p,
guards: canActivateChild
};
}
function getTokenOrFunctionIdentity(tokenOrFunction, injector) {
const NOT_FOUND = Symbol();
const result = injector.get(tokenOrFunction, NOT_FOUND);
if (result === NOT_FOUND) {
if (typeof tokenOrFunction === "function" && !isInjectable(tokenOrFunction)) {
return tokenOrFunction;
} else {
return injector.get(tokenOrFunction);
}
}
return result;
}
function getChildRouteGuards(futureNode, currNode, contexts, futurePath, checks = {
canDeactivateChecks: [],
canActivateChecks: []
}) {
const prevChildren = nodeChildrenAsMap(currNode);
futureNode.children.forEach((c) => {
getRouteGuards(c, prevChildren[c.value.outlet], contexts, futurePath.concat([c.value]), checks);
delete prevChildren[c.value.outlet];
});
Object.entries(prevChildren).forEach(([k, v]) => deactivateRouteAndItsChildren(v, contexts.getContext(k), checks));
return checks;
}
function getRouteGuards(futureNode, currNode, parentContexts, futurePath, checks = {
canDeactivateChecks: [],
canActivateChecks: []
}) {
const future = futureNode.value;
const curr = currNode ? currNode.value : null;
const context = parentContexts ? parentContexts.getContext(futureNode.value.outlet) : null;
if (curr && future.routeConfig === curr.routeConfig) {
const shouldRun = shouldRunGuardsAndResolvers(curr, future, future.routeConfig.runGuardsAndResolvers);
if (shouldRun) {
checks.canActivateChecks.push(new CanActivate(futurePath));
} else {
future.data = curr.data;
future._resolvedData = curr._resolvedData;
}
if (future.component) {
getChildRouteGuards(futureNode, currNode, context ? context.children : null, futurePath, checks);
} else {
getChildRouteGuards(futureNode, currNode, parentContexts, futurePath, checks);
}
if (shouldRun && context && context.outlet && context.outlet.isActivated) {
checks.canDeactivateChecks.push(new CanDeactivate(context.outlet.component, curr));
}
} else {
if (curr) {
deactivateRouteAndItsChildren(currNode, context, checks);
}
checks.canActivateChecks.push(new CanActivate(futurePath));
if (future.component) {
getChildRouteGuards(futureNode, null, context ? context.children : null, futurePath, checks);
} else {
getChildRouteGuards(futureNode, null, parentContexts, futurePath, checks);
}
}
return checks;
}
function shouldRunGuardsAndResolvers(curr, future, mode) {
if (typeof mode === "function") {
return mode(curr, future);
}
switch (mode) {
case "pathParamsChange":
return !equalPath(curr.url, future.url);
case "pathParamsOrQueryParamsChange":
return !equalPath(curr.url, future.url) || !shallowEqual(curr.queryParams, future.queryParams);
case "always":
return true;
case "paramsOrQueryParamsChange":
return !equalParamsAndUrlSegments(curr, future) || !shallowEqual(curr.queryParams, future.queryParams);
case "paramsChange":
default:
return !equalParamsAndUrlSegments(curr, future);
}
}
function deactivateRouteAndItsChildren(route, context, checks) {
const children = nodeChildrenAsMap(route);
const r = route.value;
Object.entries(children).forEach(([childName, node]) => {
if (!r.component) {
deactivateRouteAndItsChildren(node, context, checks);
} else if (context) {
deactivateRouteAndItsChildren(node, context.children.getContext(childName), checks);
} else {
deactivateRouteAndItsChildren(node, null, checks);
}
});
if (!r.component) {
checks.canDeactivateChecks.push(new CanDeactivate(null, r));
} else if (context && context.outlet && context.outlet.isActivated) {
checks.canDeactivateChecks.push(new CanDeactivate(context.outlet.component, r));
} else {
checks.canDeactivateChecks.push(new CanDeactivate(null, r));
}
}
function isFunction(v) {
return typeof v === "function";
}
function isBoolean(v) {
return typeof v === "boolean";
}
function isCanLoad(guard) {
return guard && isFunction(guard.canLoad);
}
function isCanActivate(guard) {
return guard && isFunction(guard.canActivate);
}
function isCanActivateChild(guard) {
return guard && isFunction(guard.canActivateChild);
}
function isCanDeactivate(guard) {
return guard && isFunction(guard.canDeactivate);
}
function isCanMatch(guard) {
return guard && isFunction(guard.canMatch);
}
function isEmptyError(e) {
return e instanceof EmptyError || e?.name === "EmptyError";
}
var INITIAL_VALUE = Symbol("INITIAL_VALUE");
function prioritizedGuardValue() {
return switchMap((obs) => {
return combineLatest(obs.map((o) => o.pipe(take(1), startWith(INITIAL_VALUE)))).pipe(map((results) => {
for (const result of results) {
if (result === true) {
continue;
} else if (result === INITIAL_VALUE) {
return INITIAL_VALUE;
} else if (result === false || isRedirect(result)) {
return result;
}
}
return true;
}), filter((item) => item !== INITIAL_VALUE), take(1));
});
}
function isRedirect(val) {
return isUrlTree(val) || val instanceof RedirectCommand;
}
function checkGuards(injector, forwardEvent) {
return mergeMap((t) => {
const {
targetSnapshot,
currentSnapshot,
guards: {
canActivateChecks,
canDeactivateChecks
}
} = t;
if (canDeactivateChecks.length === 0 && canActivateChecks.length === 0) {
return of(__spreadProps(__spreadValues({}, t), {
guardsResult: true
}));
}
return runCanDeactivateChecks(canDeactivateChecks, targetSnapshot, currentSnapshot, injector).pipe(mergeMap((canDeactivate) => {
return canDeactivate && isBoolean(canDeactivate) ? runCanActivateChecks(targetSnapshot, canActivateChecks, injector, forwardEvent) : of(canDeactivate);
}), map((guardsResult) => __spreadProps(__spreadValues({}, t), {
guardsResult
})));
});
}
function runCanDeactivateChecks(checks, futureRSS, currRSS, injector) {
return from(checks).pipe(mergeMap((check) => runCanDeactivate(check.component, check.route, currRSS, futureRSS, injector)), first((result) => {
return result !== true;
}, true));
}
function runCanActivateChecks(futureSnapshot, checks, injector, forwardEvent) {
return from(checks).pipe(concatMap((check) => {
return concat(fireChildActivationStart(check.route.parent, forwardEvent), fireActivationStart(check.route, forwardEvent), runCanActivateChild(futureSnapshot, check.path, injector), runCanActivate(futureSnapshot, check.route, injector));
}), first((result) => {
return result !== true;
}, true));
}
function fireActivationStart(snapshot, forwardEvent) {
if (snapshot !== null && forwardEvent) {
forwardEvent(new ActivationStart(snapshot));
}
return of(true);
}
function fireChildActivationStart(snapshot, forwardEvent) {
if (snapshot !== null && forwardEvent) {
forwardEvent(new ChildActivationStart(snapshot));
}
return of(true);
}
function runCanActivate(futureRSS, futureARS, injector) {
const canActivate = futureARS.routeConfig ? futureARS.routeConfig.canActivate : null;
if (!canActivate || canActivate.length === 0) return of(true);
const canActivateObservables = canActivate.map((canActivate2) => {
return defer(() => {
const closestInjector = getClosestRouteInjector(futureARS) ?? injector;
const guard = getTokenOrFunctionIdentity(canActivate2, closestInjector);
const guardVal = isCanActivate(guard) ? guard.canActivate(futureARS, futureRSS) : runInInjectionContext(closestInjector, () => guard(futureARS, futureRSS));
return wrapIntoObservable(guardVal).pipe(first());
});
});
return of(canActivateObservables).pipe(prioritizedGuardValue());
}
function runCanActivateChild(futureRSS, path, injector) {
const futureARS = path[path.length - 1];
const canActivateChildGuards = path.slice(0, path.length - 1).reverse().map((p) => getCanActivateChild(p)).filter((_) => _ !== null);
const canActivateChildGuardsMapped = canActivateChildGuards.map((d) => {
return defer(() => {
const guardsMapped = d.guards.map((canActivateChild) => {
const closestInjector = getClosestRouteInjector(d.node) ?? injector;
const guard = getTokenOrFunctionIdentity(canActivateChild, closestInjector);
const guardVal = isCanActivateChild(guard) ? guard.canActivateChild(futureARS, futureRSS) : runInInjectionContext(closestInjector, () => guard(futureARS, futureRSS));
return wrapIntoObservable(guardVal).pipe(first());
});
return of(guardsMapped).pipe(prioritizedGuardValue());
});
});
return of(canActivateChildGuardsMapped).pipe(prioritizedGuardValue());
}
function runCanDeactivate(component, currARS, currRSS, futureRSS, injector) {
const canDeactivate = currARS && currARS.routeConfig ? currARS.routeConfig.canDeactivate : null;
if (!canDeactivate || canDeactivate.length === 0) return of(true);
const canDeactivateObservables = canDeactivate.map((c) => {
const closestInjector = getClosestRouteInjector(currARS) ?? injector;
const guard = getTokenOrFunctionIdentity(c, closestInjector);
const guardVal = isCanDeactivate(guard) ? guard.canDeactivate(component, currARS, currRSS, futureRSS) : runInInjectionContext(closestInjector, () => guard(component, currARS, currRSS, futureRSS));
return wrapIntoObservable(guardVal).pipe(first());
});
return of(canDeactivateObservables).pipe(prioritizedGuardValue());
}
function runCanLoadGuards(injector, route, segments, urlSerializer) {
const canLoad = route.canLoad;
if (canLoad === void 0 || canLoad.length === 0) {
return of(true);
}
const canLoadObservables = canLoad.map((injectionToken) => {
const guard = getTokenOrFunctionIdentity(injectionToken, injector);
const guardVal = isCanLoad(guard) ? guard.canLoad(route, segments) : runInInjectionContext(injector, () => guard(route, segments));
return wrapIntoObservable(guardVal);
});
return of(canLoadObservables).pipe(prioritizedGuardValue(), redirectIfUrlTree(urlSerializer));
}
function redirectIfUrlTree(urlSerializer) {
return pipe(tap((result) => {
if (typeof result === "boolean") return;
throw redirectingNavigationError(urlSerializer, result);
}), map((result) => result === true));
}
function runCanMatchGuards(injector, route, segments, urlSerializer) {
const canMatch = route.canMatch;
if (!canMatch || canMatch.length === 0) return of(true);
const canMatchObservables = canMatch.map((injectionToken) => {
const guard = getTokenOrFunctionIdentity(injectionToken, injector);
const guardVal = isCanMatch(guard) ? guard.canMatch(route, segments) : runInInjectionContext(injector, () => guard(route, segments));
return wrapIntoObservable(guardVal);
});
return of(canMatchObservables).pipe(prioritizedGuardValue(), redirectIfUrlTree(urlSerializer));
}
var NoMatch = class {
segmentGroup;
constructor(segmentGroup) {
this.segmentGroup = segmentGroup || null;
}
};
var AbsoluteRedirect = class extends Error {
urlTree;
constructor(urlTree) {
super();
this.urlTree = urlTree;
}
};
function noMatch$1(segmentGroup) {
return throwError(new NoMatch(segmentGroup));
}
function namedOutletsRedirect(redirectTo) {
return throwError(new RuntimeError(4e3, (typeof ngDevMode === "undefined" || ngDevMode) && `Only absolute redirects can have named outlets. redirectTo: '${redirectTo}'`));
}
function canLoadFails(route) {
return throwError(navigationCancelingError((typeof ngDevMode === "undefined" || ngDevMode) && `Cannot load children because the guard of the route "path: '${route.path}'" returned false`, NavigationCancellationCode.GuardRejected));
}
var ApplyRedirects = class {
urlSerializer;
urlTree;
constructor(urlSerializer, urlTree) {
this.urlSerializer = urlSerializer;
this.urlTree = urlTree;
}
lineralizeSegments(route, urlTree) {
let res = [];
let c = urlTree.root;
while (true) {
res = res.concat(c.segments);
if (c.numberOfChildren === 0) {
return of(res);
}
if (c.numberOfChildren > 1 || !c.children[PRIMARY_OUTLET]) {
return namedOutletsRedirect(`${route.redirectTo}`);
}
c = c.children[PRIMARY_OUTLET];
}
}
applyRedirectCommands(segments, redirectTo, posParams, currentSnapshot, injector) {
return getRedirectResult(redirectTo, currentSnapshot, injector).pipe(map((redirect) => {
if (redirect instanceof UrlTree) {
throw new AbsoluteRedirect(redirect);
}
const newTree = this.applyRedirectCreateUrlTree(redirect, this.urlSerializer.parse(redirect), segments, posParams);
if (redirect[0] === "/") {
throw new AbsoluteRedirect(newTree);
}
return newTree;
}));
}
applyRedirectCreateUrlTree(redirectTo, urlTree, segments, posParams) {
const newRoot = this.createSegmentGroup(redirectTo, urlTree.root, segments, posParams);
return new UrlTree(newRoot, this.createQueryParams(urlTree.queryParams, this.urlTree.queryParams), urlTree.fragment);
}
createQueryParams(redirectToParams, actualParams) {
const res = {};
Object.entries(redirectToParams).forEach(([k, v]) => {
const copySourceValue = typeof v === "string" && v[0] === ":";
if (copySourceValue) {
const sourceName = v.substring(1);
res[k] = actualParams[sourceName];
} else {
res[k] = v;
}
});
return res;
}
createSegmentGroup(redirectTo, group, segments, posParams) {
const updatedSegments = this.createSegments(redirectTo, group.segments, segments, posParams);
let children = {};
Object.entries(group.children).forEach(([name, child]) => {
children[name] = this.createSegmentGroup(redirectTo, child, segments, posParams);
});
return new UrlSegmentGroup(updatedSegments, children);
}
createSegments(redirectTo, redirectToSegments, actualSegments, posParams) {
return redirectToSegments.map((s) => s.path[0] === ":" ? this.findPosParam(redirectTo, s, posParams) : this.findOrReturn(s, actualSegments));
}
findPosParam(redirectTo, redirectToUrlSegment, posParams) {
const pos = posParams[redirectToUrlSegment.path.substring(1)];
if (!pos) throw new RuntimeError(4001, (typeof ngDevMode === "undefined" || ngDevMode) && `Cannot redirect to '${redirectTo}'. Cannot find '${redirectToUrlSegment.path}'.`);
return pos;
}
findOrReturn(redirectToUrlSegment, actualSegments) {
let idx = 0;
for (const s of actualSegments) {
if (s.path === redirectToUrlSegment.path) {
actualSegments.splice(idx);
return s;
}
idx++;
}
return redirectToUrlSegment;
}
};
function getRedirectResult(redirectTo, currentSnapshot, injector) {
if (typeof redirectTo === "string") {
return of(redirectTo);
}
const redirectToFn = redirectTo;
const {
queryParams,
fragment,
routeConfig,
url,
outlet,
params,
data,
title
} = currentSnapshot;
return wrapIntoObservable(runInInjectionContext(injector, () => redirectToFn({
params,
data,
queryParams,
fragment,
routeConfig,
url,
outlet,
title
})));
}
var noMatch = {
matched: false,
consumedSegments: [],
remainingSegments: [],
parameters: {},
positionalParamSegments: {}
};
function matchWithChecks(segmentGroup, route, segments, injector, urlSerializer) {
const result = match(segmentGroup, route, segments);
if (!result.matched) {
return of(result);
}
injector = getOrCreateRouteInjectorIfNeeded(route, injector);
return runCanMatchGuards(injector, route, segments, urlSerializer).pipe(map((v) => v === true ? result : __spreadValues({}, noMatch)));
}
function match(segmentGroup, route, segments) {
if (route.path === "**") {
return createWildcardMatchResult(segments);
}
if (route.path === "") {
if (route.pathMatch === "full" && (segmentGroup.hasChildren() || segments.length > 0)) {
return __spreadValues({}, noMatch);
}
return {
matched: true,
consumedSegments: [],
remainingSegments: segments,
parameters: {},
positionalParamSegments: {}
};
}
const matcher = route.matcher || defaultUrlMatcher;
const res = matcher(segments, segmentGroup, route);
if (!res) return __spreadValues({}, noMatch);
const posParams = {};
Object.entries(res.posParams ?? {}).forEach(([k, v]) => {
posParams[k] = v.path;
});
const parameters = res.consumed.length > 0 ? __spreadValues(__spreadValues({}, posParams), res.consumed[res.consumed.length - 1].parameters) : posParams;
return {
matched: true,
consumedSegments: res.consumed,
remainingSegments: segments.slice(res.consumed.length),
// TODO(atscott): investigate combining parameters and positionalParamSegments
parameters,
positionalParamSegments: res.posParams ?? {}
};
}
function createWildcardMatchResult(segments) {
return {
matched: true,
parameters: segments.length > 0 ? last2(segments).parameters : {},
consumedSegments: segments,
remainingSegments: [],
positionalParamSegments: {}
};
}
function split(segmentGroup, consumedSegments, slicedSegments, config) {
if (slicedSegments.length > 0 && containsEmptyPathMatchesWithNamedOutlets(segmentGroup, slicedSegments, config)) {
const s2 = new UrlSegmentGroup(consumedSegments, createChildrenForEmptyPaths(config, new UrlSegmentGroup(slicedSegments, segmentGroup.children)));
return {
segmentGroup: s2,
slicedSegments: []
};
}
if (slicedSegments.length === 0 && containsEmptyPathMatches(segmentGroup, slicedSegments, config)) {
const s2 = new UrlSegmentGroup(segmentGroup.segments, addEmptyPathsToChildrenIfNeeded(segmentGroup, slicedSegments, config, segmentGroup.children));
return {
segmentGroup: s2,
slicedSegments
};
}
const s = new UrlSegmentGroup(segmentGroup.segments, segmentGroup.children);
return {
segmentGroup: s,
slicedSegments
};
}
function addEmptyPathsToChildrenIfNeeded(segmentGroup, slicedSegments, routes, children) {
const res = {};
for (const r of routes) {
if (emptyPathMatch(segmentGroup, slicedSegments, r) && !children[getOutlet(r)]) {
const s = new UrlSegmentGroup([], {});
res[getOutlet(r)] = s;
}
}
return __spreadValues(__spreadValues({}, children), res);
}
function createChildrenForEmptyPaths(routes, primarySegment) {
const res = {};
res[PRIMARY_OUTLET] = primarySegment;
for (const r of routes) {
if (r.path === "" && getOutlet(r) !== PRIMARY_OUTLET) {
const s = new UrlSegmentGroup([], {});
res[getOutlet(r)] = s;
}
}
return res;
}
function containsEmptyPathMatchesWithNamedOutlets(segmentGroup, slicedSegments, routes) {
return routes.some((r) => emptyPathMatch(segmentGroup, slicedSegments, r) && getOutlet(r) !== PRIMARY_OUTLET);
}
function containsEmptyPathMatches(segmentGroup, slicedSegments, routes) {
return routes.some((r) => emptyPathMatch(segmentGroup, slicedSegments, r));
}
function emptyPathMatch(segmentGroup, slicedSegments, r) {
if ((segmentGroup.hasChildren() || slicedSegments.length > 0) && r.pathMatch === "full") {
return false;
}
return r.path === "";
}
function noLeftoversInUrl(segmentGroup, segments, outlet) {
return segments.length === 0 && !segmentGroup.children[outlet];
}
var NoLeftoversInUrl = class {
};
function recognize$1(injector, configLoader, rootComponentType, config, urlTree, urlSerializer, paramsInheritanceStrategy = "emptyOnly") {
return new Recognizer(injector, configLoader, rootComponentType, config, urlTree, paramsInheritanceStrategy, urlSerializer).recognize();
}
var MAX_ALLOWED_REDIRECTS = 31;
var Recognizer = class {
injector;
configLoader;
rootComponentType;
config;
urlTree;
paramsInheritanceStrategy;
urlSerializer;
applyRedirects;
absoluteRedirectCount = 0;
allowRedirects = true;
constructor(injector, configLoader, rootComponentType, config, urlTree, paramsInheritanceStrategy, urlSerializer) {
this.injector = injector;
this.configLoader = configLoader;
this.rootComponentType = rootComponentType;
this.config = config;
this.urlTree = urlTree;
this.paramsInheritanceStrategy = paramsInheritanceStrategy;
this.urlSerializer = urlSerializer;
this.applyRedirects = new ApplyRedirects(this.urlSerializer, this.urlTree);
}
noMatchError(e) {
return new RuntimeError(4002, typeof ngDevMode === "undefined" || ngDevMode ? `Cannot match any routes. URL Segment: '${e.segmentGroup}'` : `'${e.segmentGroup}'`);
}
recognize() {
const rootSegmentGroup = split(this.urlTree.root, [], [], this.config).segmentGroup;
return this.match(rootSegmentGroup).pipe(map(({
children,
rootSnapshot
}) => {
const rootNode = new TreeNode(rootSnapshot, children);
const routeState = new RouterStateSnapshot("", rootNode);
const tree2 = createUrlTreeFromSnapshot(rootSnapshot, [], this.urlTree.queryParams, this.urlTree.fragment);
tree2.queryParams = this.urlTree.queryParams;
routeState.url = this.urlSerializer.serialize(tree2);
return {
state: routeState,
tree: tree2
};
}));
}
match(rootSegmentGroup) {
const rootSnapshot = new ActivatedRouteSnapshot([], Object.freeze({}), Object.freeze(__spreadValues({}, this.urlTree.queryParams)), this.urlTree.fragment, Object.freeze({}), PRIMARY_OUTLET, this.rootComponentType, null, {});
return this.processSegmentGroup(this.injector, this.config, rootSegmentGroup, PRIMARY_OUTLET, rootSnapshot).pipe(map((children) => {
return {
children,
rootSnapshot
};
}), catchError((e) => {
if (e instanceof AbsoluteRedirect) {
this.urlTree = e.urlTree;
return this.match(e.urlTree.root);
}
if (e instanceof NoMatch) {
throw this.noMatchError(e);
}
throw e;
}));
}
processSegmentGroup(injector, config, segmentGroup, outlet, parentRoute) {
if (segmentGroup.segments.length === 0 && segmentGroup.hasChildren()) {
return this.processChildren(injector, config, segmentGroup, parentRoute);
}
return this.processSegment(injector, config, segmentGroup, segmentGroup.segments, outlet, true, parentRoute).pipe(map((child) => child instanceof TreeNode ? [child] : []));
}
/**
* Matches every child outlet in the `segmentGroup` to a `Route` in the config. Returns `null` if
* we cannot find a match for _any_ of the children.
*
* @param config - The `Routes` to match against
* @param segmentGroup - The `UrlSegmentGroup` whose children need to be matched against the
* config.
*/
processChildren(injector, config, segmentGroup, parentRoute) {
const childOutlets = [];
for (const child of Object.keys(segmentGroup.children)) {
if (child === "primary") {
childOutlets.unshift(child);
} else {
childOutlets.push(child);
}
}
return from(childOutlets).pipe(concatMap((childOutlet) => {
const child = segmentGroup.children[childOutlet];
const sortedConfig = sortByMatchingOutlets(config, childOutlet);
return this.processSegmentGroup(injector, sortedConfig, child, childOutlet, parentRoute);
}), scan((children, outletChildren) => {
children.push(...outletChildren);
return children;
}), defaultIfEmpty(null), last(), mergeMap((children) => {
if (children === null) return noMatch$1(segmentGroup);
const mergedChildren = mergeEmptyPathMatches(children);
if (typeof ngDevMode === "undefined" || ngDevMode) {
checkOutletNameUniqueness(mergedChildren);
}
sortActivatedRouteSnapshots(mergedChildren);
return of(mergedChildren);
}));
}
processSegment(injector, routes, segmentGroup, segments, outlet, allowRedirects, parentRoute) {
return from(routes).pipe(concatMap((r) => {
return this.processSegmentAgainstRoute(r._injector ?? injector, routes, r, segmentGroup, segments, outlet, allowRedirects, parentRoute).pipe(catchError((e) => {
if (e instanceof NoMatch) {
return of(null);
}
throw e;
}));
}), first((x) => !!x), catchError((e) => {
if (isEmptyError(e)) {
if (noLeftoversInUrl(segmentGroup, segments, outlet)) {
return of(new NoLeftoversInUrl());
}
return noMatch$1(segmentGroup);
}
throw e;
}));
}
processSegmentAgainstRoute(injector, routes, route, rawSegment, segments, outlet, allowRedirects, parentRoute) {
if (getOutlet(route) !== outlet && (outlet === PRIMARY_OUTLET || !emptyPathMatch(rawSegment, segments, route))) {
return noMatch$1(rawSegment);
}
if (route.redirectTo === void 0) {
return this.matchSegmentAgainstRoute(injector, rawSegment, route, segments, outlet, parentRoute);
}
if (this.allowRedirects && allowRedirects) {
return this.expandSegmentAgainstRouteUsingRedirect(injector, rawSegment, routes, route, segments, outlet, parentRoute);
}
return noMatch$1(rawSegment);
}
expandSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet, parentRoute) {
const {
matched,
parameters,
consumedSegments,
positionalParamSegments,
remainingSegments
} = match(segmentGroup, route, segments);
if (!matched) return noMatch$1(segmentGroup);
if (typeof route.redirectTo === "string" && route.redirectTo[0] === "/") {
this.absoluteRedirectCount++;
if (this.absoluteRedirectCount > MAX_ALLOWED_REDIRECTS) {
if (ngDevMode) {
throw new RuntimeError(4016, `Detected possible infinite redirect when redirecting from '${this.urlTree}' to '${route.redirectTo}'.
This is currently a dev mode only error but will become a call stack size exceeded error in production in a future major version.`);
}
this.allowRedirects = false;
}
}
const currentSnapshot = new ActivatedRouteSnapshot(segments, parameters, Object.freeze(__spreadValues({}, this.urlTree.queryParams)), this.urlTree.fragment, getData(route), getOutlet(route), route.component ?? route._loadedComponent ?? null, route, getResolve(route));
const inherited = getInherited(currentSnapshot, parentRoute, this.paramsInheritanceStrategy);
currentSnapshot.params = Object.freeze(inherited.params);
currentSnapshot.data = Object.freeze(inherited.data);
const newTree$ = this.applyRedirects.applyRedirectCommands(consumedSegments, route.redirectTo, positionalParamSegments, currentSnapshot, injector);
return newTree$.pipe(switchMap((newTree) => this.applyRedirects.lineralizeSegments(route, newTree)), mergeMap((newSegments) => {
return this.processSegment(injector, routes, segmentGroup, newSegments.concat(remainingSegments), outlet, false, parentRoute);
}));
}
matchSegmentAgainstRoute(injector, rawSegment, route, segments, outlet, parentRoute) {
const matchResult = matchWithChecks(rawSegment, route, segments, injector, this.urlSerializer);
if (route.path === "**") {
rawSegment.children = {};
}
return matchResult.pipe(switchMap((result) => {
if (!result.matched) {
return noMatch$1(rawSegment);
}
injector = route._injector ?? injector;
return this.getChildConfig(injector, route, segments).pipe(switchMap(({
routes: childConfig
}) => {
const childInjector = route._loadedInjector ?? injector;
const {
parameters,
consumedSegments,
remainingSegments
} = result;
const snapshot = new ActivatedRouteSnapshot(consumedSegments, parameters, Object.freeze(__spreadValues({}, this.urlTree.queryParams)), this.urlTree.fragment, getData(route), getOutlet(route), route.component ?? route._loadedComponent ?? null, route, getResolve(route));
const inherited = getInherited(snapshot, parentRoute, this.paramsInheritanceStrategy);
snapshot.params = Object.freeze(inherited.params);
snapshot.data = Object.freeze(inherited.data);
const {
segmentGroup,
slicedSegments
} = split(rawSegment, consumedSegments, remainingSegments, childConfig);
if (slicedSegments.length === 0 && segmentGroup.hasChildren()) {
return this.processChildren(childInjector, childConfig, segmentGroup, snapshot).pipe(map((children) => {
return new TreeNode(snapshot, children);
}));
}
if (childConfig.length === 0 && slicedSegments.length === 0) {
return of(new TreeNode(snapshot, []));
}
const matchedOnOutlet = getOutlet(route) === outlet;
return this.processSegment(childInjector, childConfig, segmentGroup, slicedSegments, matchedOnOutlet ? PRIMARY_OUTLET : outlet, true, snapshot).pipe(map((child) => {
return new TreeNode(snapshot, child instanceof TreeNode ? [child] : []);
}));
}));
}));
}
getChildConfig(injector, route, segments) {
if (route.children) {
return of({
routes: route.children,
injector
});
}
if (route.loadChildren) {
if (route._loadedRoutes !== void 0) {
return of({
routes: route._loadedRoutes,
injector: route._loadedInjector
});
}
return runCanLoadGuards(injector, route, segments, this.urlSerializer).pipe(mergeMap((shouldLoadResult) => {
if (shouldLoadResult) {
return this.configLoader.loadChildren(injector, route).pipe(tap((cfg) => {
route._loadedRoutes = cfg.routes;
route._loadedInjector = cfg.injector;
}));
}
return canLoadFails(route);
}));
}
return of({
routes: [],
injector
});
}
};
function sortActivatedRouteSnapshots(nodes) {
nodes.sort((a, b) => {
if (a.value.outlet === PRIMARY_OUTLET) return -1;
if (b.value.outlet === PRIMARY_OUTLET) return 1;
return a.value.outlet.localeCompare(b.value.outlet);
});
}
function hasEmptyPathConfig(node) {
const config = node.value.routeConfig;
return config && config.path === "";
}
function mergeEmptyPathMatches(nodes) {
const result = [];
const mergedNodes = /* @__PURE__ */ new Set();
for (const node of nodes) {
if (!hasEmptyPathConfig(node)) {
result.push(node);
continue;
}
const duplicateEmptyPathNode = result.find((resultNode) => node.value.routeConfig === resultNode.value.routeConfig);
if (duplicateEmptyPathNode !== void 0) {
duplicateEmptyPathNode.children.push(...node.children);
mergedNodes.add(duplicateEmptyPathNode);
} else {
result.push(node);
}
}
for (const mergedNode of mergedNodes) {
const mergedChildren = mergeEmptyPathMatches(mergedNode.children);
result.push(new TreeNode(mergedNode.value, mergedChildren));
}
return result.filter((n) => !mergedNodes.has(n));
}
function checkOutletNameUniqueness(nodes) {
const names = {};
nodes.forEach((n) => {
const routeWithSameOutletName = names[n.value.outlet];
if (routeWithSameOutletName) {
const p = routeWithSameOutletName.url.map((s) => s.toString()).join("/");
const c = n.value.url.map((s) => s.toString()).join("/");
throw new RuntimeError(4006, (typeof ngDevMode === "undefined" || ngDevMode) && `Two segments cannot have the same outlet name: '${p}' and '${c}'.`);
}
names[n.value.outlet] = n.value;
});
}
function getData(route) {
return route.data || {};
}
function getResolve(route) {
return route.resolve || {};
}
function recognize(injector, configLoader, rootComponentType, config, serializer, paramsInheritanceStrategy) {
return mergeMap((t) => recognize$1(injector, configLoader, rootComponentType, config, t.extractedUrl, serializer, paramsInheritanceStrategy).pipe(map(({
state: targetSnapshot,
tree: urlAfterRedirects
}) => {
return __spreadProps(__spreadValues({}, t), {
targetSnapshot,
urlAfterRedirects
});
})));
}
function resolveData(paramsInheritanceStrategy, injector) {
return mergeMap((t) => {
const {
targetSnapshot,
guards: {
canActivateChecks
}
} = t;
if (!canActivateChecks.length) {
return of(t);
}
const routesWithResolversToRun = new Set(canActivateChecks.map((check) => check.route));
const routesNeedingDataUpdates = /* @__PURE__ */ new Set();
for (const route of routesWithResolversToRun) {
if (routesNeedingDataUpdates.has(route)) {
continue;
}
for (const newRoute of flattenRouteTree(route)) {
routesNeedingDataUpdates.add(newRoute);
}
}
let routesProcessed = 0;
return from(routesNeedingDataUpdates).pipe(concatMap((route) => {
if (routesWithResolversToRun.has(route)) {
return runResolve(route, targetSnapshot, paramsInheritanceStrategy, injector);
} else {
route.data = getInherited(route, route.parent, paramsInheritanceStrategy).resolve;
return of(void 0);
}
}), tap(() => routesProcessed++), takeLast(1), mergeMap((_) => routesProcessed === routesNeedingDataUpdates.size ? of(t) : EMPTY));
});
}
function flattenRouteTree(route) {
const descendants = route.children.map((child) => flattenRouteTree(child)).flat();
return [route, ...descendants];
}
function runResolve(futureARS, futureRSS, paramsInheritanceStrategy, injector) {
const config = futureARS.routeConfig;
const resolve = futureARS._resolve;
if (config?.title !== void 0 && !hasStaticTitle(config)) {
resolve[RouteTitleKey] = config.title;
}
return defer(() => {
futureARS.data = getInherited(futureARS, futureARS.parent, paramsInheritanceStrategy).resolve;
return resolveNode(resolve, futureARS, futureRSS, injector).pipe(map((resolvedData) => {
futureARS._resolvedData = resolvedData;
futureARS.data = __spreadValues(__spreadValues({}, futureARS.data), resolvedData);
return null;
}));
});
}
function resolveNode(resolve, futureARS, futureRSS, injector) {
const keys = getDataKeys(resolve);
if (keys.length === 0) {
return of({});
}
const data = {};
return from(keys).pipe(mergeMap((key) => getResolver(resolve[key], futureARS, futureRSS, injector).pipe(first(), tap((value) => {
if (value instanceof RedirectCommand) {
throw redirectingNavigationError(new DefaultUrlSerializer(), value);
}
data[key] = value;
}))), takeLast(1), map(() => data), catchError((e) => isEmptyError(e) ? EMPTY : throwError(e)));
}
function getResolver(injectionToken, futureARS, futureRSS, injector) {
const closestInjector = getClosestRouteInjector(futureARS) ?? injector;
const resolver = getTokenOrFunctionIdentity(injectionToken, closestInjector);
const resolverValue = resolver.resolve ? resolver.resolve(futureARS, futureRSS) : runInInjectionContext(closestInjector, () => resolver(futureARS, futureRSS));
return wrapIntoObservable(resolverValue);
}
function switchTap(next) {
return switchMap((v) => {
const nextResult = next(v);
if (nextResult) {
return from(nextResult).pipe(map(() => v));
}
return of(v);
});
}
var TitleStrategy = class _TitleStrategy {
/**
* @returns The `title` of the deepest primary route.
*/
buildTitle(snapshot) {
let pageTitle;
let route = snapshot.root;
while (route !== void 0) {
pageTitle = this.getResolvedTitleForRoute(route) ?? pageTitle;
route = route.children.find((child) => child.outlet === PRIMARY_OUTLET);
}
return pageTitle;
}
/**
* Given an `ActivatedRouteSnapshot`, returns the final value of the
* `Route.title` property, which can either be a static string or a resolved value.
*/
getResolvedTitleForRoute(snapshot) {
return snapshot.data[RouteTitleKey];
}
static ɵfac = function TitleStrategy_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _TitleStrategy)();
};
static ɵprov = ɵɵdefineInjectable({
token: _TitleStrategy,
factory: () => (() => inject(DefaultTitleStrategy))(),
providedIn: "root"
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(TitleStrategy, [{
type: Injectable,
args: [{
providedIn: "root",
useFactory: () => inject(DefaultTitleStrategy)
}]
}], null, null);
})();
var DefaultTitleStrategy = class _DefaultTitleStrategy extends TitleStrategy {
title;
constructor(title) {
super();
this.title = title;
}
/**
* Sets the title of the browser to the given value.
*
* @param title The `pageTitle` from the deepest primary route.
*/
updateTitle(snapshot) {
const title = this.buildTitle(snapshot);
if (title !== void 0) {
this.title.setTitle(title);
}
}
static ɵfac = function DefaultTitleStrategy_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _DefaultTitleStrategy)(ɵɵinject(Title));
};
static ɵprov = ɵɵdefineInjectable({
token: _DefaultTitleStrategy,
factory: _DefaultTitleStrategy.ɵfac,
providedIn: "root"
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(DefaultTitleStrategy, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], () => [{
type: Title
}], null);
})();
var ROUTER_CONFIGURATION = new InjectionToken(typeof ngDevMode === "undefined" || ngDevMode ? "router config" : "", {
providedIn: "root",
factory: () => ({})
});
var ROUTES = new InjectionToken(ngDevMode ? "ROUTES" : "");
var RouterConfigLoader = class _RouterConfigLoader {
componentLoaders = /* @__PURE__ */ new WeakMap();
childrenLoaders = /* @__PURE__ */ new WeakMap();
onLoadStartListener;
onLoadEndListener;
compiler = inject(Compiler);
loadComponent(injector, route) {
if (this.componentLoaders.get(route)) {
return this.componentLoaders.get(route);
} else if (route._loadedComponent) {
return of(route._loadedComponent);
}
if (this.onLoadStartListener) {
this.onLoadStartListener(route);
}
const loadRunner = wrapIntoObservable(runInInjectionContext(injector, () => route.loadComponent())).pipe(map(maybeUnwrapDefaultExport), switchMap(maybeResolveResources), tap((component) => {
if (this.onLoadEndListener) {
this.onLoadEndListener(route);
}
(typeof ngDevMode === "undefined" || ngDevMode) && assertStandalone(route.path ?? "", component);
route._loadedComponent = component;
}), finalize(() => {
this.componentLoaders.delete(route);
}));
const loader = new ConnectableObservable(loadRunner, () => new Subject()).pipe(refCount());
this.componentLoaders.set(route, loader);
return loader;
}
loadChildren(parentInjector, route) {
if (this.childrenLoaders.get(route)) {
return this.childrenLoaders.get(route);
} else if (route._loadedRoutes) {
return of({
routes: route._loadedRoutes,
injector: route._loadedInjector
});
}
if (this.onLoadStartListener) {
this.onLoadStartListener(route);
}
const moduleFactoryOrRoutes$ = loadChildren(route, this.compiler, parentInjector, this.onLoadEndListener);
const loadRunner = moduleFactoryOrRoutes$.pipe(finalize(() => {
this.childrenLoaders.delete(route);
}));
const loader = new ConnectableObservable(loadRunner, () => new Subject()).pipe(refCount());
this.childrenLoaders.set(route, loader);
return loader;
}
static ɵfac = function RouterConfigLoader_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _RouterConfigLoader)();
};
static ɵprov = ɵɵdefineInjectable({
token: _RouterConfigLoader,
factory: _RouterConfigLoader.ɵfac,
providedIn: "root"
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RouterConfigLoader, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], null, null);
})();
function loadChildren(route, compiler, parentInjector, onLoadEndListener) {
return wrapIntoObservable(runInInjectionContext(parentInjector, () => route.loadChildren())).pipe(map(maybeUnwrapDefaultExport), switchMap(maybeResolveResources), mergeMap((t) => {
if (t instanceof NgModuleFactory$1 || Array.isArray(t)) {
return of(t);
} else {
return from(compiler.compileModuleAsync(t));
}
}), map((factoryOrRoutes) => {
if (onLoadEndListener) {
onLoadEndListener(route);
}
let injector;
let rawRoutes;
let requireStandaloneComponents = false;
if (Array.isArray(factoryOrRoutes)) {
rawRoutes = factoryOrRoutes;
requireStandaloneComponents = true;
} else {
injector = factoryOrRoutes.create(parentInjector).injector;
rawRoutes = injector.get(ROUTES, [], {
optional: true,
self: true
}).flat();
}
const routes = rawRoutes.map(standardizeConfig);
(typeof ngDevMode === "undefined" || ngDevMode) && validateConfig(routes, route.path, requireStandaloneComponents);
return {
routes,
injector
};
}));
}
function isWrappedDefaultExport(value) {
return value && typeof value === "object" && "default" in value;
}
function maybeUnwrapDefaultExport(input2) {
return isWrappedDefaultExport(input2) ? input2["default"] : input2;
}
function maybeResolveResources(value) {
if (false) {
return resolveComponentResources(fetch).catch((error) => {
console.error(error);
return Promise.resolve();
}).then(() => value);
}
return of(value);
}
var UrlHandlingStrategy = class _UrlHandlingStrategy {
static ɵfac = function UrlHandlingStrategy_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _UrlHandlingStrategy)();
};
static ɵprov = ɵɵdefineInjectable({
token: _UrlHandlingStrategy,
factory: () => (() => inject(DefaultUrlHandlingStrategy))(),
providedIn: "root"
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(UrlHandlingStrategy, [{
type: Injectable,
args: [{
providedIn: "root",
useFactory: () => inject(DefaultUrlHandlingStrategy)
}]
}], null, null);
})();
var DefaultUrlHandlingStrategy = class _DefaultUrlHandlingStrategy {
shouldProcessUrl(url) {
return true;
}
extract(url) {
return url;
}
merge(newUrlPart, wholeUrl) {
return newUrlPart;
}
static ɵfac = function DefaultUrlHandlingStrategy_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _DefaultUrlHandlingStrategy)();
};
static ɵprov = ɵɵdefineInjectable({
token: _DefaultUrlHandlingStrategy,
factory: _DefaultUrlHandlingStrategy.ɵfac,
providedIn: "root"
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(DefaultUrlHandlingStrategy, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], null, null);
})();
var CREATE_VIEW_TRANSITION = new InjectionToken(ngDevMode ? "view transition helper" : "");
var VIEW_TRANSITION_OPTIONS = new InjectionToken(ngDevMode ? "view transition options" : "");
function createViewTransition(injector, from2, to) {
const transitionOptions = injector.get(VIEW_TRANSITION_OPTIONS);
const document = injector.get(DOCUMENT);
if (!document.startViewTransition || transitionOptions.skipNextTransition) {
transitionOptions.skipNextTransition = false;
return new Promise((resolve) => setTimeout(resolve));
}
let resolveViewTransitionStarted;
const viewTransitionStarted = new Promise((resolve) => {
resolveViewTransitionStarted = resolve;
});
const transition = document.startViewTransition(() => {
resolveViewTransitionStarted();
return createRenderPromise(injector);
});
transition.ready.catch((error) => {
if (typeof ngDevMode === "undefined" || ngDevMode) {
console.error(error);
}
});
const {
onViewTransitionCreated
} = transitionOptions;
if (onViewTransitionCreated) {
runInInjectionContext(injector, () => onViewTransitionCreated({
transition,
from: from2,
to
}));
}
return viewTransitionStarted;
}
function createRenderPromise(injector) {
return new Promise((resolve) => {
afterNextRender({
read: () => setTimeout(resolve)
}, {
injector
});
});
}
var NAVIGATION_ERROR_HANDLER = new InjectionToken(typeof ngDevMode === "undefined" || ngDevMode ? "navigation error handler" : "");
var NavigationTransitions = class _NavigationTransitions {
// Some G3 targets expect the navigation object to be mutated (and not getting a new reference on changes).
currentNavigation = signal(null, ...ngDevMode ? [{
debugName: "currentNavigation",
equal: () => false
}] : [{
equal: () => false
}]);
currentTransition = null;
lastSuccessfulNavigation = null;
/**
* These events are used to communicate back to the Router about the state of the transition. The
* Router wants to respond to these events in various ways. Because the `NavigationTransition`
* class is not public, this event subject is not publicly exposed.
*/
events = new Subject();
/**
* Used to abort the current transition with an error.
*/
transitionAbortWithErrorSubject = new Subject();
configLoader = inject(RouterConfigLoader);
environmentInjector = inject(EnvironmentInjector);
destroyRef = inject(DestroyRef);
urlSerializer = inject(UrlSerializer);
rootContexts = inject(ChildrenOutletContexts);
location = inject(Location);
inputBindingEnabled = inject(INPUT_BINDER, {
optional: true
}) !== null;
titleStrategy = inject(TitleStrategy);
options = inject(ROUTER_CONFIGURATION, {
optional: true
}) || {};
paramsInheritanceStrategy = this.options.paramsInheritanceStrategy || "emptyOnly";
urlHandlingStrategy = inject(UrlHandlingStrategy);
createViewTransition = inject(CREATE_VIEW_TRANSITION, {
optional: true
});
navigationErrorHandler = inject(NAVIGATION_ERROR_HANDLER, {
optional: true
});
navigationId = 0;
get hasRequestedNavigation() {
return this.navigationId !== 0;
}
transitions;
/**
* Hook that enables you to pause navigation after the preactivation phase.
* Used by `RouterModule`.
*
* @internal
*/
afterPreactivation = () => of(void 0);
/** @internal */
rootComponentType = null;
destroyed = false;
constructor() {
const onLoadStart = (r) => this.events.next(new RouteConfigLoadStart(r));
const onLoadEnd = (r) => this.events.next(new RouteConfigLoadEnd(r));
this.configLoader.onLoadEndListener = onLoadEnd;
this.configLoader.onLoadStartListener = onLoadStart;
this.destroyRef.onDestroy(() => {
this.destroyed = true;
});
}
complete() {
this.transitions?.complete();
}
handleNavigationRequest(request) {
const id = ++this.navigationId;
untracked(() => {
this.transitions?.next(__spreadProps(__spreadValues({}, request), {
extractedUrl: this.urlHandlingStrategy.extract(request.rawUrl),
targetSnapshot: null,
targetRouterState: null,
guards: {
canActivateChecks: [],
canDeactivateChecks: []
},
guardsResult: null,
abortController: new AbortController(),
id
}));
});
}
setupNavigations(router) {
this.transitions = new BehaviorSubject(null);
return this.transitions.pipe(
filter((t) => t !== null),
// Using switchMap so we cancel executing navigations when a new one comes in
switchMap((overallTransitionState) => {
let completedOrAborted = false;
return of(overallTransitionState).pipe(
switchMap((t) => {
if (this.navigationId > overallTransitionState.id) {
const cancellationReason = typeof ngDevMode === "undefined" || ngDevMode ? `Navigation ID ${overallTransitionState.id} is not equal to the current navigation id ${this.navigationId}` : "";
this.cancelNavigationTransition(overallTransitionState, cancellationReason, NavigationCancellationCode.SupersededByNewNavigation);
return EMPTY;
}
this.currentTransition = overallTransitionState;
this.currentNavigation.set({
id: t.id,
initialUrl: t.rawUrl,
extractedUrl: t.extractedUrl,
targetBrowserUrl: typeof t.extras.browserUrl === "string" ? this.urlSerializer.parse(t.extras.browserUrl) : t.extras.browserUrl,
trigger: t.source,
extras: t.extras,
previousNavigation: !this.lastSuccessfulNavigation ? null : __spreadProps(__spreadValues({}, this.lastSuccessfulNavigation), {
previousNavigation: null
}),
abort: () => t.abortController.abort()
});
const urlTransition = !router.navigated || this.isUpdatingInternalState() || this.isUpdatedBrowserUrl();
const onSameUrlNavigation = t.extras.onSameUrlNavigation ?? router.onSameUrlNavigation;
if (!urlTransition && onSameUrlNavigation !== "reload") {
const reason = typeof ngDevMode === "undefined" || ngDevMode ? `Navigation to ${t.rawUrl} was ignored because it is the same as the current Router URL.` : "";
this.events.next(new NavigationSkipped(t.id, this.urlSerializer.serialize(t.rawUrl), reason, NavigationSkippedCode.IgnoredSameUrlNavigation));
t.resolve(false);
return EMPTY;
}
if (this.urlHandlingStrategy.shouldProcessUrl(t.rawUrl)) {
return of(t).pipe(
// Fire NavigationStart event
switchMap((t2) => {
this.events.next(new NavigationStart(t2.id, this.urlSerializer.serialize(t2.extractedUrl), t2.source, t2.restoredState));
if (t2.id !== this.navigationId) {
return EMPTY;
}
return Promise.resolve(t2);
}),
// Recognize
recognize(this.environmentInjector, this.configLoader, this.rootComponentType, router.config, this.urlSerializer, this.paramsInheritanceStrategy),
// Update URL if in `eager` update mode
tap((t2) => {
overallTransitionState.targetSnapshot = t2.targetSnapshot;
overallTransitionState.urlAfterRedirects = t2.urlAfterRedirects;
this.currentNavigation.update((nav) => {
nav.finalUrl = t2.urlAfterRedirects;
return nav;
});
const routesRecognized = new RoutesRecognized(t2.id, this.urlSerializer.serialize(t2.extractedUrl), this.urlSerializer.serialize(t2.urlAfterRedirects), t2.targetSnapshot);
this.events.next(routesRecognized);
})
);
} else if (urlTransition && this.urlHandlingStrategy.shouldProcessUrl(t.currentRawUrl)) {
const {
id,
extractedUrl,
source,
restoredState,
extras
} = t;
const navStart = new NavigationStart(id, this.urlSerializer.serialize(extractedUrl), source, restoredState);
this.events.next(navStart);
const targetSnapshot = createEmptyState(this.rootComponentType).snapshot;
this.currentTransition = overallTransitionState = __spreadProps(__spreadValues({}, t), {
targetSnapshot,
urlAfterRedirects: extractedUrl,
extras: __spreadProps(__spreadValues({}, extras), {
skipLocationChange: false,
replaceUrl: false
})
});
this.currentNavigation.update((nav) => {
nav.finalUrl = extractedUrl;
return nav;
});
return of(overallTransitionState);
} else {
const reason = typeof ngDevMode === "undefined" || ngDevMode ? `Navigation was ignored because the UrlHandlingStrategy indicated neither the current URL ${t.currentRawUrl} nor target URL ${t.rawUrl} should be processed.` : "";
this.events.next(new NavigationSkipped(t.id, this.urlSerializer.serialize(t.extractedUrl), reason, NavigationSkippedCode.IgnoredByUrlHandlingStrategy));
t.resolve(false);
return EMPTY;
}
}),
// --- GUARDS ---
tap((t) => {
const guardsStart = new GuardsCheckStart(t.id, this.urlSerializer.serialize(t.extractedUrl), this.urlSerializer.serialize(t.urlAfterRedirects), t.targetSnapshot);
this.events.next(guardsStart);
}),
map((t) => {
this.currentTransition = overallTransitionState = __spreadProps(__spreadValues({}, t), {
guards: getAllRouteGuards(t.targetSnapshot, t.currentSnapshot, this.rootContexts)
});
return overallTransitionState;
}),
checkGuards(this.environmentInjector, (evt) => this.events.next(evt)),
tap((t) => {
overallTransitionState.guardsResult = t.guardsResult;
if (t.guardsResult && typeof t.guardsResult !== "boolean") {
throw redirectingNavigationError(this.urlSerializer, t.guardsResult);
}
const guardsEnd = new GuardsCheckEnd(t.id, this.urlSerializer.serialize(t.extractedUrl), this.urlSerializer.serialize(t.urlAfterRedirects), t.targetSnapshot, !!t.guardsResult);
this.events.next(guardsEnd);
}),
filter((t) => {
if (!t.guardsResult) {
this.cancelNavigationTransition(t, "", NavigationCancellationCode.GuardRejected);
return false;
}
return true;
}),
// --- RESOLVE ---
switchTap((t) => {
if (t.guards.canActivateChecks.length === 0) {
return void 0;
}
return of(t).pipe(tap((t2) => {
const resolveStart = new ResolveStart(t2.id, this.urlSerializer.serialize(t2.extractedUrl), this.urlSerializer.serialize(t2.urlAfterRedirects), t2.targetSnapshot);
this.events.next(resolveStart);
}), switchMap((t2) => {
let dataResolved = false;
return of(t2).pipe(resolveData(this.paramsInheritanceStrategy, this.environmentInjector), tap({
next: () => dataResolved = true,
complete: () => {
if (!dataResolved) {
this.cancelNavigationTransition(t2, typeof ngDevMode === "undefined" || ngDevMode ? `At least one route resolver didn't emit any value.` : "", NavigationCancellationCode.NoDataFromResolver);
}
}
}));
}), tap((t2) => {
const resolveEnd = new ResolveEnd(t2.id, this.urlSerializer.serialize(t2.extractedUrl), this.urlSerializer.serialize(t2.urlAfterRedirects), t2.targetSnapshot);
this.events.next(resolveEnd);
}));
}),
// --- LOAD COMPONENTS ---
switchTap((t) => {
const loadComponents = (route) => {
const loaders = [];
if (route.routeConfig?.loadComponent) {
const injector = getClosestRouteInjector(route) ?? this.environmentInjector;
loaders.push(this.configLoader.loadComponent(injector, route.routeConfig).pipe(tap((loadedComponent) => {
route.component = loadedComponent;
}), map(() => void 0)));
}
for (const child of route.children) {
loaders.push(...loadComponents(child));
}
return loaders;
};
return combineLatest(loadComponents(t.targetSnapshot.root)).pipe(defaultIfEmpty(null), take(1));
}),
switchTap(() => this.afterPreactivation()),
switchMap(() => {
const {
currentSnapshot,
targetSnapshot
} = overallTransitionState;
const viewTransitionStarted = this.createViewTransition?.(this.environmentInjector, currentSnapshot.root, targetSnapshot.root);
return viewTransitionStarted ? from(viewTransitionStarted).pipe(map(() => overallTransitionState)) : of(overallTransitionState);
}),
map((t) => {
const targetRouterState = createRouterState(router.routeReuseStrategy, t.targetSnapshot, t.currentRouterState);
this.currentTransition = overallTransitionState = __spreadProps(__spreadValues({}, t), {
targetRouterState
});
this.currentNavigation.update((nav) => {
nav.targetRouterState = targetRouterState;
return nav;
});
return overallTransitionState;
}),
tap(() => {
this.events.next(new BeforeActivateRoutes());
}),
activateRoutes(this.rootContexts, router.routeReuseStrategy, (evt) => this.events.next(evt), this.inputBindingEnabled),
// Ensure that if some observable used to drive the transition doesn't
// complete, the navigation still finalizes This should never happen, but
// this is done as a safety measure to avoid surfacing this error (#49567).
take(1),
takeUntil(new Observable((subscriber) => {
const abortSignal = overallTransitionState.abortController.signal;
const handler = () => subscriber.next();
abortSignal.addEventListener("abort", handler);
return () => abortSignal.removeEventListener("abort", handler);
}).pipe(
// Ignore aborts if we are already completed, canceled, or are in the activation stage (we have targetRouterState)
filter(() => !completedOrAborted && !overallTransitionState.targetRouterState),
tap(() => {
this.cancelNavigationTransition(overallTransitionState, overallTransitionState.abortController.signal.reason + "", NavigationCancellationCode.Aborted);
})
)),
tap({
next: (t) => {
completedOrAborted = true;
this.lastSuccessfulNavigation = untracked(this.currentNavigation);
this.events.next(new NavigationEnd(t.id, this.urlSerializer.serialize(t.extractedUrl), this.urlSerializer.serialize(t.urlAfterRedirects)));
this.titleStrategy?.updateTitle(t.targetRouterState.snapshot);
t.resolve(true);
},
complete: () => {
completedOrAborted = true;
}
}),
// There used to be a lot more logic happening directly within the
// transition Observable. Some of this logic has been refactored out to
// other places but there may still be errors that happen there. This gives
// us a way to cancel the transition from the outside. This may also be
// required in the future to support something like the abort signal of the
// Navigation API where the navigation gets aborted from outside the
// transition.
takeUntil(this.transitionAbortWithErrorSubject.pipe(tap((err) => {
throw err;
}))),
finalize(() => {
if (!completedOrAborted) {
const cancelationReason = typeof ngDevMode === "undefined" || ngDevMode ? `Navigation ID ${overallTransitionState.id} is not equal to the current navigation id ${this.navigationId}` : "";
this.cancelNavigationTransition(overallTransitionState, cancelationReason, NavigationCancellationCode.SupersededByNewNavigation);
}
if (this.currentTransition?.id === overallTransitionState.id) {
this.currentNavigation.set(null);
this.currentTransition = null;
}
}),
catchError((e) => {
if (this.destroyed) {
overallTransitionState.resolve(false);
return EMPTY;
}
completedOrAborted = true;
if (isNavigationCancelingError(e)) {
this.events.next(new NavigationCancel(overallTransitionState.id, this.urlSerializer.serialize(overallTransitionState.extractedUrl), e.message, e.cancellationCode));
if (!isRedirectingNavigationCancelingError(e)) {
overallTransitionState.resolve(false);
} else {
this.events.next(new RedirectRequest(e.url, e.navigationBehaviorOptions));
}
} else {
const navigationError = new NavigationError(overallTransitionState.id, this.urlSerializer.serialize(overallTransitionState.extractedUrl), e, overallTransitionState.targetSnapshot ?? void 0);
try {
const navigationErrorHandlerResult = runInInjectionContext(this.environmentInjector, () => this.navigationErrorHandler?.(navigationError));
if (navigationErrorHandlerResult instanceof RedirectCommand) {
const {
message,
cancellationCode
} = redirectingNavigationError(this.urlSerializer, navigationErrorHandlerResult);
this.events.next(new NavigationCancel(overallTransitionState.id, this.urlSerializer.serialize(overallTransitionState.extractedUrl), message, cancellationCode));
this.events.next(new RedirectRequest(navigationErrorHandlerResult.redirectTo, navigationErrorHandlerResult.navigationBehaviorOptions));
} else {
this.events.next(navigationError);
throw e;
}
} catch (ee) {
if (this.options.resolveNavigationPromiseOnError) {
overallTransitionState.resolve(false);
} else {
overallTransitionState.reject(ee);
}
}
}
return EMPTY;
})
);
})
);
}
cancelNavigationTransition(t, reason, code) {
const navCancel = new NavigationCancel(t.id, this.urlSerializer.serialize(t.extractedUrl), reason, code);
this.events.next(navCancel);
t.resolve(false);
}
/**
* @returns Whether we're navigating to somewhere that is not what the Router is
* currently set to.
*/
isUpdatingInternalState() {
return this.currentTransition?.extractedUrl.toString() !== this.currentTransition?.currentUrlTree.toString();
}
/**
* @returns Whether we're updating the browser URL to something new (navigation is going
* to somewhere not displayed in the URL bar and we will update the URL
* bar if navigation succeeds).
*/
isUpdatedBrowserUrl() {
const currentBrowserUrl = this.urlHandlingStrategy.extract(this.urlSerializer.parse(this.location.path(true)));
const currentNavigation = untracked(this.currentNavigation);
const targetBrowserUrl = currentNavigation?.targetBrowserUrl ?? currentNavigation?.extractedUrl;
return currentBrowserUrl.toString() !== targetBrowserUrl?.toString() && !currentNavigation?.extras.skipLocationChange;
}
static ɵfac = function NavigationTransitions_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _NavigationTransitions)();
};
static ɵprov = ɵɵdefineInjectable({
token: _NavigationTransitions,
factory: _NavigationTransitions.ɵfac,
providedIn: "root"
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(NavigationTransitions, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], () => [], null);
})();
function isBrowserTriggeredNavigation(source) {
return source !== IMPERATIVE_NAVIGATION;
}
var RouteReuseStrategy = class _RouteReuseStrategy {
static ɵfac = function RouteReuseStrategy_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _RouteReuseStrategy)();
};
static ɵprov = ɵɵdefineInjectable({
token: _RouteReuseStrategy,
factory: () => (() => inject(DefaultRouteReuseStrategy))(),
providedIn: "root"
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RouteReuseStrategy, [{
type: Injectable,
args: [{
providedIn: "root",
useFactory: () => inject(DefaultRouteReuseStrategy)
}]
}], null, null);
})();
var BaseRouteReuseStrategy = class {
/**
* Whether the given route should detach for later reuse.
* Always returns false for `BaseRouteReuseStrategy`.
* */
shouldDetach(route) {
return false;
}
/**
* A no-op; the route is never stored since this strategy never detaches routes for later re-use.
*/
store(route, detachedTree) {
}
/** Returns `false`, meaning the route (and its subtree) is never reattached */
shouldAttach(route) {
return false;
}
/** Returns `null` because this strategy does not store routes for later re-use. */
retrieve(route) {
return null;
}
/**
* Determines if a route should be reused.
* This strategy returns `true` when the future route config and current route config are
* identical.
*/
shouldReuseRoute(future, curr) {
return future.routeConfig === curr.routeConfig;
}
};
var DefaultRouteReuseStrategy = class _DefaultRouteReuseStrategy extends BaseRouteReuseStrategy {
static ɵfac = /* @__PURE__ */ (() => {
let ɵDefaultRouteReuseStrategy_BaseFactory;
return function DefaultRouteReuseStrategy_Factory(__ngFactoryType__) {
return (ɵDefaultRouteReuseStrategy_BaseFactory || (ɵDefaultRouteReuseStrategy_BaseFactory = ɵɵgetInheritedFactory(_DefaultRouteReuseStrategy)))(__ngFactoryType__ || _DefaultRouteReuseStrategy);
};
})();
static ɵprov = ɵɵdefineInjectable({
token: _DefaultRouteReuseStrategy,
factory: _DefaultRouteReuseStrategy.ɵfac,
providedIn: "root"
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(DefaultRouteReuseStrategy, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], null, null);
})();
var StateManager = class _StateManager {
urlSerializer = inject(UrlSerializer);
options = inject(ROUTER_CONFIGURATION, {
optional: true
}) || {};
canceledNavigationResolution = this.options.canceledNavigationResolution || "replace";
location = inject(Location);
urlHandlingStrategy = inject(UrlHandlingStrategy);
urlUpdateStrategy = this.options.urlUpdateStrategy || "deferred";
currentUrlTree = new UrlTree();
/**
* Returns the currently activated `UrlTree`.
*
* This `UrlTree` shows only URLs that the `Router` is configured to handle (through
* `UrlHandlingStrategy`).
*
* The value is set after finding the route config tree to activate but before activating the
* route.
*/
getCurrentUrlTree() {
return this.currentUrlTree;
}
rawUrlTree = this.currentUrlTree;
/**
* Returns a `UrlTree` that is represents what the browser is actually showing.
*
* In the life of a navigation transition:
* 1. When a navigation begins, the raw `UrlTree` is updated to the full URL that's being
* navigated to.
* 2. During a navigation, redirects are applied, which might only apply to _part_ of the URL (due
* to `UrlHandlingStrategy`).
* 3. Just before activation, the raw `UrlTree` is updated to include the redirects on top of the
* original raw URL.
*
* Note that this is _only_ here to support `UrlHandlingStrategy.extract` and
* `UrlHandlingStrategy.shouldProcessUrl`. Without those APIs, the current `UrlTree` would not
* deviated from the raw `UrlTree`.
*
* For `extract`, a raw `UrlTree` is needed because `extract` may only return part
* of the navigation URL. Thus, the current `UrlTree` may only represent _part_ of the browser
* URL. When a navigation gets cancelled and the router needs to reset the URL or a new navigation
* occurs, it needs to know the _whole_ browser URL, not just the part handled by
* `UrlHandlingStrategy`.
* For `shouldProcessUrl`, when the return is `false`, the router ignores the navigation but
* still updates the raw `UrlTree` with the assumption that the navigation was caused by the
* location change listener due to a URL update by the AngularJS router. In this case, the router
* still need to know what the browser's URL is for future navigations.
*/
getRawUrlTree() {
return this.rawUrlTree;
}
createBrowserPath({
finalUrl,
initialUrl,
targetBrowserUrl
}) {
const rawUrl = finalUrl !== void 0 ? this.urlHandlingStrategy.merge(finalUrl, initialUrl) : initialUrl;
const url = targetBrowserUrl ?? rawUrl;
const path = url instanceof UrlTree ? this.urlSerializer.serialize(url) : url;
return path;
}
commitTransition({
targetRouterState,
finalUrl,
initialUrl
}) {
if (finalUrl && targetRouterState) {
this.currentUrlTree = finalUrl;
this.rawUrlTree = this.urlHandlingStrategy.merge(finalUrl, initialUrl);
this.routerState = targetRouterState;
} else {
this.rawUrlTree = initialUrl;
}
}
routerState = createEmptyState(null);
/** Returns the current RouterState. */
getRouterState() {
return this.routerState;
}
stateMemento = this.createStateMemento();
updateStateMemento() {
this.stateMemento = this.createStateMemento();
}
createStateMemento() {
return {
rawUrlTree: this.rawUrlTree,
currentUrlTree: this.currentUrlTree,
routerState: this.routerState
};
}
resetInternalState({
finalUrl
}) {
this.routerState = this.stateMemento.routerState;
this.currentUrlTree = this.stateMemento.currentUrlTree;
this.rawUrlTree = this.urlHandlingStrategy.merge(this.currentUrlTree, finalUrl ?? this.rawUrlTree);
}
static ɵfac = function StateManager_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _StateManager)();
};
static ɵprov = ɵɵdefineInjectable({
token: _StateManager,
factory: () => (() => inject(HistoryStateManager))(),
providedIn: "root"
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(StateManager, [{
type: Injectable,
args: [{
providedIn: "root",
useFactory: () => inject(HistoryStateManager)
}]
}], null, null);
})();
var HistoryStateManager = class _HistoryStateManager extends StateManager {
/**
* The id of the currently active page in the router.
* Updated to the transition's target id on a successful navigation.
*
* This is used to track what page the router last activated. When an attempted navigation fails,
* the router can then use this to compute how to restore the state back to the previously active
* page.
*/
currentPageId = 0;
lastSuccessfulId = -1;
restoredState() {
return this.location.getState();
}
/**
* The ɵrouterPageId of whatever page is currently active in the browser history. This is
* important for computing the target page id for new navigations because we need to ensure each
* page id in the browser history is 1 more than the previous entry.
*/
get browserPageId() {
if (this.canceledNavigationResolution !== "computed") {
return this.currentPageId;
}
return this.restoredState()?.ɵrouterPageId ?? this.currentPageId;
}
registerNonRouterCurrentEntryChangeListener(listener) {
return this.location.subscribe((event) => {
if (event["type"] === "popstate") {
setTimeout(() => {
listener(event["url"], event.state, "popstate");
});
}
});
}
handleRouterEvent(e, currentTransition) {
if (e instanceof NavigationStart) {
this.updateStateMemento();
} else if (e instanceof NavigationSkipped) {
this.commitTransition(currentTransition);
} else if (e instanceof RoutesRecognized) {
if (this.urlUpdateStrategy === "eager") {
if (!currentTransition.extras.skipLocationChange) {
this.setBrowserUrl(this.createBrowserPath(currentTransition), currentTransition);
}
}
} else if (e instanceof BeforeActivateRoutes) {
this.commitTransition(currentTransition);
if (this.urlUpdateStrategy === "deferred" && !currentTransition.extras.skipLocationChange) {
this.setBrowserUrl(this.createBrowserPath(currentTransition), currentTransition);
}
} else if (e instanceof NavigationCancel && e.code !== NavigationCancellationCode.SupersededByNewNavigation && e.code !== NavigationCancellationCode.Redirect) {
this.restoreHistory(currentTransition);
} else if (e instanceof NavigationError) {
this.restoreHistory(currentTransition, true);
} else if (e instanceof NavigationEnd) {
this.lastSuccessfulId = e.id;
this.currentPageId = this.browserPageId;
}
}
setBrowserUrl(path, {
extras,
id
}) {
const {
replaceUrl,
state
} = extras;
if (this.location.isCurrentPathEqualTo(path) || !!replaceUrl) {
const currentBrowserPageId = this.browserPageId;
const newState = __spreadValues(__spreadValues({}, state), this.generateNgRouterState(id, currentBrowserPageId));
this.location.replaceState(path, "", newState);
} else {
const newState = __spreadValues(__spreadValues({}, state), this.generateNgRouterState(id, this.browserPageId + 1));
this.location.go(path, "", newState);
}
}
/**
* Performs the necessary rollback action to restore the browser URL to the
* state before the transition.
*/
restoreHistory(navigation, restoringFromCaughtError = false) {
if (this.canceledNavigationResolution === "computed") {
const currentBrowserPageId = this.browserPageId;
const targetPagePosition = this.currentPageId - currentBrowserPageId;
if (targetPagePosition !== 0) {
this.location.historyGo(targetPagePosition);
} else if (this.getCurrentUrlTree() === navigation.finalUrl && targetPagePosition === 0) {
this.resetInternalState(navigation);
this.resetUrlToCurrentUrlTree();
} else ;
} else if (this.canceledNavigationResolution === "replace") {
if (restoringFromCaughtError) {
this.resetInternalState(navigation);
}
this.resetUrlToCurrentUrlTree();
}
}
resetUrlToCurrentUrlTree() {
this.location.replaceState(this.urlSerializer.serialize(this.getRawUrlTree()), "", this.generateNgRouterState(this.lastSuccessfulId, this.currentPageId));
}
generateNgRouterState(navigationId, routerPageId) {
if (this.canceledNavigationResolution === "computed") {
return {
navigationId,
ɵrouterPageId: routerPageId
};
}
return {
navigationId
};
}
static ɵfac = /* @__PURE__ */ (() => {
let ɵHistoryStateManager_BaseFactory;
return function HistoryStateManager_Factory(__ngFactoryType__) {
return (ɵHistoryStateManager_BaseFactory || (ɵHistoryStateManager_BaseFactory = ɵɵgetInheritedFactory(_HistoryStateManager)))(__ngFactoryType__ || _HistoryStateManager);
};
})();
static ɵprov = ɵɵdefineInjectable({
token: _HistoryStateManager,
factory: _HistoryStateManager.ɵfac,
providedIn: "root"
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(HistoryStateManager, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], null, null);
})();
function afterNextNavigation(router, action) {
router.events.pipe(filter((e) => e instanceof NavigationEnd || e instanceof NavigationCancel || e instanceof NavigationError || e instanceof NavigationSkipped), map((e) => {
if (e instanceof NavigationEnd || e instanceof NavigationSkipped) {
return 0;
}
const redirecting = e instanceof NavigationCancel ? e.code === NavigationCancellationCode.Redirect || e.code === NavigationCancellationCode.SupersededByNewNavigation : false;
return redirecting ? 2 : 1;
}), filter(
(result) => result !== 2
/* NavigationResult.REDIRECTING */
), take(1)).subscribe(() => {
action();
});
}
var exactMatchOptions = {
paths: "exact",
fragment: "ignored",
matrixParams: "ignored",
queryParams: "exact"
};
var subsetMatchOptions = {
paths: "subset",
fragment: "ignored",
matrixParams: "ignored",
queryParams: "subset"
};
var Router = class _Router {
get currentUrlTree() {
return this.stateManager.getCurrentUrlTree();
}
get rawUrlTree() {
return this.stateManager.getRawUrlTree();
}
disposed = false;
nonRouterCurrentEntryChangeSubscription;
console = inject(Console);
stateManager = inject(StateManager);
options = inject(ROUTER_CONFIGURATION, {
optional: true
}) || {};
pendingTasks = inject(PendingTasksInternal);
urlUpdateStrategy = this.options.urlUpdateStrategy || "deferred";
navigationTransitions = inject(NavigationTransitions);
urlSerializer = inject(UrlSerializer);
location = inject(Location);
urlHandlingStrategy = inject(UrlHandlingStrategy);
injector = inject(EnvironmentInjector);
/**
* The private `Subject` type for the public events exposed in the getter. This is used internally
* to push events to. The separate field allows us to expose separate types in the public API
* (i.e., an Observable rather than the Subject).
*/
_events = new Subject();
/**
* An event stream for routing events.
*/
get events() {
return this._events;
}
/**
* The current state of routing in this NgModule.
*/
get routerState() {
return this.stateManager.getRouterState();
}
/**
* True if at least one navigation event has occurred,
* false otherwise.
*/
navigated = false;
/**
* A strategy for re-using routes.
*
* @deprecated Configure using `providers` instead:
* `{provide: RouteReuseStrategy, useClass: MyStrategy}`.
*/
routeReuseStrategy = inject(RouteReuseStrategy);
/**
* How to handle a navigation request to the current URL.
*
*
* @deprecated Configure this through `provideRouter` or `RouterModule.forRoot` instead.
* @see {@link withRouterConfig}
* @see {@link provideRouter}
* @see {@link RouterModule}
*/
onSameUrlNavigation = this.options.onSameUrlNavigation || "ignore";
config = inject(ROUTES, {
optional: true
})?.flat() ?? [];
/**
* Indicates whether the application has opted in to binding Router data to component inputs.
*
* This option is enabled by the `withComponentInputBinding` feature of `provideRouter` or
* `bindToComponentInputs` in the `ExtraOptions` of `RouterModule.forRoot`.
*/
componentInputBindingEnabled = !!inject(INPUT_BINDER, {
optional: true
});
/**
* Signal of the current `Navigation` object when the router is navigating, and `null` when idle.
*
* Note: The current navigation becomes to null after the NavigationEnd event is emitted.
*/
currentNavigation = this.navigationTransitions.currentNavigation.asReadonly();
constructor() {
this.resetConfig(this.config);
this.navigationTransitions.setupNavigations(this).subscribe({
error: (e) => {
this.console.warn(ngDevMode ? `Unhandled Navigation Error: ${e}` : e);
}
});
this.subscribeToNavigationEvents();
}
eventsSubscription = new Subscription();
subscribeToNavigationEvents() {
const subscription = this.navigationTransitions.events.subscribe((e) => {
try {
const currentTransition = this.navigationTransitions.currentTransition;
const currentNavigation = untracked(this.navigationTransitions.currentNavigation);
if (currentTransition !== null && currentNavigation !== null) {
this.stateManager.handleRouterEvent(e, currentNavigation);
if (e instanceof NavigationCancel && e.code !== NavigationCancellationCode.Redirect && e.code !== NavigationCancellationCode.SupersededByNewNavigation) {
this.navigated = true;
} else if (e instanceof NavigationEnd) {
this.navigated = true;
} else if (e instanceof RedirectRequest) {
const opts = e.navigationBehaviorOptions;
const mergedTree = this.urlHandlingStrategy.merge(e.url, currentTransition.currentRawUrl);
const extras = __spreadValues({
browserUrl: currentTransition.extras.browserUrl,
info: currentTransition.extras.info,
skipLocationChange: currentTransition.extras.skipLocationChange,
// The URL is already updated at this point if we have 'eager' URL
// updates or if the navigation was triggered by the browser (back
// button, URL bar, etc). We want to replace that item in history
// if the navigation is rejected.
replaceUrl: currentTransition.extras.replaceUrl || this.urlUpdateStrategy === "eager" || isBrowserTriggeredNavigation(currentTransition.source)
}, opts);
this.scheduleNavigation(mergedTree, IMPERATIVE_NAVIGATION, null, extras, {
resolve: currentTransition.resolve,
reject: currentTransition.reject,
promise: currentTransition.promise
});
}
}
if (isPublicRouterEvent(e)) {
this._events.next(e);
}
} catch (e2) {
this.navigationTransitions.transitionAbortWithErrorSubject.next(e2);
}
});
this.eventsSubscription.add(subscription);
}
/** @internal */
resetRootComponentType(rootComponentType) {
this.routerState.root.component = rootComponentType;
this.navigationTransitions.rootComponentType = rootComponentType;
}
/**
* Sets up the location change listener and performs the initial navigation.
*/
initialNavigation() {
this.setUpLocationChangeListener();
if (!this.navigationTransitions.hasRequestedNavigation) {
this.navigateToSyncWithBrowser(this.location.path(true), IMPERATIVE_NAVIGATION, this.stateManager.restoredState());
}
}
/**
* Sets up the location change listener. This listener detects navigations triggered from outside
* the Router (the browser back/forward buttons, for example) and schedules a corresponding Router
* navigation so that the correct events, guards, etc. are triggered.
*/
setUpLocationChangeListener() {
this.nonRouterCurrentEntryChangeSubscription ??= this.stateManager.registerNonRouterCurrentEntryChangeListener((url, state, source) => {
this.navigateToSyncWithBrowser(url, source, state);
});
}
/**
* Schedules a router navigation to synchronize Router state with the browser state.
*
* This is done as a response to a popstate event and the initial navigation. These
* two scenarios represent times when the browser URL/state has been updated and
* the Router needs to respond to ensure its internal state matches.
*/
navigateToSyncWithBrowser(url, source, state) {
const extras = {
replaceUrl: true
};
const restoredState = state?.navigationId ? state : null;
if (state) {
const stateCopy = __spreadValues({}, state);
delete stateCopy.navigationId;
delete stateCopy.ɵrouterPageId;
if (Object.keys(stateCopy).length !== 0) {
extras.state = stateCopy;
}
}
const urlTree = this.parseUrl(url);
this.scheduleNavigation(urlTree, source, restoredState, extras).catch((e) => {
if (this.disposed) {
return;
}
this.injector.get(INTERNAL_APPLICATION_ERROR_HANDLER)(e);
});
}
/** The current URL. */
get url() {
return this.serializeUrl(this.currentUrlTree);
}
/**
* Returns the current `Navigation` object when the router is navigating,
* and `null` when idle.
*
* @deprecated 20.2 Use the `currentNavigation` signal instead.
*/
getCurrentNavigation() {
return untracked(this.navigationTransitions.currentNavigation);
}
/**
* The `Navigation` object of the most recent navigation to succeed and `null` if there
* has not been a successful navigation yet.
*/
get lastSuccessfulNavigation() {
return this.navigationTransitions.lastSuccessfulNavigation;
}
/**
* Resets the route configuration used for navigation and generating links.
*
* @param config The route array for the new configuration.
*
* @usageNotes
*
* ```ts
* router.resetConfig([
* { path: 'team/:id', component: TeamCmp, children: [
* { path: 'simple', component: SimpleCmp },
* { path: 'user/:name', component: UserCmp }
* ]}
* ]);
* ```
*/
resetConfig(config) {
(typeof ngDevMode === "undefined" || ngDevMode) && validateConfig(config);
this.config = config.map(standardizeConfig);
this.navigated = false;
}
/** @docs-private */
ngOnDestroy() {
this.dispose();
}
/** Disposes of the router. */
dispose() {
this._events.unsubscribe();
this.navigationTransitions.complete();
if (this.nonRouterCurrentEntryChangeSubscription) {
this.nonRouterCurrentEntryChangeSubscription.unsubscribe();
this.nonRouterCurrentEntryChangeSubscription = void 0;
}
this.disposed = true;
this.eventsSubscription.unsubscribe();
}
/**
* Appends URL segments to the current URL tree to create a new URL tree.
*
* @param commands An array of URL fragments with which to construct the new URL tree.
* If the path is static, can be the literal URL string. For a dynamic path, pass an array of path
* segments, followed by the parameters for each segment.
* The fragments are applied to the current URL tree or the one provided in the `relativeTo`
* property of the options object, if supplied.
* @param navigationExtras Options that control the navigation strategy.
* @returns The new URL tree.
*
* @usageNotes
*
* ```
* // create /team/33/user/11
* router.createUrlTree(['/team', 33, 'user', 11]);
*
* // create /team/33;expand=true/user/11
* router.createUrlTree(['/team', 33, {expand: true}, 'user', 11]);
*
* // you can collapse static segments like this (this works only with the first passed-in value):
* router.createUrlTree(['/team/33/user', userId]);
*
* // If the first segment can contain slashes, and you do not want the router to split it,
* // you can do the following:
* router.createUrlTree([{segmentPath: '/one/two'}]);
*
* // create /team/33/(user/11//right:chat)
* router.createUrlTree(['/team', 33, {outlets: {primary: 'user/11', right: 'chat'}}]);
*
* // remove the right secondary node
* router.createUrlTree(['/team', 33, {outlets: {primary: 'user/11', right: null}}]);
*
* // assuming the current url is `/team/33/user/11` and the route points to `user/11`
*
* // navigate to /team/33/user/11/details
* router.createUrlTree(['details'], {relativeTo: route});
*
* // navigate to /team/33/user/22
* router.createUrlTree(['../22'], {relativeTo: route});
*
* // navigate to /team/44/user/22
* router.createUrlTree(['../../team/44/user/22'], {relativeTo: route});
*
* Note that a value of `null` or `undefined` for `relativeTo` indicates that the
* tree should be created relative to the root.
* ```
*/
createUrlTree(commands, navigationExtras = {}) {
const {
relativeTo,
queryParams,
fragment,
queryParamsHandling,
preserveFragment
} = navigationExtras;
const f = preserveFragment ? this.currentUrlTree.fragment : fragment;
let q = null;
switch (queryParamsHandling ?? this.options.defaultQueryParamsHandling) {
case "merge":
q = __spreadValues(__spreadValues({}, this.currentUrlTree.queryParams), queryParams);
break;
case "preserve":
q = this.currentUrlTree.queryParams;
break;
default:
q = queryParams || null;
}
if (q !== null) {
q = this.removeEmptyProps(q);
}
let relativeToUrlSegmentGroup;
try {
const relativeToSnapshot = relativeTo ? relativeTo.snapshot : this.routerState.snapshot.root;
relativeToUrlSegmentGroup = createSegmentGroupFromRoute(relativeToSnapshot);
} catch (e) {
if (typeof commands[0] !== "string" || commands[0][0] !== "/") {
commands = [];
}
relativeToUrlSegmentGroup = this.currentUrlTree.root;
}
return createUrlTreeFromSegmentGroup(relativeToUrlSegmentGroup, commands, q, f ?? null);
}
/**
* Navigates to a view using an absolute route path.
*
* @param url An absolute path for a defined route. The function does not apply any delta to the
* current URL.
* @param extras An object containing properties that modify the navigation strategy.
*
* @returns A Promise that resolves to 'true' when navigation succeeds,
* to 'false' when navigation fails, or is rejected on error.
*
* @usageNotes
*
* The following calls request navigation to an absolute path.
*
* ```ts
* router.navigateByUrl("/team/33/user/11");
*
* // Navigate without updating the URL
* router.navigateByUrl("/team/33/user/11", { skipLocationChange: true });
* ```
*
* @see [Routing and Navigation guide](guide/routing/common-router-tasks)
*
*/
navigateByUrl(url, extras = {
skipLocationChange: false
}) {
const urlTree = isUrlTree(url) ? url : this.parseUrl(url);
const mergedTree = this.urlHandlingStrategy.merge(urlTree, this.rawUrlTree);
return this.scheduleNavigation(mergedTree, IMPERATIVE_NAVIGATION, null, extras);
}
/**
* Navigate based on the provided array of commands and a starting point.
* If no starting route is provided, the navigation is absolute.
*
* @param commands An array of URL fragments with which to construct the target URL.
* If the path is static, can be the literal URL string. For a dynamic path, pass an array of path
* segments, followed by the parameters for each segment.
* The fragments are applied to the current URL or the one provided in the `relativeTo` property
* of the options object, if supplied.
* @param extras An options object that determines how the URL should be constructed or
* interpreted.
*
* @returns A Promise that resolves to `true` when navigation succeeds, or `false` when navigation
* fails. The Promise is rejected when an error occurs if `resolveNavigationPromiseOnError` is
* not `true`.
*
* @usageNotes
*
* The following calls request navigation to a dynamic route path relative to the current URL.
*
* ```ts
* router.navigate(['team', 33, 'user', 11], {relativeTo: route});
*
* // Navigate without updating the URL, overriding the default behavior
* router.navigate(['team', 33, 'user', 11], {relativeTo: route, skipLocationChange: true});
* ```
*
* @see [Routing and Navigation guide](guide/routing/common-router-tasks)
*
*/
navigate(commands, extras = {
skipLocationChange: false
}) {
validateCommands(commands);
return this.navigateByUrl(this.createUrlTree(commands, extras), extras);
}
/** Serializes a `UrlTree` into a string */
serializeUrl(url) {
return this.urlSerializer.serialize(url);
}
/** Parses a string into a `UrlTree` */
parseUrl(url) {
try {
return this.urlSerializer.parse(url);
} catch {
return this.urlSerializer.parse("/");
}
}
isActive(url, matchOptions) {
let options;
if (matchOptions === true) {
options = __spreadValues({}, exactMatchOptions);
} else if (matchOptions === false) {
options = __spreadValues({}, subsetMatchOptions);
} else {
options = matchOptions;
}
if (isUrlTree(url)) {
return containsTree(this.currentUrlTree, url, options);
}
const urlTree = this.parseUrl(url);
return containsTree(this.currentUrlTree, urlTree, options);
}
removeEmptyProps(params) {
return Object.entries(params).reduce((result, [key, value]) => {
if (value !== null && value !== void 0) {
result[key] = value;
}
return result;
}, {});
}
scheduleNavigation(rawUrl, source, restoredState, extras, priorPromise) {
if (this.disposed) {
return Promise.resolve(false);
}
let resolve;
let reject;
let promise;
if (priorPromise) {
resolve = priorPromise.resolve;
reject = priorPromise.reject;
promise = priorPromise.promise;
} else {
promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
}
const taskId = this.pendingTasks.add();
afterNextNavigation(this, () => {
queueMicrotask(() => this.pendingTasks.remove(taskId));
});
this.navigationTransitions.handleNavigationRequest({
source,
restoredState,
currentUrlTree: this.currentUrlTree,
currentRawUrl: this.currentUrlTree,
rawUrl,
extras,
resolve,
reject,
promise,
currentSnapshot: this.routerState.snapshot,
currentRouterState: this.routerState
});
return promise.catch((e) => {
return Promise.reject(e);
});
}
static ɵfac = function Router_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _Router)();
};
static ɵprov = ɵɵdefineInjectable({
token: _Router,
factory: _Router.ɵfac,
providedIn: "root"
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(Router, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], () => [], null);
})();
function validateCommands(commands) {
for (let i = 0; i < commands.length; i++) {
const cmd = commands[i];
if (cmd == null) {
throw new RuntimeError(4008, (typeof ngDevMode === "undefined" || ngDevMode) && `The requested path contains ${cmd} segment at index ${i}`);
}
}
}
// node_modules/@angular/router/fesm2022/router_module.mjs
var RouterLink = class _RouterLink {
router;
route;
tabIndexAttribute;
renderer;
el;
locationStrategy;
/** @nodoc */
reactiveHref = signal(null, ...ngDevMode ? [{
debugName: "reactiveHref"
}] : []);
/**
* Represents an `href` attribute value applied to a host element,
* when a host element is an `<a>`/`<area>` tag or a compatible custom element.
* For other tags, the value is `null`.
*/
get href() {
return untracked(this.reactiveHref);
}
/** @deprecated */
set href(value) {
this.reactiveHref.set(value);
}
/**
* Represents the `target` attribute on a host element.
* This is only used when the host element is
* an `<a>`/`<area>` tag or a compatible custom element.
*/
target;
/**
* Passed to {@link Router#createUrlTree} as part of the
* `UrlCreationOptions`.
* @see {@link UrlCreationOptions#queryParams}
* @see {@link Router#createUrlTree}
*/
queryParams;
/**
* Passed to {@link Router#createUrlTree} as part of the
* `UrlCreationOptions`.
* @see {@link UrlCreationOptions#fragment}
* @see {@link Router#createUrlTree}
*/
fragment;
/**
* Passed to {@link Router#createUrlTree} as part of the
* `UrlCreationOptions`.
* @see {@link UrlCreationOptions#queryParamsHandling}
* @see {@link Router#createUrlTree}
*/
queryParamsHandling;
/**
* Passed to {@link Router#navigateByUrl} as part of the
* `NavigationBehaviorOptions`.
* @see {@link NavigationBehaviorOptions#state}
* @see {@link Router#navigateByUrl}
*/
state;
/**
* Passed to {@link Router#navigateByUrl} as part of the
* `NavigationBehaviorOptions`.
* @see {@link NavigationBehaviorOptions#info}
* @see {@link Router#navigateByUrl}
*/
info;
/**
* Passed to {@link Router#createUrlTree} as part of the
* `UrlCreationOptions`.
* Specify a value here when you do not want to use the default value
* for `routerLink`, which is the current activated route.
* Note that a value of `undefined` here will use the `routerLink` default.
* @see {@link UrlCreationOptions#relativeTo}
* @see {@link Router#createUrlTree}
*/
relativeTo;
/** Whether a host element is an `<a>`/`<area>` tag or a compatible custom element. */
isAnchorElement;
subscription;
/** @internal */
onChanges = new Subject();
applicationErrorHandler = inject(INTERNAL_APPLICATION_ERROR_HANDLER);
options = inject(ROUTER_CONFIGURATION, {
optional: true
});
constructor(router, route, tabIndexAttribute, renderer, el, locationStrategy) {
this.router = router;
this.route = route;
this.tabIndexAttribute = tabIndexAttribute;
this.renderer = renderer;
this.el = el;
this.locationStrategy = locationStrategy;
this.reactiveHref.set(inject(new HostAttributeToken("href"), {
optional: true
}));
const tagName = el.nativeElement.tagName?.toLowerCase();
this.isAnchorElement = tagName === "a" || tagName === "area" || !!// Avoid breaking in an SSR context where customElements might not be defined.
(typeof customElements === "object" && // observedAttributes is an optional static property/getter on a custom element.
// The spec states that this must be an array of strings.
customElements.get(tagName)?.observedAttributes?.includes?.("href"));
if (!this.isAnchorElement) {
this.subscribeToNavigationEventsIfNecessary();
} else {
this.setTabIndexIfNotOnNativeEl("0");
}
}
subscribeToNavigationEventsIfNecessary() {
if (this.subscription !== void 0 || !this.isAnchorElement) {
return;
}
let createSubcription = this.preserveFragment;
const dependsOnRouterState = (handling) => handling === "merge" || handling === "preserve";
createSubcription ||= dependsOnRouterState(this.queryParamsHandling);
createSubcription ||= !this.queryParamsHandling && !dependsOnRouterState(this.options?.defaultQueryParamsHandling);
if (!createSubcription) {
return;
}
this.subscription = this.router.events.subscribe((s) => {
if (s instanceof NavigationEnd) {
this.updateHref();
}
});
}
/**
* Passed to {@link Router#createUrlTree} as part of the
* `UrlCreationOptions`.
* @see {@link UrlCreationOptions#preserveFragment}
* @see {@link Router#createUrlTree}
*/
preserveFragment = false;
/**
* Passed to {@link Router#navigateByUrl} as part of the
* `NavigationBehaviorOptions`.
* @see {@link NavigationBehaviorOptions#skipLocationChange}
* @see {@link Router#navigateByUrl}
*/
skipLocationChange = false;
/**
* Passed to {@link Router#navigateByUrl} as part of the
* `NavigationBehaviorOptions`.
* @see {@link NavigationBehaviorOptions#replaceUrl}
* @see {@link Router#navigateByUrl}
*/
replaceUrl = false;
/**
* Modifies the tab index if there was not a tabindex attribute on the element during
* instantiation.
*/
setTabIndexIfNotOnNativeEl(newTabIndex) {
if (this.tabIndexAttribute != null || this.isAnchorElement) {
return;
}
this.applyAttributeValue("tabindex", newTabIndex);
}
/** @docs-private */
// TODO(atscott): Remove changes parameter in major version as a breaking change.
ngOnChanges(changes) {
if (ngDevMode && isUrlTree(this.routerLinkInput) && (this.fragment !== void 0 || this.queryParams || this.queryParamsHandling || this.preserveFragment || this.relativeTo)) {
throw new RuntimeError(4016, "Cannot configure queryParams or fragment when using a UrlTree as the routerLink input value.");
}
if (this.isAnchorElement) {
this.updateHref();
this.subscribeToNavigationEventsIfNecessary();
}
this.onChanges.next(this);
}
routerLinkInput = null;
/**
* Commands to pass to {@link Router#createUrlTree} or a `UrlTree`.
* - **array**: commands to pass to {@link Router#createUrlTree}.
* - **string**: shorthand for array of commands with just the string, i.e. `['/route']`
* - **UrlTree**: a `UrlTree` for this link rather than creating one from the commands
* and other inputs that correspond to properties of `UrlCreationOptions`.
* - **null|undefined**: effectively disables the `routerLink`
* @see {@link Router#createUrlTree}
*/
set routerLink(commandsOrUrlTree) {
if (commandsOrUrlTree == null) {
this.routerLinkInput = null;
this.setTabIndexIfNotOnNativeEl(null);
} else {
if (isUrlTree(commandsOrUrlTree)) {
this.routerLinkInput = commandsOrUrlTree;
} else {
this.routerLinkInput = Array.isArray(commandsOrUrlTree) ? commandsOrUrlTree : [commandsOrUrlTree];
}
this.setTabIndexIfNotOnNativeEl("0");
}
}
/** @docs-private */
onClick(button, ctrlKey, shiftKey, altKey, metaKey) {
const urlTree = this.urlTree;
if (urlTree === null) {
return true;
}
if (this.isAnchorElement) {
if (button !== 0 || ctrlKey || shiftKey || altKey || metaKey) {
return true;
}
if (typeof this.target === "string" && this.target != "_self") {
return true;
}
}
const extras = {
skipLocationChange: this.skipLocationChange,
replaceUrl: this.replaceUrl,
state: this.state,
info: this.info
};
this.router.navigateByUrl(urlTree, extras)?.catch((e) => {
this.applicationErrorHandler(e);
});
return !this.isAnchorElement;
}
/** @docs-private */
ngOnDestroy() {
this.subscription?.unsubscribe();
}
updateHref() {
const urlTree = this.urlTree;
this.reactiveHref.set(urlTree !== null && this.locationStrategy ? this.locationStrategy?.prepareExternalUrl(this.router.serializeUrl(urlTree)) ?? "" : null);
}
applyAttributeValue(attrName, attrValue) {
const renderer = this.renderer;
const nativeElement = this.el.nativeElement;
if (attrValue !== null) {
renderer.setAttribute(nativeElement, attrName, attrValue);
} else {
renderer.removeAttribute(nativeElement, attrName);
}
}
get urlTree() {
if (this.routerLinkInput === null) {
return null;
} else if (isUrlTree(this.routerLinkInput)) {
return this.routerLinkInput;
}
return this.router.createUrlTree(this.routerLinkInput, {
// If the `relativeTo` input is not defined, we want to use `this.route` by default.
// Otherwise, we should use the value provided by the user in the input.
relativeTo: this.relativeTo !== void 0 ? this.relativeTo : this.route,
queryParams: this.queryParams,
fragment: this.fragment,
queryParamsHandling: this.queryParamsHandling,
preserveFragment: this.preserveFragment
});
}
static ɵfac = function RouterLink_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _RouterLink)(ɵɵdirectiveInject(Router), ɵɵdirectiveInject(ActivatedRoute), ɵɵinjectAttribute("tabindex"), ɵɵdirectiveInject(Renderer2), ɵɵdirectiveInject(ElementRef), ɵɵdirectiveInject(LocationStrategy));
};
static ɵdir = ɵɵdefineDirective({
type: _RouterLink,
selectors: [["", "routerLink", ""]],
hostVars: 2,
hostBindings: function RouterLink_HostBindings(rf, ctx) {
if (rf & 1) {
ɵɵlistener("click", function RouterLink_click_HostBindingHandler($event) {
return ctx.onClick($event.button, $event.ctrlKey, $event.shiftKey, $event.altKey, $event.metaKey);
});
}
if (rf & 2) {
ɵɵattribute("href", ctx.reactiveHref(), ɵɵsanitizeUrlOrResourceUrl)("target", ctx.target);
}
},
inputs: {
target: "target",
queryParams: "queryParams",
fragment: "fragment",
queryParamsHandling: "queryParamsHandling",
state: "state",
info: "info",
relativeTo: "relativeTo",
preserveFragment: [2, "preserveFragment", "preserveFragment", booleanAttribute],
skipLocationChange: [2, "skipLocationChange", "skipLocationChange", booleanAttribute],
replaceUrl: [2, "replaceUrl", "replaceUrl", booleanAttribute],
routerLink: "routerLink"
},
features: [ɵɵNgOnChangesFeature]
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RouterLink, [{
type: Directive,
args: [{
selector: "[routerLink]",
host: {
"[attr.href]": "reactiveHref()"
}
}]
}], () => [{
type: Router
}, {
type: ActivatedRoute
}, {
type: void 0,
decorators: [{
type: Attribute,
args: ["tabindex"]
}]
}, {
type: Renderer2
}, {
type: ElementRef
}, {
type: LocationStrategy
}], {
target: [{
type: HostBinding,
args: ["attr.target"]
}, {
type: Input
}],
queryParams: [{
type: Input
}],
fragment: [{
type: Input
}],
queryParamsHandling: [{
type: Input
}],
state: [{
type: Input
}],
info: [{
type: Input
}],
relativeTo: [{
type: Input
}],
preserveFragment: [{
type: Input,
args: [{
transform: booleanAttribute
}]
}],
skipLocationChange: [{
type: Input,
args: [{
transform: booleanAttribute
}]
}],
replaceUrl: [{
type: Input,
args: [{
transform: booleanAttribute
}]
}],
routerLink: [{
type: Input
}],
onClick: [{
type: HostListener,
args: ["click", ["$event.button", "$event.ctrlKey", "$event.shiftKey", "$event.altKey", "$event.metaKey"]]
}]
});
})();
var RouterLinkActive = class _RouterLinkActive {
router;
element;
renderer;
cdr;
link;
links;
classes = [];
routerEventsSubscription;
linkInputChangesSubscription;
_isActive = false;
get isActive() {
return this._isActive;
}
/**
* Options to configure how to determine if the router link is active.
*
* These options are passed to the `Router.isActive()` function.
*
* @see {@link Router#isActive}
*/
routerLinkActiveOptions = {
exact: false
};
/**
* Aria-current attribute to apply when the router link is active.
*
* Possible values: `'page'` | `'step'` | `'location'` | `'date'` | `'time'` | `true` | `false`.
*
* @see {@link https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current}
*/
ariaCurrentWhenActive;
/**
*
* You can use the output `isActiveChange` to get notified each time the link becomes
* active or inactive.
*
* Emits:
* true -> Route is active
* false -> Route is inactive
*
* ```html
* <a
* routerLink="/user/bob"
* routerLinkActive="active-link"
* (isActiveChange)="this.onRouterLinkActive($event)">Bob</a>
* ```
*/
isActiveChange = new EventEmitter();
constructor(router, element, renderer, cdr, link) {
this.router = router;
this.element = element;
this.renderer = renderer;
this.cdr = cdr;
this.link = link;
this.routerEventsSubscription = router.events.subscribe((s) => {
if (s instanceof NavigationEnd) {
this.update();
}
});
}
/** @docs-private */
ngAfterContentInit() {
of(this.links.changes, of(null)).pipe(mergeAll()).subscribe((_) => {
this.update();
this.subscribeToEachLinkOnChanges();
});
}
subscribeToEachLinkOnChanges() {
this.linkInputChangesSubscription?.unsubscribe();
const allLinkChanges = [...this.links.toArray(), this.link].filter((link) => !!link).map((link) => link.onChanges);
this.linkInputChangesSubscription = from(allLinkChanges).pipe(mergeAll()).subscribe((link) => {
if (this._isActive !== this.isLinkActive(this.router)(link)) {
this.update();
}
});
}
set routerLinkActive(data) {
const classes = Array.isArray(data) ? data : data.split(" ");
this.classes = classes.filter((c) => !!c);
}
/** @docs-private */
ngOnChanges(changes) {
this.update();
}
/** @docs-private */
ngOnDestroy() {
this.routerEventsSubscription.unsubscribe();
this.linkInputChangesSubscription?.unsubscribe();
}
update() {
if (!this.links || !this.router.navigated) return;
queueMicrotask(() => {
const hasActiveLinks = this.hasActiveLinks();
this.classes.forEach((c) => {
if (hasActiveLinks) {
this.renderer.addClass(this.element.nativeElement, c);
} else {
this.renderer.removeClass(this.element.nativeElement, c);
}
});
if (hasActiveLinks && this.ariaCurrentWhenActive !== void 0) {
this.renderer.setAttribute(this.element.nativeElement, "aria-current", this.ariaCurrentWhenActive.toString());
} else {
this.renderer.removeAttribute(this.element.nativeElement, "aria-current");
}
if (this._isActive !== hasActiveLinks) {
this._isActive = hasActiveLinks;
this.cdr.markForCheck();
this.isActiveChange.emit(hasActiveLinks);
}
});
}
isLinkActive(router) {
const options = isActiveMatchOptions(this.routerLinkActiveOptions) ? this.routerLinkActiveOptions : (
// While the types should disallow `undefined` here, it's possible without strict inputs
this.routerLinkActiveOptions.exact || false
);
return (link) => {
const urlTree = link.urlTree;
return urlTree ? router.isActive(urlTree, options) : false;
};
}
hasActiveLinks() {
const isActiveCheckFn = this.isLinkActive(this.router);
return this.link && isActiveCheckFn(this.link) || this.links.some(isActiveCheckFn);
}
static ɵfac = function RouterLinkActive_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _RouterLinkActive)(ɵɵdirectiveInject(Router), ɵɵdirectiveInject(ElementRef), ɵɵdirectiveInject(Renderer2), ɵɵdirectiveInject(ChangeDetectorRef), ɵɵdirectiveInject(RouterLink, 8));
};
static ɵdir = ɵɵdefineDirective({
type: _RouterLinkActive,
selectors: [["", "routerLinkActive", ""]],
contentQueries: function RouterLinkActive_ContentQueries(rf, ctx, dirIndex) {
if (rf & 1) {
ɵɵcontentQuery(dirIndex, RouterLink, 5);
}
if (rf & 2) {
let _t;
ɵɵqueryRefresh(_t = ɵɵloadQuery()) && (ctx.links = _t);
}
},
inputs: {
routerLinkActiveOptions: "routerLinkActiveOptions",
ariaCurrentWhenActive: "ariaCurrentWhenActive",
routerLinkActive: "routerLinkActive"
},
outputs: {
isActiveChange: "isActiveChange"
},
exportAs: ["routerLinkActive"],
features: [ɵɵNgOnChangesFeature]
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RouterLinkActive, [{
type: Directive,
args: [{
selector: "[routerLinkActive]",
exportAs: "routerLinkActive"
}]
}], () => [{
type: Router
}, {
type: ElementRef
}, {
type: Renderer2
}, {
type: ChangeDetectorRef
}, {
type: RouterLink,
decorators: [{
type: Optional
}]
}], {
links: [{
type: ContentChildren,
args: [RouterLink, {
descendants: true
}]
}],
routerLinkActiveOptions: [{
type: Input
}],
ariaCurrentWhenActive: [{
type: Input
}],
isActiveChange: [{
type: Output
}],
routerLinkActive: [{
type: Input
}]
});
})();
function isActiveMatchOptions(options) {
return !!options.paths;
}
var PreloadingStrategy = class {
};
var PreloadAllModules = class _PreloadAllModules {
preload(route, fn) {
return fn().pipe(catchError(() => of(null)));
}
static ɵfac = function PreloadAllModules_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _PreloadAllModules)();
};
static ɵprov = ɵɵdefineInjectable({
token: _PreloadAllModules,
factory: _PreloadAllModules.ɵfac,
providedIn: "root"
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(PreloadAllModules, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], null, null);
})();
var NoPreloading = class _NoPreloading {
preload(route, fn) {
return of(null);
}
static ɵfac = function NoPreloading_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _NoPreloading)();
};
static ɵprov = ɵɵdefineInjectable({
token: _NoPreloading,
factory: _NoPreloading.ɵfac,
providedIn: "root"
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(NoPreloading, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], null, null);
})();
var RouterPreloader = class _RouterPreloader {
router;
injector;
preloadingStrategy;
loader;
subscription;
constructor(router, injector, preloadingStrategy, loader) {
this.router = router;
this.injector = injector;
this.preloadingStrategy = preloadingStrategy;
this.loader = loader;
}
setUpPreloading() {
this.subscription = this.router.events.pipe(filter((e) => e instanceof NavigationEnd), concatMap(() => this.preload())).subscribe(() => {
});
}
preload() {
return this.processRoutes(this.injector, this.router.config);
}
/** @docs-private */
ngOnDestroy() {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
processRoutes(injector, routes) {
const res = [];
for (const route of routes) {
if (route.providers && !route._injector) {
route._injector = createEnvironmentInjector(route.providers, injector, `Route: ${route.path}`);
}
const injectorForCurrentRoute = route._injector ?? injector;
const injectorForChildren = route._loadedInjector ?? injectorForCurrentRoute;
if (route.loadChildren && !route._loadedRoutes && route.canLoad === void 0 || route.loadComponent && !route._loadedComponent) {
res.push(this.preloadConfig(injectorForCurrentRoute, route));
}
if (route.children || route._loadedRoutes) {
res.push(this.processRoutes(injectorForChildren, route.children ?? route._loadedRoutes));
}
}
return from(res).pipe(mergeAll());
}
preloadConfig(injector, route) {
return this.preloadingStrategy.preload(route, () => {
let loadedChildren$;
if (route.loadChildren && route.canLoad === void 0) {
loadedChildren$ = this.loader.loadChildren(injector, route);
} else {
loadedChildren$ = of(null);
}
const recursiveLoadChildren$ = loadedChildren$.pipe(mergeMap((config) => {
if (config === null) {
return of(void 0);
}
route._loadedRoutes = config.routes;
route._loadedInjector = config.injector;
return this.processRoutes(config.injector ?? injector, config.routes);
}));
if (route.loadComponent && !route._loadedComponent) {
const loadComponent$ = this.loader.loadComponent(injector, route);
return from([recursiveLoadChildren$, loadComponent$]).pipe(mergeAll());
} else {
return recursiveLoadChildren$;
}
});
}
static ɵfac = function RouterPreloader_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _RouterPreloader)(ɵɵinject(Router), ɵɵinject(EnvironmentInjector), ɵɵinject(PreloadingStrategy), ɵɵinject(RouterConfigLoader));
};
static ɵprov = ɵɵdefineInjectable({
token: _RouterPreloader,
factory: _RouterPreloader.ɵfac,
providedIn: "root"
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RouterPreloader, [{
type: Injectable,
args: [{
providedIn: "root"
}]
}], () => [{
type: Router
}, {
type: EnvironmentInjector
}, {
type: PreloadingStrategy
}, {
type: RouterConfigLoader
}], null);
})();
var ROUTER_SCROLLER = new InjectionToken("");
var RouterScroller = class _RouterScroller {
urlSerializer;
transitions;
viewportScroller;
zone;
options;
routerEventsSubscription;
scrollEventsSubscription;
lastId = 0;
lastSource = IMPERATIVE_NAVIGATION;
restoredId = 0;
store = {};
/** @docs-private */
constructor(urlSerializer, transitions, viewportScroller, zone, options = {}) {
this.urlSerializer = urlSerializer;
this.transitions = transitions;
this.viewportScroller = viewportScroller;
this.zone = zone;
this.options = options;
options.scrollPositionRestoration ||= "disabled";
options.anchorScrolling ||= "disabled";
}
init() {
if (this.options.scrollPositionRestoration !== "disabled") {
this.viewportScroller.setHistoryScrollRestoration("manual");
}
this.routerEventsSubscription = this.createScrollEvents();
this.scrollEventsSubscription = this.consumeScrollEvents();
}
createScrollEvents() {
return this.transitions.events.subscribe((e) => {
if (e instanceof NavigationStart) {
this.store[this.lastId] = this.viewportScroller.getScrollPosition();
this.lastSource = e.navigationTrigger;
this.restoredId = e.restoredState ? e.restoredState.navigationId : 0;
} else if (e instanceof NavigationEnd) {
this.lastId = e.id;
this.scheduleScrollEvent(e, this.urlSerializer.parse(e.urlAfterRedirects).fragment);
} else if (e instanceof NavigationSkipped && e.code === NavigationSkippedCode.IgnoredSameUrlNavigation) {
this.lastSource = void 0;
this.restoredId = 0;
this.scheduleScrollEvent(e, this.urlSerializer.parse(e.url).fragment);
}
});
}
consumeScrollEvents() {
return this.transitions.events.subscribe((e) => {
if (!(e instanceof Scroll)) return;
if (e.position) {
if (this.options.scrollPositionRestoration === "top") {
this.viewportScroller.scrollToPosition([0, 0]);
} else if (this.options.scrollPositionRestoration === "enabled") {
this.viewportScroller.scrollToPosition(e.position);
}
} else {
if (e.anchor && this.options.anchorScrolling === "enabled") {
this.viewportScroller.scrollToAnchor(e.anchor);
} else if (this.options.scrollPositionRestoration !== "disabled") {
this.viewportScroller.scrollToPosition([0, 0]);
}
}
});
}
scheduleScrollEvent(routerEvent, anchor) {
this.zone.runOutsideAngular(async () => {
await new Promise((resolve) => {
setTimeout(resolve);
if (typeof requestAnimationFrame !== "undefined") {
requestAnimationFrame(resolve);
}
});
this.zone.run(() => {
this.transitions.events.next(new Scroll(routerEvent, this.lastSource === "popstate" ? this.store[this.restoredId] : null, anchor));
});
});
}
/** @docs-private */
ngOnDestroy() {
this.routerEventsSubscription?.unsubscribe();
this.scrollEventsSubscription?.unsubscribe();
}
static ɵfac = function RouterScroller_Factory(__ngFactoryType__) {
ɵɵinvalidFactory();
};
static ɵprov = ɵɵdefineInjectable({
token: _RouterScroller,
factory: _RouterScroller.ɵfac
});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RouterScroller, [{
type: Injectable
}], () => [{
type: UrlSerializer
}, {
type: NavigationTransitions
}, {
type: ViewportScroller
}, {
type: NgZone
}, {
type: void 0
}], null);
})();
function provideRouter(routes, ...features) {
return makeEnvironmentProviders([{
provide: ROUTES,
multi: true,
useValue: routes
}, typeof ngDevMode === "undefined" || ngDevMode ? {
provide: ROUTER_IS_PROVIDED,
useValue: true
} : [], {
provide: ActivatedRoute,
useFactory: rootRoute,
deps: [Router]
}, {
provide: APP_BOOTSTRAP_LISTENER,
multi: true,
useFactory: getBootstrapListener
}, features.map((feature) => feature.ɵproviders)]);
}
function rootRoute(router) {
return router.routerState.root;
}
function routerFeature(kind, providers) {
return {
ɵkind: kind,
ɵproviders: providers
};
}
var ROUTER_IS_PROVIDED = new InjectionToken("", {
providedIn: "root",
factory: () => false
});
var routerIsProvidedDevModeCheck = {
provide: ENVIRONMENT_INITIALIZER,
multi: true,
useFactory() {
return () => {
if (!inject(ROUTER_IS_PROVIDED)) {
console.warn("`provideRoutes` was called without `provideRouter` or `RouterModule.forRoot`. This is likely a mistake.");
}
};
}
};
function provideRoutes(routes) {
return [{
provide: ROUTES,
multi: true,
useValue: routes
}, typeof ngDevMode === "undefined" || ngDevMode ? routerIsProvidedDevModeCheck : []];
}
function withInMemoryScrolling(options = {}) {
const providers = [{
provide: ROUTER_SCROLLER,
useFactory: () => {
const viewportScroller = inject(ViewportScroller);
const zone = inject(NgZone);
const transitions = inject(NavigationTransitions);
const urlSerializer = inject(UrlSerializer);
return new RouterScroller(urlSerializer, transitions, viewportScroller, zone, options);
}
}];
return routerFeature(4, providers);
}
function getBootstrapListener() {
const injector = inject(Injector);
return (bootstrappedComponentRef) => {
const ref = injector.get(ApplicationRef);
if (bootstrappedComponentRef !== ref.components[0]) {
return;
}
const router = injector.get(Router);
const bootstrapDone = injector.get(BOOTSTRAP_DONE);
if (injector.get(INITIAL_NAVIGATION) === 1) {
router.initialNavigation();
}
injector.get(ROUTER_PRELOADER, null, {
optional: true
})?.setUpPreloading();
injector.get(ROUTER_SCROLLER, null, {
optional: true
})?.init();
router.resetRootComponentType(ref.componentTypes[0]);
if (!bootstrapDone.closed) {
bootstrapDone.next();
bootstrapDone.complete();
bootstrapDone.unsubscribe();
}
};
}
var BOOTSTRAP_DONE = new InjectionToken(typeof ngDevMode === "undefined" || ngDevMode ? "bootstrap done indicator" : "", {
factory: () => {
return new Subject();
}
});
var INITIAL_NAVIGATION = new InjectionToken(typeof ngDevMode === "undefined" || ngDevMode ? "initial navigation" : "", {
providedIn: "root",
factory: () => 1
/* InitialNavigation.EnabledNonBlocking */
});
function withEnabledBlockingInitialNavigation() {
const providers = [{
provide: IS_ENABLED_BLOCKING_INITIAL_NAVIGATION,
useValue: true
}, {
provide: INITIAL_NAVIGATION,
useValue: 0
/* InitialNavigation.EnabledBlocking */
}, provideAppInitializer(() => {
const injector = inject(Injector);
const locationInitialized = injector.get(LOCATION_INITIALIZED, Promise.resolve());
return locationInitialized.then(() => {
return new Promise((resolve) => {
const router = injector.get(Router);
const bootstrapDone = injector.get(BOOTSTRAP_DONE);
afterNextNavigation(router, () => {
resolve(true);
});
injector.get(NavigationTransitions).afterPreactivation = () => {
resolve(true);
return bootstrapDone.closed ? of(void 0) : bootstrapDone;
};
router.initialNavigation();
});
});
})];
return routerFeature(2, providers);
}
function withDisabledInitialNavigation() {
const providers = [provideAppInitializer(() => {
inject(Router).setUpLocationChangeListener();
}), {
provide: INITIAL_NAVIGATION,
useValue: 2
/* InitialNavigation.Disabled */
}];
return routerFeature(3, providers);
}
function withDebugTracing() {
let providers = [];
if (typeof ngDevMode === "undefined" || ngDevMode) {
providers = [{
provide: ENVIRONMENT_INITIALIZER,
multi: true,
useFactory: () => {
const router = inject(Router);
return () => router.events.subscribe((e) => {
console.group?.(`Router Event: ${e.constructor.name}`);
console.log(stringifyEvent(e));
console.log(e);
console.groupEnd?.();
});
}
}];
} else {
providers = [];
}
return routerFeature(1, providers);
}
var ROUTER_PRELOADER = new InjectionToken(typeof ngDevMode === "undefined" || ngDevMode ? "router preloader" : "");
function withPreloading(preloadingStrategy) {
const providers = [{
provide: ROUTER_PRELOADER,
useExisting: RouterPreloader
}, {
provide: PreloadingStrategy,
useExisting: preloadingStrategy
}];
return routerFeature(0, providers);
}
function withRouterConfig(options) {
const providers = [{
provide: ROUTER_CONFIGURATION,
useValue: options
}];
return routerFeature(5, providers);
}
function withHashLocation() {
const providers = [{
provide: LocationStrategy,
useClass: HashLocationStrategy
}];
return routerFeature(6, providers);
}
function withNavigationErrorHandler(handler) {
const providers = [{
provide: NAVIGATION_ERROR_HANDLER,
useValue: handler
}];
return routerFeature(7, providers);
}
function withComponentInputBinding() {
const providers = [RoutedComponentInputBinder, {
provide: INPUT_BINDER,
useExisting: RoutedComponentInputBinder
}];
return routerFeature(8, providers);
}
function withViewTransitions(options) {
performanceMarkFeature("NgRouterViewTransitions");
const providers = [{
provide: CREATE_VIEW_TRANSITION,
useValue: createViewTransition
}, {
provide: VIEW_TRANSITION_OPTIONS,
useValue: __spreadValues({
skipNextTransition: !!options?.skipInitialTransition
}, options)
}];
return routerFeature(9, providers);
}
var ROUTER_DIRECTIVES = [RouterOutlet, RouterLink, RouterLinkActive, ɵEmptyOutletComponent];
var ROUTER_FORROOT_GUARD = new InjectionToken(typeof ngDevMode === "undefined" || ngDevMode ? "router duplicate forRoot guard" : "");
var ROUTER_PROVIDERS = [
Location,
{
provide: UrlSerializer,
useClass: DefaultUrlSerializer
},
Router,
ChildrenOutletContexts,
{
provide: ActivatedRoute,
useFactory: rootRoute,
deps: [Router]
},
RouterConfigLoader,
// Only used to warn when `provideRoutes` is used without `RouterModule` or `provideRouter`. Can
// be removed when `provideRoutes` is removed.
typeof ngDevMode === "undefined" || ngDevMode ? {
provide: ROUTER_IS_PROVIDED,
useValue: true
} : []
];
var RouterModule = class _RouterModule {
constructor() {
if (typeof ngDevMode === "undefined" || ngDevMode) {
inject(ROUTER_FORROOT_GUARD, {
optional: true
});
}
}
/**
* Creates and configures a module with all the router providers and directives.
* Optionally sets up an application listener to perform an initial navigation.
*
* When registering the NgModule at the root, import as follows:
*
* ```ts
* @NgModule({
* imports: [RouterModule.forRoot(ROUTES)]
* })
* class MyNgModule {}
* ```
*
* @param routes An array of `Route` objects that define the navigation paths for the application.
* @param config An `ExtraOptions` configuration object that controls how navigation is performed.
* @return The new `NgModule`.
*
*/
static forRoot(routes, config) {
return {
ngModule: _RouterModule,
providers: [ROUTER_PROVIDERS, typeof ngDevMode === "undefined" || ngDevMode ? config?.enableTracing ? withDebugTracing().ɵproviders : [] : [], {
provide: ROUTES,
multi: true,
useValue: routes
}, typeof ngDevMode === "undefined" || ngDevMode ? {
provide: ROUTER_FORROOT_GUARD,
useFactory: provideForRootGuard,
deps: [[Router, new Optional(), new SkipSelf()]]
} : [], config?.errorHandler ? {
provide: NAVIGATION_ERROR_HANDLER,
useValue: config.errorHandler
} : [], {
provide: ROUTER_CONFIGURATION,
useValue: config ? config : {}
}, config?.useHash ? provideHashLocationStrategy() : providePathLocationStrategy(), provideRouterScroller(), config?.preloadingStrategy ? withPreloading(config.preloadingStrategy).ɵproviders : [], config?.initialNavigation ? provideInitialNavigation(config) : [], config?.bindToComponentInputs ? withComponentInputBinding().ɵproviders : [], config?.enableViewTransitions ? withViewTransitions().ɵproviders : [], provideRouterInitializer()]
};
}
/**
* Creates a module with all the router directives and a provider registering routes,
* without creating a new Router service.
* When registering for submodules and lazy-loaded submodules, create the NgModule as follows:
*
* ```ts
* @NgModule({
* imports: [RouterModule.forChild(ROUTES)]
* })
* class MyNgModule {}
* ```
*
* @param routes An array of `Route` objects that define the navigation paths for the submodule.
* @return The new NgModule.
*
*/
static forChild(routes) {
return {
ngModule: _RouterModule,
providers: [{
provide: ROUTES,
multi: true,
useValue: routes
}]
};
}
static ɵfac = function RouterModule_Factory(__ngFactoryType__) {
return new (__ngFactoryType__ || _RouterModule)();
};
static ɵmod = ɵɵdefineNgModule({
type: _RouterModule,
imports: [RouterOutlet, RouterLink, RouterLinkActive, ɵEmptyOutletComponent],
exports: [RouterOutlet, RouterLink, RouterLinkActive, ɵEmptyOutletComponent]
});
static ɵinj = ɵɵdefineInjector({});
};
(() => {
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RouterModule, [{
type: NgModule,
args: [{
imports: ROUTER_DIRECTIVES,
exports: ROUTER_DIRECTIVES
}]
}], () => [], null);
})();
function provideRouterScroller() {
return {
provide: ROUTER_SCROLLER,
useFactory: () => {
const viewportScroller = inject(ViewportScroller);
const zone = inject(NgZone);
const config = inject(ROUTER_CONFIGURATION);
const transitions = inject(NavigationTransitions);
const urlSerializer = inject(UrlSerializer);
if (config.scrollOffset) {
viewportScroller.setOffset(config.scrollOffset);
}
return new RouterScroller(urlSerializer, transitions, viewportScroller, zone, config);
}
};
}
function provideHashLocationStrategy() {
return {
provide: LocationStrategy,
useClass: HashLocationStrategy
};
}
function providePathLocationStrategy() {
return {
provide: LocationStrategy,
useClass: PathLocationStrategy
};
}
function provideForRootGuard(router) {
if (router) {
throw new RuntimeError(4007, `The Router was provided more than once. This can happen if 'forRoot' is used outside of the root injector. Lazy loaded modules should use RouterModule.forChild() instead.`);
}
return "guarded";
}
function provideInitialNavigation(config) {
return [config.initialNavigation === "disabled" ? withDisabledInitialNavigation().ɵproviders : [], config.initialNavigation === "enabledBlocking" ? withEnabledBlockingInitialNavigation().ɵproviders : []];
}
var ROUTER_INITIALIZER = new InjectionToken(typeof ngDevMode === "undefined" || ngDevMode ? "Router Initializer" : "");
function provideRouterInitializer() {
return [
// ROUTER_INITIALIZER token should be removed. It's public API but shouldn't be. We can just
// have `getBootstrapListener` directly attached to APP_BOOTSTRAP_LISTENER.
{
provide: ROUTER_INITIALIZER,
useFactory: getBootstrapListener
},
{
provide: APP_BOOTSTRAP_LISTENER,
multi: true,
useExisting: ROUTER_INITIALIZER
}
];
}
// node_modules/@angular/router/fesm2022/router.mjs
function mapToCanMatch(providers) {
return providers.map((provider) => (...params) => inject(provider).canMatch(...params));
}
function mapToCanActivate(providers) {
return providers.map((provider) => (...params) => inject(provider).canActivate(...params));
}
function mapToCanActivateChild(providers) {
return providers.map((provider) => (...params) => inject(provider).canActivateChild(...params));
}
function mapToCanDeactivate(providers) {
return providers.map((provider) => (...params) => inject(provider).canDeactivate(...params));
}
function mapToResolve(provider) {
return (...params) => inject(provider).resolve(...params);
}
var VERSION = new Version("20.2.4");
export {
ActivatedRoute,
ActivatedRouteSnapshot,
ActivationEnd,
ActivationStart,
BaseRouteReuseStrategy,
ChildActivationEnd,
ChildActivationStart,
ChildrenOutletContexts,
DefaultTitleStrategy,
DefaultUrlSerializer,
EventType,
GuardsCheckEnd,
GuardsCheckStart,
NavigationCancel,
NavigationCancellationCode,
NavigationEnd,
NavigationError,
NavigationSkipped,
NavigationSkippedCode,
NavigationStart,
NoPreloading,
OutletContext,
PRIMARY_OUTLET,
PreloadAllModules,
PreloadingStrategy,
ROUTER_CONFIGURATION,
ROUTER_INITIALIZER,
ROUTER_OUTLET_DATA,
ROUTES,
RedirectCommand,
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,
withViewTransitions,
ɵEmptyOutletComponent,
ROUTER_PROVIDERS as ɵROUTER_PROVIDERS,
afterNextNavigation as ɵafterNextNavigation,
loadChildren as ɵloadChildren
};
/*! Bundled license information:
@angular/router/fesm2022/router2.mjs:
@angular/router/fesm2022/router_module.mjs:
@angular/router/fesm2022/router.mjs:
(**
* @license Angular v20.2.4
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*)
*/
//# sourceMappingURL=@angular_router.js.map