@mmstack/di 19.3.4 → 19.3.5

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.
@@ -5,10 +5,24 @@ import { inject, Injector, runInInjectionContext, Injectable, InjectionToken } f
5
5
  * Captures an injection context and returns a runner function.
6
6
  *
7
7
  * This runner function allows you to execute callbacks inside the captured context at a later time.
8
- * It's really just a slight DX improvement over calling runInInjectionContext over and over
8
+ * It's really just a slight DX improvement over calling `runInInjectionContext` over and over.
9
9
  *
10
- * @param passedInjector An optional injector. If not provided, the current context's injector is pulled natively via `inject(Injector)`.
10
+ * @param injector An optional injector. If not provided, the current context's injector is pulled natively via `inject(Injector)`.
11
11
  * @returns A runner function that executes any provided callback within the captured context.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * @Component({ ... })
16
+ * class MyComponent {
17
+ * // Capture at construction so we can run injection-context code later.
18
+ * private readonly run = createRunInInjectionContext();
19
+ *
20
+ * onClick = () => {
21
+ * // `inject()` works here even though we're no longer in an injection context.
22
+ * const value = this.run(() => inject(SomeService).doThing());
23
+ * };
24
+ * }
25
+ * ```
12
26
  */
13
27
  function createRunInInjectionContext(injector) {
14
28
  if (!injector)
@@ -112,7 +126,17 @@ function injectLazy(token, options) {
112
126
  };
113
127
  }
114
128
 
115
- function injectable(token, opt) {
129
+ function injectable(tokenOrFn, optOrString) {
130
+ const token = typeof tokenOrFn === 'string'
131
+ ? tokenOrFn
132
+ : typeof optOrString === 'string'
133
+ ? optOrString
134
+ : '@mmstack/di/injectable';
135
+ const opt = typeof tokenOrFn === 'function'
136
+ ? { lazyFallback: tokenOrFn }
137
+ : typeof optOrString === 'string'
138
+ ? undefined
139
+ : optOrString;
116
140
  const injectionToken = new InjectionToken(token);
117
141
  const options = opt;
118
142
  let fallback = options?.fallback;
@@ -147,8 +171,32 @@ function injectable(token, opt) {
147
171
  }
148
172
 
149
173
  /**
150
- * Creates a root-level singleton hooked into the global injector.
151
- * @example const injectUser = rootInjectable(() => ({ name: signal('John') }));
174
+ * Creates a root-level singleton wired into the global (`providedIn: 'root'`)
175
+ * injector. Returns a typed `inject()` helper calling it anywhere in an
176
+ * injection context yields the same singleton instance. Useful for app-wide
177
+ * signal stores, configuration, or services that don't need per-component
178
+ * scoping.
179
+ *
180
+ * @typeParam T The type of the singleton value produced by the factory.
181
+ * @param factory Factory invoked once (lazily) to construct the singleton.
182
+ * Receives the root `Injector` for cases where `inject()` isn't ergonomic.
183
+ * @param name Optional token name (used as the debug name).
184
+ * @returns A getter function that returns the same singleton instance on every call.
185
+ *
186
+ * @example
187
+ * ```ts
188
+ * // Define once at module scope:
189
+ * const injectCurrentUser = rootInjectable(
190
+ * () => signal<User | null>(null),
191
+ * 'CurrentUser',
192
+ * );
193
+ *
194
+ * // Consume from anywhere in an injection context:
195
+ * @Component({ ... })
196
+ * class HeaderComponent {
197
+ * readonly user = injectCurrentUser();
198
+ * }
199
+ * ```
152
200
  */
153
201
  function rootInjectable(factory, // Keeping the injector just in case
154
202
  name) {
@@ -1 +1 @@
1
- {"version":3,"file":"mmstack-di.mjs","sources":["../../../../packages/di/src/lib/create-run-in-injection-context.ts","../../../../packages/di/src/lib/create-scope.ts","../../../../packages/di/src/lib/inject-lazy.ts","../../../../packages/di/src/lib/injectable.ts","../../../../packages/di/src/lib/root-injectable.ts","../../../../packages/di/src/mmstack-di.ts"],"sourcesContent":["import { inject, Injector, runInInjectionContext } from '@angular/core';\n\n/**\n * Captures an injection context and returns a runner function.\n *\n * This runner function allows you to execute callbacks inside the captured context at a later time.\n * It's really just a slight DX improvement over calling runInInjectionContext over and over\n *\n * @param passedInjector An optional injector. If not provided, the current context's injector is pulled natively via `inject(Injector)`.\n * @returns A runner function that executes any provided callback within the captured context.\n */\n\nexport function createRunInInjectionContext(injector?: Injector) {\n if (!injector) injector = inject(Injector);\n\n return <T>(fn: () => T) => runInInjectionContext(injector, fn);\n}\n","import {\n inject,\n Injectable,\n InjectionToken,\n Injector,\n runInInjectionContext,\n type Provider,\n} from '@angular/core';\n\n@Injectable()\nclass ScopeRegistry {\n private readonly injector = inject(Injector);\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n private readonly registry = new Map<Function, any>();\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n private readonly resolving = new Set<Function>();\n\n getOrCreate<T>(\n factory: () => T,\n scopeName?: string,\n factoryName?: string,\n ): T {\n if (this.registry.has(factory)) return this.registry.get(factory);\n if (this.resolving.has(factory))\n throw new Error(\n `[mmstack/di]: Circular dependency detected in scope \"${scopeName ?? 'unknown'}\"${factoryName ? ` while resolving \"${factoryName}\"` : ''}`,\n );\n\n this.resolving.add(factory);\n try {\n const val = runInInjectionContext(this.injector, factory);\n this.registry.set(factory, val);\n return val;\n } finally {\n this.resolving.delete(factory);\n }\n }\n}\n\n/**\n * Creates a specialized dependency injection scope.\n *\n * This utility allows you to create a localized dependency injection scope where you can\n * register and provide shared state, services, or primitives that are bound to a specific\n * component tree instead of the global root injector.\n *\n * @param name Optional name for the scope, primarily used for debugging and error messages.\n * @returns A tuple containing `[registerFn, provideFn]`:\n * - `registerFn`: A function to register a factory within the scope. Returns an injection function to retrieve the value.\n * - `provideFn`: An Angular provider function that must be added to the `providers` array where the scope begins.\n *\n * @example\n * ```ts\n * const [registerInUserScope, provideUserScope] = createScope('UserScope');\n *\n * // Define a state/service bound to this scope\n * const injectUserState = registerInUserScope(() => signal({ name: 'John Doe' }));\n * const injectLogger = registerInUserScope(() => {\n * const globalLogger = inject(GlobalLogger);\n * const user = injectUserState();\n * return {\n * log: (msg: string) => globalLogger.log(`[USER MODULE (${user().name})]: ${msg}`),\n * }\n * })\n * @Component({\n * providers: [provideUserScope()] // provides a new instance of every dependency registered to the scope\n * })\n * class ParentComponent {}\n *\n * @Component({})\n * class ChildComponent {\n * readonly userState = injectUserState();\n * readonly logger = injectLogger();\n * }\n * ```\n */\nexport function createScope(name?: string) {\n const token = new InjectionToken<ScopeRegistry>(name ?? '@mmstack/di/scope');\n\n const provideFn = (): Provider => ({\n provide: token,\n useClass: ScopeRegistry,\n });\n\n const registerFn = <T>(factory: () => T, factoryName?: string) => {\n return () => {\n const registry = inject(token, { optional: true });\n if (!registry)\n throw new Error(\n `[mmstack/di]: Scope ${name ?? 'unknown'} not found. Please make sure you provide it`,\n );\n\n return registry.getOrCreate(factory, name, factoryName);\n };\n };\n\n return [registerFn, provideFn] as const;\n}\n","import {\n inject,\n Injector,\n runInInjectionContext,\n type HostAttributeToken,\n type InjectOptions,\n type ProviderToken,\n} from '@angular/core';\n\nconst UNINITIALIZED_SYMBOL = Symbol('@mmstack/di/inject-lazy/uninitialized');\n\ntype OptionalInjectOptions = Omit<InjectOptions, 'optional'> & {\n optional: true;\n};\n\ntype NonOptionalInjectOptions = Omit<InjectOptions, 'optional'> & {\n optional?: false;\n};\n\n/**\n * Defers the resolution and instantiation of a token until the returned getter function is called.\n * The resolved value is cached for subsequent calls.\n *\n * @param token The dependency token to inject.\n * @returns A getter function that returns the lazily resolved dependency.\n */\nexport function injectLazy<T>(token: ProviderToken<T>): () => T;\n\n/**\n * Defers the resolution and instantiation of a token until the returned getter function is called.\n * The resolved value is cached for subsequent calls.\n *\n * @param token The dependency token to inject.\n * @param options Injection options specifying optional resolution.\n * @returns A getter function that returns the lazily resolved dependency or null.\n */\nexport function injectLazy<T>(\n token: ProviderToken<T>,\n options: OptionalInjectOptions,\n): () => T | null;\n\n/**\n * Defers the resolution and instantiation of a token until the returned getter function is called.\n * The resolved value is cached for subsequent calls.\n *\n * @param token The dependency token to inject.\n * @param options Injection options specifying non-optional resolution.\n * @returns A getter function that returns the lazily resolved dependency.\n */\nexport function injectLazy<T>(\n token: ProviderToken<T>,\n options: NonOptionalInjectOptions,\n): () => T;\n\n/**\n * Defers the resolution and instantiation of a host attribute token until the returned getter function is called.\n * The resolved value is cached for subsequent calls.\n *\n * @param token The host attribute token to inject.\n * @returns A getter function that returns the lazily resolved attribute string.\n */\nexport function injectLazy(token: HostAttributeToken): () => string;\n\n/**\n * Defers the resolution and instantiation of a host attribute token until the returned getter function is called.\n * The resolved value is cached for subsequent calls.\n *\n * @param token The host attribute token to inject.\n * @param options Injection options specifying non-optional resolution.\n * @returns A getter function that returns the lazily resolved attribute string.\n */\nexport function injectLazy(\n token: HostAttributeToken,\n options?: {\n optional?: false;\n },\n): () => string;\n\n/**\n * Defers the resolution and instantiation of a host attribute token until the returned getter function is called.\n * The resolved value is cached for subsequent calls.\n *\n * @param token The host attribute token to inject.\n * @param options Injection options specifying optional resolution.\n * @returns A getter function that returns the lazily resolved attribute string or null.\n */\nexport function injectLazy(\n token: HostAttributeToken,\n options: {\n optional: true;\n },\n): () => string | null;\n\nexport function injectLazy<T>(\n token: ProviderToken<T> | HostAttributeToken,\n options?: Partial<OptionalInjectOptions | NonOptionalInjectOptions>,\n): () => T | string | null {\n const injector = inject(Injector);\n let instance: T | string | null | typeof UNINITIALIZED_SYMBOL =\n UNINITIALIZED_SYMBOL;\n\n return () => {\n if (instance === UNINITIALIZED_SYMBOL)\n instance = runInInjectionContext(injector, () => {\n return options\n ? inject(token as any, options as any)\n : inject(token as any);\n });\n\n return instance as T | string | null;\n };\n}\n","import {\n inject,\n InjectionToken,\n type AbstractType,\n type InjectOptions,\n type Provider,\n type Type,\n} from '@angular/core';\n\ntype ServiceType<T> =\n T extends Type<infer U>\n ? U\n : T extends AbstractType<infer U>\n ? U\n : T extends InjectionToken<infer U>\n ? U\n : never;\n\ntype MapDeps<T extends readonly any[]> = {\n [K in keyof T]: ServiceType<T[K]>;\n};\n\ntype ProviderFn<T> = {\n (value: T): Provider;\n <const TDeps extends any[]>(\n fn: (...deps: MapDeps<TDeps>) => T,\n deps: TDeps,\n ): Provider;\n};\n\ntype InjectFns<T> = [\n (opt?: Omit<InjectOptions, 'optional'>) => T,\n ProviderFn<T>,\n];\n\ntype FallbackInjectableOptions<T> = {\n /** Default value returned when the injectable is not provided */\n fallback: T;\n};\n\ntype LazyFallbackInjectableOptions<T> = {\n /** Function that returns a default value when the injectable is not provided. Useful for expensive defaults. */\n lazyFallback: () => T;\n};\n\ntype ErrorMessageInjectableOptions = {\n /** Error message thrown when the injectable is not provided */\n errorMessage: string;\n};\n\ntype InjectableOptions<T> =\n | FallbackInjectableOptions<T>\n | LazyFallbackInjectableOptions<T>\n | ErrorMessageInjectableOptions;\n\n/**\n * Creates a typed InjectionToken with inject and provide helper functions.\n *\n * @param token - Unique token identifier\n * @param opt - Optional configuration for fallback value or error message\n * @returns A tuple of [injectFn, provideFn] for type-safe dependency injection\n */\nexport function injectable<T>(token: string): InjectFns<T | null>;\n\n/**\n * Creates a typed InjectionToken with inject and provide helper functions.\n * Returns a fallback value when the injectable is not provided.\n *\n * @param token - Unique token identifier\n * @param opt - Configuration with fallback value\n * @returns A tuple of [injectFn, provideFn] for type-safe dependency injection\n */\nexport function injectable<T>(\n token: string,\n opt: FallbackInjectableOptions<T>,\n): InjectFns<T>;\n\n/**\n *\n * Creates a typed InjectionToken with inject and provide helper functions.\n * Returns a lazily evaluated fallback value when the injectable is not provided.\n *\n * @param token\n * @param opt\n */\nexport function injectable<T>(\n token: string,\n opt: LazyFallbackInjectableOptions<T>,\n): InjectFns<T>;\n\n/**\n * Creates a typed InjectionToken with inject and provide helper functions.\n * Throws an error with a custom message when the injectable is not provided.\n *\n * @param token - Unique token identifier\n * @param opt - Configuration with error message\n * @returns A tuple of [injectFn, provideFn] for type-safe dependency injection\n */\nexport function injectable<T>(\n token: string,\n opt: ErrorMessageInjectableOptions,\n): InjectFns<T>;\n\nexport function injectable<T>(\n token: string,\n opt?: InjectableOptions<T>,\n): InjectFns<T> {\n const injectionToken = new InjectionToken<T>(token);\n\n const options = opt as\n | Partial<\n FallbackInjectableOptions<T> &\n LazyFallbackInjectableOptions<T> &\n ErrorMessageInjectableOptions\n >\n | undefined;\n\n let fallback: T | undefined | null = options?.fallback;\n\n const initFallback =\n options?.lazyFallback ?? (() => options?.fallback ?? null);\n\n const fallbackFn = () => {\n if (fallback === undefined) fallback = initFallback();\n return fallback;\n };\n\n const injectFn = (iOpt?: Omit<InjectOptions, 'optional'>) => {\n const injected =\n inject(injectionToken, {\n ...iOpt,\n optional: true,\n }) ?? fallbackFn();\n\n if (injected === null && options?.errorMessage)\n throw new Error(options.errorMessage);\n\n return injected as T;\n };\n\n const provideFn = (\n fnOrValue: T | ((...deps: any[]) => T),\n deps?: any[],\n ): Provider => {\n if (deps !== undefined)\n return {\n provide: injectionToken,\n useFactory: fnOrValue as (...args: any[]) => T,\n deps,\n };\n\n return {\n provide: injectionToken,\n useValue: fnOrValue,\n };\n };\n\n return [injectFn, provideFn];\n}\n","import { inject, InjectionToken, Injector } from '@angular/core';\n\n/**\n * Creates a root-level singleton hooked into the global injector.\n * @example const injectUser = rootInjectable(() => ({ name: signal('John') }));\n */\nexport function rootInjectable<T>(\n factory: (injector: Injector) => T, // Keeping the injector just in case\n name?: string,\n): () => T {\n const token = new InjectionToken<T>(name ?? '@mmstack/di/root-injectable', {\n providedIn: 'root',\n factory: () => factory(inject(Injector)),\n });\n\n return () => inject(token);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mmstack-di.mjs","sources":["../../../../packages/di/src/lib/create-run-in-injection-context.ts","../../../../packages/di/src/lib/create-scope.ts","../../../../packages/di/src/lib/inject-lazy.ts","../../../../packages/di/src/lib/injectable.ts","../../../../packages/di/src/lib/root-injectable.ts","../../../../packages/di/src/mmstack-di.ts"],"sourcesContent":["import { inject, Injector, runInInjectionContext } from '@angular/core';\n\n/**\n * Captures an injection context and returns a runner function.\n *\n * This runner function allows you to execute callbacks inside the captured context at a later time.\n * It's really just a slight DX improvement over calling `runInInjectionContext` over and over.\n *\n * @param injector An optional injector. If not provided, the current context's injector is pulled natively via `inject(Injector)`.\n * @returns A runner function that executes any provided callback within the captured context.\n *\n * @example\n * ```ts\n * @Component({ ... })\n * class MyComponent {\n * // Capture at construction so we can run injection-context code later.\n * private readonly run = createRunInInjectionContext();\n *\n * onClick = () => {\n * // `inject()` works here even though we're no longer in an injection context.\n * const value = this.run(() => inject(SomeService).doThing());\n * };\n * }\n * ```\n */\nexport function createRunInInjectionContext(injector?: Injector) {\n if (!injector) injector = inject(Injector);\n\n return <T>(fn: () => T) => runInInjectionContext(injector, fn);\n}\n","import {\n inject,\n Injectable,\n InjectionToken,\n Injector,\n runInInjectionContext,\n type Provider,\n} from '@angular/core';\n\n@Injectable()\nclass ScopeRegistry {\n private readonly injector = inject(Injector);\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n private readonly registry = new Map<Function, any>();\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n private readonly resolving = new Set<Function>();\n\n getOrCreate<T>(\n factory: () => T,\n scopeName?: string,\n factoryName?: string,\n ): T {\n if (this.registry.has(factory)) return this.registry.get(factory);\n if (this.resolving.has(factory))\n throw new Error(\n `[mmstack/di]: Circular dependency detected in scope \"${scopeName ?? 'unknown'}\"${factoryName ? ` while resolving \"${factoryName}\"` : ''}`,\n );\n\n this.resolving.add(factory);\n try {\n const val = runInInjectionContext(this.injector, factory);\n this.registry.set(factory, val);\n return val;\n } finally {\n this.resolving.delete(factory);\n }\n }\n}\n\n/**\n * Creates a specialized dependency injection scope.\n *\n * This utility allows you to create a localized dependency injection scope where you can\n * register and provide shared state, services, or primitives that are bound to a specific\n * component tree instead of the global root injector.\n *\n * @param name Optional name for the scope, primarily used for debugging and error messages.\n * @returns A tuple containing `[registerFn, provideFn]`:\n * - `registerFn`: A function to register a factory within the scope. Returns an injection function to retrieve the value.\n * - `provideFn`: An Angular provider function that must be added to the `providers` array where the scope begins.\n *\n * @example\n * ```ts\n * const [registerInUserScope, provideUserScope] = createScope('UserScope');\n *\n * // Define a state/service bound to this scope\n * const injectUserState = registerInUserScope(() => signal({ name: 'John Doe' }));\n * const injectLogger = registerInUserScope(() => {\n * const globalLogger = inject(GlobalLogger);\n * const user = injectUserState();\n * return {\n * log: (msg: string) => globalLogger.log(`[USER MODULE (${user().name})]: ${msg}`),\n * }\n * })\n * @Component({\n * providers: [provideUserScope()] // provides a new instance of every dependency registered to the scope\n * })\n * class ParentComponent {}\n *\n * @Component({})\n * class ChildComponent {\n * readonly userState = injectUserState();\n * readonly logger = injectLogger();\n * }\n * ```\n */\nexport function createScope(name?: string) {\n const token = new InjectionToken<ScopeRegistry>(name ?? '@mmstack/di/scope');\n\n const provideFn = (): Provider => ({\n provide: token,\n useClass: ScopeRegistry,\n });\n\n const registerFn = <T>(factory: () => T, factoryName?: string) => {\n return () => {\n const registry = inject(token, { optional: true });\n if (!registry)\n throw new Error(\n `[mmstack/di]: Scope ${name ?? 'unknown'} not found. Please make sure you provide it`,\n );\n\n return registry.getOrCreate(factory, name, factoryName);\n };\n };\n\n return [registerFn, provideFn] as const;\n}\n","import {\n inject,\n Injector,\n runInInjectionContext,\n type HostAttributeToken,\n type InjectOptions,\n type ProviderToken,\n} from '@angular/core';\n\nconst UNINITIALIZED_SYMBOL = Symbol('@mmstack/di/inject-lazy/uninitialized');\n\ntype OptionalInjectOptions = Omit<InjectOptions, 'optional'> & {\n optional: true;\n};\n\ntype NonOptionalInjectOptions = Omit<InjectOptions, 'optional'> & {\n optional?: false;\n};\n\n/**\n * Defers the resolution and instantiation of a token until the returned getter\n * function is called. The resolved value is cached for subsequent calls — the\n * actual `inject()` call happens at most once, on first access.\n *\n * Useful for services that are expensive to construct, or for breaking\n * circular dependency chains in component fields.\n *\n * @typeParam T The type of the resolved dependency.\n * @param token The dependency token to inject.\n * @returns A getter function that returns the lazily resolved dependency.\n *\n * @example\n * ```ts\n * @Component({ ... })\n * class MyComponent {\n * // Injection context captured at construction; HeavyService is NOT instantiated yet.\n * private readonly getHeavy = injectLazy(HeavyService);\n *\n * onClick = () => {\n * // First access constructs HeavyService and caches it; subsequent calls return the same instance.\n * this.getHeavy().doExpensiveThing();\n * };\n * }\n * ```\n */\nexport function injectLazy<T>(token: ProviderToken<T>): () => T;\n\n/**\n * Defers the resolution and instantiation of an optional token until the\n * returned getter is called. Returns `null` (not undefined) when the token\n * isn't provided, matching Angular's `inject(token, { optional: true })`\n * semantics.\n *\n * @typeParam T The type of the resolved dependency.\n * @param token The dependency token to inject.\n * @param options Injection options specifying optional resolution.\n * @returns A getter function that returns the lazily resolved dependency or `null`.\n *\n * @example\n * ```ts\n * const getAnalytics = injectLazy(AnalyticsService, { optional: true });\n *\n * function trackEvent(name: string) {\n * getAnalytics()?.track(name); // safely no-op if Analytics isn't provided\n * }\n * ```\n */\nexport function injectLazy<T>(\n token: ProviderToken<T>,\n options: OptionalInjectOptions,\n): () => T | null;\n\n/**\n * Defers the resolution and instantiation of a token until the returned getter function is called.\n * The resolved value is cached for subsequent calls.\n *\n * @param token The dependency token to inject.\n * @param options Injection options specifying non-optional resolution.\n * @returns A getter function that returns the lazily resolved dependency.\n */\nexport function injectLazy<T>(\n token: ProviderToken<T>,\n options: NonOptionalInjectOptions,\n): () => T;\n\n/**\n * Defers reading a host attribute until the returned getter is called.\n * Mirrors {@link HostAttributeToken} resolution but lazily.\n *\n * @param token The host attribute token to inject.\n * @returns A getter function that returns the lazily resolved attribute string.\n *\n * @example\n * ```ts\n * @Directive({ ... })\n * class MyDirective {\n * private readonly getRole = injectLazy(new HostAttributeToken('role'));\n * // Only reads the DOM attribute when first accessed.\n * }\n * ```\n */\nexport function injectLazy(token: HostAttributeToken): () => string;\n\n/**\n * Defers the resolution and instantiation of a host attribute token until the returned getter function is called.\n * The resolved value is cached for subsequent calls.\n *\n * @param token The host attribute token to inject.\n * @param options Injection options specifying non-optional resolution.\n * @returns A getter function that returns the lazily resolved attribute string.\n */\nexport function injectLazy(\n token: HostAttributeToken,\n options?: {\n optional?: false;\n },\n): () => string;\n\n/**\n * Defers the resolution and instantiation of a host attribute token until the returned getter function is called.\n * The resolved value is cached for subsequent calls.\n *\n * @param token The host attribute token to inject.\n * @param options Injection options specifying optional resolution.\n * @returns A getter function that returns the lazily resolved attribute string or null.\n */\nexport function injectLazy(\n token: HostAttributeToken,\n options: {\n optional: true;\n },\n): () => string | null;\n\nexport function injectLazy<T>(\n token: ProviderToken<T> | HostAttributeToken,\n options?: Partial<OptionalInjectOptions | NonOptionalInjectOptions>,\n): () => T | string | null {\n const injector = inject(Injector);\n let instance: T | string | null | typeof UNINITIALIZED_SYMBOL =\n UNINITIALIZED_SYMBOL;\n\n return () => {\n if (instance === UNINITIALIZED_SYMBOL)\n instance = runInInjectionContext(injector, () => {\n return options\n ? inject(token as any, options as any)\n : inject(token as any);\n });\n\n return instance as T | string | null;\n };\n}\n","import {\n inject,\n InjectionToken,\n type AbstractType,\n type InjectOptions,\n type Provider,\n type Type,\n} from '@angular/core';\n\ntype ServiceType<T> =\n T extends Type<infer U>\n ? U\n : T extends AbstractType<infer U>\n ? U\n : T extends InjectionToken<infer U>\n ? U\n : never;\n\ntype MapDeps<T extends readonly any[]> = {\n [K in keyof T]: ServiceType<T[K]>;\n};\n\ntype ProviderFn<T> = {\n (value: T): Provider;\n <const TDeps extends any[]>(\n fn: (...deps: MapDeps<TDeps>) => T,\n deps: TDeps,\n ): Provider;\n};\n\ntype InjectFns<T> = [\n (opt?: Omit<InjectOptions, 'optional'>) => T,\n ProviderFn<T>,\n];\n\ntype FallbackInjectableOptions<T> = {\n /** Default value returned when the injectable is not provided */\n fallback: T;\n};\n\ntype LazyFallbackInjectableOptions<T> = {\n /** Function that returns a default value when the injectable is not provided. Useful for expensive defaults. */\n lazyFallback: () => T;\n};\n\ntype ErrorMessageInjectableOptions = {\n /** Error message thrown when the injectable is not provided */\n errorMessage: string;\n};\n\ntype InjectableOptions<T> =\n | FallbackInjectableOptions<T>\n | LazyFallbackInjectableOptions<T>\n | ErrorMessageInjectableOptions;\n\n/**\n * Creates a typed `InjectionToken` plus a tuple of `[inject, provide]` helpers.\n * Without configuration, the inject helper returns `T | null` when the token\n * hasn't been provided.\n *\n * @typeParam T The type of the value the token holds.\n * @param token Unique token identifier (used as the token's debug name).\n * @returns A tuple `[injectFn, provideFn]` for type-safe dependency injection.\n *\n * @example\n * ```ts\n * const [injectTheme, provideTheme] = injectable<'dark' | 'light'>('Theme');\n *\n * // In a provider scope:\n * bootstrapApplication(App, { providers: [provideTheme('dark')] });\n *\n * // In a consumer:\n * const theme = injectTheme(); // 'dark' | 'light' | null\n * ```\n */\nexport function injectable<T>(token: string): InjectFns<T | null>;\n\n/**\n * Creates a typed `InjectionToken` with an eager fallback value. The inject\n * helper returns `T` (never `null`): when the token isn't provided, the\n * configured `fallback` is returned.\n *\n * @typeParam T The type of the value the token holds.\n * @param token Unique token identifier.\n * @param opt Configuration with `fallback` value (evaluated immediately).\n * @returns A tuple `[injectFn, provideFn]` for type-safe dependency injection.\n *\n * @example\n * ```ts\n * const [injectConfig, provideConfig] = injectable<Config>('Config', {\n * fallback: { apiUrl: 'https://api.example.com', retries: 3 },\n * });\n *\n * const config = injectConfig(); // Always Config — never null\n * ```\n */\nexport function injectable<T>(\n token: string,\n opt: FallbackInjectableOptions<T>,\n): InjectFns<T>;\n\n/**\n * Creates a typed `InjectionToken` with a *lazy* fallback. The fallback\n * factory runs on first access (and only once) when the token isn't\n * provided — useful when constructing the default is expensive or has its\n * own dependencies.\n *\n * @typeParam T The type of the value the token holds.\n * @param token Unique token identifier.\n * @param opt Configuration with `lazyFallback` factory (deferred until needed).\n * @returns A tuple `[injectFn, provideFn]` for type-safe dependency injection.\n *\n * @example\n * ```ts\n * const [injectCache, provideCache] = injectable<Cache>('Cache', {\n * lazyFallback: () => new Cache({ size: 1000 }), // only constructed if no override is provided\n * });\n * ```\n */\nexport function injectable<T>(\n token: string,\n opt: LazyFallbackInjectableOptions<T>,\n): InjectFns<T>;\n\n/**\n * Creates a typed `InjectionToken` that throws a custom error message when\n * the token isn't provided. Use this when \"no provider\" is genuinely a bug\n * rather than a permitted state.\n *\n * @typeParam T The type of the value the token holds.\n * @param token Unique token identifier.\n * @param opt Configuration with `errorMessage` to throw on missing provider.\n * @returns A tuple `[injectFn, provideFn]` for type-safe dependency injection.\n *\n * @example\n * ```ts\n * const [injectAuth, provideAuth] = injectable<AuthService>('Auth', {\n * errorMessage: 'AuthService must be provided before any consumer reads it',\n * });\n *\n * const auth = injectAuth(); // throws if no provideAuth(...) is in scope\n * ```\n */\nexport function injectable<T>(\n token: string,\n opt: ErrorMessageInjectableOptions,\n): InjectFns<T>;\n\n/**\n * Creates a typed `InjectionToken` with a baked-in factory used as the lazy\n * fallback. The factory runs in an injection context, so it can use\n * `inject()` to compose dependencies.\n *\n * @typeParam T The type of the value the factory produces.\n * @param fn Factory function evaluated lazily on first inject if no override is provided.\n * @param name Optional token name (used as the debug name).\n * @returns A tuple `[injectFn, provideFn]` for type-safe dependency injection.\n *\n * @example\n * ```ts\n * const [injectUser, provideUser] = injectable(\n * () => inject(HttpClient).get<User>('/api/me'),\n * 'CurrentUser',\n * );\n * ```\n */\nexport function injectable<T>(fn: () => T, name?: string): InjectFns<T>;\n\nexport function injectable<T>(\n tokenOrFn: string | (() => T),\n optOrString?: InjectableOptions<T> | string,\n): InjectFns<T> {\n const token =\n typeof tokenOrFn === 'string'\n ? tokenOrFn\n : typeof optOrString === 'string'\n ? optOrString\n : '@mmstack/di/injectable';\n\n const opt =\n typeof tokenOrFn === 'function'\n ? { lazyFallback: tokenOrFn }\n : typeof optOrString === 'string'\n ? undefined\n : optOrString;\n\n const injectionToken = new InjectionToken<T>(token);\n\n const options = opt as\n | Partial<\n FallbackInjectableOptions<T> &\n LazyFallbackInjectableOptions<T> &\n ErrorMessageInjectableOptions\n >\n | undefined;\n\n let fallback: T | undefined | null = options?.fallback;\n\n const initFallback =\n options?.lazyFallback ?? (() => options?.fallback ?? null);\n\n const fallbackFn = () => {\n if (fallback === undefined) fallback = initFallback();\n return fallback;\n };\n\n const injectFn = (iOpt?: Omit<InjectOptions, 'optional'>) => {\n const injected =\n inject(injectionToken, {\n ...iOpt,\n optional: true,\n }) ?? fallbackFn();\n\n if (injected === null && options?.errorMessage)\n throw new Error(options.errorMessage);\n\n return injected as T;\n };\n\n const provideFn = (\n fnOrValue: T | ((...deps: any[]) => T),\n deps?: any[],\n ): Provider => {\n if (deps !== undefined)\n return {\n provide: injectionToken,\n useFactory: fnOrValue as (...args: any[]) => T,\n deps,\n };\n\n return {\n provide: injectionToken,\n useValue: fnOrValue,\n };\n };\n\n return [injectFn, provideFn];\n}\n","import { inject, InjectionToken, Injector } from '@angular/core';\n\n/**\n * Creates a root-level singleton wired into the global (`providedIn: 'root'`)\n * injector. Returns a typed `inject()` helper — calling it anywhere in an\n * injection context yields the same singleton instance. Useful for app-wide\n * signal stores, configuration, or services that don't need per-component\n * scoping.\n *\n * @typeParam T The type of the singleton value produced by the factory.\n * @param factory Factory invoked once (lazily) to construct the singleton.\n * Receives the root `Injector` for cases where `inject()` isn't ergonomic.\n * @param name Optional token name (used as the debug name).\n * @returns A getter function that returns the same singleton instance on every call.\n *\n * @example\n * ```ts\n * // Define once at module scope:\n * const injectCurrentUser = rootInjectable(\n * () => signal<User | null>(null),\n * 'CurrentUser',\n * );\n *\n * // Consume from anywhere in an injection context:\n * @Component({ ... })\n * class HeaderComponent {\n * readonly user = injectCurrentUser();\n * }\n * ```\n */\nexport function rootInjectable<T>(\n factory: (injector: Injector) => T, // Keeping the injector just in case\n name?: string,\n): () => T {\n const token = new InjectionToken<T>(name ?? '@mmstack/di/root-injectable', {\n providedIn: 'root',\n factory: () => factory(inject(Injector)),\n });\n\n return () => inject(token);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -3,9 +3,23 @@ import { Injector } from '@angular/core';
3
3
  * Captures an injection context and returns a runner function.
4
4
  *
5
5
  * This runner function allows you to execute callbacks inside the captured context at a later time.
6
- * It's really just a slight DX improvement over calling runInInjectionContext over and over
6
+ * It's really just a slight DX improvement over calling `runInInjectionContext` over and over.
7
7
  *
8
- * @param passedInjector An optional injector. If not provided, the current context's injector is pulled natively via `inject(Injector)`.
8
+ * @param injector An optional injector. If not provided, the current context's injector is pulled natively via `inject(Injector)`.
9
9
  * @returns A runner function that executes any provided callback within the captured context.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * @Component({ ... })
14
+ * class MyComponent {
15
+ * // Capture at construction so we can run injection-context code later.
16
+ * private readonly run = createRunInInjectionContext();
17
+ *
18
+ * onClick = () => {
19
+ * // `inject()` works here even though we're no longer in an injection context.
20
+ * const value = this.run(() => inject(SomeService).doThing());
21
+ * };
22
+ * }
23
+ * ```
10
24
  */
11
25
  export declare function createRunInInjectionContext(injector?: Injector): <T>(fn: () => T) => T;
@@ -6,20 +6,51 @@ type NonOptionalInjectOptions = Omit<InjectOptions, 'optional'> & {
6
6
  optional?: false;
7
7
  };
8
8
  /**
9
- * Defers the resolution and instantiation of a token until the returned getter function is called.
10
- * The resolved value is cached for subsequent calls.
9
+ * Defers the resolution and instantiation of a token until the returned getter
10
+ * function is called. The resolved value is cached for subsequent calls — the
11
+ * actual `inject()` call happens at most once, on first access.
12
+ *
13
+ * Useful for services that are expensive to construct, or for breaking
14
+ * circular dependency chains in component fields.
11
15
  *
16
+ * @typeParam T The type of the resolved dependency.
12
17
  * @param token The dependency token to inject.
13
18
  * @returns A getter function that returns the lazily resolved dependency.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * @Component({ ... })
23
+ * class MyComponent {
24
+ * // Injection context captured at construction; HeavyService is NOT instantiated yet.
25
+ * private readonly getHeavy = injectLazy(HeavyService);
26
+ *
27
+ * onClick = () => {
28
+ * // First access constructs HeavyService and caches it; subsequent calls return the same instance.
29
+ * this.getHeavy().doExpensiveThing();
30
+ * };
31
+ * }
32
+ * ```
14
33
  */
15
34
  export declare function injectLazy<T>(token: ProviderToken<T>): () => T;
16
35
  /**
17
- * Defers the resolution and instantiation of a token until the returned getter function is called.
18
- * The resolved value is cached for subsequent calls.
36
+ * Defers the resolution and instantiation of an optional token until the
37
+ * returned getter is called. Returns `null` (not undefined) when the token
38
+ * isn't provided, matching Angular's `inject(token, { optional: true })`
39
+ * semantics.
19
40
  *
41
+ * @typeParam T The type of the resolved dependency.
20
42
  * @param token The dependency token to inject.
21
43
  * @param options Injection options specifying optional resolution.
22
- * @returns A getter function that returns the lazily resolved dependency or null.
44
+ * @returns A getter function that returns the lazily resolved dependency or `null`.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * const getAnalytics = injectLazy(AnalyticsService, { optional: true });
49
+ *
50
+ * function trackEvent(name: string) {
51
+ * getAnalytics()?.track(name); // safely no-op if Analytics isn't provided
52
+ * }
53
+ * ```
23
54
  */
24
55
  export declare function injectLazy<T>(token: ProviderToken<T>, options: OptionalInjectOptions): () => T | null;
25
56
  /**
@@ -32,11 +63,20 @@ export declare function injectLazy<T>(token: ProviderToken<T>, options: Optional
32
63
  */
33
64
  export declare function injectLazy<T>(token: ProviderToken<T>, options: NonOptionalInjectOptions): () => T;
34
65
  /**
35
- * Defers the resolution and instantiation of a host attribute token until the returned getter function is called.
36
- * The resolved value is cached for subsequent calls.
66
+ * Defers reading a host attribute until the returned getter is called.
67
+ * Mirrors {@link HostAttributeToken} resolution but lazily.
37
68
  *
38
69
  * @param token The host attribute token to inject.
39
70
  * @returns A getter function that returns the lazily resolved attribute string.
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * @Directive({ ... })
75
+ * class MyDirective {
76
+ * private readonly getRole = injectLazy(new HostAttributeToken('role'));
77
+ * // Only reads the DOM attribute when first accessed.
78
+ * }
79
+ * ```
40
80
  */
41
81
  export declare function injectLazy(token: HostAttributeToken): () => string;
42
82
  /**
@@ -24,38 +24,102 @@ type ErrorMessageInjectableOptions = {
24
24
  errorMessage: string;
25
25
  };
26
26
  /**
27
- * Creates a typed InjectionToken with inject and provide helper functions.
27
+ * Creates a typed `InjectionToken` plus a tuple of `[inject, provide]` helpers.
28
+ * Without configuration, the inject helper returns `T | null` when the token
29
+ * hasn't been provided.
28
30
  *
29
- * @param token - Unique token identifier
30
- * @param opt - Optional configuration for fallback value or error message
31
- * @returns A tuple of [injectFn, provideFn] for type-safe dependency injection
31
+ * @typeParam T The type of the value the token holds.
32
+ * @param token Unique token identifier (used as the token's debug name).
33
+ * @returns A tuple `[injectFn, provideFn]` for type-safe dependency injection.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * const [injectTheme, provideTheme] = injectable<'dark' | 'light'>('Theme');
38
+ *
39
+ * // In a provider scope:
40
+ * bootstrapApplication(App, { providers: [provideTheme('dark')] });
41
+ *
42
+ * // In a consumer:
43
+ * const theme = injectTheme(); // 'dark' | 'light' | null
44
+ * ```
32
45
  */
33
46
  export declare function injectable<T>(token: string): InjectFns<T | null>;
34
47
  /**
35
- * Creates a typed InjectionToken with inject and provide helper functions.
36
- * Returns a fallback value when the injectable is not provided.
48
+ * Creates a typed `InjectionToken` with an eager fallback value. The inject
49
+ * helper returns `T` (never `null`): when the token isn't provided, the
50
+ * configured `fallback` is returned.
37
51
  *
38
- * @param token - Unique token identifier
39
- * @param opt - Configuration with fallback value
40
- * @returns A tuple of [injectFn, provideFn] for type-safe dependency injection
52
+ * @typeParam T The type of the value the token holds.
53
+ * @param token Unique token identifier.
54
+ * @param opt Configuration with `fallback` value (evaluated immediately).
55
+ * @returns A tuple `[injectFn, provideFn]` for type-safe dependency injection.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * const [injectConfig, provideConfig] = injectable<Config>('Config', {
60
+ * fallback: { apiUrl: 'https://api.example.com', retries: 3 },
61
+ * });
62
+ *
63
+ * const config = injectConfig(); // Always Config — never null
64
+ * ```
41
65
  */
42
66
  export declare function injectable<T>(token: string, opt: FallbackInjectableOptions<T>): InjectFns<T>;
43
67
  /**
68
+ * Creates a typed `InjectionToken` with a *lazy* fallback. The fallback
69
+ * factory runs on first access (and only once) when the token isn't
70
+ * provided — useful when constructing the default is expensive or has its
71
+ * own dependencies.
44
72
  *
45
- * Creates a typed InjectionToken with inject and provide helper functions.
46
- * Returns a lazily evaluated fallback value when the injectable is not provided.
73
+ * @typeParam T The type of the value the token holds.
74
+ * @param token Unique token identifier.
75
+ * @param opt Configuration with `lazyFallback` factory (deferred until needed).
76
+ * @returns A tuple `[injectFn, provideFn]` for type-safe dependency injection.
47
77
  *
48
- * @param token
49
- * @param opt
78
+ * @example
79
+ * ```ts
80
+ * const [injectCache, provideCache] = injectable<Cache>('Cache', {
81
+ * lazyFallback: () => new Cache({ size: 1000 }), // only constructed if no override is provided
82
+ * });
83
+ * ```
50
84
  */
51
85
  export declare function injectable<T>(token: string, opt: LazyFallbackInjectableOptions<T>): InjectFns<T>;
52
86
  /**
53
- * Creates a typed InjectionToken with inject and provide helper functions.
54
- * Throws an error with a custom message when the injectable is not provided.
87
+ * Creates a typed `InjectionToken` that throws a custom error message when
88
+ * the token isn't provided. Use this when "no provider" is genuinely a bug
89
+ * rather than a permitted state.
90
+ *
91
+ * @typeParam T The type of the value the token holds.
92
+ * @param token Unique token identifier.
93
+ * @param opt Configuration with `errorMessage` to throw on missing provider.
94
+ * @returns A tuple `[injectFn, provideFn]` for type-safe dependency injection.
55
95
  *
56
- * @param token - Unique token identifier
57
- * @param opt - Configuration with error message
58
- * @returns A tuple of [injectFn, provideFn] for type-safe dependency injection
96
+ * @example
97
+ * ```ts
98
+ * const [injectAuth, provideAuth] = injectable<AuthService>('Auth', {
99
+ * errorMessage: 'AuthService must be provided before any consumer reads it',
100
+ * });
101
+ *
102
+ * const auth = injectAuth(); // throws if no provideAuth(...) is in scope
103
+ * ```
59
104
  */
60
105
  export declare function injectable<T>(token: string, opt: ErrorMessageInjectableOptions): InjectFns<T>;
106
+ /**
107
+ * Creates a typed `InjectionToken` with a baked-in factory used as the lazy
108
+ * fallback. The factory runs in an injection context, so it can use
109
+ * `inject()` to compose dependencies.
110
+ *
111
+ * @typeParam T The type of the value the factory produces.
112
+ * @param fn Factory function evaluated lazily on first inject if no override is provided.
113
+ * @param name Optional token name (used as the debug name).
114
+ * @returns A tuple `[injectFn, provideFn]` for type-safe dependency injection.
115
+ *
116
+ * @example
117
+ * ```ts
118
+ * const [injectUser, provideUser] = injectable(
119
+ * () => inject(HttpClient).get<User>('/api/me'),
120
+ * 'CurrentUser',
121
+ * );
122
+ * ```
123
+ */
124
+ export declare function injectable<T>(fn: () => T, name?: string): InjectFns<T>;
61
125
  export {};
@@ -1,7 +1,31 @@
1
1
  import { Injector } from '@angular/core';
2
2
  /**
3
- * Creates a root-level singleton hooked into the global injector.
4
- * @example const injectUser = rootInjectable(() => ({ name: signal('John') }));
3
+ * Creates a root-level singleton wired into the global (`providedIn: 'root'`)
4
+ * injector. Returns a typed `inject()` helper calling it anywhere in an
5
+ * injection context yields the same singleton instance. Useful for app-wide
6
+ * signal stores, configuration, or services that don't need per-component
7
+ * scoping.
8
+ *
9
+ * @typeParam T The type of the singleton value produced by the factory.
10
+ * @param factory Factory invoked once (lazily) to construct the singleton.
11
+ * Receives the root `Injector` for cases where `inject()` isn't ergonomic.
12
+ * @param name Optional token name (used as the debug name).
13
+ * @returns A getter function that returns the same singleton instance on every call.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * // Define once at module scope:
18
+ * const injectCurrentUser = rootInjectable(
19
+ * () => signal<User | null>(null),
20
+ * 'CurrentUser',
21
+ * );
22
+ *
23
+ * // Consume from anywhere in an injection context:
24
+ * @Component({ ... })
25
+ * class HeaderComponent {
26
+ * readonly user = injectCurrentUser();
27
+ * }
28
+ * ```
5
29
  */
6
30
  export declare function rootInjectable<T>(factory: (injector: Injector) => T, // Keeping the injector just in case
7
31
  name?: string): () => T;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmstack/di",
3
- "version": "19.3.4",
3
+ "version": "19.3.5",
4
4
  "keywords": [
5
5
  "angular",
6
6
  "dependency injection",