@theunwalked/cardigantime 0.0.8 → 0.0.9

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.
@@ -1 +1 @@
1
- {"version":3,"file":"cardigantime.js","sources":["../src/cardigantime.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { Args, DefaultOptions, Feature, Cardigantime, Logger, Options } from 'types';\nimport { z, ZodObject } from 'zod';\nimport { configure } from './configure';\nimport { DEFAULT_FEATURES, DEFAULT_LOGGER, DEFAULT_OPTIONS } from './constants';\nimport { read } from './read';\nimport { ConfigSchema } from 'types';\nimport { validate } from './validate';\n\nexport * from './types';\nexport { ArgumentError, ConfigurationError, FileSystemError } from './validate';\n\n/**\n * Creates a new Cardigantime instance for configuration management.\n * \n * Cardigantime handles the complete configuration lifecycle including:\n * - Reading configuration from YAML files\n * - Validating configuration against Zod schemas\n * - Merging CLI arguments with file configuration and defaults\n * - Providing type-safe configuration objects\n * \n * @template T - The Zod schema shape type for your configuration\n * @param pOptions - Configuration options for the Cardigantime instance\n * @param pOptions.defaults - Default configuration settings\n * @param pOptions.defaults.configDirectory - Directory to search for configuration files (required)\n * @param pOptions.defaults.configFile - Name of the configuration file (optional, defaults to 'config.yaml')\n * @param pOptions.defaults.isRequired - Whether the config directory must exist (optional, defaults to false)\n * @param pOptions.defaults.encoding - File encoding for reading config files (optional, defaults to 'utf8')\n * @param pOptions.defaults.pathResolution - Configuration for resolving relative paths in config values relative to the config file's directory (optional)\n * @param pOptions.features - Array of features to enable (optional, defaults to ['config'])\n * @param pOptions.configShape - Zod schema shape defining your configuration structure (required)\n * @param pOptions.logger - Custom logger implementation (optional, defaults to console logger)\n * @returns A Cardigantime instance with methods for configure, read, validate, and setLogger\n * \n * @example\n * ```typescript\n * import { create } from '@theunwalked/cardigantime';\n * import { z } from 'zod';\n * \n * const MyConfigSchema = z.object({\n * apiKey: z.string().min(1),\n * timeout: z.number().default(5000),\n * debug: z.boolean().default(false),\n * contextDirectories: z.array(z.string()).optional(),\n * });\n * \n * const cardigantime = create({\n * defaults: {\n * configDirectory: './config',\n * configFile: 'myapp.yaml',\n * // Resolve relative paths in contextDirectories relative to config file location\n * pathResolution: {\n * pathFields: ['contextDirectories'],\n * resolvePathArray: ['contextDirectories']\n * }\n * },\n * configShape: MyConfigSchema.shape,\n * });\n * \n * // If config file is at ../config/myapp.yaml and contains:\n * // contextDirectories: ['./context', './data']\n * // These paths will be resolved relative to ../config/ directory\n * ```\n */\nexport const create = <T extends z.ZodRawShape>(pOptions: {\n defaults: Pick<DefaultOptions, 'configDirectory'> & Partial<Omit<DefaultOptions, 'configDirectory'>>,\n features?: Feature[],\n configShape: T, // Make configShape mandatory\n logger?: Logger,\n}): Cardigantime<T> => {\n\n\n const defaults: DefaultOptions = { ...DEFAULT_OPTIONS, ...pOptions.defaults } as DefaultOptions;\n const features = pOptions.features || DEFAULT_FEATURES;\n const configShape = pOptions.configShape;\n let logger = pOptions.logger || DEFAULT_LOGGER;\n\n const options: Options<T> = {\n defaults,\n features,\n configShape, // Store the shape\n logger,\n }\n\n const setLogger = (pLogger: Logger) => {\n logger = pLogger;\n options.logger = pLogger;\n }\n\n return {\n setLogger,\n configure: (command: Command) => configure(command, options),\n validate: (config: z.infer<ZodObject<T & typeof ConfigSchema.shape>>) => validate(config, options),\n read: (args: Args) => read(args, options),\n }\n}\n\n\n\n\n\n"],"names":["create","pOptions","defaults","DEFAULT_OPTIONS","features","DEFAULT_FEATURES","configShape","logger","DEFAULT_LOGGER","options","setLogger","pLogger","configure","command","validate","config","read","args"],"mappings":";;;;;;;;;AAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAoDO,MAAMA,MAAAA,GAAS,CAA0BC,QAAAA,GAAAA;AAQ5C,IAAA,MAAMC,QAAAA,GAA2B;AAAE,QAAA,GAAGC,eAAe;AAAE,QAAA,GAAGF,SAASC;AAAS,KAAA;IAC5E,MAAME,QAAAA,GAAWH,QAAAA,CAASG,QAAQ,IAAIC,gBAAAA;IACtC,MAAMC,WAAAA,GAAcL,SAASK,WAAW;IACxC,IAAIC,MAAAA,GAASN,QAAAA,CAASM,MAAM,IAAIC,cAAAA;AAEhC,IAAA,MAAMC,OAAAA,GAAsB;AACxBP,QAAAA,QAAAA;AACAE,QAAAA,QAAAA;AACAE,QAAAA,WAAAA;AACAC,QAAAA;AACJ,KAAA;AAEA,IAAA,MAAMG,YAAY,CAACC,OAAAA,GAAAA;QACfJ,MAAAA,GAASI,OAAAA;AACTF,QAAAA,OAAAA,CAAQF,MAAM,GAAGI,OAAAA;AACrB,KAAA;IAEA,OAAO;AACHD,QAAAA,SAAAA;QACAE,SAAAA,EAAW,CAACC,OAAAA,GAAqBD,SAAAA,CAAUC,OAAAA,EAASJ,OAAAA,CAAAA;QACpDK,QAAAA,EAAU,CAACC,MAAAA,GAA8DD,QAAAA,CAASC,MAAAA,EAAQN,OAAAA,CAAAA;QAC1FO,IAAAA,EAAM,CAACC,IAAAA,GAAeD,IAAAA,CAAKC,IAAAA,EAAMR,OAAAA;AACrC,KAAA;AACJ;;;;"}
1
+ {"version":3,"file":"cardigantime.js","sources":["../src/cardigantime.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { Args, DefaultOptions, Feature, Cardigantime, Logger, Options } from 'types';\nimport { z, ZodObject } from 'zod';\nimport { configure } from './configure';\nimport { DEFAULT_FEATURES, DEFAULT_LOGGER, DEFAULT_OPTIONS } from './constants';\nimport { read } from './read';\nimport { ConfigSchema } from 'types';\nimport { validate } from './validate';\n\nexport * from './types';\nexport { ArgumentError, ConfigurationError, FileSystemError } from './validate';\n\n/**\n * Creates a new Cardigantime instance for configuration management.\n * \n * Cardigantime handles the complete configuration lifecycle including:\n * - Reading configuration from YAML files\n * - Validating configuration against Zod schemas\n * - Merging CLI arguments with file configuration and defaults\n * - Providing type-safe configuration objects\n * \n * @template T - The Zod schema shape type for your configuration\n * @param pOptions - Configuration options for the Cardigantime instance\n * @param pOptions.defaults - Default configuration settings\n * @param pOptions.defaults.configDirectory - Directory to search for configuration files (required)\n * @param pOptions.defaults.configFile - Name of the configuration file (optional, defaults to 'config.yaml')\n * @param pOptions.defaults.isRequired - Whether the config directory must exist (optional, defaults to false)\n * @param pOptions.defaults.encoding - File encoding for reading config files (optional, defaults to 'utf8')\n * @param pOptions.defaults.pathResolution - Configuration for resolving relative paths in config values relative to the config file's directory (optional)\n * @param pOptions.features - Array of features to enable (optional, defaults to ['config'])\n * @param pOptions.configShape - Zod schema shape defining your configuration structure (required)\n * @param pOptions.logger - Custom logger implementation (optional, defaults to console logger)\n * @returns A Cardigantime instance with methods for configure, read, validate, and setLogger\n * \n * @example\n * ```typescript\n * import { create } from '@theunwalked/cardigantime';\n * import { z } from 'zod';\n * \n * const MyConfigSchema = z.object({\n * apiKey: z.string().min(1),\n * timeout: z.number().default(5000),\n * debug: z.boolean().default(false),\n * contextDirectories: z.array(z.string()).optional(),\n * });\n * \n * const cardigantime = create({\n * defaults: {\n * configDirectory: './config',\n * configFile: 'myapp.yaml',\n * // Resolve relative paths in contextDirectories relative to config file location\n * pathResolution: {\n * pathFields: ['contextDirectories'],\n * resolvePathArray: ['contextDirectories']\n * },\n * // Configure how array fields are merged in hierarchical mode\n * fieldOverlaps: {\n * 'features': 'append', // Accumulate features from all levels\n * 'excludePatterns': 'prepend' // Higher precedence patterns come first\n * }\n * },\n * configShape: MyConfigSchema.shape,\n * features: ['config', 'hierarchical'], // Enable hierarchical discovery\n * });\n * \n * // If config file is at ../config/myapp.yaml and contains:\n * // contextDirectories: ['./context', './data']\n * // These paths will be resolved relative to ../config/ directory\n * ```\n */\nexport const create = <T extends z.ZodRawShape>(pOptions: {\n defaults: Pick<DefaultOptions, 'configDirectory'> & Partial<Omit<DefaultOptions, 'configDirectory'>>,\n features?: Feature[],\n configShape: T, // Make configShape mandatory\n logger?: Logger,\n}): Cardigantime<T> => {\n\n\n const defaults: DefaultOptions = { ...DEFAULT_OPTIONS, ...pOptions.defaults } as DefaultOptions;\n const features = pOptions.features || DEFAULT_FEATURES;\n const configShape = pOptions.configShape;\n let logger = pOptions.logger || DEFAULT_LOGGER;\n\n const options: Options<T> = {\n defaults,\n features,\n configShape, // Store the shape\n logger,\n }\n\n const setLogger = (pLogger: Logger) => {\n logger = pLogger;\n options.logger = pLogger;\n }\n\n return {\n setLogger,\n configure: (command: Command) => configure(command, options),\n validate: (config: z.infer<ZodObject<T & typeof ConfigSchema.shape>>) => validate(config, options),\n read: (args: Args) => read(args, options),\n }\n}\n\n\n\n\n\n"],"names":["create","pOptions","defaults","DEFAULT_OPTIONS","features","DEFAULT_FEATURES","configShape","logger","DEFAULT_LOGGER","options","setLogger","pLogger","configure","command","validate","config","read","args"],"mappings":";;;;;;;;;AAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA0DO,MAAMA,MAAAA,GAAS,CAA0BC,QAAAA,GAAAA;AAQ5C,IAAA,MAAMC,QAAAA,GAA2B;AAAE,QAAA,GAAGC,eAAe;AAAE,QAAA,GAAGF,SAASC;AAAS,KAAA;IAC5E,MAAME,QAAAA,GAAWH,QAAAA,CAASG,QAAQ,IAAIC,gBAAAA;IACtC,MAAMC,WAAAA,GAAcL,SAASK,WAAW;IACxC,IAAIC,MAAAA,GAASN,QAAAA,CAASM,MAAM,IAAIC,cAAAA;AAEhC,IAAA,MAAMC,OAAAA,GAAsB;AACxBP,QAAAA,QAAAA;AACAE,QAAAA,QAAAA;AACAE,QAAAA,WAAAA;AACAC,QAAAA;AACJ,KAAA;AAEA,IAAA,MAAMG,YAAY,CAACC,OAAAA,GAAAA;QACfJ,MAAAA,GAASI,OAAAA;AACTF,QAAAA,OAAAA,CAAQF,MAAM,GAAGI,OAAAA;AACrB,KAAA;IAEA,OAAO;AACHD,QAAAA,SAAAA;QACAE,SAAAA,EAAW,CAACC,OAAAA,GAAqBD,SAAAA,CAAUC,OAAAA,EAASJ,OAAAA,CAAAA;QACpDK,QAAAA,EAAU,CAACC,MAAAA,GAA8DD,QAAAA,CAASC,MAAAA,EAAQN,OAAAA,CAAAA;QAC1FO,IAAAA,EAAM,CAACC,IAAAA,GAAeD,IAAAA,CAAKC,IAAAA,EAAMR,OAAAA;AACrC,KAAA;AACJ;;;;"}
package/dist/read.js CHANGED
@@ -182,7 +182,8 @@ import { loadHierarchicalConfig } from './util/hierarchical.js';
182
182
  encoding: options.defaults.encoding,
