@loozo/angular-router 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +178 -39
- package/fesm2022/loozo-angular-router-_core.mjs +33 -2
- package/fesm2022/loozo-angular-router-_core.mjs.map +1 -1
- package/fesm2022/loozo-angular-router-_generated.mjs +196 -43
- package/fesm2022/loozo-angular-router-_generated.mjs.map +1 -1
- package/fesm2022/loozo-angular-router.mjs +2 -2
- package/node/src/builders/serve.js +82 -87
- package/node/src/generation/emit.js +29 -3
- package/node/src/generation/files.d.ts +1 -0
- package/node/src/generation/files.js +13 -2
- package/node/src/generation/overlay.js +9 -2
- package/node/src/generation/sources.js +12 -5
- package/package.json +1 -1
- package/snippets/generated/destinations.generated.ts +25 -1
- package/snippets/src/routes/products/$productId/route.generated.ts +4 -2
- package/snippets/src/routes/reports/$reportId/route.generated.ts +4 -2
- package/snippets/src/routes/teams/$teamId/items/$id/inputs.ts +2 -1
- package/snippets/src/routes/teams/$teamId/items/$id/links.ts +6 -4
- package/snippets/src/routes/teams/$teamId/items/$id/page.spec.ts +29 -0
- package/snippets/src/routes/teams/$teamId/items/$id/route.generated.ts +4 -2
- package/snippets/src/routes/teams/$teamId/members/$memberId/route.generated.ts +4 -2
- package/snippets/src/routes/teams/$teamId/route.generated.ts +4 -2
- package/snippets/src/routes/teams/$teamId/route.ts +3 -0
- package/snippets/src/shell.ts +39 -3
- package/types/loozo-angular-router-_core.d.ts +135 -53
- package/types/loozo-angular-router-_generated.d.ts +111 -61
- package/types/loozo-angular-router.d.ts +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loozo-angular-router-_core.mjs","names":[],"sources":["../../_core/src/codecs.ts","../../_core/src/path.ts","../../_core/src/records.ts","../../_core/src/route.ts","../../_core/src/url.ts"],"sourcesContent":["/**\n * Converts one decoded path or search value to and from an application value.\n *\n * @remarks\n * Both methods are synchronous, and parsing should be pure and deterministic:\n * like Angular's matching callbacks, it runs once while matching and again for\n * the activated route. Neither method performs URL encoding. Codecs have no\n * Angular injection context, and their returned objects are not recursively frozen.\n * For a terminal `$name[]` path, this codec applies to each element separately.\n *\n * @typeParam Value - The logical value, never a promise of that value.\n *\n * @example\n * ```ts\n * const dateParam: ParamCodec<Date> = {\n * parse: (raw) => new Date(raw),\n * stringify: (value) => value.toISOString(),\n * };\n * ```\n */\nexport interface ParamCodec<Value> {\n /**\n * Parses one already percent-decoded value; do not decode it again.\n *\n * @param raw - A single logical string from Angular's URL inputs.\n * @returns The logical value, synchronously. Returning a promise or other\n * thenable is a programming error that fails the navigation with a TypeError.\n * @throws An application error for invalid input: an invalid path value makes\n * the route not match, and an invalid search value reads as absent or as its fallback.\n */\n parse(raw: string): Value;\n /**\n * Serializes one logical value without percent-encoding it.\n *\n * @param value - The application value to serialize.\n * @returns An unencoded string. Path output must not be empty, `.` or `..`.\n * @throws An application error when the value cannot be serialized.\n */\n stringify(value: Value): string;\n}\n\ndeclare const searchFallback: unique symbol;\n\n/**\n * A search-only codec whose key reads a fallback value when it is missing,\n * repeated or invalid, while URL creation may still omit it.\n */\nexport type FallbackCodec<Value> = ParamCodec<Value> & {\n readonly [searchFallback]: true;\n};\nexport type PathCodec = ParamCodec<any> & { readonly [searchFallback]?: never };\nexport type CodecValue<Codec> = Codec extends ParamCodec<infer Value> ? Value : never;\nexport type HasFallback<Codec> = Codec extends { readonly [searchFallback]: true } ? true : false;\n\n/** Type-only marker: a codec whose parse returns a promise fails where it is declared. */\nexport interface SynchronousParse {\n /** Never present: `parse` must return its value synchronously, not a Promise. */\n readonly \"ParamCodec.parse must return its value synchronously, not a Promise\": never;\n}\ntype ParseResult<Codec> = Codec extends { parse(raw: string): infer Result } ? Result : never;\nexport type SyncValue<Value> =\n Extract<Value, PromiseLike<unknown>> extends never ? unknown : SynchronousParse;\nexport type SyncCodecs<Codecs> = {\n [Key in keyof Codecs]: SyncValue<ParseResult<Codecs[Key]>>;\n};\n\nconst fallbacks = new WeakMap<object, { readonly value: unknown }>();\n\nexport function codecFallback(codec: object): { readonly value: unknown } | undefined {\n return fallbacks.get(codec);\n}\n\nexport function validateCodec(codec: unknown): asserts codec is ParamCodec<any> {\n if (\n codec === null ||\n (typeof codec !== \"object\" && typeof codec !== \"function\") ||\n typeof (codec as ParamCodec<unknown>).parse !== \"function\" ||\n typeof (codec as ParamCodec<unknown>).stringify !== \"function\"\n ) {\n throw new TypeError(\"Codec must have callable parse and stringify methods\");\n }\n}\n\n/**\n * Preserves strings verbatim, including empty strings and literal percent text.\n *\n * @remarks\n * Empty, dot and dotdot values are valid codec values but cannot be serialized\n * into path segments by URL creation. Search values may contain them.\n */\nexport const stringParam: ParamCodec<string> = {\n parse(raw) {\n return raw;\n },\n stringify(value) {\n if (typeof value !== \"string\") {\n throw new TypeError(\"Expected a string\");\n }\n\n return value;\n },\n};\n\n/**\n * Parses nonblank text with JavaScript `Number` and requires a finite result.\n *\n * @remarks\n * Whitespace around numbers, exponent notation and hexadecimal text are accepted.\n * Blank text, NaN and infinities throw. Stringification requires a finite number\n * and uses its JavaScript string representation (including `-0` becoming `\"0\"`).\n */\nexport const numberParam: ParamCodec<number> = {\n parse(raw) {\n const value = Number(raw);\n\n if (raw.trim() === \"\" || !Number.isFinite(value)) {\n throw new Error(\"Expected a finite number\");\n }\n\n return value;\n },\n stringify(value) {\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n throw new Error(\"Expected a finite number\");\n }\n\n return String(value);\n },\n};\n\n/**\n * Parses only lowercase `\"true\"` and `\"false\"`, and emits those same strings.\n * Other representations and nonboolean values throw.\n */\nexport const booleanParam: ParamCodec<boolean> = {\n parse(raw) {\n if (raw === \"true\") {\n return true;\n }\n\n if (raw === \"false\") {\n return false;\n }\n\n throw new Error(\"Expected true or false\");\n },\n stringify(value) {\n if (value === true) {\n return \"true\";\n }\n\n if (value === false) {\n return \"false\";\n }\n\n throw new Error(\"Expected a boolean\");\n },\n};\n\n/**\n * Creates a case-sensitive string codec from a snapshotted list of members.\n *\n * @typeParam Values - The literal list from which the value union is inferred.\n * @param values - Allowed decoded strings; an empty string is valid when listed.\n * @returns A codec whose parser and stringifier reject nonmembers.\n * @throws TypeError if the list or its entries are malformed.\n *\n * @example\n * ```ts\n * const tab = enumParam([\"details\", \"reviews\"]);\n * tab.parse(\"reviews\"); // \"reviews\"\n * ```\n */\nexport function enumParam<const Values extends readonly string[]>(\n values: Values,\n): ParamCodec<Values[number]> {\n if (!Array.isArray(values)) {\n throw new TypeError(\"Enum values must be a string list\");\n }\n\n const members = new Set<string>();\n\n for (const value of values) {\n if (typeof value !== \"string\") {\n throw new TypeError(\"Enum values must be strings\");\n }\n\n members.add(value);\n }\n\n return {\n parse(raw) {\n if (!members.has(raw)) {\n throw new Error(\"Unknown enum value\");\n }\n\n return raw as Values[number];\n },\n stringify(value) {\n if (!members.has(value)) {\n throw new Error(\"Unknown enum value\");\n }\n\n return value;\n },\n };\n}\n\n/**\n * Gives a search key a value read in place of a missing, repeated or invalid one.\n *\n * @remarks\n * Every search key is optional: a plain codec's key reads as absent when its\n * value is missing, repeated or invalid. With a fallback, the key always reads a\n * value of the codec's type, while URL creation, links, navigation and redirect\n * replacements may still omit it. The fallback is returned as is: it is neither\n * parsed nor copied. Present values delegate to the wrapped codec unchanged.\n * Fallback codecs are search-only: a path param can't use one.\n *\n * @example\n * ```ts\n * search: { page: withFallback(numberParam, 1) }\n * // ?page=abc, ?page=1&page=2 and no page all read as 1.\n * ```\n *\n * @typeParam Value - The wrapped codec's logical value.\n * @param codec - The codec used for present search values.\n * @param fallback - The value read when the key is missing, repeated or invalid.\n * @returns A search-only codec that reads the fallback in place of an absent value.\n * @throws TypeError if the codec lacks callable parse/stringify methods or already\n * has a fallback.\n */\nexport function withFallback<Value>(\n codec: ParamCodec<Value> & SyncValue<NoInfer<Value>>,\n fallback: NoInfer<Value>,\n): FallbackCodec<Value> {\n validateCodec(codec);\n\n if (codecFallback(codec)) {\n throw new TypeError(\"withFallback cannot wrap a codec that already has a fallback\");\n }\n\n const wrapper: ParamCodec<Value> = {\n parse(raw) {\n return codec.parse(raw);\n },\n stringify(value) {\n return codec.stringify(value);\n },\n };\n\n fallbacks.set(wrapper, Object.freeze({ value: fallback }));\n\n return wrapper as FallbackCodec<Value>;\n}\n","type ValidName<Name extends string> = Name extends\n | \"\"\n | \"__proto__\"\n | `...${string}`\n | `${string}?${string}`\n | `${string}*${string}`\n | `${string}[]${string}`\n ? false\n : true;\ntype SegmentValid<Segment extends string> = Segment extends `$${infer Name}`\n ? ValidName<Name>\n : Segment extends \"\" | \".\" | \"..\" | \"*\" | \"**\" | `:${string}`\n ? false\n : true;\ntype ValidateSegments<\n Path extends string,\n Scalars extends string = never,\n> = Path extends `${infer Head}/${infer Tail}`\n ? Head extends `$${string}[]`\n ? false\n : SegmentValid<Head> extends true\n ? ValidateSegments<Tail, Scalars | ScalarName<Head>>\n : false\n : Path extends `$${infer Name}[]`\n ? ValidName<Name> extends true\n ? Name extends Scalars\n ? false\n : true\n : false\n : SegmentValid<Path>;\nexport type ValidPath<Path extends string> = string extends Path\n ? never\n : Path extends \"\"\n ? Path\n : ValidateSegments<Path> extends true\n ? Path\n : never;\ntype ScalarName<Segment extends string> = Segment extends `$${infer Name}` ? Name : never;\ntype SegmentName<Segment extends string> = Segment extends `$${infer Name}[]`\n ? Name\n : ScalarName<Segment>;\nexport type PathNames<Path extends string> = Path extends `${infer Head}/${infer Tail}`\n ? SegmentName<Head> | PathNames<Tail>\n : SegmentName<Path>;\nexport type CatchallName<Path extends string> = Path extends `${string}/${infer Tail}`\n ? CatchallName<Tail>\n : Path extends `$${infer Name}[]`\n ? Name\n : never;\n\nexport type Segment =\n | { readonly kind: \"static\"; readonly text: string }\n | { readonly kind: \"scalar\" | \"catchall\"; readonly name: string };\n\nexport function parsePath(path: unknown): readonly Segment[] {\n if (typeof path !== \"string\") {\n throw new TypeError(\"Path must be a string\");\n }\n\n if (path === \"\") {\n return Object.freeze([]);\n }\n\n const segments: Segment[] = [];\n const scalarNames = new Set<string>();\n const parts = path.split(\"/\");\n\n for (let index = 0; index < parts.length; index += 1) {\n const part = parts[index];\n\n if (part.startsWith(\"$\")) {\n let name = part.slice(1);\n let kind: \"scalar\" | \"catchall\" = \"scalar\";\n\n if (name.endsWith(\"[]\")) {\n name = name.slice(0, -2);\n kind = \"catchall\";\n }\n\n if (\n name === \"\" ||\n name === \"__proto__\" ||\n name.startsWith(\"...\") ||\n name.includes(\"?\") ||\n name.includes(\"*\") ||\n name.includes(\"[]\")\n ) {\n throw new TypeError(`Invalid parameter name: ${name}`);\n }\n\n if (kind === \"catchall\" && (index !== parts.length - 1 || scalarNames.has(name))) {\n throw new TypeError(\"Catchall must be terminal and cannot repeat a scalar name\");\n }\n\n scalarNames.add(name);\n segments.push(Object.freeze({ kind, name }));\n } else {\n if (\n part === \"\" ||\n part === \".\" ||\n part === \"..\" ||\n part === \"*\" ||\n part === \"**\" ||\n part.startsWith(\":\")\n ) {\n throw new TypeError(`Invalid static segment: ${part}`);\n }\n\n if (!part.isWellFormed()) {\n throw new TypeError(\"Static path Unicode must be well formed\");\n }\n\n segments.push(Object.freeze({ kind: \"static\", text: part }));\n }\n }\n\n return Object.freeze(segments);\n}\n","export function ownRecord(\n value: unknown,\n label: string,\n allowSymbols = false,\n): Record<string, unknown> {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n throw new TypeError(`${label} must be an own record`);\n }\n\n const prototype = Object.getPrototypeOf(value);\n\n if (prototype !== Object.prototype && prototype !== null) {\n throw new TypeError(`${label} cannot contain inherited entries`);\n }\n\n for (const key of Reflect.ownKeys(value)) {\n if (\n (!allowSymbols && typeof key !== \"string\") ||\n !Object.prototype.propertyIsEnumerable.call(value, key)\n ) {\n throw new TypeError(`${label} contains an unsupported key`);\n }\n }\n\n return value as Record<string, unknown>;\n}\n\nexport function checkKeys(\n record: Record<string, unknown>,\n allowed: ReadonlySet<string>,\n label: string,\n): void {\n for (const key of Object.keys(record)) {\n if (!allowed.has(key)) {\n throw new TypeError(`Unknown ${label} key: ${key}`);\n }\n }\n}\n\nexport function has(record: object, key: PropertyKey): boolean {\n return Object.hasOwn(record, key);\n}\n","import { codecFallback, validateCodec, type ParamCodec, type PathCodec } from \"./codecs.js\";\nimport { parsePath, type Segment, type ValidPath, type CatchallName } from \"./path.js\";\nimport { checkKeys, has, ownRecord } from \"./records.js\";\nimport type {\n AnyRoute,\n CodecMap,\n EffectiveParams,\n EffectiveSearch,\n Route,\n RouteConfig,\n SearchOf,\n} from \"./types.js\";\n\nexport interface RouteMetadata {\n readonly parent?: AnyRoute;\n readonly localSegments: readonly Segment[];\n readonly segments: readonly Segment[];\n readonly localParams: Readonly<Record<string, ParamCodec<any>>>;\n readonly localSearch: Readonly<Record<string, ParamCodec<any>>>;\n readonly params: Readonly<Record<string, ParamCodec<any>>>;\n readonly search: Readonly<Record<string, ParamCodec<any>>>;\n readonly fragments: readonly string[];\n readonly config: Readonly<Record<string, unknown>>;\n}\n\nconst routes = new WeakMap<object, RouteMetadata>();\nconst configKeys = new Set([\n \"parent\",\n \"params\",\n \"search\",\n \"resolve\",\n \"runGuardsAndResolvers\",\n \"redirect\",\n \"fragments\",\n \"canActivate\",\n \"canActivateChild\",\n \"canMatch\",\n \"onInvalidParams\",\n \"canDeactivate\",\n \"providers\",\n \"title\",\n \"data\",\n]);\nconst policies = new Set([\n \"pathParamsChange\",\n \"pathParamsOrQueryParamsChange\",\n \"paramsChange\",\n \"paramsOrQueryParamsChange\",\n \"always\",\n]);\nconst identityKey = \"__loozoAngularRouterRouteId\";\n\nexport function routeMetadata(route: unknown): RouteMetadata {\n if (route === null || typeof route !== \"object\" || !routes.has(route)) {\n throw new TypeError(\"Expected a genuine route from this package instance\");\n }\n\n return routes.get(route)!;\n}\n\nfunction copyCodecs(value: unknown, path: boolean): Readonly<Record<string, ParamCodec<any>>> {\n const record = ownRecord(value, \"Codec map\");\n const result: Record<string, ParamCodec<any>> = Object.create(null);\n\n for (const key of Object.keys(record)) {\n const codec = record[key];\n\n validateCodec(codec);\n\n if (path && codecFallback(codec)) {\n throw new TypeError(\"withFallback codecs are search-only\");\n }\n\n result[key] = codec;\n }\n\n return Object.freeze(result);\n}\n\nfunction snapshotRedirect(\n value: unknown,\n source: RouteMetadata,\n): Readonly<Record<string, unknown>> {\n const redirect = ownRecord(value, \"Redirect\");\n\n checkKeys(redirect, new Set([\"to\", \"params\", \"search\", \"fragment\"]), \"redirect\");\n\n const target = routeMetadata(redirect.to);\n const mapping: Record<string, string> = Object.create(null);\n\n if (has(redirect, \"params\")) {\n const supplied = ownRecord(redirect.params, \"Redirect params\");\n\n checkKeys(supplied, new Set(Object.keys(target.params)), \"redirect params\");\n\n for (const key of Object.keys(target.params)) {\n const sourceKey = supplied[key];\n\n if (!has(supplied, key) || typeof sourceKey !== \"string\" || !has(source.params, sourceKey)) {\n throw new TypeError(`Missing or invalid redirect mapping: ${key}`);\n }\n\n mapping[key] = sourceKey;\n }\n } else {\n for (const key of Object.keys(target.params)) {\n if (!has(source.params, key)) {\n throw new TypeError(`Cannot forward redirect param: ${key}`);\n }\n\n mapping[key] = key;\n }\n }\n\n const search = ownRecord(redirect.search, \"Redirect search\");\n let searchSnapshot: Record<string, unknown>;\n\n if (search.mode === \"replace\") {\n checkKeys(search, new Set([\"mode\", \"values\"]), \"redirect search\");\n\n const values = ownRecord(search.values, \"Redirect replacement\");\n\n checkKeys(values, new Set(Object.keys(target.search)), \"search values\");\n searchSnapshot = { mode: \"replace\", values: Object.freeze({ ...values }) };\n } else if (search.mode === \"preserve\" || search.mode === \"drop\") {\n checkKeys(search, new Set([\"mode\"]), \"redirect search\");\n searchSnapshot = { mode: search.mode };\n } else {\n throw new TypeError(\"Invalid redirect search policy\");\n }\n\n const fragment = ownRecord(redirect.fragment, \"Redirect fragment\");\n\n if (fragment.mode === \"replace\") {\n checkKeys(fragment, new Set([\"mode\", \"value\"]), \"redirect fragment\");\n\n if (typeof fragment.value !== \"string\" || !target.fragments.includes(fragment.value)) {\n throw new TypeError(\"Redirect fragment must belong to target declaration\");\n }\n } else if (fragment.mode === \"preserve\" || fragment.mode === \"drop\") {\n checkKeys(fragment, new Set([\"mode\"]), \"redirect fragment\");\n } else {\n throw new TypeError(\"Invalid redirect fragment policy\");\n }\n\n return Object.freeze({\n to: redirect.to,\n params: Object.freeze(mapping),\n search: Object.freeze(searchSnapshot),\n fragment: Object.freeze({ ...fragment }),\n });\n}\n\n/**\n * Declares a nominal typed route without executing codecs or native callbacks.\n *\n * @remarks\n * Paths are decoded authored text, not URLs: use `\"\"` for root/pathless nodes,\n * `$name` for a scalar segment and terminal `$name[]` for a zero-or-more\n * catchall. Repeated local scalar names reuse one value. Leading/trailing or\n * repeated slashes, dot segments and Angular `:name`/wildcard notation are invalid.\n *\n * Parents compose effective params/search transitively, including through\n * pathless nodes. Children cannot redeclare ancestor-owned keys or have a\n * catchall parent. Fragment names belong only to this declaration.\n * The route and copied containers are shallow-frozen; application codecs,\n * callbacks, providers and opaque values retain identity and are not deep-frozen.\n *\n * For generation, author a direct default export of this call with a literal\n * path and inline config. Parent and redirect targets must be direct default\n * imports of admitted declarations. Angular owns activation and navigation;\n * declaration alone does not register a route with Angular.\n *\n * @param path - The literal local path, relative to the authored parent.\n * @param config - Local codecs, parent, fragments and supported native behavior.\n * Structural Angular options such as children, component and matcher are\n * generator-owned and cannot be overridden.\n * @returns A frozen route preserving inferred effective input and local data types.\n * @throws TypeError for invalid paths/configuration, missing or extra local\n * codecs, fallback codecs in path params, inherited key conflicts, or\n * nongenuine parent/redirect routes.\n *\n * @example\n * ```ts\n * const product = defineRoute(\"products/$productId\", {\n * params: { productId: numberParam },\n * search: { tab: withFallback(enumParam([\"details\", \"reviews\"]), \"details\") },\n * fragments: [\"summary\", \"reviews\"],\n * });\n * ```\n */\nexport function defineRoute<\n const Path extends string,\n Parent extends AnyRoute | undefined = undefined,\n Params extends Record<string, PathCodec> = {},\n Search extends CodecMap = {},\n Resolvers extends Record<string, (...args: any[]) => unknown> = {},\n const Fragments extends readonly string[] = [],\n Target extends AnyRoute | undefined = undefined,\n ReplacementKeys extends keyof SearchOf<NoInfer<Target>> = never,\n>(\n path: Path & ValidPath<Path>,\n config: RouteConfig<Path, Parent, Params, Search, Resolvers, Fragments, Target, ReplacementKeys>,\n): Route<\n Path,\n EffectiveParams<Path, Params, Parent>,\n EffectiveSearch<Search, Parent>,\n Resolvers,\n Fragments[number],\n CatchallName<Path> extends never ? false : true\n>;\n\nexport function defineRoute(path: unknown, config: unknown): AnyRoute {\n const supplied = ownRecord(config, \"Route config\");\n\n checkKeys(supplied, configKeys, \"route config\");\n\n const localSegments = parsePath(path);\n let parent: AnyRoute | undefined;\n let inherited: RouteMetadata | undefined;\n\n if (has(supplied, \"parent\")) {\n inherited = routeMetadata(supplied.parent);\n parent = supplied.parent as AnyRoute;\n\n for (const segment of inherited.segments) {\n if (segment.kind === \"catchall\") {\n throw new TypeError(\"Catchall declarations cannot have children\");\n }\n }\n }\n\n const localNames = new Set<string>();\n\n for (const segment of localSegments) {\n if (segment.kind !== \"static\") {\n localNames.add(segment.name);\n }\n }\n\n let localParams: Readonly<Record<string, ParamCodec<any>>> = Object.freeze(Object.create(null));\n\n if (localNames.size === 0) {\n if (has(supplied, \"params\")) {\n throw new TypeError(\"Static paths cannot declare params\");\n }\n } else {\n localParams = copyCodecs(supplied.params, true);\n checkKeys(localParams, localNames, \"local params\");\n\n for (const key of localNames) {\n if (!has(localParams, key)) {\n throw new TypeError(`Missing local codec: ${key}`);\n }\n\n if (inherited && has(inherited.params, key)) {\n throw new TypeError(`Inherited param already owned: ${key}`);\n }\n }\n }\n\n let localSearch: Readonly<Record<string, ParamCodec<any>>> = Object.freeze(Object.create(null));\n\n if (has(supplied, \"search\")) {\n localSearch = copyCodecs(supplied.search, false);\n }\n\n for (const key of Object.keys(localSearch)) {\n if (inherited && has(inherited.search, key)) {\n throw new TypeError(`Inherited search already owned: ${key}`);\n }\n }\n\n const retained: Record<string, unknown> = { ...supplied };\n const result: {\n path: string;\n resolve?: Readonly<Record<PropertyKey, unknown>>;\n runGuardsAndResolvers?: unknown;\n } = { path: path as string };\n\n if (has(supplied, \"resolve\")) {\n const resolve = ownRecord(supplied.resolve, \"Resolvers\", true) as Record<PropertyKey, unknown>;\n const copied: Record<PropertyKey, unknown> = Object.create(null);\n\n for (const key of Reflect.ownKeys(resolve)) {\n if (key === identityKey || typeof resolve[key] !== \"function\") {\n throw new TypeError(`Invalid resolver: ${String(key)}`);\n }\n\n copied[key] = resolve[key];\n }\n\n result.resolve = Object.freeze(copied);\n retained.resolve = result.resolve;\n }\n\n if (has(supplied, \"runGuardsAndResolvers\")) {\n const policy = supplied.runGuardsAndResolvers;\n\n if (typeof policy !== \"function\" && (typeof policy !== \"string\" || !policies.has(policy))) {\n throw new TypeError(\"Invalid native rerun policy\");\n }\n\n result.runGuardsAndResolvers = policy;\n }\n\n for (const key of [\"canActivate\", \"canActivateChild\", \"canMatch\", \"canDeactivate\", \"providers\"]) {\n if (!has(supplied, key)) {\n continue;\n }\n\n const list = supplied[key];\n\n if (!Array.isArray(list)) {\n throw new TypeError(`${key} must be an array`);\n }\n\n if (key === \"canActivate\" || key === \"canActivateChild\" || key === \"canMatch\") {\n for (const callback of list) {\n if (typeof callback !== \"function\") {\n throw new TypeError(`${key} entries must be callbacks`);\n }\n }\n } else if (key === \"canDeactivate\") {\n for (const guard of list) {\n if (\n guard === null ||\n (typeof guard !== \"function\" && typeof guard !== \"object\" && typeof guard !== \"string\")\n ) {\n throw new TypeError(\"canDeactivate entries must be native callbacks or tokens\");\n }\n }\n }\n\n retained[key] = Object.freeze([...list]);\n }\n\n if (has(supplied, \"onInvalidParams\")) {\n if (typeof supplied.onInvalidParams !== \"function\") {\n throw new TypeError(\"onInvalidParams must be a callback\");\n }\n\n if (localNames.size === 0) {\n throw new TypeError(\"onInvalidParams requires local path params\");\n }\n }\n\n if (\n has(supplied, \"title\") &&\n typeof supplied.title !== \"string\" &&\n typeof supplied.title !== \"function\"\n ) {\n throw new TypeError(\"Title must be a string or a callback\");\n }\n\n if (has(supplied, \"data\")) {\n const data = ownRecord(supplied.data, \"Static data\", true);\n\n if (has(data, identityKey)) {\n throw new TypeError(\"Static data cannot set generated identity\");\n }\n\n retained.data = Object.freeze({ ...data });\n }\n\n const fragments: string[] = [];\n\n if (has(supplied, \"fragments\")) {\n if (!Array.isArray(supplied.fragments)) {\n throw new TypeError(\"Fragments must be a string list\");\n }\n\n for (const name of supplied.fragments) {\n if (typeof name !== \"string\") {\n throw new TypeError(\"Fragment names must be strings\");\n }\n\n fragments.push(name);\n }\n }\n\n retained.fragments = Object.freeze(fragments);\n retained.params = localParams;\n retained.search = localSearch;\n\n const metadata: RouteMetadata = {\n parent,\n localSegments,\n segments: Object.freeze([...(inherited?.segments ?? []), ...localSegments]),\n localParams,\n localSearch,\n params: Object.freeze({ ...inherited?.params, ...localParams }),\n search: Object.freeze({ ...inherited?.search, ...localSearch }),\n fragments: retained.fragments as readonly string[],\n config: retained,\n };\n\n if (has(supplied, \"redirect\")) {\n if (\n has(supplied, \"canActivate\") ||\n has(supplied, \"canMatch\") ||\n has(supplied, \"onInvalidParams\")\n ) {\n throw new TypeError(\"Redirect cannot declare own canActivate, canMatch or onInvalidParams\");\n }\n\n retained.redirect = snapshotRedirect(supplied.redirect, metadata);\n }\n\n Object.freeze(retained);\n routes.set(result, Object.freeze(metadata));\n\n return Object.freeze(result) as AnyRoute;\n}\n","import type { ParamCodec } from \"./codecs.js\";\nimport { ownRecord, checkKeys, has } from \"./records.js\";\nimport { routeMetadata } from \"./route.js\";\nimport type { AnyRoute, SearchOf, UrlValues } from \"./types.js\";\n\nfunction encode(value: string): string {\n return encodeURIComponent(value).replaceAll(\"(\", \"%28\").replaceAll(\")\", \"%29\");\n}\n\nfunction stringify(codec: ParamCodec<any>, value: unknown, path: boolean): string {\n const text = codec.stringify(value);\n\n if (typeof text !== \"string\") {\n throw new TypeError(\"Codec stringify must return a string\");\n }\n\n if (path && (text === \"\" || text === \".\" || text === \"..\")) {\n throw new TypeError(\"Path output cannot be empty, dot or dotdot\");\n }\n\n return encode(text);\n}\n\n/**\n * Synchronously serializes a route's explicit values into a root-relative URL.\n *\n * @remarks\n * Includes inherited path/search declarations, but only this route's fragment\n * names. Every effective path value must be supplied; any search key may be\n * omitted. Searchless/paramless routes forbid those records. Catchalls require readonly arrays, including a valid empty array.\n * Values are never taken from a current navigation.\n *\n * Stringifies without calling parsers, guards, resolvers or redirects. Static\n * segments and logical values are component-encoded (also escaping parentheses),\n * so a dynamic slash becomes `%2F`. Search keys are globally sorted; omitted\n * and `undefined` values are left out. An empty effective path produces `/`.\n * Redirect declarations serialize their source URL, not their redirect target.\n *\n * @param route - A genuine declaration from this physical package instance,\n * not a generated destination, spread/copy or structural lookalike.\n * @param values - Explicit destination-typed params, search and optional fragment.\n * Pass an empty object when the route needs no values.\n * @returns A root-relative URL string, typed `` `/${string}` ``; this does not navigate or\n * return a UrlTree.\n * @throws TypeError for invalid routes/records, missing or unknown keys,\n * undeclared fragments, nonarray catchalls, nonstring codec output, or empty/dot\n * path output. Application stringifier failures propagate unchanged.\n * @throws URIError for ill-formed Unicode in a serialized value.\n *\n * @example\n * ```ts\n * const product = defineRoute(\"products/$productId\", {\n * params: { productId: numberParam },\n * fragments: [\"summary\"],\n * });\n * createUrl(product, { params: { productId: 42 }, fragment: \"summary\" });\n * // /products/42#summary\n * ```\n */\nexport function createUrl<\n Target extends AnyRoute,\n SearchKeys extends keyof SearchOf<NoInfer<Target>> = never,\n>(route: Target, values: UrlValues<NoInfer<Target>, SearchKeys>): `/${string}`;\n\nexport function createUrl(route: unknown, values: unknown): `/${string}` {\n const metadata = routeMetadata(route);\n const options = ownRecord(values, \"URL options\");\n\n checkKeys(options, new Set([\"params\", \"search\", \"fragment\"]), \"URL options\");\n\n const paramKeys = Object.keys(metadata.params);\n let params: Record<string, unknown> = Object.create(null);\n\n if (paramKeys.length === 0) {\n if (has(options, \"params\")) {\n throw new TypeError(\"Route has no path params\");\n }\n } else {\n params = ownRecord(options.params, \"Path values\");\n checkKeys(params, new Set(paramKeys), \"path values\");\n\n for (const key of paramKeys) {\n if (!has(params, key)) {\n throw new TypeError(`Missing path value: ${key}`);\n }\n }\n }\n\n const searchKeys = Object.keys(metadata.search).sort();\n let search: Record<string, unknown> = Object.create(null);\n\n if (searchKeys.length === 0) {\n if (has(options, \"search\")) {\n throw new TypeError(\"Route has no search declarations\");\n }\n } else {\n if (has(options, \"search\")) {\n search = ownRecord(options.search, \"Search values\");\n }\n\n checkKeys(search, new Set(searchKeys), \"search values\");\n }\n\n if (has(options, \"fragment\")) {\n if (typeof options.fragment !== \"string\" || !metadata.fragments.includes(options.fragment)) {\n throw new TypeError(\"Fragment must belong to this declaration\");\n }\n }\n\n // Check all cardinalities before invoking application stringifiers.\n for (const segment of metadata.segments) {\n if (segment.kind === \"catchall\" && !Array.isArray(params[segment.name])) {\n throw new TypeError(`Catchall requires an array: ${segment.name}`);\n }\n }\n\n const parts: string[] = [];\n\n for (const segment of metadata.segments) {\n if (segment.kind === \"static\") {\n parts.push(encode(segment.text));\n } else if (segment.kind === \"scalar\") {\n parts.push(stringify(metadata.params[segment.name], params[segment.name], true));\n } else {\n for (const value of params[segment.name] as readonly unknown[]) {\n parts.push(stringify(metadata.params[segment.name], value, true));\n }\n }\n }\n\n let url: `/${string}` = `/${parts.join(\"/\")}`;\n const query: string[] = [];\n\n for (const key of searchKeys) {\n const value = search[key];\n\n if (!has(search, key) || value === undefined) {\n continue;\n }\n\n query.push(`${encode(key)}=${stringify(metadata.search[key], value, false)}`);\n }\n\n if (query.length > 0) {\n url = `${url}?${query.join(\"&\")}`;\n }\n\n if (has(options, \"fragment\")) {\n url = `${url}#${encode(options.fragment as string)}`;\n }\n\n return url;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"loozo-angular-router-_core.mjs","names":[],"sources":["../../_core/src/codecs.ts","../../_core/src/path.ts","../../_core/src/records.ts","../../_core/src/route.ts","../../_core/src/url.ts"],"sourcesContent":["/**\n * Converts one decoded path or search value to and from an application value.\n *\n * @remarks\n * Both methods are synchronous, and parsing should be pure and deterministic:\n * like Angular's matching callbacks, it runs once while matching and again for\n * the activated route. Neither method performs URL encoding. Codecs have no\n * Angular injection context, and their returned objects are not recursively frozen.\n * For a terminal `$name[]` path or an `arrayParam` search key, this codec applies\n * to each element separately.\n *\n * @typeParam Value - The logical value, never a promise of that value.\n *\n * @example\n * ```ts\n * const dateParam: ParamCodec<Date> = {\n * parse: (raw) => new Date(raw),\n * stringify: (value) => value.toISOString(),\n * };\n * ```\n */\nexport interface ParamCodec<Value> {\n /**\n * Parses one already percent-decoded value; do not decode it again.\n *\n * @param raw - A single logical string from Angular's URL inputs.\n * @returns The logical value, synchronously. Returning a promise or other\n * thenable is a programming error that fails the navigation with a TypeError.\n * @throws An application error for invalid input: an invalid path value makes\n * the route not match, and an invalid search value reads as absent or as its fallback\n * (an `arrayParam` key reads an empty array).\n */\n parse(raw: string): Value;\n /**\n * Serializes one logical value without percent-encoding it.\n *\n * @param value - The application value to serialize.\n * @returns An unencoded string. Path output must not be empty, `.` or `..`.\n * @throws An application error when the value cannot be serialized.\n */\n stringify(value: Value): string;\n}\n\ndeclare const searchFallback: unique symbol;\ndeclare const searchArray: unique symbol;\n\n/**\n * A search-only codec whose key reads a fallback value when it is missing,\n * repeated or invalid, while URL creation may still omit it.\n */\nexport type FallbackCodec<Value> = ParamCodec<Value> & {\n readonly [searchFallback]: true;\n};\n/**\n * A search-only codec whose key reads every repeated value, in URL order, as a\n * readonly array; its parse and stringify handle one value each.\n */\nexport type ArrayCodec<Value> = ParamCodec<Value> & {\n readonly [searchArray]: true;\n};\n/** Codecs that may only wrap a plain codec: not a fallback or array codec. */\ntype PlainCodec = { readonly [searchFallback]?: never; readonly [searchArray]?: never };\nexport type PathCodec = ParamCodec<any> & PlainCodec;\nexport type CodecValue<Codec> = Codec extends ParamCodec<infer Value> ? Value : never;\nexport type HasFallback<Codec> = Codec extends { readonly [searchFallback]: true } ? true : false;\nexport type IsArray<Codec> = Codec extends { readonly [searchArray]: true } ? true : false;\n\n/** Type-only marker: a codec whose parse returns a promise fails where it is declared. */\nexport interface SynchronousParse {\n /** Never present: `parse` must return its value synchronously, not a Promise. */\n readonly \"ParamCodec.parse must return its value synchronously, not a Promise\": never;\n}\ntype ParseResult<Codec> = Codec extends { parse(raw: string): infer Result } ? Result : never;\nexport type SyncValue<Value> =\n Extract<Value, PromiseLike<unknown>> extends never ? unknown : SynchronousParse;\nexport type SyncCodecs<Codecs> = {\n [Key in keyof Codecs]: SyncValue<ParseResult<Codecs[Key]>>;\n};\n\nconst fallbacks = new WeakMap<object, { readonly value: unknown }>();\n\nconst arrays = new WeakSet<object>();\n\nexport function codecFallback(codec: object): { readonly value: unknown } | undefined {\n return fallbacks.get(codec);\n}\n\nexport function isArrayCodec(codec: object): boolean {\n return arrays.has(codec);\n}\n\nexport function validateCodec(codec: unknown): asserts codec is ParamCodec<any> {\n if (\n codec === null ||\n (typeof codec !== \"object\" && typeof codec !== \"function\") ||\n typeof (codec as ParamCodec<unknown>).parse !== \"function\" ||\n typeof (codec as ParamCodec<unknown>).stringify !== \"function\"\n ) {\n throw new TypeError(\"Codec must have callable parse and stringify methods\");\n }\n}\n\n/**\n * Preserves strings verbatim, including empty strings and literal percent text.\n *\n * @remarks\n * Empty, dot and dotdot values are valid codec values but cannot be serialized\n * into path segments by URL creation. Search values may contain them.\n */\nexport const stringParam: ParamCodec<string> = {\n parse(raw) {\n return raw;\n },\n stringify(value) {\n if (typeof value !== \"string\") {\n throw new TypeError(\"Expected a string\");\n }\n\n return value;\n },\n};\n\n/**\n * Parses nonblank text with JavaScript `Number` and requires a finite result.\n *\n * @remarks\n * Whitespace around numbers, exponent notation and hexadecimal text are accepted.\n * Blank text, NaN and infinities throw. Stringification requires a finite number\n * and uses its JavaScript string representation (including `-0` becoming `\"0\"`).\n */\nexport const numberParam: ParamCodec<number> = {\n parse(raw) {\n const value = Number(raw);\n\n if (raw.trim() === \"\" || !Number.isFinite(value)) {\n throw new Error(\"Expected a finite number\");\n }\n\n return value;\n },\n stringify(value) {\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n throw new Error(\"Expected a finite number\");\n }\n\n return String(value);\n },\n};\n\n/**\n * Parses only lowercase `\"true\"` and `\"false\"`, and emits those same strings.\n * Other representations and nonboolean values throw.\n */\nexport const booleanParam: ParamCodec<boolean> = {\n parse(raw) {\n if (raw === \"true\") {\n return true;\n }\n\n if (raw === \"false\") {\n return false;\n }\n\n throw new Error(\"Expected true or false\");\n },\n stringify(value) {\n if (value === true) {\n return \"true\";\n }\n\n if (value === false) {\n return \"false\";\n }\n\n throw new Error(\"Expected a boolean\");\n },\n};\n\n/**\n * Creates a case-sensitive string codec from a snapshotted list of members.\n *\n * @typeParam Values - The literal list from which the value union is inferred.\n * @param values - Allowed decoded strings; an empty string is valid when listed.\n * @returns A codec whose parser and stringifier reject nonmembers.\n * @throws TypeError if the list or its entries are malformed.\n *\n * @example\n * ```ts\n * const tab = enumParam([\"details\", \"reviews\"]);\n * tab.parse(\"reviews\"); // \"reviews\"\n * ```\n */\nexport function enumParam<const Values extends readonly string[]>(\n values: Values,\n): ParamCodec<Values[number]> {\n if (!Array.isArray(values)) {\n throw new TypeError(\"Enum values must be a string list\");\n }\n\n const members = new Set<string>();\n\n for (const value of values) {\n if (typeof value !== \"string\") {\n throw new TypeError(\"Enum values must be strings\");\n }\n\n members.add(value);\n }\n\n return {\n parse(raw) {\n if (!members.has(raw)) {\n throw new Error(\"Unknown enum value\");\n }\n\n return raw as Values[number];\n },\n stringify(value) {\n if (!members.has(value)) {\n throw new Error(\"Unknown enum value\");\n }\n\n return value;\n },\n };\n}\n\n/**\n * Gives a search key a value read in place of a missing, repeated or invalid one.\n *\n * @remarks\n * Every search key is optional: a plain codec's key reads as absent when its\n * value is missing, repeated or invalid. With a fallback, the key always reads a\n * value of the codec's type, while URL creation, links, navigation and redirect\n * replacements may still omit it. The fallback is returned as is: it is neither\n * parsed nor copied. Present values delegate to the wrapped codec unchanged.\n * Fallback codecs are search-only: a path param can't use one, and neither\n * `withFallback` nor `arrayParam` can wrap one.\n *\n * @example\n * ```ts\n * search: { page: withFallback(numberParam, 1) }\n * // ?page=abc, ?page=1&page=2 and no page all read as 1.\n * ```\n *\n * @typeParam Value - The wrapped codec's logical value.\n * @param codec - The codec used for present search values.\n * @param fallback - The value read when the key is missing, repeated or invalid.\n * @returns A search-only codec that reads the fallback in place of an absent value.\n * @throws TypeError if the codec lacks callable parse/stringify methods, already\n * has a fallback or is an `arrayParam` codec.\n */\nexport function withFallback<Value>(\n codec: ParamCodec<Value> & SyncValue<NoInfer<Value>> & PlainCodec,\n fallback: NoInfer<Value>,\n): FallbackCodec<Value> {\n validateCodec(codec);\n\n if (codecFallback(codec)) {\n throw new TypeError(\"withFallback cannot wrap a codec that already has a fallback\");\n }\n\n if (arrays.has(codec)) {\n throw new TypeError(\"withFallback cannot wrap an arrayParam codec\");\n }\n\n const wrapper: ParamCodec<Value> = {\n parse(raw) {\n return codec.parse(raw);\n },\n stringify(value) {\n return codec.stringify(value);\n },\n };\n\n fallbacks.set(wrapper, Object.freeze({ value: fallback }));\n\n return wrapper as FallbackCodec<Value>;\n}\n\n/**\n * Reads every value of a repeated search key (`?tag=a&tag=b`) as a readonly array.\n *\n * @remarks\n * The key always reads an array, never `undefined`: each value parses with the\n * wrapped codec, in URL order and keeping duplicates. A missing key reads `[]`, and\n * so does a key with any invalid value: one invalid value empties the whole list.\n * URL creation, links, navigation and redirect replacements write one `key=value`\n * pair per element in array order; `[]` and `undefined` leave the key out, so an\n * empty list and a missing key share one URL. Array codecs are search-only (a path\n * uses a terminal `$name[]` instead) and take no fallback: `withFallback` can't wrap\n * one, and `arrayParam` can't wrap a fallback or another array codec.\n *\n * @example\n * ```ts\n * search: { tag: arrayParam(enumParam([\"news\", \"guides\"])) }\n * // ?tag=news&tag=guides reads [\"news\", \"guides\"]; no tag and ?tag=other read [].\n * ```\n *\n * @typeParam Value - The wrapped codec's logical value.\n * @param codec - The codec for each value.\n * @returns A search-only codec whose key reads `readonly Value[]`.\n * @throws TypeError if the codec lacks callable parse/stringify methods, has a\n * fallback or is already an array codec.\n */\nexport function arrayParam<Value>(\n codec: ParamCodec<Value> & SyncValue<NoInfer<Value>> & PlainCodec,\n): ArrayCodec<Value> {\n validateCodec(codec);\n\n if (codecFallback(codec)) {\n throw new TypeError(\"arrayParam cannot wrap a codec that has a fallback\");\n }\n\n if (arrays.has(codec)) {\n throw new TypeError(\"arrayParam cannot wrap another arrayParam codec\");\n }\n\n const wrapper: ParamCodec<Value> = {\n parse(raw) {\n return codec.parse(raw);\n },\n stringify(value) {\n return codec.stringify(value);\n },\n };\n\n arrays.add(wrapper);\n\n return wrapper as ArrayCodec<Value>;\n}\n","type ValidName<Name extends string> = Name extends\n | \"\"\n | \"__proto__\"\n | `...${string}`\n | `${string}?${string}`\n | `${string}*${string}`\n | `${string}[]${string}`\n ? false\n : true;\ntype SegmentValid<Segment extends string> = Segment extends `$${infer Name}`\n ? ValidName<Name>\n : Segment extends \"\" | \".\" | \"..\" | \"*\" | \"**\" | `:${string}`\n ? false\n : true;\ntype ValidateSegments<\n Path extends string,\n Scalars extends string = never,\n> = Path extends `${infer Head}/${infer Tail}`\n ? Head extends `$${string}[]`\n ? false\n : SegmentValid<Head> extends true\n ? ValidateSegments<Tail, Scalars | ScalarName<Head>>\n : false\n : Path extends `$${infer Name}[]`\n ? ValidName<Name> extends true\n ? Name extends Scalars\n ? false\n : true\n : false\n : SegmentValid<Path>;\nexport type ValidPath<Path extends string> = string extends Path\n ? never\n : Path extends \"\"\n ? Path\n : ValidateSegments<Path> extends true\n ? Path\n : never;\ntype ScalarName<Segment extends string> = Segment extends `$${infer Name}` ? Name : never;\ntype SegmentName<Segment extends string> = Segment extends `$${infer Name}[]`\n ? Name\n : ScalarName<Segment>;\nexport type PathNames<Path extends string> = Path extends `${infer Head}/${infer Tail}`\n ? SegmentName<Head> | PathNames<Tail>\n : SegmentName<Path>;\nexport type CatchallName<Path extends string> = Path extends `${string}/${infer Tail}`\n ? CatchallName<Tail>\n : Path extends `$${infer Name}[]`\n ? Name\n : never;\n\nexport type Segment =\n | { readonly kind: \"static\"; readonly text: string }\n | { readonly kind: \"scalar\" | \"catchall\"; readonly name: string };\n\nexport function parsePath(path: unknown): readonly Segment[] {\n if (typeof path !== \"string\") {\n throw new TypeError(\"Path must be a string\");\n }\n\n if (path === \"\") {\n return Object.freeze([]);\n }\n\n const segments: Segment[] = [];\n const scalarNames = new Set<string>();\n const parts = path.split(\"/\");\n\n for (let index = 0; index < parts.length; index += 1) {\n const part = parts[index];\n\n if (part.startsWith(\"$\")) {\n let name = part.slice(1);\n let kind: \"scalar\" | \"catchall\" = \"scalar\";\n\n if (name.endsWith(\"[]\")) {\n name = name.slice(0, -2);\n kind = \"catchall\";\n }\n\n if (\n name === \"\" ||\n name === \"__proto__\" ||\n name.startsWith(\"...\") ||\n name.includes(\"?\") ||\n name.includes(\"*\") ||\n name.includes(\"[]\")\n ) {\n throw new TypeError(`Invalid parameter name: ${name}`);\n }\n\n if (kind === \"catchall\" && (index !== parts.length - 1 || scalarNames.has(name))) {\n throw new TypeError(\"Catchall must be terminal and cannot repeat a scalar name\");\n }\n\n scalarNames.add(name);\n segments.push(Object.freeze({ kind, name }));\n } else {\n if (\n part === \"\" ||\n part === \".\" ||\n part === \"..\" ||\n part === \"*\" ||\n part === \"**\" ||\n part.startsWith(\":\")\n ) {\n throw new TypeError(`Invalid static segment: ${part}`);\n }\n\n if (!part.isWellFormed()) {\n throw new TypeError(\"Static path Unicode must be well formed\");\n }\n\n segments.push(Object.freeze({ kind: \"static\", text: part }));\n }\n }\n\n return Object.freeze(segments);\n}\n","export function ownRecord(\n value: unknown,\n label: string,\n allowSymbols = false,\n): Record<string, unknown> {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n throw new TypeError(`${label} must be an own record`);\n }\n\n const prototype = Object.getPrototypeOf(value);\n\n if (prototype !== Object.prototype && prototype !== null) {\n throw new TypeError(`${label} cannot contain inherited entries`);\n }\n\n for (const key of Reflect.ownKeys(value)) {\n if (\n (!allowSymbols && typeof key !== \"string\") ||\n !Object.prototype.propertyIsEnumerable.call(value, key)\n ) {\n throw new TypeError(`${label} contains an unsupported key`);\n }\n }\n\n return value as Record<string, unknown>;\n}\n\nexport function checkKeys(\n record: Record<string, unknown>,\n allowed: ReadonlySet<string>,\n label: string,\n): void {\n for (const key of Object.keys(record)) {\n if (!allowed.has(key)) {\n throw new TypeError(`Unknown ${label} key: ${key}`);\n }\n }\n}\n\nexport function has(record: object, key: PropertyKey): boolean {\n return Object.hasOwn(record, key);\n}\n","import {\n codecFallback,\n isArrayCodec,\n validateCodec,\n type ParamCodec,\n type PathCodec,\n} from \"./codecs.js\";\nimport { parsePath, type Segment, type ValidPath, type CatchallName } from \"./path.js\";\nimport { checkKeys, has, ownRecord } from \"./records.js\";\nimport type {\n AnyRoute,\n CodecMap,\n EffectiveData,\n EffectiveTitle,\n EffectiveParams,\n EffectiveSearch,\n Route,\n RouteConfig,\n SearchOf,\n} from \"./types.js\";\n\nexport interface RouteMetadata {\n readonly parent?: AnyRoute;\n readonly localSegments: readonly Segment[];\n readonly segments: readonly Segment[];\n readonly localParams: Readonly<Record<string, ParamCodec<any>>>;\n readonly localSearch: Readonly<Record<string, ParamCodec<any>>>;\n readonly params: Readonly<Record<string, ParamCodec<any>>>;\n readonly search: Readonly<Record<string, ParamCodec<any>>>;\n readonly fragments: readonly string[];\n readonly config: Readonly<Record<string, unknown>>;\n}\n\nconst routes = new WeakMap<object, RouteMetadata>();\nconst configKeys = new Set([\n \"parent\",\n \"params\",\n \"search\",\n \"resolve\",\n \"runGuardsAndResolvers\",\n \"redirect\",\n \"fragments\",\n \"canActivate\",\n \"canActivateChild\",\n \"canMatch\",\n \"onInvalidParams\",\n \"canDeactivate\",\n \"providers\",\n \"title\",\n \"data\",\n]);\nconst policies = new Set([\n \"pathParamsChange\",\n \"pathParamsOrQueryParamsChange\",\n \"paramsChange\",\n \"paramsOrQueryParamsChange\",\n \"always\",\n]);\nconst identityKey = \"__loozoAngularRouterRouteId\";\n\nexport function routeMetadata(route: unknown): RouteMetadata {\n if (route === null || typeof route !== \"object\" || !routes.has(route)) {\n throw new TypeError(\"Expected a genuine route from this package instance\");\n }\n\n return routes.get(route)!;\n}\n\nfunction copyCodecs(value: unknown, path: boolean): Readonly<Record<string, ParamCodec<any>>> {\n const record = ownRecord(value, \"Codec map\");\n const result: Record<string, ParamCodec<any>> = Object.create(null);\n\n for (const key of Object.keys(record)) {\n const codec = record[key];\n\n validateCodec(codec);\n\n if (path && codecFallback(codec)) {\n throw new TypeError(\"withFallback codecs are search-only\");\n }\n\n if (path && isArrayCodec(codec)) {\n throw new TypeError(\"arrayParam codecs are search-only\");\n }\n\n result[key] = codec;\n }\n\n return Object.freeze(result);\n}\n\nfunction snapshotRedirect(\n value: unknown,\n source: RouteMetadata,\n): Readonly<Record<string, unknown>> {\n const redirect = ownRecord(value, \"Redirect\");\n\n checkKeys(redirect, new Set([\"to\", \"params\", \"search\", \"fragment\"]), \"redirect\");\n\n const target = routeMetadata(redirect.to);\n const mapping: Record<string, string> = Object.create(null);\n\n if (has(redirect, \"params\")) {\n const supplied = ownRecord(redirect.params, \"Redirect params\");\n\n checkKeys(supplied, new Set(Object.keys(target.params)), \"redirect params\");\n\n for (const key of Object.keys(target.params)) {\n const sourceKey = supplied[key];\n\n if (!has(supplied, key) || typeof sourceKey !== \"string\" || !has(source.params, sourceKey)) {\n throw new TypeError(`Missing or invalid redirect mapping: ${key}`);\n }\n\n mapping[key] = sourceKey;\n }\n } else {\n for (const key of Object.keys(target.params)) {\n if (!has(source.params, key)) {\n throw new TypeError(`Cannot forward redirect param: ${key}`);\n }\n\n mapping[key] = key;\n }\n }\n\n const search = ownRecord(redirect.search, \"Redirect search\");\n let searchSnapshot: Record<string, unknown>;\n\n if (search.mode === \"replace\") {\n checkKeys(search, new Set([\"mode\", \"values\"]), \"redirect search\");\n\n const values = ownRecord(search.values, \"Redirect replacement\");\n\n checkKeys(values, new Set(Object.keys(target.search)), \"search values\");\n\n // A structural check only: it runs no codec.\n for (const key of Object.keys(values)) {\n if (\n isArrayCodec(target.search[key]) &&\n values[key] !== undefined &&\n !Array.isArray(values[key])\n ) {\n throw new TypeError(`Redirect search array requires an array: ${key}`);\n }\n }\n\n searchSnapshot = { mode: \"replace\", values: Object.freeze({ ...values }) };\n } else if (search.mode === \"preserve\" || search.mode === \"drop\") {\n checkKeys(search, new Set([\"mode\"]), \"redirect search\");\n searchSnapshot = { mode: search.mode };\n } else {\n throw new TypeError(\"Invalid redirect search policy\");\n }\n\n const fragment = ownRecord(redirect.fragment, \"Redirect fragment\");\n\n if (fragment.mode === \"replace\") {\n checkKeys(fragment, new Set([\"mode\", \"value\"]), \"redirect fragment\");\n\n if (typeof fragment.value !== \"string\" || !target.fragments.includes(fragment.value)) {\n throw new TypeError(\"Redirect fragment must belong to target declaration\");\n }\n } else if (fragment.mode === \"preserve\" || fragment.mode === \"drop\") {\n checkKeys(fragment, new Set([\"mode\"]), \"redirect fragment\");\n } else {\n throw new TypeError(\"Invalid redirect fragment policy\");\n }\n\n return Object.freeze({\n to: redirect.to,\n params: Object.freeze(mapping),\n search: Object.freeze(searchSnapshot),\n fragment: Object.freeze({ ...fragment }),\n });\n}\n\n/**\n * Declares a nominal typed route without executing codecs or native callbacks.\n *\n * @remarks\n * Paths are decoded authored text, not URLs: use `\"\"` for root/pathless nodes,\n * `$name` for a scalar segment and terminal `$name[]` for a zero-or-more\n * catchall. Repeated local scalar names reuse one value. Leading/trailing or\n * repeated slashes, dot segments and Angular `:name`/wildcard notation are invalid.\n *\n * Parents compose effective params/search and resolver data transitively,\n * including through pathless nodes; a local resolver key hides an inherited\n * one. Children cannot redeclare ancestor-owned param or search keys or have a\n * catchall parent. Fragment names belong only to this declaration.\n * The route and copied containers are shallow-frozen; application codecs,\n * callbacks, providers and opaque values retain identity and are not deep-frozen.\n *\n * For generation, author a direct default export of this call with a literal\n * path and inline config. Parent and redirect targets must be direct default\n * imports of admitted declarations. Angular owns activation and navigation;\n * declaration alone does not register a route with Angular.\n *\n * @param path - The literal local path, relative to the authored parent.\n * @param config - Local codecs, parent, fragments and supported native behavior.\n * Structural Angular options such as children, component and matcher are\n * generator-owned and cannot be overridden.\n * @returns A frozen route preserving inferred effective input and resolver data types.\n * @throws TypeError for invalid paths/configuration, missing or extra local\n * codecs, fallback or array codecs in path params, inherited key conflicts,\n * nonarray redirect replacements for array search keys, or nongenuine\n * parent/redirect routes.\n *\n * @example\n * ```ts\n * const product = defineRoute(\"products/$productId\", {\n * params: { productId: numberParam },\n * search: { tab: withFallback(enumParam([\"details\", \"reviews\"]), \"details\") },\n * fragments: [\"summary\", \"reviews\"],\n * });\n * ```\n */\nexport function defineRoute<\n const Path extends string,\n Parent extends AnyRoute | undefined = undefined,\n Params extends Record<string, PathCodec> = {},\n Search extends CodecMap = {},\n Resolvers extends Record<string, (...args: any[]) => unknown> = {},\n const Fragments extends readonly string[] = [],\n Target extends AnyRoute | undefined = undefined,\n ReplacementKeys extends keyof SearchOf<NoInfer<Target>> = never,\n // Stays unknown without a title, so it never narrows the callback's contextual type.\n Title = unknown,\n>(\n path: Path & ValidPath<Path>,\n config: RouteConfig<\n Path,\n Parent,\n Params,\n Search,\n Resolvers,\n Fragments,\n Target,\n ReplacementKeys,\n Title\n >,\n): Route<\n Path,\n EffectiveParams<Path, Params, Parent>,\n EffectiveSearch<Search, Parent>,\n Resolvers,\n Fragments[number],\n CatchallName<Path> extends never ? false : true,\n EffectiveData<Resolvers, Parent>,\n EffectiveTitle<Title, Parent>\n>;\n\nexport function defineRoute(path: unknown, config: unknown): AnyRoute {\n const supplied = ownRecord(config, \"Route config\");\n\n checkKeys(supplied, configKeys, \"route config\");\n\n const localSegments = parsePath(path);\n let parent: AnyRoute | undefined;\n let inherited: RouteMetadata | undefined;\n\n if (has(supplied, \"parent\")) {\n inherited = routeMetadata(supplied.parent);\n parent = supplied.parent as AnyRoute;\n\n for (const segment of inherited.segments) {\n if (segment.kind === \"catchall\") {\n throw new TypeError(\"Catchall declarations cannot have children\");\n }\n }\n }\n\n const localNames = new Set<string>();\n\n for (const segment of localSegments) {\n if (segment.kind !== \"static\") {\n localNames.add(segment.name);\n }\n }\n\n let localParams: Readonly<Record<string, ParamCodec<any>>> = Object.freeze(Object.create(null));\n\n if (localNames.size === 0) {\n if (has(supplied, \"params\")) {\n throw new TypeError(\"Static paths cannot declare params\");\n }\n } else {\n localParams = copyCodecs(supplied.params, true);\n checkKeys(localParams, localNames, \"local params\");\n\n for (const key of localNames) {\n if (!has(localParams, key)) {\n throw new TypeError(`Missing local codec: ${key}`);\n }\n\n if (inherited && has(inherited.params, key)) {\n throw new TypeError(`Inherited param already owned: ${key}`);\n }\n }\n }\n\n let localSearch: Readonly<Record<string, ParamCodec<any>>> = Object.freeze(Object.create(null));\n\n if (has(supplied, \"search\")) {\n localSearch = copyCodecs(supplied.search, false);\n }\n\n for (const key of Object.keys(localSearch)) {\n if (inherited && has(inherited.search, key)) {\n throw new TypeError(`Inherited search already owned: ${key}`);\n }\n }\n\n const retained: Record<string, unknown> = { ...supplied };\n const result: {\n path: string;\n resolve?: Readonly<Record<PropertyKey, unknown>>;\n runGuardsAndResolvers?: unknown;\n } = { path: path as string };\n\n if (has(supplied, \"resolve\")) {\n const resolve = ownRecord(supplied.resolve, \"Resolvers\", true) as Record<PropertyKey, unknown>;\n const copied: Record<PropertyKey, unknown> = Object.create(null);\n\n for (const key of Reflect.ownKeys(resolve)) {\n if (key === identityKey || typeof resolve[key] !== \"function\") {\n throw new TypeError(`Invalid resolver: ${String(key)}`);\n }\n\n copied[key] = resolve[key];\n }\n\n result.resolve = Object.freeze(copied);\n retained.resolve = result.resolve;\n }\n\n if (has(supplied, \"runGuardsAndResolvers\")) {\n const policy = supplied.runGuardsAndResolvers;\n\n if (typeof policy !== \"function\" && (typeof policy !== \"string\" || !policies.has(policy))) {\n throw new TypeError(\"Invalid native rerun policy\");\n }\n\n result.runGuardsAndResolvers = policy;\n }\n\n for (const key of [\"canActivate\", \"canActivateChild\", \"canMatch\", \"canDeactivate\", \"providers\"]) {\n if (!has(supplied, key)) {\n continue;\n }\n\n const list = supplied[key];\n\n if (!Array.isArray(list)) {\n throw new TypeError(`${key} must be an array`);\n }\n\n if (key === \"canActivate\" || key === \"canActivateChild\" || key === \"canMatch\") {\n for (const callback of list) {\n if (typeof callback !== \"function\") {\n throw new TypeError(`${key} entries must be callbacks`);\n }\n }\n } else if (key === \"canDeactivate\") {\n for (const guard of list) {\n if (\n guard === null ||\n (typeof guard !== \"function\" && typeof guard !== \"object\" && typeof guard !== \"string\")\n ) {\n throw new TypeError(\"canDeactivate entries must be native callbacks or tokens\");\n }\n }\n }\n\n retained[key] = Object.freeze([...list]);\n }\n\n if (has(supplied, \"onInvalidParams\")) {\n if (typeof supplied.onInvalidParams !== \"function\") {\n throw new TypeError(\"onInvalidParams must be a callback\");\n }\n\n if (localNames.size === 0) {\n throw new TypeError(\"onInvalidParams requires local path params\");\n }\n }\n\n if (\n has(supplied, \"title\") &&\n typeof supplied.title !== \"string\" &&\n typeof supplied.title !== \"function\"\n ) {\n throw new TypeError(\"Title must be a string or a callback\");\n }\n\n if (has(supplied, \"data\")) {\n const data = ownRecord(supplied.data, \"Static data\", true);\n\n if (has(data, identityKey)) {\n throw new TypeError(\"Static data cannot set generated identity\");\n }\n\n retained.data = Object.freeze({ ...data });\n }\n\n const fragments: string[] = [];\n\n if (has(supplied, \"fragments\")) {\n if (!Array.isArray(supplied.fragments)) {\n throw new TypeError(\"Fragments must be a string list\");\n }\n\n for (const name of supplied.fragments) {\n if (typeof name !== \"string\") {\n throw new TypeError(\"Fragment names must be strings\");\n }\n\n fragments.push(name);\n }\n }\n\n retained.fragments = Object.freeze(fragments);\n retained.params = localParams;\n retained.search = localSearch;\n\n const metadata: RouteMetadata = {\n parent,\n localSegments,\n segments: Object.freeze([...(inherited?.segments ?? []), ...localSegments]),\n localParams,\n localSearch,\n params: Object.freeze({ ...inherited?.params, ...localParams }),\n search: Object.freeze({ ...inherited?.search, ...localSearch }),\n fragments: retained.fragments as readonly string[],\n config: retained,\n };\n\n if (has(supplied, \"redirect\")) {\n if (\n has(supplied, \"canActivate\") ||\n has(supplied, \"canMatch\") ||\n has(supplied, \"onInvalidParams\")\n ) {\n throw new TypeError(\"Redirect cannot declare own canActivate, canMatch or onInvalidParams\");\n }\n\n retained.redirect = snapshotRedirect(supplied.redirect, metadata);\n }\n\n Object.freeze(retained);\n routes.set(result, Object.freeze(metadata));\n\n return Object.freeze(result) as AnyRoute;\n}\n","import { isArrayCodec, type ParamCodec } from \"./codecs.js\";\nimport { ownRecord, checkKeys, has } from \"./records.js\";\nimport { routeMetadata } from \"./route.js\";\nimport type { AnyRoute, SearchOf, UrlValues } from \"./types.js\";\n\nfunction encode(value: string): string {\n return encodeURIComponent(value).replaceAll(\"(\", \"%28\").replaceAll(\")\", \"%29\");\n}\n\nfunction stringify(codec: ParamCodec<any>, value: unknown, path: boolean): string {\n const text = codec.stringify(value);\n\n if (typeof text !== \"string\") {\n throw new TypeError(\"Codec stringify must return a string\");\n }\n\n if (path && (text === \"\" || text === \".\" || text === \"..\")) {\n throw new TypeError(\"Path output cannot be empty, dot or dotdot\");\n }\n\n return encode(text);\n}\n\n/**\n * Synchronously serializes a route's explicit values into a root-relative URL.\n *\n * @remarks\n * Includes inherited path/search declarations, but only this route's fragment\n * names. Every effective path value must be supplied; any search key may be\n * omitted. Searchless/paramless routes forbid those records. Catchalls and\n * `arrayParam` search keys require readonly arrays, including a valid empty array.\n * Values are never taken from a current navigation.\n *\n * Stringifies without calling parsers, guards, resolvers or redirects. Static\n * segments and logical values are component-encoded (also escaping parentheses),\n * so a dynamic slash becomes `%2F`. Search keys are globally sorted; omitted\n * and `undefined` values are left out. An `arrayParam` key writes one pair per\n * element in array order, and nothing for `[]`. An empty effective path produces `/`.\n * Redirect declarations serialize their source URL, not their redirect target.\n *\n * @param route - A genuine declaration from this physical package instance,\n * not a generated destination, spread/copy or structural lookalike.\n * @param values - Explicit destination-typed params, search and optional fragment.\n * Pass an empty object when the route needs no values.\n * @returns A root-relative URL string, typed `` `/${string}` ``; this does not navigate or\n * return a UrlTree.\n * @throws TypeError for invalid routes/records, missing or unknown keys,\n * undeclared fragments, nonarray catchalls or array search values, nonstring codec output, or empty/dot\n * path output. Application stringifier failures propagate unchanged.\n * @throws URIError for ill-formed Unicode in a serialized value.\n *\n * @example\n * ```ts\n * const product = defineRoute(\"products/$productId\", {\n * params: { productId: numberParam },\n * fragments: [\"summary\"],\n * });\n * createUrl(product, { params: { productId: 42 }, fragment: \"summary\" });\n * // /products/42#summary\n * ```\n */\nexport function createUrl<\n Target extends AnyRoute,\n SearchKeys extends keyof SearchOf<NoInfer<Target>> = never,\n>(route: Target, values: UrlValues<NoInfer<Target>, SearchKeys>): `/${string}`;\n\nexport function createUrl(route: unknown, values: unknown): `/${string}` {\n const metadata = routeMetadata(route);\n const options = ownRecord(values, \"URL options\");\n\n checkKeys(options, new Set([\"params\", \"search\", \"fragment\"]), \"URL options\");\n\n const paramKeys = Object.keys(metadata.params);\n let params: Record<string, unknown> = Object.create(null);\n\n if (paramKeys.length === 0) {\n if (has(options, \"params\")) {\n throw new TypeError(\"Route has no path params\");\n }\n } else {\n params = ownRecord(options.params, \"Path values\");\n checkKeys(params, new Set(paramKeys), \"path values\");\n\n for (const key of paramKeys) {\n if (!has(params, key)) {\n throw new TypeError(`Missing path value: ${key}`);\n }\n }\n }\n\n const searchKeys = Object.keys(metadata.search).sort();\n let search: Record<string, unknown> = Object.create(null);\n\n if (searchKeys.length === 0) {\n if (has(options, \"search\")) {\n throw new TypeError(\"Route has no search declarations\");\n }\n } else {\n if (has(options, \"search\")) {\n search = ownRecord(options.search, \"Search values\");\n }\n\n checkKeys(search, new Set(searchKeys), \"search values\");\n }\n\n if (has(options, \"fragment\")) {\n if (typeof options.fragment !== \"string\" || !metadata.fragments.includes(options.fragment)) {\n throw new TypeError(\"Fragment must belong to this declaration\");\n }\n }\n\n // Check all cardinalities before invoking application stringifiers.\n for (const segment of metadata.segments) {\n if (segment.kind === \"catchall\" && !Array.isArray(params[segment.name])) {\n throw new TypeError(`Catchall requires an array: ${segment.name}`);\n }\n }\n\n for (const key of searchKeys) {\n if (!isArrayCodec(metadata.search[key]) || !has(search, key)) {\n continue;\n }\n\n const value = search[key];\n\n if (value !== undefined && !Array.isArray(value)) {\n throw new TypeError(`Search array requires an array: ${key}`);\n }\n }\n\n const parts: string[] = [];\n\n for (const segment of metadata.segments) {\n if (segment.kind === \"static\") {\n parts.push(encode(segment.text));\n } else if (segment.kind === \"scalar\") {\n parts.push(stringify(metadata.params[segment.name], params[segment.name], true));\n } else {\n for (const value of params[segment.name] as readonly unknown[]) {\n parts.push(stringify(metadata.params[segment.name], value, true));\n }\n }\n }\n\n let url: `/${string}` = `/${parts.join(\"/\")}`;\n const query: string[] = [];\n\n for (const key of searchKeys) {\n const value = search[key];\n\n if (!has(search, key) || value === undefined) {\n continue;\n }\n\n if (!isArrayCodec(metadata.search[key])) {\n query.push(`${encode(key)}=${stringify(metadata.search[key], value, false)}`);\n\n continue;\n }\n\n for (const element of value as readonly unknown[]) {\n query.push(`${encode(key)}=${stringify(metadata.search[key], element, false)}`);\n }\n }\n\n if (query.length > 0) {\n url = `${url}?${query.join(\"&\")}`;\n }\n\n if (has(options, \"fragment\")) {\n url = `${url}#${encode(options.fragment as string)}`;\n }\n\n return url;\n}\n"],"mappings":"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"}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import { DestroyRef, computed, inject, signal } from "@angular/core";
|
|
2
|
-
import { ActivatedRoute, RedirectCommand, Router, UrlTree } from "@angular/router";
|
|
1
|
+
import { DestroyRef, computed, inject, signal, untracked } from "@angular/core";
|
|
2
|
+
import { ActivatedRoute, NavigationEnd, RedirectCommand, Router, UrlTree } from "@angular/router";
|
|
3
3
|
import { from, isObservable, map, merge } from "rxjs";
|
|
4
|
-
import { codecFallback, createUrl, routeMetadata } from "@loozo/angular-router/_core";
|
|
5
|
-
function
|
|
4
|
+
import { codecFallback, createUrl, isArrayCodec, routeMetadata } from "@loozo/angular-router/_core";
|
|
5
|
+
function routeIdentity(snapshot) {
|
|
6
6
|
const data = snapshot.routeConfig?.data;
|
|
7
|
-
|
|
7
|
+
if (!data || !Object.hasOwn(data, "__loozoAngularRouterRouteId")) return;
|
|
8
|
+
return data.__loozoAngularRouterRouteId;
|
|
9
|
+
}
|
|
10
|
+
function hasIdentity(snapshot, id) {
|
|
11
|
+
return routeIdentity(snapshot) === id;
|
|
8
12
|
}
|
|
9
13
|
function assertIdentity(snapshot, id) {
|
|
10
14
|
if (!hasIdentity(snapshot, id)) throw new Error(`Generated route wiring identity mismatch: ${id}`);
|
|
@@ -77,6 +81,10 @@ function parseSearch(definition, snapshot) {
|
|
|
77
81
|
for (const key of Object.keys(metadata.search)) {
|
|
78
82
|
const codec = metadata.search[key];
|
|
79
83
|
const raws = snapshot.queryParamMap.getAll(key);
|
|
84
|
+
if (isArrayCodec(codec)) {
|
|
85
|
+
search[key] = parseArray(codec, raws);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
80
88
|
if (raws.length === 1 && typeof raws[0] === "string") {
|
|
81
89
|
const result = parse(codec, raws[0]);
|
|
82
90
|
if ("value" in result) {
|
|
@@ -89,6 +97,16 @@ function parseSearch(definition, snapshot) {
|
|
|
89
97
|
}
|
|
90
98
|
return Object.freeze(search);
|
|
91
99
|
}
|
|
100
|
+
function parseArray(codec, raws) {
|
|
101
|
+
const values = [];
|
|
102
|
+
for (const raw of raws) {
|
|
103
|
+
if (typeof raw !== "string") return Object.freeze([]);
|
|
104
|
+
const result = parse(codec, raw);
|
|
105
|
+
if ("cause" in result) return Object.freeze([]);
|
|
106
|
+
values.push(result.value);
|
|
107
|
+
}
|
|
108
|
+
return Object.freeze(values);
|
|
109
|
+
}
|
|
92
110
|
const full = /* @__PURE__ */ new WeakMap();
|
|
93
111
|
const paths = /* @__PURE__ */ new WeakMap();
|
|
94
112
|
const matching = /* @__PURE__ */ new WeakMap();
|
|
@@ -250,9 +268,14 @@ function redirect(definition) {
|
|
|
250
268
|
const values = config.search.values;
|
|
251
269
|
for (const key of Object.keys(target.search).sort()) {
|
|
252
270
|
if (!Object.hasOwn(values, key) || values[key] === void 0) continue;
|
|
253
|
-
const
|
|
254
|
-
if (
|
|
255
|
-
|
|
271
|
+
const codec = target.search[key];
|
|
272
|
+
if (!isArrayCodec(codec)) {
|
|
273
|
+
replacement[key] = stringifySearch(codec, values[key], key);
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
const raws = [];
|
|
277
|
+
for (const value of values[key]) raws.push(stringifySearch(codec, value, key));
|
|
278
|
+
if (raws.length > 0) replacement[key] = raws;
|
|
256
279
|
}
|
|
257
280
|
}
|
|
258
281
|
const tree = router.parseUrl(path);
|
|
@@ -263,6 +286,11 @@ function redirect(definition) {
|
|
|
263
286
|
return tree;
|
|
264
287
|
};
|
|
265
288
|
}
|
|
289
|
+
function stringifySearch(codec, value, key) {
|
|
290
|
+
const raw = codec.stringify(value);
|
|
291
|
+
if (typeof raw !== "string") throw new TypeError(`Redirect search codec must stringify to a string: ${key}`);
|
|
292
|
+
return raw;
|
|
293
|
+
}
|
|
266
294
|
function createUrlForPath(definition, params) {
|
|
267
295
|
const metadata = routeMetadata(definition);
|
|
268
296
|
const parts = [];
|
|
@@ -286,28 +314,134 @@ function createUrlForPath(definition, params) {
|
|
|
286
314
|
}
|
|
287
315
|
return `/${parts.join("/")}`;
|
|
288
316
|
}
|
|
289
|
-
function observeRoute(set, id) {
|
|
290
|
-
const activated = inject(ActivatedRoute);
|
|
291
|
-
const router = inject(Router);
|
|
317
|
+
function observeRoute(set, id, activated, router, teardown) {
|
|
292
318
|
assertIdentity(activated.snapshot, id);
|
|
293
319
|
const snapshot = signal(activated.snapshot, ...ngDevMode ? [{ debugName: "snapshot" }] : /* istanbul ignore next */ []);
|
|
294
320
|
const subscription = merge(activated.queryParams, activated.fragment, activated.params, activated.url, activated.data, router.events).subscribe(() => {
|
|
295
321
|
snapshot.set(activated.snapshot);
|
|
296
322
|
});
|
|
297
|
-
|
|
323
|
+
teardown(() => subscription.unsubscribe());
|
|
298
324
|
const inputs = computed(() => parseInputs(set, id, snapshot()), ...ngDevMode ? [{ debugName: "inputs" }] : /* istanbul ignore next */ []);
|
|
299
|
-
const resolvers = routeMetadata(set.records[id].definition()).config.resolve ?? {};
|
|
300
325
|
return {
|
|
301
326
|
params: computed(() => inputs().params),
|
|
302
327
|
search: computed(() => inputs().search),
|
|
303
|
-
data: computed(() =>
|
|
304
|
-
|
|
305
|
-
const own = Object.create(null);
|
|
306
|
-
for (const key of Reflect.ownKeys(resolvers)) if (Object.hasOwn(data, key)) own[key] = data[key];
|
|
307
|
-
return Object.freeze(own);
|
|
308
|
-
})
|
|
328
|
+
data: computed(() => effectiveData(set, id, snapshot())),
|
|
329
|
+
title: computed(() => effectiveTitle(set, id, snapshot()))
|
|
309
330
|
};
|
|
310
331
|
}
|
|
332
|
+
function effectiveData(set, id, snapshot) {
|
|
333
|
+
const data = Object.create(null);
|
|
334
|
+
for (const ownerId of set.records[id].owners) {
|
|
335
|
+
const resolvers = routeMetadata(set.records[ownerId].definition()).config.resolve;
|
|
336
|
+
if (!resolvers) continue;
|
|
337
|
+
const owner = snapshot.pathFromRoot.findLast((record) => hasIdentity(record, ownerId));
|
|
338
|
+
if (!owner) throw new Error(`Generated route ancestor missing: ${ownerId}`);
|
|
339
|
+
for (const key of Reflect.ownKeys(resolvers)) if (Object.hasOwn(owner.data, key)) data[key] = owner.data[key];
|
|
340
|
+
}
|
|
341
|
+
return Object.freeze(data);
|
|
342
|
+
}
|
|
343
|
+
function effectiveTitle(set, id, snapshot) {
|
|
344
|
+
const owners = set.records[id].owners;
|
|
345
|
+
for (let index = owners.length - 1; index >= 0; index -= 1) {
|
|
346
|
+
const ownerId = owners[index];
|
|
347
|
+
if (routeMetadata(set.records[ownerId].definition()).config.title === void 0) continue;
|
|
348
|
+
const owner = snapshot.pathFromRoot.findLast((record) => hasIdentity(record, ownerId));
|
|
349
|
+
if (!owner) throw new Error(`Generated route ancestor missing: ${ownerId}`);
|
|
350
|
+
return owner.title;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
function injectGeneratedActiveRoute(set) {
|
|
354
|
+
const router = inject(Router);
|
|
355
|
+
const destroyRef = inject(DestroyRef);
|
|
356
|
+
const entries = /* @__PURE__ */ new Map();
|
|
357
|
+
let destroyed = false;
|
|
358
|
+
let selected;
|
|
359
|
+
function createEntry(route, id, parent) {
|
|
360
|
+
const releases = [];
|
|
361
|
+
const view = observeRoute(set, id, route, router, (release) => {
|
|
362
|
+
releases.push(release);
|
|
363
|
+
});
|
|
364
|
+
const ids = [...parent?.ids ?? [], id];
|
|
365
|
+
const chain = [...parent?.handle.chain ?? []];
|
|
366
|
+
const handle = {
|
|
367
|
+
...createHandle(set, id, router, view),
|
|
368
|
+
is: (destination) => destinationId(set, destination) === id,
|
|
369
|
+
contains: (destination) => ids.includes(destinationId(set, destination)),
|
|
370
|
+
chain
|
|
371
|
+
};
|
|
372
|
+
chain.push(handle);
|
|
373
|
+
Object.freeze(chain);
|
|
374
|
+
return {
|
|
375
|
+
handle,
|
|
376
|
+
parent,
|
|
377
|
+
ids,
|
|
378
|
+
release: () => {
|
|
379
|
+
for (const release of releases) release();
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
function reconcile(live) {
|
|
384
|
+
const kept = /* @__PURE__ */ new Set();
|
|
385
|
+
let parent;
|
|
386
|
+
for (const route of live) {
|
|
387
|
+
const id = routeIdentity(route);
|
|
388
|
+
if (typeof id !== "string" || !Object.hasOwn(set.records, id)) continue;
|
|
389
|
+
let entry = entries.get(route);
|
|
390
|
+
if (entry && entry.parent !== parent) {
|
|
391
|
+
entry.release();
|
|
392
|
+
entry = void 0;
|
|
393
|
+
}
|
|
394
|
+
if (!entry) {
|
|
395
|
+
entry = createEntry(route, id, parent);
|
|
396
|
+
entries.set(route, entry);
|
|
397
|
+
}
|
|
398
|
+
kept.add(route);
|
|
399
|
+
parent = entry;
|
|
400
|
+
}
|
|
401
|
+
for (const [route, entry] of entries) if (!kept.has(route)) {
|
|
402
|
+
entry.release();
|
|
403
|
+
entries.delete(route);
|
|
404
|
+
}
|
|
405
|
+
return parent?.handle;
|
|
406
|
+
}
|
|
407
|
+
const selection = computed(() => {
|
|
408
|
+
if (destroyed) return selected;
|
|
409
|
+
const success = router.lastSuccessfulNavigation();
|
|
410
|
+
const live = untracked(() => committedChain(router, success));
|
|
411
|
+
if (!live) {
|
|
412
|
+
router.currentNavigation();
|
|
413
|
+
selected = void 0;
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
selected = untracked(() => reconcile(live));
|
|
417
|
+
return selected;
|
|
418
|
+
}, ...ngDevMode ? [{ debugName: "selection" }] : /* istanbul ignore next */ []);
|
|
419
|
+
const commits = router.events.subscribe((event) => {
|
|
420
|
+
if (event instanceof NavigationEnd) selection();
|
|
421
|
+
});
|
|
422
|
+
destroyRef.onDestroy(() => {
|
|
423
|
+
destroyed = true;
|
|
424
|
+
commits.unsubscribe();
|
|
425
|
+
for (const entry of entries.values()) entry.release();
|
|
426
|
+
entries.clear();
|
|
427
|
+
});
|
|
428
|
+
return selection;
|
|
429
|
+
}
|
|
430
|
+
function committedChain(router, success) {
|
|
431
|
+
const state = router.routerState;
|
|
432
|
+
const live = [];
|
|
433
|
+
let route = state.root;
|
|
434
|
+
let snapshot = state.snapshot.root;
|
|
435
|
+
while (route) {
|
|
436
|
+
if (route.snapshot !== snapshot) return;
|
|
437
|
+
live.push(route);
|
|
438
|
+
route = route.firstChild;
|
|
439
|
+
snapshot = snapshot.firstChild;
|
|
440
|
+
}
|
|
441
|
+
if (snapshot !== null) return;
|
|
442
|
+
if (router.currentNavigation() === null) return live;
|
|
443
|
+
if (success?.finalUrl && router.serializeUrl(success.finalUrl) === state.snapshot.url) return live;
|
|
444
|
+
}
|
|
311
445
|
const destinations = /* @__PURE__ */ new WeakMap();
|
|
312
446
|
function createDestination(getSet, id) {
|
|
313
447
|
const destination = Object.freeze({});
|
|
@@ -317,6 +451,12 @@ function createDestination(getSet, id) {
|
|
|
317
451
|
});
|
|
318
452
|
return destination;
|
|
319
453
|
}
|
|
454
|
+
function destinationId(set, destination) {
|
|
455
|
+
let identity;
|
|
456
|
+
if (typeof destination === "object" && destination !== null) identity = destinations.get(destination);
|
|
457
|
+
if (!identity || identity.getSet() !== set || !Object.hasOwn(set.records, identity.id)) throw new TypeError("Expected a destination from the same generated set");
|
|
458
|
+
return identity.id;
|
|
459
|
+
}
|
|
320
460
|
function nativeOptions(definition) {
|
|
321
461
|
const config = routeMetadata(definition).config;
|
|
322
462
|
const options = {};
|
|
@@ -330,37 +470,50 @@ function nativeOptions(definition) {
|
|
|
330
470
|
}
|
|
331
471
|
function injectGeneratedRoute(set, id) {
|
|
332
472
|
const router = inject(Router);
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
473
|
+
const destroy = inject(DestroyRef);
|
|
474
|
+
return createHandle(set, id, router, observeRoute(set, id, inject(ActivatedRoute), router, (release) => {
|
|
475
|
+
destroy.onDestroy(release);
|
|
476
|
+
}));
|
|
477
|
+
}
|
|
478
|
+
function createHandle(set, id, router, view) {
|
|
479
|
+
function resolve(args) {
|
|
480
|
+
const record = args[0];
|
|
481
|
+
if (args.length !== 1 || typeof record !== "object" || record === null || Array.isArray(record)) throw new TypeError("Expected one navigation target record");
|
|
482
|
+
const values = {};
|
|
483
|
+
const rest = [];
|
|
484
|
+
let to;
|
|
485
|
+
for (const [key, value] of Object.entries(record)) if (key === "to") to = value;
|
|
486
|
+
else if (key === "params" || key === "search" || key === "fragment") values[key] = value;
|
|
487
|
+
else rest.push([key, value]);
|
|
488
|
+
const options = Object.fromEntries(rest);
|
|
336
489
|
let target = id;
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
347
|
-
} else {
|
|
348
|
-
if (typeof selector !== "object" || selector === null) throw new TypeError("Expected a literal selector or genuine generated destination");
|
|
349
|
-
const destination = destinations.get(selector);
|
|
350
|
-
if (!destination || destination.getSet() !== set || !Object.hasOwn(set.records, destination.id)) throw new TypeError("Expected a destination from the same generated set");
|
|
351
|
-
target = destination.id;
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
return createUrl(set.destinations[target](), values);
|
|
490
|
+
if (typeof to === "string") {
|
|
491
|
+
if (Object.hasOwn(set.absolute, to)) target = set.absolute[to];
|
|
492
|
+
else if (to === ".." && Object.hasOwn(set.parents, id)) target = set.parents[id];
|
|
493
|
+
else throw new TypeError(`Unknown generated selector: ${to}`);
|
|
494
|
+
} else if (to !== void 0) target = destinationId(set, to);
|
|
495
|
+
return {
|
|
496
|
+
url: createUrl(set.destinations[target](), values),
|
|
497
|
+
options
|
|
498
|
+
};
|
|
355
499
|
}
|
|
356
500
|
return {
|
|
357
501
|
params: view.params,
|
|
358
502
|
search: view.search,
|
|
359
503
|
data: view.data,
|
|
360
|
-
|
|
361
|
-
|
|
504
|
+
title: view.title,
|
|
505
|
+
link: ((...args) => {
|
|
506
|
+
const { url, options } = resolve(args);
|
|
507
|
+
const behavior = Object.keys(options);
|
|
508
|
+
if (behavior.length > 0) throw new TypeError(`link takes no navigation behavior options (${behavior.join(", ")}); set them on RouterLink`);
|
|
509
|
+
return router.parseUrl(url);
|
|
510
|
+
}),
|
|
511
|
+
navigate: ((...args) => {
|
|
512
|
+
const { url, options } = resolve(args);
|
|
513
|
+
return router.navigateByUrl(url, options);
|
|
514
|
+
})
|
|
362
515
|
};
|
|
363
516
|
}
|
|
364
|
-
export { assertIdentity, callbacks, createDestination, injectGeneratedRoute, nativeOptions, parseInputs, redirect };
|
|
517
|
+
export { assertIdentity, callbacks, createDestination, createHandle, destinationId, injectGeneratedActiveRoute, injectGeneratedRoute, nativeOptions, parseInputs, redirect };
|
|
365
518
|
|
|
366
519
|
//# sourceMappingURL=loozo-angular-router-_generated.mjs.map
|