@signe/di 2.2.0 → 2.3.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.js +16 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/merge-config.ts +27 -8
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
|
-
|
|
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":"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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","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
package/src/merge-config.ts
CHANGED
|
@@ -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
|
-
|
|
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;
|