183
183
  logger,
184
184
  pathFields: (_options_defaults_pathResolution1 = options.defaults.pathResolution) === null || _options_defaults_pathResolution1 === void 0 ? void 0 : _options_defaults_pathResolution1.pathFields,
185
- resolvePathArray: (_options_defaults_pathResolution2 = options.defaults.pathResolution) === null || _options_defaults_pathResolution2 === void 0 ? void 0 : _options_defaults_pathResolution2.resolvePathArray
185
+ resolvePathArray: (_options_defaults_pathResolution2 = options.defaults.pathResolution) === null || _options_defaults_pathResolution2 === void 0 ? void 0 : _options_defaults_pathResolution2.resolvePathArray,
186
+ fieldOverlaps: options.defaults.fieldOverlaps
186
187
  });
187
188
  rawFileConfig = hierarchicalResult.config;
188
189
  if (hierarchicalResult.discoveredDirs.length > 0) {
package/dist/read.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"read.js","sources":["../src/read.ts"],"sourcesContent":["import * as yaml from 'js-yaml';\nimport * as path from 'path';\nimport { z, ZodObject } from 'zod';\nimport { Args, ConfigSchema, Options } from './types';\nimport * as Storage from './util/storage';\nimport { loadHierarchicalConfig } from './util/hierarchical';\n\n/**\n * Removes undefined values from an object to create a clean configuration.\n * This is used to merge configuration sources while avoiding undefined pollution.\n * \n * @param obj - The object to clean\n * @returns A new object with undefined values filtered out\n */\nfunction clean(obj: any) {\n return Object.fromEntries(\n Object.entries(obj).filter(([_, v]) => v !== undefined)\n );\n}\n\n/**\n * Resolves relative paths in configuration values relative to the configuration file's directory.\n * \n * @param config - The configuration object to process\n * @param configDir - The directory containing the configuration file\n * @param pathFields - Array of field names (using dot notation) that contain paths to be resolved\n * @param resolvePathArray - Array of field names whose array elements should all be resolved as paths\n * @returns The configuration object with resolved paths\n */\nfunction resolveConfigPaths(\n config: any,\n configDir: string,\n pathFields: string[] = [],\n resolvePathArray: string[] = []\n): any {\n if (!config || typeof config !== 'object' || pathFields.length === 0) {\n return config;\n }\n\n const resolvedConfig = { ...config };\n\n for (const fieldPath of pathFields) {\n const value = getNestedValue(resolvedConfig, fieldPath);\n if (value !== undefined) {\n const shouldResolveArrayElements = resolvePathArray.includes(fieldPath);\n const resolvedValue = resolvePathValue(value, configDir, shouldResolveArrayElements);\n setNestedValue(resolvedConfig, fieldPath, resolvedValue);\n }\n }\n\n return resolvedConfig;\n}\n\n/**\n * Gets a nested value from an object using dot notation.\n */\nfunction getNestedValue(obj: any, path: string): any {\n return path.split('.').reduce((current, key) => current?.[key], obj);\n}\n\n/**\n * Sets a nested value in an object using dot notation.\n */\nfunction setNestedValue(obj: any, path: string, value: any): void {\n const keys = path.split('.');\n const lastKey = keys.pop()!;\n const target = keys.reduce((current, key) => {\n if (!(key in current)) {\n current[key] = {};\n }\n return current[key];\n }, obj);\n target[lastKey] = value;\n}\n\n/**\n * Resolves a path value (string or array of strings) relative to the config directory.\n */\nfunction resolvePathValue(value: any, configDir: string, resolveArrayElements: boolean): any {\n if (typeof value === 'string') {\n return resolveSinglePath(value, configDir);\n }\n\n if (Array.isArray(value) && resolveArrayElements) {\n return value.map(item =>\n typeof item === 'string' ? resolveSinglePath(item, configDir) : item\n );\n }\n\n return value;\n}\n\n/**\n * Resolves a single path string relative to the config directory if it's a relative path.\n */\nfunction resolveSinglePath(pathStr: string, configDir: string): string {\n if (!pathStr || path.isAbsolute(pathStr)) {\n return pathStr;\n }\n\n return path.resolve(configDir, pathStr);\n}\n\n/**\n * Validates and secures a user-provided path to prevent path traversal attacks.\n * \n * Security checks include:\n * - Path traversal prevention (blocks '..')\n * - Absolute path detection\n * - Path separator validation\n * \n * @param userPath - The user-provided path component\n * @param basePath - The base directory to join the path with\n * @returns The safely joined and normalized path\n * @throws {Error} When path traversal or absolute paths are detected\n */\nfunction validatePath(userPath: string, basePath: string): string {\n if (!userPath || !basePath) {\n throw new Error('Invalid path parameters');\n }\n\n const normalized = path.normalize(userPath);\n\n // Prevent path traversal attacks\n if (normalized.includes('..') || path.isAbsolute(normalized)) {\n throw new Error('Invalid path: path traversal detected');\n }\n\n // Ensure the path doesn't start with a path separator\n if (normalized.startsWith('/') || normalized.startsWith('\\\\')) {\n throw new Error('Invalid path: absolute path detected');\n }\n\n return path.join(basePath, normalized);\n}\n\n/**\n * Validates a configuration directory path for security and basic formatting.\n * \n * Performs validation to prevent:\n * - Null byte injection attacks\n * - Extremely long paths that could cause DoS\n * - Empty or invalid directory specifications\n * \n * @param configDir - The configuration directory path to validate\n * @returns The normalized configuration directory path\n * @throws {Error} When the directory path is invalid or potentially dangerous\n */\nfunction validateConfigDirectory(configDir: string): string {\n if (!configDir) {\n throw new Error('Configuration directory is required');\n }\n\n // Check for null bytes which could be used for path injection\n if (configDir.includes('\\0')) {\n throw new Error('Invalid path: null byte detected');\n }\n\n const normalized = path.normalize(configDir);\n\n // Basic validation - could be expanded based on requirements\n if (normalized.length > 1000) {\n throw new Error('Configuration directory path too long');\n }\n\n return normalized;\n}\n\n/**\n * Reads configuration from files and merges it with CLI arguments.\n * \n * This function implements the core configuration loading logic:\n * 1. Validates and resolves the configuration directory path\n * 2. Attempts to read the YAML configuration file\n * 3. Safely parses the YAML content with security protections\n * 4. Merges file configuration with runtime arguments\n * 5. Returns a typed configuration object\n * \n * The function handles missing files gracefully and provides detailed\n * logging for troubleshooting configuration issues.\n * \n * @template T - The Zod schema shape type for configuration validation\n * @param args - Parsed command-line arguments containing potential config overrides\n * @param options - Cardigantime options with defaults, schema, and logger\n * @returns Promise resolving to the merged and typed configuration object\n * @throws {Error} When configuration directory is invalid or required files cannot be read\n * \n * @example\n * ```typescript\n * const config = await read(cliArgs, {\n * defaults: { configDirectory: './config', configFile: 'app.yaml' },\n * configShape: MySchema.shape,\n * logger: console,\n * features: ['config']\n * });\n * // config is fully typed based on your schema\n * ```\n */\nexport const read = async <T extends z.ZodRawShape>(args: Args, options: Options<T>): Promise<z.infer<ZodObject<T & typeof ConfigSchema.shape>>> => {\n const logger = options.logger;\n\n const rawConfigDir = args.configDirectory || options.defaults?.configDirectory;\n if (!rawConfigDir) {\n throw new Error('Configuration directory must be specified');\n }\n\n const resolvedConfigDir = validateConfigDirectory(rawConfigDir);\n logger.verbose('Resolved config directory');\n\n let rawFileConfig: object = {};\n\n // Check if hierarchical configuration discovery is enabled\n if (options.features.includes('hierarchical')) {\n logger.verbose('Hierarchical configuration discovery enabled');\n\n try {\n // Extract the config directory name from the path for hierarchical discovery\n const configDirName = path.basename(resolvedConfigDir);\n const startingDir = path.dirname(resolvedConfigDir);\n\n logger.debug(`Using hierarchical discovery: configDirName=${configDirName}, startingDir=${startingDir}`);\n\n const hierarchicalResult = await loadHierarchicalConfig({\n configDirName,\n configFileName: options.defaults.configFile,\n startingDir,\n encoding: options.defaults.encoding,\n logger,\n pathFields: options.defaults.pathResolution?.pathFields,\n resolvePathArray: options.defaults.pathResolution?.resolvePathArray\n });\n\n rawFileConfig = hierarchicalResult.config;\n\n if (hierarchicalResult.discoveredDirs.length > 0) {\n logger.verbose(`Hierarchical discovery found ${hierarchicalResult.discoveredDirs.length} configuration directories`);\n hierarchicalResult.discoveredDirs.forEach(dir => {\n logger.debug(` Level ${dir.level}: ${dir.path}`);\n });\n } else {\n logger.verbose('No configuration directories found in hierarchy');\n }\n\n if (hierarchicalResult.errors.length > 0) {\n hierarchicalResult.errors.forEach(error => logger.warn(`Hierarchical config warning: ${error}`));\n }\n\n } catch (error: any) {\n logger.error('Hierarchical configuration loading failed: ' + (error.message || 'Unknown error'));\n // Fall back to single directory mode\n logger.verbose('Falling back to single directory configuration loading');\n rawFileConfig = await loadSingleDirectoryConfig(resolvedConfigDir, options, logger);\n }\n } else {\n // Use traditional single directory configuration loading\n logger.verbose('Using single directory configuration loading');\n rawFileConfig = await loadSingleDirectoryConfig(resolvedConfigDir, options, logger);\n }\n\n // Apply path resolution if configured\n let processedConfig = rawFileConfig;\n if (options.defaults.pathResolution?.pathFields) {\n processedConfig = resolveConfigPaths(\n rawFileConfig,\n resolvedConfigDir,\n options.defaults.pathResolution.pathFields,\n options.defaults.pathResolution.resolvePathArray || []\n );\n }\n\n const config: z.infer<ZodObject<T & typeof ConfigSchema.shape>> = clean({\n ...processedConfig,\n ...{\n configDirectory: resolvedConfigDir,\n }\n }) as z.infer<ZodObject<T & typeof ConfigSchema.shape>>;\n\n return config;\n}\n\n/**\n * Loads configuration from a single directory (traditional mode).\n * \n * @param resolvedConfigDir - The resolved configuration directory path\n * @param options - Cardigantime options\n * @param logger - Logger instance\n * @returns Promise resolving to the configuration object\n */\nasync function loadSingleDirectoryConfig<T extends z.ZodRawShape>(\n resolvedConfigDir: string,\n options: Options<T>,\n logger: any\n): Promise<object> {\n const storage = Storage.create({ log: logger.debug });\n const configFile = validatePath(options.defaults.configFile, resolvedConfigDir);\n logger.verbose('Attempting to load config file for cardigantime');\n\n let rawFileConfig: object = {};\n\n try {\n const yamlContent = await storage.readFile(configFile, options.defaults.encoding);\n\n // SECURITY FIX: Use safer parsing options to prevent code execution vulnerabilities\n const parsedYaml = yaml.load(yamlContent);\n\n if (parsedYaml !== null && typeof parsedYaml === 'object') {\n rawFileConfig = parsedYaml;\n logger.verbose('Loaded configuration file successfully');\n } else if (parsedYaml !== null) {\n logger.warn('Ignoring invalid configuration format. Expected an object, got ' + typeof parsedYaml);\n }\n } catch (error: any) {\n if (error.code === 'ENOENT' || /not found|no such file/i.test(error.message)) {\n logger.verbose('Configuration file not found. Using empty configuration.');\n } else {\n // SECURITY FIX: Don't expose internal paths or detailed error information\n logger.error('Failed to load or parse configuration file: ' + (error.message || 'Unknown error'));\n }\n }\n\n return rawFileConfig;\n}"],"names":["clean","obj","Object","fromEntries","entries","filter","_","v","undefined","resolveConfigPaths","config","configDir","pathFields","resolvePathArray","length","resolvedConfig","fieldPath","value","getNestedValue","shouldResolveArrayElements","includes","resolvedValue","resolvePathValue","setNestedValue","path","split","reduce","current","key","keys","lastKey","pop","target","resolveArrayElements","resolveSinglePath","Array","isArray","map","item","pathStr","isAbsolute","resolve","validatePath","userPath","basePath","Error","normalized","normalize","startsWith","join","validateConfigDirectory","read","args","options","logger","rawConfigDir","configDirectory","defaults","resolvedConfigDir","verbose","rawFileConfig","features","configDirName","basename","startingDir","dirname","debug","hierarchicalResult","loadHierarchicalConfig","configFileName","configFile","encoding","pathResolution","discoveredDirs","forEach","dir","level","errors","error","warn","message","loadSingleDirectoryConfig","processedConfig","storage","Storage","log","yamlContent","readFile","parsedYaml","yaml","load","code","test"],"mappings":"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"}
1
+ {"version":3,"file":"read.js","sources":["../src/read.ts"],"sourcesContent":["import * as yaml from 'js-yaml';\nimport * as path from 'path';\nimport { z, ZodObject } from 'zod';\nimport { Args, ConfigSchema, Options } from './types';\nimport * as Storage from './util/storage';\nimport { loadHierarchicalConfig } from './util/hierarchical';\n\n/**\n * Removes undefined values from an object to create a clean configuration.\n * This is used to merge configuration sources while avoiding undefined pollution.\n * \n * @param obj - The object to clean\n * @returns A new object with undefined values filtered out\n */\nfunction clean(obj: any) {\n return Object.fromEntries(\n Object.entries(obj).filter(([_, v]) => v !== undefined)\n );\n}\n\n/**\n * Resolves relative paths in configuration values relative to the configuration file's directory.\n * \n * @param config - The configuration object to process\n * @param configDir - The directory containing the configuration file\n * @param pathFields - Array of field names (using dot notation) that contain paths to be resolved\n * @param resolvePathArray - Array of field names whose array elements should all be resolved as paths\n * @returns The configuration object with resolved paths\n */\nfunction resolveConfigPaths(\n config: any,\n configDir: string,\n pathFields: string[] = [],\n resolvePathArray: string[] = []\n): any {\n if (!config || typeof config !== 'object' || pathFields.length === 0) {\n return config;\n }\n\n const resolvedConfig = { ...config };\n\n for (const fieldPath of pathFields) {\n const value = getNestedValue(resolvedConfig, fieldPath);\n if (value !== undefined) {\n const shouldResolveArrayElements = resolvePathArray.includes(fieldPath);\n const resolvedValue = resolvePathValue(value, configDir, shouldResolveArrayElements);\n setNestedValue(resolvedConfig, fieldPath, resolvedValue);\n }\n }\n\n return resolvedConfig;\n}\n\n/**\n * Gets a nested value from an object using dot notation.\n */\nfunction getNestedValue(obj: any, path: string): any {\n return path.split('.').reduce((current, key) => current?.[key], obj);\n}\n\n/**\n * Sets a nested value in an object using dot notation.\n */\nfunction setNestedValue(obj: any, path: string, value: any): void {\n const keys = path.split('.');\n const lastKey = keys.pop()!;\n const target = keys.reduce((current, key) => {\n if (!(key in current)) {\n current[key] = {};\n }\n return current[key];\n }, obj);\n target[lastKey] = value;\n}\n\n/**\n * Resolves a path value (string or array of strings) relative to the config directory.\n */\nfunction resolvePathValue(value: any, configDir: string, resolveArrayElements: boolean): any {\n if (typeof value === 'string') {\n return resolveSinglePath(value, configDir);\n }\n\n if (Array.isArray(value) && resolveArrayElements) {\n return value.map(item =>\n typeof item === 'string' ? resolveSinglePath(item, configDir) : item\n );\n }\n\n return value;\n}\n\n/**\n * Resolves a single path string relative to the config directory if it's a relative path.\n */\nfunction resolveSinglePath(pathStr: string, configDir: string): string {\n if (!pathStr || path.isAbsolute(pathStr)) {\n return pathStr;\n }\n\n return path.resolve(configDir, pathStr);\n}\n\n/**\n * Validates and secures a user-provided path to prevent path traversal attacks.\n * \n * Security checks include:\n * - Path traversal prevention (blocks '..')\n * - Absolute path detection\n * - Path separator validation\n * \n * @param userPath - The user-provided path component\n * @param basePath - The base directory to join the path with\n * @returns The safely joined and normalized path\n * @throws {Error} When path traversal or absolute paths are detected\n */\nfunction validatePath(userPath: string, basePath: string): string {\n if (!userPath || !basePath) {\n throw new Error('Invalid path parameters');\n }\n\n const normalized = path.normalize(userPath);\n\n // Prevent path traversal attacks\n if (normalized.includes('..') || path.isAbsolute(normalized)) {\n throw new Error('Invalid path: path traversal detected');\n }\n\n // Ensure the path doesn't start with a path separator\n if (normalized.startsWith('/') || normalized.startsWith('\\\\')) {\n throw new Error('Invalid path: absolute path detected');\n }\n\n return path.join(basePath, normalized);\n}\n\n/**\n * Validates a configuration directory path for security and basic formatting.\n * \n * Performs validation to prevent:\n * - Null byte injection attacks\n * - Extremely long paths that could cause DoS\n * - Empty or invalid directory specifications\n * \n * @param configDir - The configuration directory path to validate\n * @returns The normalized configuration directory path\n * @throws {Error} When the directory path is invalid or potentially dangerous\n */\nfunction validateConfigDirectory(configDir: string): string {\n if (!configDir) {\n throw new Error('Configuration directory is required');\n }\n\n // Check for null bytes which could be used for path injection\n if (configDir.includes('\\0')) {\n throw new Error('Invalid path: null byte detected');\n }\n\n const normalized = path.normalize(configDir);\n\n // Basic validation - could be expanded based on requirements\n if (normalized.length > 1000) {\n throw new Error('Configuration directory path too long');\n }\n\n return normalized;\n}\n\n/**\n * Reads configuration from files and merges it with CLI arguments.\n * \n * This function implements the core configuration loading logic:\n * 1. Validates and resolves the configuration directory path\n * 2. Attempts to read the YAML configuration file\n * 3. Safely parses the YAML content with security protections\n * 4. Merges file configuration with runtime arguments\n * 5. Returns a typed configuration object\n * \n * The function handles missing files gracefully and provides detailed\n * logging for troubleshooting configuration issues.\n * \n * @template T - The Zod schema shape type for configuration validation\n * @param args - Parsed command-line arguments containing potential config overrides\n * @param options - Cardigantime options with defaults, schema, and logger\n * @returns Promise resolving to the merged and typed configuration object\n * @throws {Error} When configuration directory is invalid or required files cannot be read\n * \n * @example\n * ```typescript\n * const config = await read(cliArgs, {\n * defaults: { configDirectory: './config', configFile: 'app.yaml' },\n * configShape: MySchema.shape,\n * logger: console,\n * features: ['config']\n * });\n * // config is fully typed based on your schema\n * ```\n */\nexport const read = async <T extends z.ZodRawShape>(args: Args, options: Options<T>): Promise<z.infer<ZodObject<T & typeof ConfigSchema.shape>>> => {\n const logger = options.logger;\n\n const rawConfigDir = args.configDirectory || options.defaults?.configDirectory;\n if (!rawConfigDir) {\n throw new Error('Configuration directory must be specified');\n }\n\n const resolvedConfigDir = validateConfigDirectory(rawConfigDir);\n logger.verbose('Resolved config directory');\n\n let rawFileConfig: object = {};\n\n // Check if hierarchical configuration discovery is enabled\n if (options.features.includes('hierarchical')) {\n logger.verbose('Hierarchical configuration discovery enabled');\n\n try {\n // Extract the config directory name from the path for hierarchical discovery\n const configDirName = path.basename(resolvedConfigDir);\n const startingDir = path.dirname(resolvedConfigDir);\n\n logger.debug(`Using hierarchical discovery: configDirName=${configDirName}, startingDir=${startingDir}`);\n\n const hierarchicalResult = await loadHierarchicalConfig({\n configDirName,\n configFileName: options.defaults.configFile,\n startingDir,\n encoding: options.defaults.encoding,\n logger,\n pathFields: options.defaults.pathResolution?.pathFields,\n resolvePathArray: options.defaults.pathResolution?.resolvePathArray,\n fieldOverlaps: options.defaults.fieldOverlaps\n });\n\n rawFileConfig = hierarchicalResult.config;\n\n if (hierarchicalResult.discoveredDirs.length > 0) {\n logger.verbose(`Hierarchical discovery found ${hierarchicalResult.discoveredDirs.length} configuration directories`);\n hierarchicalResult.discoveredDirs.forEach(dir => {\n logger.debug(` Level ${dir.level}: ${dir.path}`);\n });\n } else {\n logger.verbose('No configuration directories found in hierarchy');\n }\n\n if (hierarchicalResult.errors.length > 0) {\n hierarchicalResult.errors.forEach(error => logger.warn(`Hierarchical config warning: ${error}`));\n }\n\n } catch (error: any) {\n logger.error('Hierarchical configuration loading failed: ' + (error.message || 'Unknown error'));\n // Fall back to single directory mode\n logger.verbose('Falling back to single directory configuration loading');\n rawFileConfig = await loadSingleDirectoryConfig(resolvedConfigDir, options, logger);\n }\n } else {\n // Use traditional single directory configuration loading\n logger.verbose('Using single directory configuration loading');\n rawFileConfig = await loadSingleDirectoryConfig(resolvedConfigDir, options, logger);\n }\n\n // Apply path resolution if configured\n let processedConfig = rawFileConfig;\n if (options.defaults.pathResolution?.pathFields) {\n processedConfig = resolveConfigPaths(\n rawFileConfig,\n resolvedConfigDir,\n options.defaults.pathResolution.pathFields,\n options.defaults.pathResolution.resolvePathArray || []\n );\n }\n\n const config: z.infer<ZodObject<T & typeof ConfigSchema.shape>> = clean({\n ...processedConfig,\n ...{\n configDirectory: resolvedConfigDir,\n }\n }) as z.infer<ZodObject<T & typeof ConfigSchema.shape>>;\n\n return config;\n}\n\n/**\n * Loads configuration from a single directory (traditional mode).\n * \n * @param resolvedConfigDir - The resolved configuration directory path\n * @param options - Cardigantime options\n * @param logger - Logger instance\n * @returns Promise resolving to the configuration object\n */\nasync function loadSingleDirectoryConfig<T extends z.ZodRawShape>(\n resolvedConfigDir: string,\n options: Options<T>,\n logger: any\n): Promise<object> {\n const storage = Storage.create({ log: logger.debug });\n const configFile = validatePath(options.defaults.configFile, resolvedConfigDir);\n logger.verbose('Attempting to load config file for cardigantime');\n\n let rawFileConfig: object = {};\n\n try {\n const yamlContent = await storage.readFile(configFile, options.defaults.encoding);\n\n // SECURITY FIX: Use safer parsing options to prevent code execution vulnerabilities\n const parsedYaml = yaml.load(yamlContent);\n\n if (parsedYaml !== null && typeof parsedYaml === 'object') {\n rawFileConfig = parsedYaml;\n logger.verbose('Loaded configuration file successfully');\n } else if (parsedYaml !== null) {\n logger.warn('Ignoring invalid configuration format. Expected an object, got ' + typeof parsedYaml);\n }\n } catch (error: any) {\n if (error.code === 'ENOENT' || /not found|no such file/i.test(error.message)) {\n logger.verbose('Configuration file not found. Using empty configuration.');\n } else {\n // SECURITY FIX: Don't expose internal paths or detailed error information\n logger.error('Failed to load or parse configuration file: ' + (error.message || 'Unknown error'));\n }\n }\n\n return rawFileConfig;\n}"],"names":["clean","obj","Object","fromEntries","entries","filter","_","v","undefined","resolveConfigPaths","config","configDir","pathFields","resolvePathArray","length","resolvedConfig","fieldPath","value","getNestedValue","shouldResolveArrayElements","includes","resolvedValue","resolvePathValue","setNestedValue","path","split","reduce","current","key","keys","lastKey","pop","target","resolveArrayElements","resolveSinglePath","Array","isArray","map","item","pathStr","isAbsolute","resolve","validatePath","userPath","basePath","Error","normalized","normalize","startsWith","join","validateConfigDirectory","read","args","options","logger","rawConfigDir","configDirectory","defaults","resolvedConfigDir","verbose","rawFileConfig","features","configDirName","basename","startingDir","dirname","debug","hierarchicalResult","loadHierarchicalConfig","configFileName","configFile","encoding","pathResolution","fieldOverlaps","discoveredDirs","forEach","dir","level","errors","error","warn","message","loadSingleDirectoryConfig","processedConfig","storage","Storage","log","yamlContent","readFile","parsedYaml","yaml","load","code","test"],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -7,6 +7,30 @@ import { ZodObject, z } from 'zod';
7
7
  * - 'hierarchical': Hierarchical configuration discovery and layering
8
8
  */
9
9
  export type Feature = 'config' | 'hierarchical';
10
+ /**
11
+ * Defines how array fields should be merged in hierarchical configurations.
12
+ *
13
+ * - 'override': Higher precedence arrays completely replace lower precedence arrays (default)
14
+ * - 'append': Higher precedence array elements are appended to lower precedence arrays
15
+ * - 'prepend': Higher precedence array elements are prepended to lower precedence arrays
16
+ */
17
+ export type ArrayOverlapMode = 'override' | 'append' | 'prepend';
18
+ /**
19
+ * Configuration for how fields should be merged in hierarchical configurations.
20
+ * Maps field names (using dot notation) to their overlap behavior.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const fieldOverlaps: FieldOverlapOptions = {
25
+ * 'features': 'append', // features arrays will be combined by appending
26
+ * 'api.endpoints': 'prepend', // nested endpoint arrays will be combined by prepending
27
+ * 'excludePatterns': 'override' // excludePatterns arrays will replace each other (default behavior)
28
+ * };
29
+ * ```
30
+ */
31
+ export interface FieldOverlapOptions {
32
+ [fieldPath: string]: ArrayOverlapMode;
33
+ }
10
34
  /**
11
35
  * Configuration for resolving relative paths in configuration values.
12
36
  * Paths specified in these fields will be resolved relative to the configuration file's directory.
@@ -32,6 +56,12 @@ export interface DefaultOptions {
32
56
  encoding: string;
33
57
  /** Configuration for resolving relative paths in configuration values */
34
58
  pathResolution?: PathResolutionOptions;
59
+ /**
60
+ * Configuration for how array fields should be merged in hierarchical mode.
61
+ * Only applies when the 'hierarchical' feature is enabled.
62
+ * If not specified, all arrays use 'override' behavior (default).
63
+ */
64
+ fieldOverlaps?: FieldOverlapOptions;
35
65
  }
