{"version":3,"file":"ngxtension-inject-params.mjs","sources":["../../../../libs/ngxtension/inject-params/src/inject-params.ts","../../../../libs/ngxtension/inject-params/src/ngxtension-inject-params.ts"],"sourcesContent":["import { inject, type Signal } from '@angular/core';\nimport { toObservable, toSignal } from '@angular/core/rxjs-interop';\nimport { ActivatedRoute, type Params } from '@angular/router';\nimport { assertInjector } from 'ngxtension/assert-injector';\nimport { injectLeafActivatedRoute } from 'ngxtension/inject-leaf-activated-route';\nimport {\n\tDefaultValueOptions,\n\tInjectorOptions,\n\tParseOptions,\n\tRequiredOptions,\n} from 'ngxtension/shared';\nimport { map, switchMap, type Observable } from 'rxjs';\n\ntype ParamsTransformFn<ReadT> = (params: Params) => ReadT;\n\nfunction missingRequiredParamError(key: string | undefined): Error {\n\treturn new Error(\n\t\t`[ngxtension:injectParams] Parameter ${key} is required but was not provided.`,\n\t);\n}\n\n/**\n * Merges all params from the route hierarchy by walking from root to the given route.\n * Child route params override parent route params if there are naming conflicts.\n */\nfunction mergeRouteParams(route: ActivatedRoute): Params {\n\t// Build path from root to current route\n\tconst routePath: ActivatedRoute[] = [];\n\tlet currentRoute: ActivatedRoute | null = route;\n\n\twhile (currentRoute) {\n\t\troutePath.unshift(currentRoute);\n\t\tcurrentRoute = currentRoute.parent;\n\t}\n\n\t// Merge params from root to leaf (child params override parent params)\n\tconst mergedParams: Params = {};\n\tfor (const r of routePath) {\n\t\tconst params = r.snapshot?.params || {};\n\t\tObject.assign(mergedParams, params);\n\t}\n\n\treturn mergedParams;\n}\n\n/**\n * The `ParamsOptions` type defines options for configuring the behavior of the `injectParams` function.\n *\n * @template ReadT - The expected type of the read value.\n * @template WriteT - The type of the value to be written.\n * @template DefaultValueT - The type of the default value.\n */\nexport type ParamsOptions<ReadT, WriteT, DefaultValueT> = ParseOptions<\n\tReadT,\n\tWriteT\n> &\n\tDefaultValueOptions<DefaultValueT> &\n\tInjectorOptions &\n\tRequiredOptions;\n\n/**\n * Internal helper function that implements the core logic for injectParams.\n * This is shared between injectParams and injectParams.global.\n */\nfunction injectParamsCore<T>(\n\tparamsObservable: Observable<Params>,\n\tinitialParams: Params,\n\tkeyOrParamsTransform?: string | ((params: Params) => T),\n\toptions: ParamsOptions<T, string, T> = {},\n): Signal<T | Params | string | null> {\n\tconst { parse, defaultValue, required } = options;\n\n\tif (!keyOrParamsTransform) {\n\t\treturn toSignal(paramsObservable, { initialValue: initialParams });\n\t}\n\n\tif (typeof keyOrParamsTransform === 'function') {\n\t\treturn toSignal(paramsObservable.pipe(map(keyOrParamsTransform)), {\n\t\t\tinitialValue: keyOrParamsTransform(initialParams),\n\t\t});\n\t}\n\n\tconst getParam = (params: Params) => {\n\t\tconst param = params?.[keyOrParamsTransform as string] as\n\t\t\t| string\n\t\t\t| undefined;\n\n\t\tif (!param) {\n\t\t\tif (required) {\n\t\t\t\tthrow missingRequiredParamError(keyOrParamsTransform);\n\t\t\t}\n\t\t\treturn defaultValue ?? null;\n\t\t}\n\n\t\treturn parse ? parse(param) : param;\n\t};\n\n\treturn toSignal(paramsObservable.pipe(map(getParam)), {\n\t\tinitialValue: getParam(initialParams),\n\t});\n}\n\n/**\n * Base interface for parameter injection function overloads\n */\ninterface InjectParamsBase {\n\t/**\n\t * @returns A `Signal` that emits the entire parameters object.\n\t */\n\t(): Signal<Params>;\n\n\t/**\n\t * @param {string} key - The name of the parameter to retrieve.\n\t * @returns {Signal} A `Signal` that emits the value of the specified parameter, or `null` if it's not present.\n\t */\n\t(key: string): Signal<string | null>;\n\n\t/**\n\t * @param {string} key - The name of the parameter to retrieve.\n\t * @param {ParamsOptions} options - Configuration options with required flag that ensures a non-null return.\n\t * @returns {Signal} A `Signal` that emits the value of the specified parameter. Throws an error if the parameter is not present.\n\t */\n\t<ReadT = string>(\n\t\tkey: string,\n\t\toptions: ParamsOptions<ReadT, string, ReadT> & { required: true },\n\t): Signal<ReadT>;\n\n\t/**\n\t * @param {string} key - The name of the parameter to retrieve.\n\t * @param {ParamsOptions} options - Configuration options with both parse and required that ensures a non-null return.\n\t * @returns {Signal} A `Signal` that emits the parsed value. Throws an error if the parameter is not present.\n\t */\n\t<ReadT>(\n\t\tkey: string,\n\t\toptions: ParamsOptions<ReadT, string, never> & {\n\t\t\tparse: (v: string) => ReadT;\n\t\t\trequired: true;\n\t\t},\n\t): Signal<ReadT>;\n\n\t/**\n\t * @param {string} key - The name of the parameter to retrieve.\n\t * @param {ParamsOptions} options - Configuration options with both parse and defaultValue that ensures a non-null return.\n\t * @returns {Signal} A `Signal` that emits the parsed and transformed value, or the default value.\n\t */\n\t<ReadT>(\n\t\tkey: string,\n\t\toptions: ParamsOptions<ReadT, string, ReadT> & {\n\t\t\tparse: (v: string) => ReadT;\n\t\t\tdefaultValue: ReadT;\n\t\t},\n\t): Signal<ReadT>;\n\n\t/**\n\t * @param {string} key - The name of the parameter to retrieve.\n\t * @param {ParamsOptions} options - Configuration options with defaultValue that ensures a non-null return.\n\t * @returns {Signal} A `Signal` that emits the transformed value of the specified parameter, or the default value.\n\t */\n\t<ReadT>(\n\t\tkey: string,\n\t\toptions: ParamsOptions<ReadT, string, ReadT> & { defaultValue: ReadT },\n\t): Signal<ReadT>;\n\n\t/**\n\t * @param {string} key - The name of the parameter to retrieve.\n\t * @param {ParamsOptions} options - Configuration options with parse function that ensures a typed return.\n\t * @returns {Signal} A `Signal` that emits the parsed value of the specified parameter, or `null` if it's not present.\n\t */\n\t<ReadT>(\n\t\tkey: string,\n\t\toptions: ParamsOptions<ReadT, string, never> & {\n\t\t\tparse: (v: string) => ReadT;\n\t\t},\n\t): Signal<ReadT | null>;\n\n\t/**\n\t * @param {string} key - The name of the parameter to retrieve.\n\t * @param {ParamsOptions} options - Optional configuration options for the parameter.\n\t * @returns {Signal} A `Signal` that emits the transformed value of the specified parameter, or `null` if it's not present.\n\t */\n\t<ReadT>(\n\t\tkey?: string,\n\t\toptions?: ParamsOptions<ReadT, string, ReadT>,\n\t): Signal<ReadT | null>;\n\n\t/**\n\t * It retrieves the value of a parameter based on a custom transform function applied to the parameters object.\n\t *\n\t * @template ReadT - The expected type of the read value.\n\t * @param {ParamsTransformFn<ReadT>} fn - A transform function that takes the parameters object (`params: Params`) and returns the desired value.\n\t * @param options - Optional configuration options for the parameter.\n\t * @returns {Signal} A `Signal` that emits the transformed value based on the provided custom transform function.\n\t */\n\t<ReadT>(\n\t\tfn: ParamsTransformFn<ReadT>,\n\t\toptions?: InjectorOptions,\n\t): Signal<ReadT>;\n\n\t<T>(\n\t\tkeyOrParamsTransform?: string | ((params: Params) => T),\n\t\toptions?: ParamsOptions<T, string, T>,\n\t): Signal<T | Params | string | null>;\n}\n\n/**\n * Interface defining the global variant of injectParams\n */\ntype InjectParamsGlobal = InjectParamsBase;\n\n/**\n * Interface for the injectParams function with global property\n */\ninterface InjectParamsFn extends InjectParamsBase {\n\t/**\n\t * Global variant of `injectParams` that retrieves params from the leaf (deepest) `ActivatedRoute` in the router state tree.\n\t * This allows you to access all route parameters from the entire route hierarchy, including child routes,\n\t * regardless of where your component is positioned in the component tree.\n\t *\n\t * @example\n\t * // Get all params from route hierarchy\n\t * const params = injectParams.global();\n\t *\n\t * @example\n\t * // Get specific param from route hierarchy\n\t * const childId = injectParams.global('childId');\n\t *\n\t * @example\n\t * // Transform params from route hierarchy\n\t * const allKeys = injectParams.global((params) => Object.keys(params));\n\t *\n\t * @example\n\t * // With parse option\n\t * const productId = injectParams.global('productId', { parse: numberAttribute });\n\t */\n\tglobal: InjectParamsGlobal;\n}\n\n/**\n * Injects the params from the current route.\n * If a key is provided, it will return the value of that key.\n * If a transform function is provided, it will return the result of that function.\n * Otherwise, it will return the entire params object.\n *\n * Type overloads are defined in the InjectParamsFn interface.\n *\n * @example\n * const userId = injectParams('id'); // returns the value of the 'id' param\n * const userId = injectParams(p => p['id'] as string); // same as above but can be used with a custom transform function\n * const params = injectParams(); // returns the entire params object\n *\n */\nexport const injectParams: InjectParamsFn = <T>(\n\tkeyOrParamsTransform?: string | ((params: Params) => T),\n\toptions?: ParamsOptions<T, string, T>,\n): Signal<T | Params | string | null> => {\n\treturn assertInjector(injectParams, options?.injector, () => {\n\t\tconst route = inject(ActivatedRoute);\n\t\treturn injectParamsCore(\n\t\t\troute.params,\n\t\t\troute.snapshot.params,\n\t\t\tkeyOrParamsTransform,\n\t\t\toptions,\n\t\t);\n\t});\n};\n\n/**\n * Global variant of `injectParams` that retrieves params from the leaf (deepest) `ActivatedRoute` in the router state tree.\n * This allows you to access all route parameters from the entire route hierarchy, including child routes,\n * regardless of where your component is positioned in the component tree.\n *\n * Type overloads are defined in the InjectParamsGlobal interface.\n *\n * @example\n * // Get all params from route hierarchy\n * const params = injectParams.global();\n *\n * @example\n * // Get specific param from route hierarchy\n * const childId = injectParams.global('childId');\n *\n * @example\n * // Transform params from route hierarchy\n * const allKeys = injectParams.global((params) => Object.keys(params));\n *\n * @example\n * // With parse option\n * const productId = injectParams.global('productId', { parse: numberAttribute });\n */\nconst injectParamsGlobal: InjectParamsGlobal = <T>(\n\tkeyOrParamsTransform?: string | ((params: Params) => T),\n\toptions?: ParamsOptions<T, string, T>,\n): Signal<T | Params | string | null> => {\n\treturn assertInjector(injectParamsGlobal, options?.injector, () => {\n\t\t// Use the leaf route reactively and merge all params from the hierarchy\n\t\tconst leafRoute = injectLeafActivatedRoute();\n\t\tconst leafRoute$ = toObservable(leafRoute);\n\n\t\t// Create an observable that emits merged params from the route hierarchy\n\t\tconst mergedParams$ = leafRoute$.pipe(\n\t\t\tswitchMap((route) => route.params),\n\t\t\tmap(() => mergeRouteParams(leafRoute())),\n\t\t);\n\n\t\treturn injectParamsCore(\n\t\t\tmergedParams$,\n\t\t\tmergeRouteParams(leafRoute()),\n\t\t\tkeyOrParamsTransform,\n\t\t\toptions,\n\t\t);\n\t});\n};\n\n// Augment injectParams with global property\ninjectParams.global = injectParamsGlobal;\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}