@signe/di 1.4.0 → 1.4.1

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/dist/index.d.ts CHANGED
@@ -87,8 +87,11 @@ type Providers = (Provider | Providers)[];
87
87
  */
88
88
  /**
89
89
  * Stores and manages the state of injected dependencies
90
+ * @template TState - Type for the state
91
+ * @template TActions - Type for the actions
92
+ * @template TValues - Type for additional values
90
93
  */
91
- declare class Context {
94
+ declare class Context<TState = any, TActions = any, TValues extends Record<string, any> = Record<string, any>> {
92
95
  /** Internal storage for injected values */
93
96
  private values;
94
97
  /**
@@ -96,13 +99,13 @@ declare class Context {
96
99
  * @param key - Unique identifier for the value
97
100
  * @param value - Value to store
98
101
  */
99
- set(key: string, value: any): void;
102
+ set<K extends keyof TValues>(key: K, value: TValues[K]): void;
100
103
  /**
101
104
  * Retrieves a value from the context
102
105
  * @param key - Unique identifier for the value
103
106
  * @returns The stored value or undefined if not found
104
107
  */
105
- get(key: string): any;
108
+ get<K extends keyof TValues>(key: K): TValues[K];
106
109
  }
107
110
 
108
111
  /**
@@ -126,6 +129,13 @@ declare function provide<T>(context: Context, name: string, value: T): T;
126
129
  * @returns True if the service has been injected, false otherwise
127
130
  */
128
131
  declare function isInjected(context: Context, name: string): boolean;
132
+ /**
133
+ * Checks if a service has been provided in the context
134
+ * @param context - The injection context
135
+ * @param name - Name of the service to check
136
+ * @returns True if the service has been provided, false otherwise
137
+ */
138
+ declare function isProvided(context: Context, name: string): boolean;
129
139
  /**
130
140
  * Retrieves a service from the dependency injection context
131
141
  * @template T - Type of the service to inject
@@ -217,4 +227,4 @@ declare function mergeConfig(baseConfig: AppConfig, config: AppConfig): AppConfi
217
227
  */
218
228
  declare function injector(context: Context, providers: Providers): Promise<void>;
219
229
 
220
- export { type AppConfig, type ClassProvider, Context, type ExistingProvider, type FactoryFn, type FactoryProvider, type Provider, type ProviderContext, type ProviderToken, type Providers, type ValueProvider, findProvider, findProviders, inject, injector, isInjected, mergeConfig, override, provide };
230
+ export { type AppConfig, type ClassProvider, Context, type ExistingProvider, type FactoryFn, type FactoryProvider, type Provider, type ProviderContext, type ProviderToken, type Providers, type ValueProvider, findProvider, findProviders, inject, injector, isInjected, isProvided, mergeConfig, override, provide };
package/dist/index.js CHANGED
@@ -11,6 +11,10 @@ function isInjected(context, name) {
11
11
  return context.get("injected:" + name) === true;
12
12
  }
13
13
  __name(isInjected, "isInjected");
14
+ function isProvided(context, name) {
15
+ return context.get("inject:" + name) !== void 0;
16
+ }
17
+ __name(isProvided, "isProvided");
14
18
  function inject(context, service, args = []) {
15
19
  const isClass = typeof service === "function";
16
20
  const name = isClass ? service.name : service;
@@ -175,6 +179,7 @@ export {
175
179
  inject,
176
180
  injector,
177
181
  isInjected,
182
+ isProvided,
178
183
  mergeConfig,
179
184
  override,
180
185
  provide
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/inject.ts","../src/merge-config.ts","../src/provider.ts","../src/context.ts"],"sourcesContent":["/**\n * Core functionality for dependency injection\n * @module @signe/di/inject\n */\n\nimport { Provider, Providers } from \"./types\";\nimport { Context } from \"./context\";\n\n/**\n * Provides a value to the dependency injection context\n * @template T - Type of the value being provided\n * @param context - The injection context\n * @param name - Identifier for the provided value\n * @param value - The value to provide\n * @returns The provided value\n */\nexport function provide<T>(context: Context, name: string, value: T): T {\n context.set(\"inject:\" + name, value);\n return value;\n}\n\n/**\n * Checks if a service has been injected into the context\n * @param context - The injection context\n * @param name - Name of the service to check\n * @returns True if the service has been injected, false otherwise\n */\nexport function isInjected(context: Context, name: string): boolean {\n return context.get('injected:' + name) === true;\n}\n\n/**\n * Retrieves a service from the dependency injection context\n * @template T - Type of the service to inject\n * @param context - The injection context\n * @param service - Class constructor or string identifier of the service\n * @param args - Optional arguments for service instantiation\n * @returns The injected service instance\n * @throws {Error} If the requested service is not found in the context\n */\nexport function inject<T>(\n context: Context,\n service: (new (...args: any[]) => T) | string,\n args: any[] = []\n): T {\n const isClass = typeof service === \"function\";\n const name = isClass ? service.name : service;\n const value = context.get(\"inject:\" + name);\n if (value) {\n context.set('injected:' + name, true)\n return value as T;\n }\n throw new Error(`Injection provider ${name} not found`);\n}\n\n/**\n * Overrides or adds a provider in the providers array\n * @param providers - Array of existing providers\n * @param newProvider - Provider to add or replace with\n * @param options - Configuration options\n * @param options.upsert - If true, adds the provider when not found\n * @param options.key - Custom key to identify the provider\n * @returns Updated array of providers\n */\nexport function override(\n providers: Providers,\n newProvider: Provider,\n options?: {\n upsert?: boolean,\n key?: string\n }\n) {\n let { upsert = false, key } = options ?? {};\n if (!key) {\n key = (\n typeof newProvider === \"function\" ? newProvider.name : newProvider.provide\n ) as string;\n }\n\n // Flatten the providers array\n const flatProviders = providers.flat();\n \n // Check if provider exists\n const exists = flatProviders.some(provider => {\n if (typeof provider === \"function\") {\n return provider.name === key;\n } else if (typeof provider === \"object\") {\n return (provider as any).provide === key;\n }\n return false;\n });\n\n // Map and replace if found\n const mappedProviders = flatProviders.map((provider) => {\n if (typeof provider === \"function\" && provider.name === key) {\n return newProvider;\n } else if (typeof provider === \"object\" && (provider as any).provide === key) {\n return newProvider;\n }\n return provider;\n });\n\n // If upsert is true and provider wasn't found, add it to the end\n if (upsert && !exists) {\n mappedProviders.push(newProvider);\n }\n\n return mappedProviders;\n}\n\n/**\n * Finds all providers matching the given name or pattern\n * @template T - Type of provider to return\n * @param providers - Array of providers to search\n * @param name - String or RegExp to match against provider names\n * @returns Array of matching providers\n */\nexport function findProviders<T extends Provider = Provider>(providers: Providers, name: string | RegExp): T[] {\n const results: any[] = [];\n \n for (const provider of providers) {\n if (Array.isArray(provider)) {\n // Recursively search in nested arrays and concat results\n results.push(...findProviders(provider, name));\n } else if (findProvider(provider as any, name)) {\n // Add matching provider to results\n results.push(provider as T);\n }\n }\n \n return results;\n}\n\n/**\n * Finds the first provider matching the given name or pattern\n * @template T - Type of provider to return\n * @param providers - Array of providers to search\n * @param name - String or RegExp to match against provider names\n * @returns Matching provider or null if not found\n */\nexport function findProvider<T extends Provider = Provider>(providers: Providers, name: string | RegExp): T | null {\n // Handle single provider case\n if (!Array.isArray(providers)) {\n if (typeof providers === \"object\" && 'provide' in providers) {\n const provider = providers as any\n const providerName = typeof provider.provide === \"function\"\n ? provider.provide.name \n : provider.provide;\n\n if (name instanceof RegExp) {\n if (name.test(providerName)) return providers as T;\n } else {\n if (providerName === name) return providers as T;\n }\n }\n return null;\n }\n\n // Original array handling logic\n for (const provider of providers) {\n // If provider is an array, recursively search in it\n if (Array.isArray(provider)) {\n const found = findProvider(provider, name);\n if (found) return found as T;\n continue;\n }\n\n // Check object provider\n if (typeof provider === \"object\" && 'provide' in provider) {\n const providerName = typeof provider.provide === \"function\" \n ? provider.provide.name \n : provider.provide;\n\n // Handle RegExp matching\n if (name instanceof RegExp) {\n if (name.test(providerName)) return provider as T;\n } else {\n // Handle exact string matching\n if (providerName === name) return provider as T;\n }\n }\n }\n return null;\n}\n","/**\n * Configuration merging functionality for dependency injection\n * @module @signe/di/merge-config\n */\n\nimport { findProvider, override } from \"./inject\";\n\n/**\n * Application configuration interface\n */\nexport interface AppConfig {\n /** Array of dependency providers */\n providers: any[];\n /** Optional static files configuration */\n staticFiles?: {\n /** Path to static files */\n path: string;\n /** Static file serving configuration */\n serve: any;\n }\n}\n\n/**\n * Merges two application configurations\n * @param baseConfig - Base configuration to merge into\n * @param config - Configuration to merge with base\n * @returns Merged configuration with providers properly combined\n */\nexport function mergeConfig(baseConfig: AppConfig, config: AppConfig): AppConfig {\n const mergedConfig: AppConfig = {\n ...baseConfig,\n ...config\n }\n for (let provider of config.providers) {\n const isFound = findProvider(baseConfig.providers, provider.provide)\n if (!isFound) {\n mergedConfig.providers = override(baseConfig.providers, provider, { upsert: true })\n }\n }\n return mergedConfig;\n}\n","/**\n * Provider system implementation for dependency injection\n * @module @signe/di/provider\n */\n\nimport { ClassProvider, Provider, Providers, ProviderToken } from \"./types\";\nimport { inject, provide } from \"./inject\";\nimport { Context } from \"./context\";\n\n/**\n * Type guard to check if a provider is a ClassProvider\n * @param provider - Provider to check\n * @returns True if the provider is a ClassProvider\n */\nfunction isClassProvider(provider: Provider): provider is ClassProvider {\n if (typeof provider === 'string') {\n return false;\n }\n return 'useClass' in provider && typeof provider.useClass === 'function';\n}\n\n/**\n * Processes and instantiates all providers in the given context\n * @param context - The injection context\n * @param providers - Array of providers to process\n * @returns Promise that resolves when all providers are processed\n * \n * @example\n * ```typescript\n * const context = new Context();\n * const providers = [\n * UserService,\n * { provide: 'CONFIG', useValue: { apiUrl: 'http://api.example.com' } },\n * { provide: AuthService, useFactory: (ctx) => new AuthService(ctx) }\n * ];\n * \n * await injector(context, providers);\n * ```\n */\nexport async function injector(context: Context, providers: Providers) {\n providers = providers.flat();\n for (const provider of providers) {\n let token: ProviderToken;\n let instance: any;\n\n if (typeof provider === 'function') {\n // If provider is a class, treat it as a ClassProvider\n token = provider;\n instance = new provider(context);\n } else {\n token = (provider as any).provide;\n const provideUserClass = (provider as any).useClass;\n const isClass = typeof provideUserClass === 'function';\n if (isClass) {\n instance = new provideUserClass(context);\n } else if ('useValue' in provider) {\n instance = provider.useValue;\n } else if ('useFactory' in provider) {\n instance = provider.useFactory?.(context);\n if (instance instanceof Promise) {\n instance = await instance;\n }\n } else if ('useExisting' in provider) {\n instance = inject(context, provider.useExisting);\n }\n }\n\n const name = typeof token === 'function' ? token.name : token;\n provide(context, name, instance);\n }\n}","/**\n * Context class for managing dependency injection state\n * @module @signe/di/context\n */\n\n/**\n * Stores and manages the state of injected dependencies\n */\nexport class Context {\n /** Internal storage for injected values */\n private values: { [key: string]: any } = {}\n\n /**\n * Sets a value in the context\n * @param key - Unique identifier for the value\n * @param value - Value to store\n */\n set(key: string, value: any) {\n this.values[key] = value\n }\n\n /**\n * Retrieves a value from the context\n * @param key - Unique identifier for the value\n * @returns The stored value or undefined if not found\n */\n get(key: string) {\n return this.values[key]\n }\n}"],"mappings":"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","names":["provide","context","name","value","set","isInjected","get","inject","service","args","isClass","Error","override","providers","newProvider","options","upsert","key","flatProviders","flat","exists","some","provider","mappedProviders","map","push","findProviders","results","Array","isArray","findProvider","providerName","RegExp","test","found","mergeConfig","baseConfig","config","mergedConfig","provider","providers","isFound","findProvider","provide","override","upsert","injector","context","providers","flat","provider","token","instance","provide","provideUserClass","useClass","isClass","useValue","useFactory","Promise","inject","useExisting","name","Context","values","set","key","value","get"]}
1
+ {"version":3,"sources":["../src/inject.ts","../src/merge-config.ts","../src/provider.ts","../src/context.ts"],"sourcesContent":["/**\n * Core functionality for dependency injection\n * @module @signe/di/inject\n */\n\nimport { Provider, Providers } from \"./types\";\nimport { Context } from \"./context\";\n\n/**\n * Provides a value to the dependency injection context\n * @template T - Type of the value being provided\n * @param context - The injection context\n * @param name - Identifier for the provided value\n * @param value - The value to provide\n * @returns The provided value\n */\nexport function provide<T>(context: Context, name: string, value: T): T {\n context.set(\"inject:\" + name, value);\n return value;\n}\n\n/**\n * Checks if a service has been injected into the context\n * @param context - The injection context\n * @param name - Name of the service to check\n * @returns True if the service has been injected, false otherwise\n */\nexport function isInjected(context: Context, name: string): boolean {\n return context.get('injected:' + name) === true;\n}\n\n/**\n * Checks if a service has been provided in the context\n * @param context - The injection context\n * @param name - Name of the service to check\n * @returns True if the service has been provided, false otherwise\n */\nexport function isProvided(context: Context, name: string): boolean {\n return context.get('inject:' + name) !== undefined;\n}\n\n/**\n * Retrieves a service from the dependency injection context\n * @template T - Type of the service to inject\n * @param context - The injection context\n * @param service - Class constructor or string identifier of the service\n * @param args - Optional arguments for service instantiation\n * @returns The injected service instance\n * @throws {Error} If the requested service is not found in the context\n */\nexport function inject<T>(\n context: Context,\n service: (new (...args: any[]) => T) | string,\n args: any[] = []\n): T {\n const isClass = typeof service === \"function\";\n const name = isClass ? service.name : service;\n const value = context.get(\"inject:\" + name);\n if (value) {\n context.set('injected:' + name, true)\n return value as T;\n }\n throw new Error(`Injection provider ${name} not found`);\n}\n\n/**\n * Overrides or adds a provider in the providers array\n * @param providers - Array of existing providers\n * @param newProvider - Provider to add or replace with\n * @param options - Configuration options\n * @param options.upsert - If true, adds the provider when not found\n * @param options.key - Custom key to identify the provider\n * @returns Updated array of providers\n */\nexport function override(\n providers: Providers,\n newProvider: Provider,\n options?: {\n upsert?: boolean,\n key?: string\n }\n) {\n let { upsert = false, key } = options ?? {};\n if (!key) {\n key = (\n typeof newProvider === \"function\" ? newProvider.name : newProvider.provide\n ) as string;\n }\n\n // Flatten the providers array\n const flatProviders = providers.flat();\n \n // Check if provider exists\n const exists = flatProviders.some(provider => {\n if (typeof provider === \"function\") {\n return provider.name === key;\n } else if (typeof provider === \"object\") {\n return (provider as any).provide === key;\n }\n return false;\n });\n\n // Map and replace if found\n const mappedProviders = flatProviders.map((provider) => {\n if (typeof provider === \"function\" && provider.name === key) {\n return newProvider;\n } else if (typeof provider === \"object\" && (provider as any).provide === key) {\n return newProvider;\n }\n return provider;\n });\n\n // If upsert is true and provider wasn't found, add it to the end\n if (upsert && !exists) {\n mappedProviders.push(newProvider);\n }\n\n return mappedProviders;\n}\n\n/**\n * Finds all providers matching the given name or pattern\n * @template T - Type of provider to return\n * @param providers - Array of providers to search\n * @param name - String or RegExp to match against provider names\n * @returns Array of matching providers\n */\nexport function findProviders<T extends Provider = Provider>(providers: Providers, name: string | RegExp): T[] {\n const results: any[] = [];\n \n for (const provider of providers) {\n if (Array.isArray(provider)) {\n // Recursively search in nested arrays and concat results\n results.push(...findProviders(provider, name));\n } else if (findProvider(provider as any, name)) {\n // Add matching provider to results\n results.push(provider as T);\n }\n }\n \n return results;\n}\n\n/**\n * Finds the first provider matching the given name or pattern\n * @template T - Type of provider to return\n * @param providers - Array of providers to search\n * @param name - String or RegExp to match against provider names\n * @returns Matching provider or null if not found\n */\nexport function findProvider<T extends Provider = Provider>(providers: Providers, name: string | RegExp): T | null {\n // Handle single provider case\n if (!Array.isArray(providers)) {\n if (typeof providers === \"object\" && 'provide' in providers) {\n const provider = providers as any\n const providerName = typeof provider.provide === \"function\"\n ? provider.provide.name \n : provider.provide;\n\n if (name instanceof RegExp) {\n if (name.test(providerName)) return providers as T;\n } else {\n if (providerName === name) return providers as T;\n }\n }\n return null;\n }\n\n // Original array handling logic\n for (const provider of providers) {\n // If provider is an array, recursively search in it\n if (Array.isArray(provider)) {\n const found = findProvider(provider, name);\n if (found) return found as T;\n continue;\n }\n\n // Check object provider\n if (typeof provider === \"object\" && 'provide' in provider) {\n const providerName = typeof provider.provide === \"function\" \n ? provider.provide.name \n : provider.provide;\n\n // Handle RegExp matching\n if (name instanceof RegExp) {\n if (name.test(providerName)) return provider as T;\n } else {\n // Handle exact string matching\n if (providerName === name) return provider as T;\n }\n }\n }\n return null;\n}\n","/**\n * Configuration merging functionality for dependency injection\n * @module @signe/di/merge-config\n */\n\nimport { findProvider, override } from \"./inject\";\n\n/**\n * Application configuration interface\n */\nexport interface AppConfig {\n /** Array of dependency providers */\n providers: any[];\n /** Optional static files configuration */\n staticFiles?: {\n /** Path to static files */\n path: string;\n /** Static file serving configuration */\n serve: any;\n }\n}\n\n/**\n * Merges two application configurations\n * @param baseConfig - Base configuration to merge into\n * @param config - Configuration to merge with base\n * @returns Merged configuration with providers properly combined\n */\nexport function mergeConfig(baseConfig: AppConfig, config: AppConfig): AppConfig {\n const mergedConfig: AppConfig = {\n ...baseConfig,\n ...config\n }\n for (let provider of config.providers) {\n const isFound = findProvider(baseConfig.providers, provider.provide)\n if (!isFound) {\n mergedConfig.providers = override(baseConfig.providers, provider, { upsert: true })\n }\n }\n return mergedConfig;\n}\n","/**\n * Provider system implementation for dependency injection\n * @module @signe/di/provider\n */\n\nimport { ClassProvider, Provider, Providers, ProviderToken } from \"./types\";\nimport { inject, provide } from \"./inject\";\nimport { Context } from \"./context\";\n\n/**\n * Type guard to check if a provider is a ClassProvider\n * @param provider - Provider to check\n * @returns True if the provider is a ClassProvider\n */\nfunction isClassProvider(provider: Provider): provider is ClassProvider {\n if (typeof provider === 'string') {\n return false;\n }\n return 'useClass' in provider && typeof provider.useClass === 'function';\n}\n\n/**\n * Processes and instantiates all providers in the given context\n * @param context - The injection context\n * @param providers - Array of providers to process\n * @returns Promise that resolves when all providers are processed\n * \n * @example\n * ```typescript\n * const context = new Context();\n * const providers = [\n * UserService,\n * { provide: 'CONFIG', useValue: { apiUrl: 'http://api.example.com' } },\n * { provide: AuthService, useFactory: (ctx) => new AuthService(ctx) }\n * ];\n * \n * await injector(context, providers);\n * ```\n */\nexport async function injector(context: Context, providers: Providers) {\n providers = providers.flat();\n for (const provider of providers) {\n let token: ProviderToken;\n let instance: any;\n\n if (typeof provider === 'function') {\n // If provider is a class, treat it as a ClassProvider\n token = provider;\n instance = new provider(context);\n } else {\n token = (provider as any).provide;\n const provideUserClass = (provider as any).useClass;\n const isClass = typeof provideUserClass === 'function';\n if (isClass) {\n instance = new provideUserClass(context);\n } else if ('useValue' in provider) {\n instance = provider.useValue;\n } else if ('useFactory' in provider) {\n instance = provider.useFactory?.(context);\n if (instance instanceof Promise) {\n instance = await instance;\n }\n } else if ('useExisting' in provider) {\n instance = inject(context, provider.useExisting);\n }\n }\n\n const name = typeof token === 'function' ? token.name : token;\n provide(context, name, instance);\n }\n}","/**\n * Context class for managing dependency injection state\n * @module @signe/di/context\n */\n\n/**\n * Stores and manages the state of injected dependencies\n * @template TState - Type for the state\n * @template TActions - Type for the actions\n * @template TValues - Type for additional values\n */\nexport class Context<\n TState = any,\n TActions = any,\n TValues extends Record<string, any> = Record<string, any>\n> {\n /** Internal storage for injected values */\n private values: TValues = {} as TValues\n\n /**\n * Sets a value in the context\n * @param key - Unique identifier for the value\n * @param value - Value to store\n */\n set<K extends keyof TValues>(key: K, value: TValues[K]) {\n this.values[key] = value\n }\n\n /**\n * Retrieves a value from the context\n * @param key - Unique identifier for the value\n * @returns The stored value or undefined if not found\n */\n get<K extends keyof TValues>(key: K): TValues[K] {\n return this.values[key]\n }\n}"],"mappings":"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","names":["provide","context","name","value","set","isInjected","get","isProvided","undefined","inject","service","args","isClass","Error","override","providers","newProvider","options","upsert","key","flatProviders","flat","exists","some","provider","mappedProviders","map","push","findProviders","results","Array","isArray","findProvider","providerName","RegExp","test","found","mergeConfig","baseConfig","config","mergedConfig","provider","providers","isFound","findProvider","provide","override","upsert","injector","context","providers","flat","provider","token","instance","provide","provideUserClass","useClass","isClass","useValue","useFactory","Promise","inject","useExisting","name","Context","values","set","key","value","get"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signe/di",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "exports": {
package/src/context.ts CHANGED
@@ -5,17 +5,24 @@
5
5
 
6
6
  /**
7
7
  * Stores and manages the state of injected dependencies
8
+ * @template TState - Type for the state
9
+ * @template TActions - Type for the actions
10
+ * @template TValues - Type for additional values
8
11
  */
9
- export class Context {
12
+ export class Context<
13
+ TState = any,
14
+ TActions = any,
15
+ TValues extends Record<string, any> = Record<string, any>
16
+ > {
10
17
  /** Internal storage for injected values */
11
- private values: { [key: string]: any } = {}
18
+ private values: TValues = {} as TValues
12
19
 
13
20
  /**
14
21
  * Sets a value in the context
15
22
  * @param key - Unique identifier for the value
16
23
  * @param value - Value to store
17
24
  */
18
- set(key: string, value: any) {
25
+ set<K extends keyof TValues>(key: K, value: TValues[K]) {
19
26
  this.values[key] = value
20
27
  }
21
28
 
@@ -24,7 +31,7 @@ export class Context {
24
31
  * @param key - Unique identifier for the value
25
32
  * @returns The stored value or undefined if not found
26
33
  */
27
- get(key: string) {
34
+ get<K extends keyof TValues>(key: K): TValues[K] {
28
35
  return this.values[key]
29
36
  }
30
37
  }
package/src/inject.ts CHANGED
@@ -29,6 +29,16 @@ export function isInjected(context: Context, name: string): boolean {
29
29
  return context.get('injected:' + name) === true;
30
30
  }
31
31
 
32
+ /**
33
+ * Checks if a service has been provided in the context
34
+ * @param context - The injection context
35
+ * @param name - Name of the service to check
36
+ * @returns True if the service has been provided, false otherwise
37
+ */
38
+ export function isProvided(context: Context, name: string): boolean {
39
+ return context.get('inject:' + name) !== undefined;
40
+ }
41
+
32
42
  /**
33
43
  * Retrieves a service from the dependency injection context
34
44
  * @template T - Type of the service to inject