36
66
  /**
37
67
  * Complete options object passed to Cardigantime functions.
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sources":["../src/types.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { ZodObject } from \"zod\";\n\nimport { z } from \"zod\";\n\n/**\n * Available features that can be enabled in Cardigantime.\n * Currently supports:\n * - 'config': Configuration file reading and validation\n * - 'hierarchical': Hierarchical configuration discovery and layering\n */\nexport type Feature = 'config' | 'hierarchical';\n\n/**\n * Configuration for resolving relative paths in configuration values.\n * Paths specified in these fields will be resolved relative to the configuration file's directory.\n */\nexport interface PathResolutionOptions {\n /** Array of field names (using dot notation) that contain paths to be resolved */\n pathFields?: string[];\n /** Array of field names whose array elements should all be resolved as paths */\n resolvePathArray?: string[];\n}\n\n/**\n * Default configuration options for Cardigantime.\n * These define the basic behavior of configuration loading.\n */\nexport interface DefaultOptions {\n /** Directory path where configuration files are located */\n configDirectory: string;\n /** Name of the configuration file (e.g., 'config.yaml', 'app.yml') */\n configFile: string;\n /** Whether the configuration directory must exist. If true, throws error if directory doesn't exist */\n isRequired: boolean;\n /** File encoding for reading configuration files (e.g., 'utf8', 'ascii') */\n encoding: string;\n /** Configuration for resolving relative paths in configuration values */\n pathResolution?: PathResolutionOptions;\n}\n\n/**\n * Complete options object passed to Cardigantime functions.\n * Combines defaults, features, schema shape, and logger.\n * \n * @template T - The Zod schema shape type for configuration validation\n */\nexport interface Options<T extends z.ZodRawShape> {\n /** Default configuration options */\n defaults: DefaultOptions,\n /** Array of enabled features */\n features: Feature[],\n /** Zod schema shape for validating user configuration */\n configShape: T;\n /** Logger instance for debugging and error reporting */\n logger: Logger;\n}\n\n/**\n * Logger interface for Cardigantime's internal logging.\n * Compatible with popular logging libraries like Winston, Bunyan, etc.\n */\nexport interface Logger {\n /** Debug-level logging for detailed troubleshooting information */\n debug: (message: string, ...args: any[]) => void;\n /** Info-level logging for general information */\n info: (message: string, ...args: any[]) => void;\n /** Warning-level logging for non-critical issues */\n warn: (message: string, ...args: any[]) => void;\n /** Error-level logging for critical problems */\n error: (message: string, ...args: any[]) => void;\n /** Verbose-level logging for extensive detail */\n verbose: (message: string, ...args: any[]) => void;\n /** Silly-level logging for maximum detail */\n silly: (message: string, ...args: any[]) => void;\n}\n\n/**\n * Main Cardigantime interface providing configuration management functionality.\n * \n * @template T - The Zod schema shape type for configuration validation\n */\nexport interface Cardigantime<T extends z.ZodRawShape> {\n /** \n * Adds Cardigantime's CLI options to a Commander.js command.\n * This includes options like --config-directory for runtime config path overrides.\n */\n configure: (command: Command) => Promise<Command>;\n /** Sets a custom logger for debugging and error reporting */\n setLogger: (logger: Logger) => void;\n /** \n * Reads configuration from files and merges with CLI arguments.\n * Returns a fully typed configuration object.\n */\n read: (args: Args) => Promise<z.infer<ZodObject<T & typeof ConfigSchema.shape>>>;\n /** \n * Validates the merged configuration against the Zod schema.\n * Throws ConfigurationError if validation fails.\n */\n validate: (config: z.infer<ZodObject<T & typeof ConfigSchema.shape>>) => Promise<void>;\n}\n\n/**\n * Parsed command-line arguments object, typically from Commander.js opts().\n * Keys correspond to CLI option names with values from user input.\n */\nexport interface Args {\n [key: string]: any;\n}\n\n/**\n * Base Zod schema for core Cardigantime configuration.\n * Contains the minimum required configuration fields.\n */\nexport const ConfigSchema = z.object({\n /** The resolved configuration directory path */\n configDirectory: z.string(),\n});\n\n/**\n * Base configuration type derived from the core schema.\n */\nexport type Config = z.infer<typeof ConfigSchema>;\n"],"names":["ConfigSchema","z","object","configDirectory","string"],"mappings":";;AA8GA;;;AAGC,IACM,MAAMA,YAAAA,GAAeC,CAAAA,CAAEC,MAAM,CAAC;qDAEjCC,eAAAA,EAAiBF,CAAAA,CAAEG,MAAM;AAC7B,CAAA;;;;"}
1
+ {"version":3,"file":"types.js","sources":["../src/types.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { ZodObject } from \"zod\";\n\nimport { z } from \"zod\";\n\n/**\n * Available features that can be enabled in Cardigantime.\n * Currently supports:\n * - 'config': Configuration file reading and validation\n * - 'hierarchical': Hierarchical configuration discovery and layering\n */\nexport type Feature = 'config' | 'hierarchical';\n\n/**\n * Defines how array fields should be merged in hierarchical configurations.\n * \n * - 'override': Higher precedence arrays completely replace lower precedence arrays (default)\n * - 'append': Higher precedence array elements are appended to lower precedence arrays\n * - 'prepend': Higher precedence array elements are prepended to lower precedence arrays\n */\nexport type ArrayOverlapMode = 'override' | 'append' | 'prepend';\n\n/**\n * Configuration for how fields should be merged in hierarchical configurations.\n * Maps field names (using dot notation) to their overlap behavior.\n * \n * @example\n * ```typescript\n * const fieldOverlaps: FieldOverlapOptions = {\n * 'features': 'append', // features arrays will be combined by appending\n * 'api.endpoints': 'prepend', // nested endpoint arrays will be combined by prepending\n * 'excludePatterns': 'override' // excludePatterns arrays will replace each other (default behavior)\n * };\n * ```\n */\nexport interface FieldOverlapOptions {\n [fieldPath: string]: ArrayOverlapMode;\n}\n\n/**\n * Configuration for resolving relative paths in configuration values.\n * Paths specified in these fields will be resolved relative to the configuration file's directory.\n */\nexport interface PathResolutionOptions {\n /** Array of field names (using dot notation) that contain paths to be resolved */\n pathFields?: string[];\n /** Array of field names whose array elements should all be resolved as paths */\n resolvePathArray?: string[];\n}\n\n/**\n * Default configuration options for Cardigantime.\n * These define the basic behavior of configuration loading.\n */\nexport interface DefaultOptions {\n /** Directory path where configuration files are located */\n configDirectory: string;\n /** Name of the configuration file (e.g., 'config.yaml', 'app.yml') */\n configFile: string;\n /** Whether the configuration directory must exist. If true, throws error if directory doesn't exist */\n isRequired: boolean;\n /** File encoding for reading configuration files (e.g., 'utf8', 'ascii') */\n encoding: string;\n /** Configuration for resolving relative paths in configuration values */\n pathResolution?: PathResolutionOptions;\n /** \n * Configuration for how array fields should be merged in hierarchical mode.\n * Only applies when the 'hierarchical' feature is enabled.\n * If not specified, all arrays use 'override' behavior (default).\n */\n fieldOverlaps?: FieldOverlapOptions;\n}\n\n/**\n * Complete options object passed to Cardigantime functions.\n * Combines defaults, features, schema shape, and logger.\n * \n * @template T - The Zod schema shape type for configuration validation\n */\nexport interface Options<T extends z.ZodRawShape> {\n /** Default configuration options */\n defaults: DefaultOptions,\n /** Array of enabled features */\n features: Feature[],\n /** Zod schema shape for validating user configuration */\n configShape: T;\n /** Logger instance for debugging and error reporting */\n logger: Logger;\n}\n\n/**\n * Logger interface for Cardigantime's internal logging.\n * Compatible with popular logging libraries like Winston, Bunyan, etc.\n */\nexport interface Logger {\n /** Debug-level logging for detailed troubleshooting information */\n debug: (message: string, ...args: any[]) => void;\n /** Info-level logging for general information */\n info: (message: string, ...args: any[]) => void;\n /** Warning-level logging for non-critical issues */\n warn: (message: string, ...args: any[]) => void;\n /** Error-level logging for critical problems */\n error: (message: string, ...args: any[]) => void;\n /** Verbose-level logging for extensive detail */\n verbose: (message: string, ...args: any[]) => void;\n /** Silly-level logging for maximum detail */\n silly: (message: string, ...args: any[]) => void;\n}\n\n/**\n * Main Cardigantime interface providing configuration management functionality.\n * \n * @template T - The Zod schema shape type for configuration validation\n */\nexport interface Cardigantime<T extends z.ZodRawShape> {\n /** \n * Adds Cardigantime's CLI options to a Commander.js command.\n * This includes options like --config-directory for runtime config path overrides.\n */\n configure: (command: Command) => Promise<Command>;\n /** Sets a custom logger for debugging and error reporting */\n setLogger: (logger: Logger) => void;\n /** \n * Reads configuration from files and merges with CLI arguments.\n * Returns a fully typed configuration object.\n */\n read: (args: Args) => Promise<z.infer<ZodObject<T & typeof ConfigSchema.shape>>>;\n /** \n * Validates the merged configuration against the Zod schema.\n * Throws ConfigurationError if validation fails.\n */\n validate: (config: z.infer<ZodObject<T & typeof ConfigSchema.shape>>) => Promise<void>;\n}\n\n/**\n * Parsed command-line arguments object, typically from Commander.js opts().\n * Keys correspond to CLI option names with values from user input.\n */\nexport interface Args {\n [key: string]: any;\n}\n\n/**\n * Base Zod schema for core Cardigantime configuration.\n * Contains the minimum required configuration fields.\n */\nexport const ConfigSchema = z.object({\n /** The resolved configuration directory path */\n configDirectory: z.string(),\n});\n\n/**\n * Base configuration type derived from the core schema.\n */\nexport type Config = z.infer<typeof ConfigSchema>;\n"],"names":["ConfigSchema","z","object","configDirectory","string"],"mappings":";;AA8IA;;;AAGC,IACM,MAAMA,YAAAA,GAAeC,CAAAA,CAAEC,MAAM,CAAC;qDAEjCC,eAAAA,EAAiBF,CAAAA,CAAEG,MAAM;AAC7B,CAAA;;;;"}
@@ -1,4 +1,4 @@
1
- import { Logger } from '../types';
1
+ import { Logger, FieldOverlapOptions } from '../types';
2
2
  /**
3
3
  * Represents a discovered configuration directory with its path and precedence level.
4
4
  */
