@signe/di 2.3.0 → 2.3.2

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.js CHANGED
@@ -99,6 +99,21 @@ function findProvider(providers, name) {
99
99
  __name(findProvider, "findProvider");
100
100
 
101
101
  // src/merge-config.ts
102
+ function processProvider(mergedConfig, baseConfig, provider) {
103
+ if (Array.isArray(provider)) {
104
+ for (const nestedProvider of provider) {
105
+ processProvider(mergedConfig, baseConfig, nestedProvider);
106
+ }
107
+ return;
108
+ }
109
+ const existingProvider = findProvider(baseConfig.providers, provider.provide);
110
+ if (existingProvider) {
111
+ mergedConfig.providers = override(mergedConfig.providers, provider);
112
+ } else {
113
+ mergedConfig.providers.push(provider);
114
+ }
115
+ }
116
+ __name(processProvider, "processProvider");
102
117
  function mergeConfig(baseConfig, config) {
103
118
  const mergedConfig = {
104
119
  ...baseConfig,
@@ -109,12 +124,7 @@ function mergeConfig(baseConfig, config) {
109
124
  // Start with a copy of base providers
110
125
  };
111
126
  for (const provider of config.providers) {
112
- const existingProvider = findProvider(baseConfig.providers, provider.provide);
113
- if (existingProvider) {
114
- mergedConfig.providers = override(mergedConfig.providers, provider);
115
- } else {
116
- mergedConfig.providers.push(provider);
117
- }
127
+ processProvider(mergedConfig, baseConfig, provider);
118
128
  }
119
129
  return mergedConfig;
120
130
  }
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 * 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 // Create a new config object with everything except providers\n const mergedConfig: AppConfig = {\n ...baseConfig,\n ...config,\n providers: [...baseConfig.providers] // Start with a copy of base providers\n }\n\n // Process each provider from the config to merge\n for (const provider of config.providers) {\n const existingProvider = findProvider(baseConfig.providers, provider.provide)\n if (existingProvider) {\n // Replace existing provider\n mergedConfig.providers = override(mergedConfig.providers, provider)\n } else {\n // Add new provider\n mergedConfig.providers.push(provider)\n }\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","providers","provider","existingProvider","findProvider","provide","override","push","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 * Process a provider or nested provider array and add it to the merged config\n * @param mergedConfig - Configuration being built\n * @param baseConfig - Original base configuration \n * @param provider - Provider or nested provider array to process\n */\nfunction processProvider(mergedConfig: AppConfig, baseConfig: AppConfig, provider: any) {\n // Handle nested arrays of providers\n if (Array.isArray(provider)) {\n for (const nestedProvider of provider) {\n processProvider(mergedConfig, baseConfig, nestedProvider);\n }\n return;\n }\n\n // Handle individual provider\n const existingProvider = findProvider(baseConfig.providers, provider.provide);\n if (existingProvider) {\n // Replace existing provider\n mergedConfig.providers = override(mergedConfig.providers, provider);\n } else {\n // Add new provider\n mergedConfig.providers.push(provider);\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 // Create a new config object with everything except providers\n const mergedConfig: AppConfig = {\n ...baseConfig,\n ...config,\n providers: [...baseConfig.providers] // Start with a copy of base providers\n }\n\n // Process each provider from the config to merge\n for (const provider of config.providers) {\n processProvider(mergedConfig, baseConfig, provider);\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":";;;;AAgBO,SAASA,QAAWC,SAAkBC,MAAcC,OAAQ;AACjEF,UAAQG,IAAI,YAAYF,MAAMC,KAAAA;AAC9B,SAAOA;AACT;AAHgBH;AAWT,SAASK,WAAWJ,SAAkBC,MAAY;AACvD,SAAOD,QAAQK,IAAI,cAAcJ,IAAAA,MAAU;AAC7C;AAFgBG;AAUT,SAASE,WAAWN,SAAkBC,MAAY;AACvD,SAAOD,QAAQK,IAAI,YAAYJ,IAAAA,MAAUM;AAC3C;AAFgBD;AAaT,SAASE,OACdR,SACAS,SACAC,OAAc,CAAA,GAAE;AAEhB,QAAMC,UAAU,OAAOF,YAAY;AACnC,QAAMR,OAAOU,UAAUF,QAAQR,OAAOQ;AACtC,QAAMP,QAAQF,QAAQK,IAAI,YAAYJ,IAAAA;AACtC,MAAIC,OAAO;AACTF,YAAQG,IAAI,cAAcF,MAAM,IAAA;AAChC,WAAOC;EACT;AACA,QAAM,IAAIU,MAAM,sBAAsBX,IAAAA,YAAgB;AACxD;AAbgBO;AAwBT,SAASK,SACdC,WACAC,aACAC,SAGC;AAED,MAAI,EAAEC,SAAS,OAAOC,IAAG,IAAKF,WAAW,CAAC;AAC1C,MAAI,CAACE,KAAK;AACRA,UACE,OAAOH,gBAAgB,aAAaA,YAAYd,OAAOc,YAAYhB;EAEvE;AAGA,QAAMoB,gBAAgBL,UAAUM,KAAI;AAGpC,QAAMC,SAASF,cAAcG,KAAKC,CAAAA,aAAAA;AAChC,QAAI,OAAOA,aAAa,YAAY;AAClC,aAAOA,SAAStB,SAASiB;IAC3B,WAAW,OAAOK,aAAa,UAAU;AACvC,aAAQA,SAAiBxB,YAAYmB;IACvC;AACA,WAAO;EACT,CAAA;AAGA,QAAMM,kBAAkBL,cAAcM,IAAI,CAACF,aAAAA;AACzC,QAAI,OAAOA,aAAa,cAAcA,SAAStB,SAASiB,KAAK;AAC3D,aAAOH;IACT,WAAW,OAAOQ,aAAa,YAAaA,SAAiBxB,YAAYmB,KAAK;AAC5E,aAAOH;IACT;AACA,WAAOQ;EACT,CAAA;AAGA,MAAIN,UAAU,CAACI,QAAQ;AACrBG,oBAAgBE,KAAKX,WAAAA;EACvB;AAEA,SAAOS;AACT;AA5CgBX;AAqDT,SAASc,cAA6Cb,WAAsBb,MAAqB;AACtG,QAAM2B,UAAiB,CAAA;AAEvB,aAAWL,YAAYT,WAAW;AAChC,QAAIe,MAAMC,QAAQP,QAAAA,GAAW;AAE3BK,cAAQF,KAAI,GAAIC,cAAcJ,UAAUtB,IAAAA,CAAAA;IAC1C,WAAW8B,aAAaR,UAAiBtB,IAAAA,GAAO;AAE9C2B,cAAQF,KAAKH,QAAAA;IACf;EACF;AAEA,SAAOK;AACT;AAdgBD;AAuBT,SAASI,aAA4CjB,WAAsBb,MAAqB;AAErG,MAAI,CAAC4B,MAAMC,QAAQhB,SAAAA,GAAY;AAC7B,QAAI,OAAOA,cAAc,YAAY,aAAaA,WAAW;AAC3D,YAAMS,WAAWT;AACjB,YAAMkB,eAAe,OAAOT,SAASxB,YAAY,aAC7CwB,SAASxB,QAAQE,OACjBsB,SAASxB;AAEb,UAAIE,gBAAgBgC,QAAQ;AAC1B,YAAIhC,KAAKiC,KAAKF,YAAAA,EAAe,QAAOlB;MACtC,OAAO;AACL,YAAIkB,iBAAiB/B,KAAM,QAAOa;MACpC;IACF;AACA,WAAO;EACT;AAGA,aAAWS,YAAYT,WAAW;AAEhC,QAAIe,MAAMC,QAAQP,QAAAA,GAAW;AAC3B,YAAMY,QAAQJ,aAAaR,UAAUtB,IAAAA;AACrC,UAAIkC,MAAO,QAAOA;AAClB;IACF;AAGA,QAAI,OAAOZ,aAAa,YAAY,aAAaA,UAAU;AACzD,YAAMS,eAAe,OAAOT,SAASxB,YAAY,aAC7CwB,SAASxB,QAAQE,OACjBsB,SAASxB;AAGb,UAAIE,gBAAgBgC,QAAQ;AAC1B,YAAIhC,KAAKiC,KAAKF,YAAAA,EAAe,QAAOT;MACtC,OAAO;AAEL,YAAIS,iBAAiB/B,KAAM,QAAOsB;MACpC;IACF;EACF;AACA,SAAO;AACT;AA3CgBQ;;;AC1HhB,SAASK,gBAAgBC,cAAyBC,YAAuBC,UAAa;AAElF,MAAIC,MAAMC,QAAQF,QAAAA,GAAW;AACzB,eAAWG,kBAAkBH,UAAU;AACnCH,sBAAgBC,cAAcC,YAAYI,cAAAA;IAC9C;AACA;EACJ;AAGA,QAAMC,mBAAmBC,aAAaN,WAAWO,WAAWN,SAASO,OAAO;AAC5E,MAAIH,kBAAkB;AAElBN,iBAAaQ,YAAYE,SAASV,aAAaQ,WAAWN,QAAAA;EAC9D,OAAO;AAEHF,iBAAaQ,UAAUG,KAAKT,QAAAA;EAChC;AACJ;AAlBSH;AA0BF,SAASa,YAAYX,YAAuBY,QAAiB;AAEhE,QAAMb,eAA0B;IAC5B,GAAGC;IACH,GAAGY;IACHL,WAAW;SAAIP,WAAWO;;;EAC9B;AAGA,aAAWN,YAAYW,OAAOL,WAAW;AACrCT,oBAAgBC,cAAcC,YAAYC,QAAAA;EAC9C;AAEA,SAAOF;AACX;AAdgBY;;;ACfhB,eAAsBE,SAASC,SAAkBC,WAAoB;AACjEA,cAAYA,UAAUC,KAAI;AAC1B,aAAWC,YAAYF,WAAW;AAC9B,QAAIG;AACJ,QAAIC;AAEJ,QAAI,OAAOF,aAAa,YAAY;AAEhCC,cAAQD;AACRE,iBAAW,IAAIF,SAASH,OAAAA;IAC5B,OAAO;AACHI,cAASD,SAAiBG;AAC1B,YAAMC,mBAAoBJ,SAAiBK;AAC3C,YAAMC,UAAU,OAAOF,qBAAqB;AAC5C,UAAIE,SAAS;AACTJ,mBAAW,IAAIE,iBAAiBP,OAAAA;MACpC,WAAW,cAAcG,UAAU;AAC/BE,mBAAWF,SAASO;MACxB,WAAW,gBAAgBP,UAAU;AACjCE,mBAAWF,SAASQ,aAAaX,OAAAA;AACjC,YAAIK,oBAAoBO,SAAS;AAC7BP,qBAAW,MAAMA;QACrB;MACJ,WAAW,iBAAiBF,UAAU;AAClCE,mBAAWQ,OAAOb,SAASG,SAASW,WAAW;MACnD;IACJ;AAEA,UAAMC,OAAO,OAAOX,UAAU,aAAaA,MAAMW,OAAOX;AACxDE,YAAQN,SAASe,MAAMV,QAAAA;EAC3B;AACJ;AA/BsBN;;;AC5Bf,IAAMiB,UAAN,MAAMA;EAXb,OAWaA;;;;EAMDC,SAAkB,CAAC;;;;;;EAO3BC,IAA6BC,KAAQC,OAAmB;AACpD,SAAKH,OAAOE,GAAAA,IAAOC;EACvB;;;;;;EAOAC,IAA6BF,KAAoB;AAC7C,WAAO,KAAKF,OAAOE,GAAAA;EACvB;AACJ;","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","processProvider","mergedConfig","baseConfig","provider","Array","isArray","nestedProvider","existingProvider","findProvider","providers","provide","override","push","mergeConfig","config","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": "2.3.0",
3
+ "version": "2.3.2",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "exports": {
@@ -20,6 +20,32 @@ export interface AppConfig {
20
20
  }
21
21
  }
22
22
 
23
+ /**
24
+ * Process a provider or nested provider array and add it to the merged config
25
+ * @param mergedConfig - Configuration being built
26
+ * @param baseConfig - Original base configuration
27
+ * @param provider - Provider or nested provider array to process
28
+ */
29
+ function processProvider(mergedConfig: AppConfig, baseConfig: AppConfig, provider: any) {
30
+ // Handle nested arrays of providers
31
+ if (Array.isArray(provider)) {
32
+ for (const nestedProvider of provider) {
33
+ processProvider(mergedConfig, baseConfig, nestedProvider);
34
+ }
35
+ return;
36
+ }
37
+
38
+ // Handle individual provider
39
+ const existingProvider = findProvider(baseConfig.providers, provider.provide);
40
+ if (existingProvider) {
41
+ // Replace existing provider
42
+ mergedConfig.providers = override(mergedConfig.providers, provider);
43
+ } else {
44
+ // Add new provider
45
+ mergedConfig.providers.push(provider);
46
+ }
47
+ }
48
+
23
49
  /**
24
50
  * Merges two application configurations
25
51
  * @param baseConfig - Base configuration to merge into
@@ -36,14 +62,7 @@ export function mergeConfig(baseConfig: AppConfig, config: AppConfig): AppConfig
36
62
 
37
63
  // Process each provider from the config to merge
38
64
  for (const provider of config.providers) {
39
- const existingProvider = findProvider(baseConfig.providers, provider.provide)
40
- if (existingProvider) {
41
- // Replace existing provider
42
- mergedConfig.providers = override(mergedConfig.providers, provider)
43
- } else {
44
- // Add new provider
45
- mergedConfig.providers.push(provider)
46
- }
65
+ processProvider(mergedConfig, baseConfig, provider);
47
66
  }
48
67
 
49
68
  return mergedConfig;