This commit is contained in:
Boki 2025-06-20 21:04:09 -04:00
parent caf1c5fcaf
commit 20b7180a43
5 changed files with 207 additions and 158 deletions

View file

@ -1,15 +1,15 @@
import { join } from 'path';
import { z } from 'zod';
import {
ConfigManagerOptions,
Environment,
ConfigLoader,
DeepPartial,
ConfigSchema
} from './types';
import { ConfigError, ConfigValidationError } from './errors';
import { EnvLoader } from './loaders/env.loader';
import { FileLoader } from './loaders/file.loader';
import { ConfigError, ConfigValidationError } from './errors';
import {
ConfigLoader,
ConfigManagerOptions,
ConfigSchema,
DeepPartial,
Environment,
} from './types';
export class ConfigManager<T = Record<string, unknown>> {
private config: T | null = null;
@ -19,7 +19,7 @@ export class ConfigManager<T = Record<string, unknown>> {
constructor(options: ConfigManagerOptions = {}) {
this.environment = options.environment || this.detectEnvironment();
// Default loaders if none provided
if (options.loaders) {
this.loaders = options.loaders;
@ -59,7 +59,11 @@ export class ConfigManager<T = Record<string, unknown>> {
const mergedConfig = this.deepMerge(...configs) as T;
// Add environment if not present
if (typeof mergedConfig === 'object' && mergedConfig !== null && !('environment' in mergedConfig)) {
if (
typeof mergedConfig === 'object' &&
mergedConfig !== null &&
!('environment' in mergedConfig)
) {
(mergedConfig as Record<string, unknown>)['environment'] = this.environment;
}
@ -69,10 +73,7 @@ export class ConfigManager<T = Record<string, unknown>> {
this.config = this.schema.parse(mergedConfig) as T;
} catch (error) {
if (error instanceof z.ZodError) {
throw new ConfigValidationError(
'Configuration validation failed',
error.errors
);
throw new ConfigValidationError('Configuration validation failed', error.errors);
}
throw error;
}
@ -132,7 +133,10 @@ export class ConfigManager<T = Record<string, unknown>> {
throw new ConfigError('Configuration not initialized. Call initialize() first.');
}
const updated = this.deepMerge(this.config as Record<string, unknown>, updates as Record<string, unknown>) as T;
const updated = this.deepMerge(
this.config as Record<string, unknown>,
updates as Record<string, unknown>
) as T;
// Re-validate if schema is present
if (this.schema) {
@ -204,13 +208,13 @@ export class ConfigManager<T = Record<string, unknown>> {
if (value === null || value === undefined) {
result[key] = value;
} else if (
typeof value === 'object' &&
typeof value === 'object' &&
!Array.isArray(value) &&
!(value instanceof Date) &&
!(value instanceof RegExp)
) {
result[key] = this.deepMerge(
(result[key] as Record<string, unknown>) || {} as Record<string, unknown>,
(result[key] as Record<string, unknown>) || ({} as Record<string, unknown>),
value as Record<string, unknown>
);
} else {
@ -221,4 +225,4 @@ export class ConfigManager<T = Record<string, unknown>> {
return result;
}
}
}