@@ -28,6 +28,8 @@ export interface HierarchicalDiscoveryOptions {
28
28
  pathFields?: string[];
29
29
  /** Array of field names whose array elements should all be resolved as paths */
30
30
  resolvePathArray?: string[];
31
+ /** Configuration for how array fields should be merged in hierarchical mode */
32
+ fieldOverlaps?: FieldOverlapOptions;
31
33
  }
32
34
  /**
33
35
  * Result of loading configurations from multiple directories.
@@ -78,25 +80,27 @@ export declare function discoverConfigDirectories(options: HierarchicalDiscovery
78
80
  */
79
81
  export declare function loadConfigFromDirectory(configDir: string, configFileName: string, encoding?: string, logger?: Logger, pathFields?: string[], resolvePathArray?: string[]): Promise<object | null>;
80
82
  /**
81
- * Deep merges multiple configuration objects with proper precedence.
83
+ * Deep merges multiple configuration objects with proper precedence and configurable array overlap behavior.
82
84
  *
83
85
  * Objects are merged from lowest precedence to highest precedence,
84
86
  * meaning that properties in later objects override properties in earlier objects.
85
- * Arrays are replaced entirely (not merged).
87
+ * Arrays can be merged using different strategies based on the fieldOverlaps configuration.
86
88
  *
87
89
  * @param configs Array of configuration objects, ordered from lowest to highest precedence
90
+ * @param fieldOverlaps Configuration for how array fields should be merged (optional)
88
91
  * @returns Merged configuration object
89
92
  *
90
93
  * @example
91
94
  * ```typescript
92
95
  * const merged = deepMergeConfigs([
93
- * { api: { timeout: 5000 }, debug: true }, // Lower precedence
94
- * { api: { retries: 3 }, features: ['auth'] }, // Higher precedence
95
- * ]);
96
- * // Result: { api: { timeout: 5000, retries: 3 }, debug: true, features: ['auth'] }
96
+ * { api: { timeout: 5000 }, features: ['auth'] }, // Lower precedence
97
+ * { api: { retries: 3 }, features: ['analytics'] }, // Higher precedence
98
+ * ], {
99
+ * 'features': 'append' // Results in features: ['auth', 'analytics']
100
+ * });
97
101
  * ```
98
102
  */
99
- export declare function deepMergeConfigs(configs: object[]): object;
103
+ export declare function deepMergeConfigs(configs: object[], fieldOverlaps?: FieldOverlapOptions): object;
100
104
  /**
101
105
  * Loads configurations from multiple directories and merges them with proper precedence.
102
106
  *
@@ -115,10 +119,14 @@ export declare function deepMergeConfigs(configs: object[]): object;
115
119
  * configDirName: '.kodrdriv',
116
120
  * configFileName: 'config.yaml',
117
121
  * startingDir: '/project/subdir',
118
- * maxLevels: 5
122
+ * maxLevels: 5,
123
+ * fieldOverlaps: {
124
+ * 'features': 'append',
125
+ * 'excludePatterns': 'prepend'
126
+ * }
119
127
  * });
120
128
  *
121
- * // result.config contains merged configuration
129
+ * // result.config contains merged configuration with custom array merging
122
130
  * // result.discoveredDirs shows where configs were found
123
131
  * // result.errors contains any non-fatal errors
124
132
  * ```
@@ -176,24 +176,26 @@ import { create } from './storage.js';
176
176
  }
177
177
  }
178
178
  /**
179
- * Deep merges multiple configuration objects with proper precedence.
179
+ * Deep merges multiple configuration objects with proper precedence and configurable array overlap behavior.
180
180
  *
181
181
  * Objects are merged from lowest precedence to highest precedence,
182
182
  * meaning that properties in later objects override properties in earlier objects.
183
- * Arrays are replaced entirely (not merged).
183
+ * Arrays can be merged using different strategies based on the fieldOverlaps configuration.
184
184
  *
185
185
  * @param configs Array of configuration objects, ordered from lowest to highest precedence
186
+ * @param fieldOverlaps Configuration for how array fields should be merged (optional)
186
187
  * @returns Merged configuration object
187
188
  *
188
189
  * @example
189
190
  * ```typescript
190
191
  * const merged = deepMergeConfigs([
191
- * { api: { timeout: 5000 }, debug: true }, // Lower precedence
192
- * { api: { retries: 3 }, features: ['auth'] }, // Higher precedence
193
- * ]);
194
- * // Result: { api: { timeout: 5000, retries: 3 }, debug: true, features: ['auth'] }
192
+ * { api: { timeout: 5000 }, features: ['auth'] }, // Lower precedence
193
+ * { api: { retries: 3 }, features: ['analytics'] }, // Higher precedence
194
+ * ], {
195
+ * 'features': 'append' // Results in features: ['auth', 'analytics']
196
+ * });
195
197
  * ```
196
- */ function deepMergeConfigs(configs) {
198
+ */ function deepMergeConfigs(configs, fieldOverlaps) {
197
199
  if (configs.length === 0) {
198
200
  return {};
199
201
  }
@@ -203,16 +205,18 @@ import { create } from './storage.js';
203
205
  };
204
206
  }
205
207
  return configs.reduce((merged, current)=>{
206
- return deepMergeTwo(merged, current);
208
+ return deepMergeTwo(merged, current, fieldOverlaps);
207
209
  }, {});
208
210
  }
209
211
  /**
210
- * Deep merges two objects with proper precedence.
212
+ * Deep merges two objects with proper precedence and configurable array overlap behavior.
211
213
  *
212
214
  * @param target Target object (lower precedence)
213
215
  * @param source Source object (higher precedence)
216
+ * @param fieldOverlaps Configuration for how array fields should be merged (optional)
217
+ * @param currentPath Current field path for nested merging (used internally)
214
218
  * @returns Merged object
215
- */ function deepMergeTwo(target, source) {
219
+ */ function deepMergeTwo(target, source, fieldOverlaps, currentPath = '') {
216
220
  // Handle null/undefined
217
221
  if (source == null) return target;
218
222
  if (target == null) return source;
@@ -220,11 +224,17 @@ import { create } from './storage.js';
220
224
  if (typeof source !== 'object' || typeof target !== 'object') {
221
225
  return source; // Source takes precedence
222
226
  }
223
- // Handle arrays - replace entirely, don't merge
227
+ // Handle arrays with configurable overlap behavior
224
228
  if (Array.isArray(source)) {
225
- return [
226
- ...source
227
- ];
229
+ if (Array.isArray(target) && fieldOverlaps) {
230
+ const overlapMode = getOverlapModeForPath(currentPath, fieldOverlaps);
231
+ return mergeArrays(target, source, overlapMode);
232
+ } else {
233
+ // Default behavior: replace entirely
234
+ return [
235
+ ...source
236
+ ];
237
+ }
228
238
  }
229
239
  if (Array.isArray(target)) {
230
240
  return source; // Source object replaces target array
@@ -235,17 +245,72 @@ import { create } from './storage.js';
235
245
  };
236
246
  for(const key in source){
237
247
  if (Object.prototype.hasOwnProperty.call(source, key)) {
248
+ const fieldPath = currentPath ? `${currentPath}.${key}` : key;
238
249
  if (Object.prototype.hasOwnProperty.call(result, key) && typeof result[key] === 'object' && typeof source[key] === 'object' && !Array.isArray(source[key]) && !Array.isArray(result[key])) {
239
250
  // Recursively merge nested objects
240
- result[key] = deepMergeTwo(result[key], source[key]);
251
+ result[key] = deepMergeTwo(result[key], source[key], fieldOverlaps, fieldPath);
241
252
  } else {
242
- // Replace with source value (higher precedence)
243
- result[key] = source[key];
253
+ // Handle arrays and primitives with overlap consideration
254
+ if (Array.isArray(source[key]) && Array.isArray(result[key]) && fieldOverlaps) {
255
+ const overlapMode = getOverlapModeForPath(fieldPath, fieldOverlaps);
256
+ result[key] = mergeArrays(result[key], source[key], overlapMode);
257
+ } else {
258
+ // Replace with source value (higher precedence)
259
+ result[key] = source[key];
260
+ }
244
261
  }
245
262
  }
246
263
  }
247
264
  return result;
248
265
  }
266
+ /**
267
+ * Determines the overlap mode for a given field path.
268
+ *
269
+ * @param fieldPath The current field path (dot notation)
270
+ * @param fieldOverlaps Configuration mapping field paths to overlap modes
271
+ * @returns The overlap mode to use for this field path
272
+ */ function getOverlapModeForPath(fieldPath, fieldOverlaps) {
273
+ // Check for exact match first
274
+ if (fieldPath in fieldOverlaps) {
275
+ return fieldOverlaps[fieldPath];
276
+ }
277
+ // Check for any parent path matches (for nested configurations)
278
+ const pathParts = fieldPath.split('.');
279
+ for(let i = pathParts.length - 1; i > 0; i--){
280
+ const parentPath = pathParts.slice(0, i).join('.');
281
+ if (parentPath in fieldOverlaps) {
282
+ return fieldOverlaps[parentPath];
283
+ }
284
+ }
285
+ // Default to override if no specific configuration found
286
+ return 'override';
287
+ }
288
+ /**
289
+ * Merges two arrays based on the specified overlap mode.
290
+ *
291
+ * @param targetArray The lower precedence array
292
+ * @param sourceArray The higher precedence array
293
+ * @param mode The overlap mode to use
294
+ * @returns The merged array
295
+ */ function mergeArrays(targetArray, sourceArray, mode) {
296
+ switch(mode){
297
+ case 'append':
298
+ return [
299
+ ...targetArray,
300
+ ...sourceArray
301
+ ];
302
+ case 'prepend':
303
+ return [
304
+ ...sourceArray,
305
+ ...targetArray
306
+ ];
307
+ case 'override':
308
+ default:
309
+ return [
310
+ ...sourceArray
311
+ ];
312
+ }
313
+ }
249
314
  /**
250
315
  * Loads configurations from multiple directories and merges them with proper precedence.
251
316
  *
@@ -264,15 +329,19 @@ import { create } from './storage.js';
264
329
  * configDirName: '.kodrdriv',
265
330
  * configFileName: 'config.yaml',
266
331
  * startingDir: '/project/subdir',
267
- * maxLevels: 5
332
+ * maxLevels: 5,
333
+ * fieldOverlaps: {
334
+ * 'features': 'append',
335
+ * 'excludePatterns': 'prepend'
336
+ * }
268
337
  * });
269
338
  *
270
- * // result.config contains merged configuration
339
+ * // result.config contains merged configuration with custom array merging
271
340
  * // result.discoveredDirs shows where configs were found
272
341
  * // result.errors contains any non-fatal errors
273
342
  * ```
274
343
  */ async function loadHierarchicalConfig(options) {
275
- const { configFileName, encoding = 'utf8', logger, pathFields, resolvePathArray } = options;
344
+ const { configFileName, encoding = 'utf8', logger, pathFields, resolvePathArray, fieldOverlaps } = options;
276
345
  logger === null || logger === void 0 ? void 0 : logger.verbose('Starting hierarchical configuration loading');
277
346
  // Discover all configuration directories
278
347
  const discoveredDirs = await discoverConfigDirectories(options);
@@ -306,8 +375,8 @@ import { create } from './storage.js';
306
375
  logger === null || logger === void 0 ? void 0 : logger.debug(errorMsg);
307
376
  }
308
377
  }
309
- // Merge all configurations with proper precedence
310
- const mergedConfig = deepMergeConfigs(configs);
378
+ // Merge all configurations with proper precedence and configurable array overlap
379
+ const mergedConfig = deepMergeConfigs(configs, fieldOverlaps);
311
380
  logger === null || logger === void 0 ? void 0 : logger.verbose(`Hierarchical loading complete. Merged ${configs.length} configurations`);
312
381
  return {
313
382
  config: mergedConfig,
@@ -1 +1 @@
1
- {"version":3,"file":"hierarchical.js","sources":["../../src/util/hierarchical.ts"],"sourcesContent":["import path from 'path';\nimport * as yaml from 'js-yaml';\nimport { create as createStorage } from './storage';\nimport { Logger } from '../types';\n\n/**\n * Resolves relative paths in configuration values relative to the configuration file's directory.\n */\nfunction resolveConfigPaths(\n config: any,\n configDir: string,\n pathFields: string[] = [],\n resolvePathArray: string[] = []\n): any {\n if (!config || typeof config !== 'object' || pathFields.length === 0) {\n return config;\n }\n\n const resolvedConfig = { ...config };\n\n for (const fieldPath of pathFields) {\n const value = getNestedValue(resolvedConfig, fieldPath);\n if (value !== undefined) {\n const shouldResolveArrayElements = resolvePathArray.includes(fieldPath);\n const resolvedValue = resolvePathValue(value, configDir, shouldResolveArrayElements);\n setNestedValue(resolvedConfig, fieldPath, resolvedValue);\n }\n }\n\n return resolvedConfig;\n}\n\n/**\n * Gets a nested value from an object using dot notation.\n */\nfunction getNestedValue(obj: any, path: string): any {\n return path.split('.').reduce((current, key) => current?.[key], obj);\n}\n\n/**\n * Sets a nested value in an object using dot notation.\n */\nfunction setNestedValue(obj: any, path: string, value: any): void {\n const keys = path.split('.');\n const lastKey = keys.pop()!;\n const target = keys.reduce((current, key) => {\n if (!(key in current)) {\n current[key] = {};\n }\n return current[key];\n }, obj);\n target[lastKey] = value;\n}\n\n/**\n * Resolves a path value (string or array of strings) relative to the config directory.\n */\nfunction resolvePathValue(value: any, configDir: string, resolveArrayElements: boolean): any {\n if (typeof value === 'string') {\n return resolveSinglePath(value, configDir);\n }\n\n if (Array.isArray(value) && resolveArrayElements) {\n return value.map(item =>\n typeof item === 'string' ? resolveSinglePath(item, configDir) : item\n );\n }\n\n return value;\n}\n\n/**\n * Resolves a single path string relative to the config directory if it's a relative path.\n */\nfunction resolveSinglePath(pathStr: string, configDir: string): string {\n if (!pathStr || path.isAbsolute(pathStr)) {\n return pathStr;\n }\n\n return path.resolve(configDir, pathStr);\n}\n\n/**\n * Represents a discovered configuration directory with its path and precedence level.\n */\nexport interface DiscoveredConfigDir {\n /** Absolute path to the configuration directory */\n path: string;\n /** Distance from the starting directory (0 = closest/highest precedence) */\n level: number;\n}\n\n/**\n * Options for hierarchical configuration discovery.\n */\nexport interface HierarchicalDiscoveryOptions {\n /** Name of the configuration directory to look for (e.g., '.kodrdriv') */\n configDirName: string;\n /** Name of the configuration file within each directory */\n configFileName: string;\n /** Maximum number of parent directories to traverse (default: 10) */\n maxLevels?: number;\n /** Starting directory for discovery (default: process.cwd()) */\n startingDir?: string;\n /** File encoding for reading configuration files */\n encoding?: string;\n /** Logger for debugging */\n logger?: Logger;\n /** Array of field names that contain paths to be resolved */\n pathFields?: string[];\n /** Array of field names whose array elements should all be resolved as paths */\n resolvePathArray?: string[];\n}\n\n/**\n * Result of loading configurations from multiple directories.\n */\nexport interface HierarchicalConfigResult {\n /** Merged configuration object with proper precedence */\n config: object;\n /** Array of directories where configuration was found */\n discoveredDirs: DiscoveredConfigDir[];\n /** Array of any errors encountered during loading (non-fatal) */\n errors: string[];\n}\n\n/**\n * Discovers configuration directories by traversing up the directory tree.\n * \n * Starting from the specified directory (or current working directory),\n * this function searches for directories with the given name, continuing\n * up the directory tree until it reaches the filesystem root or the\n * maximum number of levels.\n * \n * @param options Configuration options for discovery\n * @returns Promise resolving to array of discovered configuration directories\n * \n * @example\n * ```typescript\n * const dirs = await discoverConfigDirectories({\n * configDirName: '.kodrdriv',\n * configFileName: 'config.yaml',\n * maxLevels: 5\n * });\n * // Returns: [\n * // { path: '/project/.kodrdriv', level: 0 },\n * // { path: '/project/parent/.kodrdriv', level: 1 }\n * // ]\n * ```\n */\nexport async function discoverConfigDirectories(\n options: HierarchicalDiscoveryOptions\n): Promise<DiscoveredConfigDir[]> {\n const {\n configDirName,\n maxLevels = 10,\n startingDir = process.cwd(),\n logger\n } = options;\n\n const storage = createStorage({ log: logger?.debug || (() => { }) });\n const discoveredDirs: DiscoveredConfigDir[] = [];\n\n let currentDir = path.resolve(startingDir);\n let level = 0;\n const visited = new Set<string>(); // Prevent infinite loops with symlinks\n\n logger?.debug(`Starting hierarchical discovery from: ${currentDir}`);\n\n while (level < maxLevels) {\n // Prevent infinite loops with symlinks\n const realPath = path.resolve(currentDir);\n if (visited.has(realPath)) {\n logger?.debug(`Already visited ${realPath}, stopping discovery`);\n break;\n }\n visited.add(realPath);\n\n const configDirPath = path.join(currentDir, configDirName);\n logger?.debug(`Checking for config directory: ${configDirPath}`);\n\n try {\n const exists = await storage.exists(configDirPath);\n const isReadable = exists && await storage.isDirectoryReadable(configDirPath);\n\n if (exists && isReadable) {\n discoveredDirs.push({\n path: configDirPath,\n level\n });\n logger?.debug(`Found config directory at level ${level}: ${configDirPath}`);\n } else if (exists && !isReadable) {\n logger?.debug(`Config directory exists but is not readable: ${configDirPath}`);\n }\n } catch (error: any) {\n logger?.debug(`Error checking config directory ${configDirPath}: ${error.message}`);\n }\n\n // Move up one directory level\n const parentDir = path.dirname(currentDir);\n\n // Check if we've reached the root directory\n if (parentDir === currentDir) {\n logger?.debug('Reached filesystem root, stopping discovery');\n break;\n }\n\n currentDir = parentDir;\n level++;\n }\n\n logger?.verbose(`Discovery complete. Found ${discoveredDirs.length} config directories`);\n return discoveredDirs;\n}\n\n/**\n * Loads and parses a configuration file from a directory.\n * \n * @param configDir Path to the configuration directory\n * @param configFileName Name of the configuration file\n * @param encoding File encoding\n * @param logger Optional logger\n * @param pathFields Optional array of field names that contain paths to be resolved\n * @param resolvePathArray Optional array of field names whose array elements should all be resolved as paths\n * @returns Promise resolving to parsed configuration object or null if not found\n */\nexport async function loadConfigFromDirectory(\n configDir: string,\n configFileName: string,\n encoding: string = 'utf8',\n logger?: Logger,\n pathFields?: string[],\n resolvePathArray?: string[]\n): Promise<object | null> {\n const storage = createStorage({ log: logger?.debug || (() => { }) });\n const configFilePath = path.join(configDir, configFileName);\n\n try {\n logger?.verbose(`Attempting to load config file: ${configFilePath}`);\n\n const exists = await storage.exists(configFilePath);\n if (!exists) {\n logger?.debug(`Config file does not exist: ${configFilePath}`);\n return null;\n }\n\n const isReadable = await storage.isFileReadable(configFilePath);\n if (!isReadable) {\n logger?.debug(`Config file exists but is not readable: ${configFilePath}`);\n return null;\n }\n\n const yamlContent = await storage.readFile(configFilePath, encoding);\n const parsedYaml = yaml.load(yamlContent);\n\n if (parsedYaml !== null && typeof parsedYaml === 'object') {\n let config = parsedYaml as object;\n\n // Apply path resolution if configured\n if (pathFields && pathFields.length > 0) {\n config = resolveConfigPaths(config, configDir, pathFields, resolvePathArray || []);\n }\n\n logger?.verbose(`Successfully loaded config from: ${configFilePath}`);\n return config;\n } else {\n logger?.debug(`Config file contains invalid format: ${configFilePath}`);\n return null;\n }\n } catch (error: any) {\n logger?.debug(`Error loading config from ${configFilePath}: ${error.message}`);\n return null;\n }\n}\n\n/**\n * Deep merges multiple configuration objects with proper precedence.\n * \n * Objects are merged from lowest precedence to highest precedence,\n * meaning that properties in later objects override properties in earlier objects.\n * Arrays are replaced entirely (not merged).\n * \n * @param configs Array of configuration objects, ordered from lowest to highest precedence\n * @returns Merged configuration object\n * \n * @example\n * ```typescript\n * const merged = deepMergeConfigs([\n * { api: { timeout: 5000 }, debug: true }, // Lower precedence\n * { api: { retries: 3 }, features: ['auth'] }, // Higher precedence\n * ]);\n * // Result: { api: { timeout: 5000, retries: 3 }, debug: true, features: ['auth'] }\n * ```\n */\nexport function deepMergeConfigs(configs: object[]): object {\n if (configs.length === 0) {\n return {};\n }\n\n if (configs.length === 1) {\n return { ...configs[0] };\n }\n\n return configs.reduce((merged, current) => {\n return deepMergeTwo(merged, current);\n }, {});\n}\n\n/**\n * Deep merges two objects with proper precedence.\n * \n * @param target Target object (lower precedence)\n * @param source Source object (higher precedence)\n * @returns Merged object\n */\nfunction deepMergeTwo(target: any, source: any): any {\n // Handle null/undefined\n if (source == null) return target;\n if (target == null) return source;\n\n // Handle non-objects (primitives, arrays, functions, etc.)\n if (typeof source !== 'object' || typeof target !== 'object') {\n return source; // Source takes precedence\n }\n\n // Handle arrays - replace entirely, don't merge\n if (Array.isArray(source)) {\n return [...source];\n }\n\n if (Array.isArray(target)) {\n return source; // Source object replaces target array\n }\n\n // Deep merge objects\n const result = { ...target };\n\n for (const key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n if (Object.prototype.hasOwnProperty.call(result, key) &&\n typeof result[key] === 'object' &&\n typeof source[key] === 'object' &&\n !Array.isArray(source[key]) &&\n !Array.isArray(result[key])) {\n // Recursively merge nested objects\n result[key] = deepMergeTwo(result[key], source[key]);\n } else {\n // Replace with source value (higher precedence)\n result[key] = source[key];\n }\n }\n }\n\n return result;\n}\n\n/**\n * Loads configurations from multiple directories and merges them with proper precedence.\n * \n * This is the main function for hierarchical configuration loading. It:\n * 1. Discovers configuration directories up the directory tree\n * 2. Loads configuration files from each discovered directory\n * 3. Merges them with proper precedence (closer directories win)\n * 4. Returns the merged configuration with metadata\n * \n * @param options Configuration options for hierarchical loading\n * @returns Promise resolving to hierarchical configuration result\n * \n * @example\n * ```typescript\n * const result = await loadHierarchicalConfig({\n * configDirName: '.kodrdriv',\n * configFileName: 'config.yaml',\n * startingDir: '/project/subdir',\n * maxLevels: 5\n * });\n * \n * // result.config contains merged configuration\n * // result.discoveredDirs shows where configs were found\n * // result.errors contains any non-fatal errors\n * ```\n */\nexport async function loadHierarchicalConfig(\n options: HierarchicalDiscoveryOptions\n): Promise<HierarchicalConfigResult> {\n const { configFileName, encoding = 'utf8', logger, pathFields, resolvePathArray } = options;\n\n logger?.verbose('Starting hierarchical configuration loading');\n\n // Discover all configuration directories\n const discoveredDirs = await discoverConfigDirectories(options);\n\n if (discoveredDirs.length === 0) {\n logger?.verbose('No configuration directories found');\n return {\n config: {},\n discoveredDirs: [],\n errors: []\n };\n }\n\n // Load configurations from each directory\n const configs: object[] = [];\n const errors: string[] = [];\n\n // Sort by level (highest level first = lowest precedence first)\n const sortedDirs = [...discoveredDirs].sort((a, b) => b.level - a.level);\n\n for (const dir of sortedDirs) {\n try {\n const config = await loadConfigFromDirectory(\n dir.path,\n configFileName,\n encoding,\n logger,\n pathFields,\n resolvePathArray\n );\n\n if (config !== null) {\n configs.push(config);\n logger?.debug(`Loaded config from level ${dir.level}: ${dir.path}`);\n } else {\n logger?.debug(`No valid config found at level ${dir.level}: ${dir.path}`);\n }\n } catch (error: any) {\n const errorMsg = `Failed to load config from ${dir.path}: ${error.message}`;\n errors.push(errorMsg);\n logger?.debug(errorMsg);\n }\n }\n\n // Merge all configurations with proper precedence\n const mergedConfig = deepMergeConfigs(configs);\n\n logger?.verbose(`Hierarchical loading complete. Merged ${configs.length} configurations`);\n\n return {\n config: mergedConfig,\n discoveredDirs,\n errors\n };\n} "],"names":["resolveConfigPaths","config","configDir","pathFields","resolvePathArray","length","resolvedConfig","fieldPath","value","getNestedValue","undefined","shouldResolveArrayElements","includes","resolvedValue","resolvePathValue","setNestedValue","obj","path","split","reduce","current","key","keys","lastKey","pop","target","resolveArrayElements","resolveSinglePath","Array","isArray","map","item","pathStr","isAbsolute","resolve","discoverConfigDirectories","options","configDirName","maxLevels","startingDir","process","cwd","logger","storage","createStorage","log","debug","discoveredDirs","currentDir","level","visited","Set","realPath","has","add","configDirPath","join","exists","isReadable","isDirectoryReadable","push","error","message","parentDir","dirname","verbose","loadConfigFromDirectory","configFileName","encoding","configFilePath","isFileReadable","yamlContent","readFile","parsedYaml","yaml","load","deepMergeConfigs","configs","merged","deepMergeTwo","source","result","Object","prototype","hasOwnProperty","call","loadHierarchicalConfig","errors","sortedDirs","sort","a","b","dir","errorMsg","mergedConfig"],"mappings":"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"}
1
+ {"version":3,"file":"hierarchical.js","sources":["../../src/util/hierarchical.ts"],"sourcesContent":["import path from 'path';\nimport * as yaml from 'js-yaml';\nimport { create as createStorage } from './storage';\nimport { Logger, FieldOverlapOptions, ArrayOverlapMode } from '../types';\n\n/**\n * Resolves relative paths in configuration values relative to the configuration file's directory.\n */\nfunction resolveConfigPaths(\n config: any,\n configDir: string,\n pathFields: string[] = [],\n resolvePathArray: string[] = []\n): any {\n if (!config || typeof config !== 'object' || pathFields.length === 0) {\n return config;\n }\n\n const resolvedConfig = { ...config };\n\n for (const fieldPath of pathFields) {\n const value = getNestedValue(resolvedConfig, fieldPath);\n if (value !== undefined) {\n const shouldResolveArrayElements = resolvePathArray.includes(fieldPath);\n const resolvedValue = resolvePathValue(value, configDir, shouldResolveArrayElements);\n setNestedValue(resolvedConfig, fieldPath, resolvedValue);\n }\n }\n\n return resolvedConfig;\n}\n\n/**\n * Gets a nested value from an object using dot notation.\n */\nfunction getNestedValue(obj: any, path: string): any {\n return path.split('.').reduce((current, key) => current?.[key], obj);\n}\n\n/**\n * Sets a nested value in an object using dot notation.\n */\nfunction setNestedValue(obj: any, path: string, value: any): void {\n const keys = path.split('.');\n const lastKey = keys.pop()!;\n const target = keys.reduce((current, key) => {\n if (!(key in current)) {\n current[key] = {};\n }\n return current[key];\n }, obj);\n target[lastKey] = value;\n}\n\n/**\n * Resolves a path value (string or array of strings) relative to the config directory.\n */\nfunction resolvePathValue(value: any, configDir: string, resolveArrayElements: boolean): any {\n if (typeof value === 'string') {\n return resolveSinglePath(value, configDir);\n }\n\n if (Array.isArray(value) && resolveArrayElements) {\n return value.map(item =>\n typeof item === 'string' ? resolveSinglePath(item, configDir) : item\n );\n }\n\n return value;\n}\n\n/**\n * Resolves a single path string relative to the config directory if it's a relative path.\n */\nfunction resolveSinglePath(pathStr: string, configDir: string): string {\n if (!pathStr || path.isAbsolute(pathStr)) {\n return pathStr;\n }\n\n return path.resolve(configDir, pathStr);\n}\n\n/**\n * Represents a discovered configuration directory with its path and precedence level.\n */\nexport interface DiscoveredConfigDir {\n /** Absolute path to the configuration directory */\n path: string;\n /** Distance from the starting directory (0 = closest/highest precedence) */\n level: number;\n}\n\n/**\n * Options for hierarchical configuration discovery.\n */\nexport interface HierarchicalDiscoveryOptions {\n /** Name of the configuration directory to look for (e.g., '.kodrdriv') */\n configDirName: string;\n /** Name of the configuration file within each directory */\n configFileName: string;\n /** Maximum number of parent directories to traverse (default: 10) */\n maxLevels?: number;\n /** Starting directory for discovery (default: process.cwd()) */\n startingDir?: string;\n /** File encoding for reading configuration files */\n encoding?: string;\n /** Logger for debugging */\n logger?: Logger;\n /** Array of field names that contain paths to be resolved */\n pathFields?: string[];\n /** Array of field names whose array elements should all be resolved as paths */\n resolvePathArray?: string[];\n /** Configuration for how array fields should be merged in hierarchical mode */\n fieldOverlaps?: FieldOverlapOptions;\n}\n\n/**\n * Result of loading configurations from multiple directories.\n */\nexport interface HierarchicalConfigResult {\n /** Merged configuration object with proper precedence */\n config: object;\n /** Array of directories where configuration was found */\n discoveredDirs: DiscoveredConfigDir[];\n /** Array of any errors encountered during loading (non-fatal) */\n errors: string[];\n}\n\n/**\n * Discovers configuration directories by traversing up the directory tree.\n * \n * Starting from the specified directory (or current working directory),\n * this function searches for directories with the given name, continuing\n * up the directory tree until it reaches the filesystem root or the\n * maximum number of levels.\n * \n * @param options Configuration options for discovery\n * @returns Promise resolving to array of discovered configuration directories\n * \n * @example\n * ```typescript\n * const dirs = await discoverConfigDirectories({\n * configDirName: '.kodrdriv',\n * configFileName: 'config.yaml',\n * maxLevels: 5\n * });\n * // Returns: [\n * // { path: '/project/.kodrdriv', level: 0 },\n * // { path: '/project/parent/.kodrdriv', level: 1 }\n * // ]\n * ```\n */\nexport async function discoverConfigDirectories(\n options: HierarchicalDiscoveryOptions\n): Promise<DiscoveredConfigDir[]> {\n const {\n configDirName,\n maxLevels = 10,\n startingDir = process.cwd(),\n logger\n } = options;\n\n const storage = createStorage({ log: logger?.debug || (() => { }) });\n const discoveredDirs: DiscoveredConfigDir[] = [];\n\n let currentDir = path.resolve(startingDir);\n let level = 0;\n const visited = new Set<string>(); // Prevent infinite loops with symlinks\n\n logger?.debug(`Starting hierarchical discovery from: ${currentDir}`);\n\n while (level < maxLevels) {\n // Prevent infinite loops with symlinks\n const realPath = path.resolve(currentDir);\n if (visited.has(realPath)) {\n logger?.debug(`Already visited ${realPath}, stopping discovery`);\n break;\n }\n visited.add(realPath);\n\n const configDirPath = path.join(currentDir, configDirName);\n logger?.debug(`Checking for config directory: ${configDirPath}`);\n\n try {\n const exists = await storage.exists(configDirPath);\n const isReadable = exists && await storage.isDirectoryReadable(configDirPath);\n\n if (exists && isReadable) {\n discoveredDirs.push({\n path: configDirPath,\n level\n });\n logger?.debug(`Found config directory at level ${level}: ${configDirPath}`);\n } else if (exists && !isReadable) {\n logger?.debug(`Config directory exists but is not readable: ${configDirPath}`);\n }\n } catch (error: any) {\n logger?.debug(`Error checking config directory ${configDirPath}: ${error.message}`);\n }\n\n // Move up one directory level\n const parentDir = path.dirname(currentDir);\n\n // Check if we've reached the root directory\n if (parentDir === currentDir) {\n logger?.debug('Reached filesystem root, stopping discovery');\n break;\n }\n\n currentDir = parentDir;\n level++;\n }\n\n logger?.verbose(`Discovery complete. Found ${discoveredDirs.length} config directories`);\n return discoveredDirs;\n}\n\n/**\n * Loads and parses a configuration file from a directory.\n * \n * @param configDir Path to the configuration directory\n * @param configFileName Name of the configuration file\n * @param encoding File encoding\n * @param logger Optional logger\n * @param pathFields Optional array of field names that contain paths to be resolved\n * @param resolvePathArray Optional array of field names whose array elements should all be resolved as paths\n * @returns Promise resolving to parsed configuration object or null if not found\n */\nexport async function loadConfigFromDirectory(\n configDir: string,\n configFileName: string,\n encoding: string = 'utf8',\n logger?: Logger,\n pathFields?: string[],\n resolvePathArray?: string[]\n): Promise<object | null> {\n const storage = createStorage({ log: logger?.debug || (() => { }) });\n const configFilePath = path.join(configDir, configFileName);\n\n try {\n logger?.verbose(`Attempting to load config file: ${configFilePath}`);\n\n const exists = await storage.exists(configFilePath);\n if (!exists) {\n logger?.debug(`Config file does not exist: ${configFilePath}`);\n return null;\n }\n\n const isReadable = await storage.isFileReadable(configFilePath);\n if (!isReadable) {\n logger?.debug(`Config file exists but is not readable: ${configFilePath}`);\n return null;\n }\n\n const yamlContent = await storage.readFile(configFilePath, encoding);\n const parsedYaml = yaml.load(yamlContent);\n\n if (parsedYaml !== null && typeof parsedYaml === 'object') {\n let config = parsedYaml as object;\n\n // Apply path resolution if configured\n if (pathFields && pathFields.length > 0) {\n config = resolveConfigPaths(config, configDir, pathFields, resolvePathArray || []);\n }\n\n logger?.verbose(`Successfully loaded config from: ${configFilePath}`);\n return config;\n } else {\n logger?.debug(`Config file contains invalid format: ${configFilePath}`);\n return null;\n }\n } catch (error: any) {\n logger?.debug(`Error loading config from ${configFilePath}: ${error.message}`);\n return null;\n }\n}\n\n/**\n * Deep merges multiple configuration objects with proper precedence and configurable array overlap behavior.\n * \n * Objects are merged from lowest precedence to highest precedence,\n * meaning that properties in later objects override properties in earlier objects.\n * Arrays can be merged using different strategies based on the fieldOverlaps configuration.\n * \n * @param configs Array of configuration objects, ordered from lowest to highest precedence\n * @param fieldOverlaps Configuration for how array fields should be merged (optional)\n * @returns Merged configuration object\n * \n * @example\n * ```typescript\n * const merged = deepMergeConfigs([\n * { api: { timeout: 5000 }, features: ['auth'] }, // Lower precedence\n * { api: { retries: 3 }, features: ['analytics'] }, // Higher precedence\n * ], {\n * 'features': 'append' // Results in features: ['auth', 'analytics']\n * });\n * ```\n */\nexport function deepMergeConfigs(configs: object[], fieldOverlaps?: FieldOverlapOptions): object {\n if (configs.length === 0) {\n return {};\n }\n\n if (configs.length === 1) {\n return { ...configs[0] };\n }\n\n return configs.reduce((merged, current) => {\n return deepMergeTwo(merged, current, fieldOverlaps);\n }, {});\n}\n\n/**\n * Deep merges two objects with proper precedence and configurable array overlap behavior.\n * \n * @param target Target object (lower precedence)\n * @param source Source object (higher precedence)\n * @param fieldOverlaps Configuration for how array fields should be merged (optional)\n * @param currentPath Current field path for nested merging (used internally)\n * @returns Merged object\n */\nfunction deepMergeTwo(target: any, source: any, fieldOverlaps?: FieldOverlapOptions, currentPath: string = ''): any {\n // Handle null/undefined\n if (source == null) return target;\n if (target == null) return source;\n\n // Handle non-objects (primitives, arrays, functions, etc.)\n if (typeof source !== 'object' || typeof target !== 'object') {\n return source; // Source takes precedence\n }\n\n // Handle arrays with configurable overlap behavior\n if (Array.isArray(source)) {\n if (Array.isArray(target) && fieldOverlaps) {\n const overlapMode = getOverlapModeForPath(currentPath, fieldOverlaps);\n return mergeArrays(target, source, overlapMode);\n } else {\n // Default behavior: replace entirely\n return [...source];\n }\n }\n\n if (Array.isArray(target)) {\n return source; // Source object replaces target array\n }\n\n // Deep merge objects\n const result = { ...target };\n\n for (const key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n const fieldPath = currentPath ? `${currentPath}.${key}` : key;\n\n if (Object.prototype.hasOwnProperty.call(result, key) &&\n typeof result[key] === 'object' &&\n typeof source[key] === 'object' &&\n !Array.isArray(source[key]) &&\n !Array.isArray(result[key])) {\n // Recursively merge nested objects\n result[key] = deepMergeTwo(result[key], source[key], fieldOverlaps, fieldPath);\n } else {\n // Handle arrays and primitives with overlap consideration\n if (Array.isArray(source[key]) && Array.isArray(result[key]) && fieldOverlaps) {\n const overlapMode = getOverlapModeForPath(fieldPath, fieldOverlaps);\n result[key] = mergeArrays(result[key], source[key], overlapMode);\n } else {\n // Replace with source value (higher precedence)\n result[key] = source[key];\n }\n }\n }\n }\n\n return result;\n}\n\n/**\n * Determines the overlap mode for a given field path.\n * \n * @param fieldPath The current field path (dot notation)\n * @param fieldOverlaps Configuration mapping field paths to overlap modes\n * @returns The overlap mode to use for this field path\n */\nfunction getOverlapModeForPath(fieldPath: string, fieldOverlaps: FieldOverlapOptions): ArrayOverlapMode {\n // Check for exact match first\n if (fieldPath in fieldOverlaps) {\n return fieldOverlaps[fieldPath];\n }\n\n // Check for any parent path matches (for nested configurations)\n const pathParts = fieldPath.split('.');\n for (let i = pathParts.length - 1; i > 0; i--) {\n const parentPath = pathParts.slice(0, i).join('.');\n if (parentPath in fieldOverlaps) {\n return fieldOverlaps[parentPath];\n }\n }\n\n // Default to override if no specific configuration found\n return 'override';\n}\n\n/**\n * Merges two arrays based on the specified overlap mode.\n * \n * @param targetArray The lower precedence array\n * @param sourceArray The higher precedence array\n * @param mode The overlap mode to use\n * @returns The merged array\n */\nfunction mergeArrays(targetArray: any[], sourceArray: any[], mode: ArrayOverlapMode): any[] {\n switch (mode) {\n case 'append':\n return [...targetArray, ...sourceArray];\n case 'prepend':\n return [...sourceArray, ...targetArray];\n case 'override':\n default:\n return [...sourceArray];\n }\n}\n\n/**\n * Loads configurations from multiple directories and merges them with proper precedence.\n * \n * This is the main function for hierarchical configuration loading. It:\n * 1. Discovers configuration directories up the directory tree\n * 2. Loads configuration files from each discovered directory\n * 3. Merges them with proper precedence (closer directories win)\n * 4. Returns the merged configuration with metadata\n * \n * @param options Configuration options for hierarchical loading\n * @returns Promise resolving to hierarchical configuration result\n * \n * @example\n * ```typescript\n * const result = await loadHierarchicalConfig({\n * configDirName: '.kodrdriv',\n * configFileName: 'config.yaml',\n * startingDir: '/project/subdir',\n * maxLevels: 5,\n * fieldOverlaps: {\n * 'features': 'append',\n * 'excludePatterns': 'prepend'\n * }\n * });\n * \n * // result.config contains merged configuration with custom array merging\n * // result.discoveredDirs shows where configs were found\n * // result.errors contains any non-fatal errors\n * ```\n */\nexport async function loadHierarchicalConfig(\n options: HierarchicalDiscoveryOptions\n): Promise<HierarchicalConfigResult> {\n const { configFileName, encoding = 'utf8', logger, pathFields, resolvePathArray, fieldOverlaps } = options;\n\n logger?.verbose('Starting hierarchical configuration loading');\n\n // Discover all configuration directories\n const discoveredDirs = await discoverConfigDirectories(options);\n\n if (discoveredDirs.length === 0) {\n logger?.verbose('No configuration directories found');\n return {\n config: {},\n discoveredDirs: [],\n errors: []\n };\n }\n\n // Load configurations from each directory\n const configs: object[] = [];\n const errors: string[] = [];\n\n // Sort by level (highest level first = lowest precedence first)\n const sortedDirs = [...discoveredDirs].sort((a, b) => b.level - a.level);\n\n for (const dir of sortedDirs) {\n try {\n const config = await loadConfigFromDirectory(\n dir.path,\n configFileName,\n encoding,\n logger,\n pathFields,\n resolvePathArray\n );\n\n if (config !== null) {\n configs.push(config);\n logger?.debug(`Loaded config from level ${dir.level}: ${dir.path}`);\n } else {\n logger?.debug(`No valid config found at level ${dir.level}: ${dir.path}`);\n }\n } catch (error: any) {\n const errorMsg = `Failed to load config from ${dir.path}: ${error.message}`;\n errors.push(errorMsg);\n logger?.debug(errorMsg);\n }\n }\n\n // Merge all configurations with proper precedence and configurable array overlap\n const mergedConfig = deepMergeConfigs(configs, fieldOverlaps);\n\n logger?.verbose(`Hierarchical loading complete. Merged ${configs.length} configurations`);\n\n return {\n config: mergedConfig,\n discoveredDirs,\n errors\n };\n} "],"names":["resolveConfigPaths","config","configDir","pathFields","resolvePathArray","length","resolvedConfig","fieldPath","value","getNestedValue","undefined","shouldResolveArrayElements","includes","resolvedValue","resolvePathValue","setNestedValue","obj","path","split","reduce","current","key","keys","lastKey","pop","target","resolveArrayElements","resolveSinglePath","Array","isArray","map","item","pathStr","isAbsolute","resolve","discoverConfigDirectories","options","configDirName","maxLevels","startingDir","process","cwd","logger","storage","createStorage","log","debug","discoveredDirs","currentDir","level","visited","Set","realPath","has","add","configDirPath","join","exists","isReadable","isDirectoryReadable","push","error","message","parentDir","dirname","verbose","loadConfigFromDirectory","configFileName","encoding","configFilePath","isFileReadable","yamlContent","readFile","parsedYaml","yaml","load","deepMergeConfigs","configs","fieldOverlaps","merged","deepMergeTwo","source","currentPath","overlapMode","getOverlapModeForPath","mergeArrays","result","Object","prototype","hasOwnProperty","call","pathParts","i","parentPath","slice","targetArray","sourceArray","mode","loadHierarchicalConfig","errors","sortedDirs","sort","a","b","dir","errorMsg","mergedConfig"],"mappings":"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"}