@theunwalked/cardigantime 0.0.12 → 0.0.13

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":"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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"}
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 directories that actually contained valid configuration files */\n resolvedConfigDirs: 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 resolvedConfigDirs: [],\n errors: []\n };\n }\n\n // Load configurations from each directory\n const configs: object[] = [];\n const resolvedConfigDirs: DiscoveredConfigDir[] = [];\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 resolvedConfigDirs.push(dir);\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 resolvedConfigDirs,\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","resolvedConfigDirs","errors","sortedDirs","sort","a","b","dir","errorMsg","mergedConfig"],"mappings":"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"}
@@ -59,4 +59,4 @@ export declare const extractConfigFileDefaults: (schema: z.ZodTypeAny) => any;
59
59
  * // Note: apiKey is not included since it has no default
60
60
  * ```
61
61
  */
62
- export declare const generateDefaultConfig: <T extends z.ZodRawShape>(configShape: T, configDirectory: string) => Record<string, any>;
62
+ export declare const generateDefaultConfig: <T extends z.ZodRawShape>(configShape: T, _configDirectory: string) => Record<string, any>;
@@ -98,7 +98,7 @@ import { z } from 'zod';
98
98
  * // Returns: { timeout: 5000, features: ['auth', 'logging'] }
99
99
  * // Note: apiKey is not included since it has no default
100
100
  * ```
101
- */ const generateDefaultConfig = (configShape, configDirectory)=>{
101
+ */ const generateDefaultConfig = (configShape, _configDirectory)=>{
102
102
  // Create the full schema by combining base and user schema
103
103
  const fullSchema = z.object({
104
104
  ...configShape
@@ -1 +1 @@
1
- {"version":3,"file":"schema-defaults.js","sources":["../../src/util/schema-defaults.ts"],"sourcesContent":["import { z, ZodObject } from 'zod';\n\n/**\n * Extracts default values from a Zod schema recursively.\n * \n * This function traverses a Zod schema and builds an object containing\n * all the default values defined in the schema. It handles:\n * - ZodDefault types with explicit default values\n * - ZodOptional/ZodNullable types by unwrapping them\n * - ZodObject types by recursively processing their shape\n * - ZodArray types by providing an empty array as default\n * \n * @param schema - The Zod schema to extract defaults from\n * @returns An object containing all default values from the schema\n * \n * @example\n * ```typescript\n * const schema = z.object({\n * name: z.string().default('app'),\n * port: z.number().default(3000),\n * debug: z.boolean().default(false),\n * database: z.object({\n * host: z.string().default('localhost'),\n * port: z.number().default(5432)\n * })\n * });\n * \n * const defaults = extractSchemaDefaults(schema);\n * // Returns: { name: 'app', port: 3000, debug: false, database: { host: 'localhost', port: 5432 } }\n * ```\n */\nexport const extractSchemaDefaults = (schema: z.ZodTypeAny): any => {\n // Handle ZodDefault - extract the default value\n if (schema._def && schema._def.typeName === 'ZodDefault') {\n const defaultSchema = schema as z.ZodDefault<any>;\n return defaultSchema._def.defaultValue();\n }\n\n // Handle ZodOptional and ZodNullable - only recurse if there's an explicit default\n if (schema._def && (schema._def.typeName === 'ZodOptional' || schema._def.typeName === 'ZodNullable')) {\n const unwrappable = schema as z.ZodOptional<any> | z.ZodNullable<any>;\n const unwrapped = unwrappable.unwrap();\n\n // Only provide defaults if the unwrapped schema has explicit defaults\n // This prevents optional arrays/objects from automatically getting [] or {} defaults\n if (unwrapped._def && unwrapped._def.typeName === 'ZodDefault') {\n return extractSchemaDefaults(unwrapped);\n }\n\n // For optional fields without explicit defaults, return undefined\n return undefined;\n }\n\n // Handle ZodObject - recursively process shape\n if (schema._def && schema._def.typeName === 'ZodObject') {\n const objectSchema = schema as z.ZodObject<any>;\n const result: any = {};\n\n for (const [key, subschema] of Object.entries(objectSchema.shape)) {\n const defaultValue = extractSchemaDefaults(subschema as z.ZodTypeAny);\n if (defaultValue !== undefined) {\n result[key] = defaultValue;\n }\n }\n\n return Object.keys(result).length > 0 ? result : undefined;\n }\n\n // Handle ZodArray - provide empty array as default\n if (schema._def && schema._def.typeName === 'ZodArray') {\n const arraySchema = schema as z.ZodArray<any>;\n const elementDefaults = extractSchemaDefaults(arraySchema.element);\n // Return an empty array, or an array with one example element if it has defaults\n return elementDefaults !== undefined ? [elementDefaults] : [];\n }\n\n // Handle ZodRecord - provide empty object as default\n if (schema._def && schema._def.typeName === 'ZodRecord') {\n return {};\n }\n\n // For other types, return undefined (no default available)\n return undefined;\n};\n\n/**\n * Extracts meaningful defaults for config file generation, including sensible defaults for optional fields.\n * This is more generous than extractSchemaDefaults for the purpose of creating helpful config files.\n */\nexport const extractConfigFileDefaults = (schema: z.ZodTypeAny): any => {\n // Handle ZodDefault - extract the default value\n if (schema._def && schema._def.typeName === 'ZodDefault') {\n const defaultSchema = schema as z.ZodDefault<any>;\n return defaultSchema._def.defaultValue();\n }\n\n // Handle ZodOptional and ZodNullable - provide sensible defaults for config generation\n if (schema._def && (schema._def.typeName === 'ZodOptional' || schema._def.typeName === 'ZodNullable')) {\n const unwrappable = schema as z.ZodOptional<any> | z.ZodNullable<any>;\n const unwrapped = unwrappable.unwrap();\n\n // Recurse into the unwrapped schema to get its default or provide a sensible one\n const unwrappedDefault = extractConfigFileDefaults(unwrapped);\n if (unwrappedDefault !== undefined) {\n return unwrappedDefault;\n }\n\n // Provide sensible defaults for common types when generating config files\n if (unwrapped._def) {\n switch (unwrapped._def.typeName) {\n case 'ZodBoolean':\n return false;\n case 'ZodNumber':\n return 0;\n case 'ZodString':\n return '';\n case 'ZodArray':\n return [];\n case 'ZodRecord':\n return {};\n case 'ZodObject':\n return extractConfigFileDefaults(unwrapped);\n }\n }\n\n return undefined;\n }\n\n // Handle ZodObject - recursively process shape\n if (schema._def && schema._def.typeName === 'ZodObject') {\n const objectSchema = schema as z.ZodObject<any>;\n const result: any = {};\n\n for (const [key, subschema] of Object.entries(objectSchema.shape)) {\n const defaultValue = extractConfigFileDefaults(subschema as z.ZodTypeAny);\n if (defaultValue !== undefined) {\n result[key] = defaultValue;\n }\n }\n\n return Object.keys(result).length > 0 ? result : {};\n }\n\n // Handle ZodArray - provide empty array as default\n if (schema._def && schema._def.typeName === 'ZodArray') {\n return [];\n }\n\n // Handle ZodRecord - provide empty object as default\n if (schema._def && schema._def.typeName === 'ZodRecord') {\n return {};\n }\n\n // For other types, return undefined (no default available)\n return undefined;\n};\n\n/**\n * Generates a complete configuration object with all default values populated.\n * \n * This function combines the base ConfigSchema with a user-provided schema shape\n * and extracts all available default values to create a complete configuration\n * example that can be serialized to YAML.\n * \n * @template T - The Zod schema shape type\n * @param configShape - The user's configuration schema shape\n * @param configDirectory - The configuration directory to include in the defaults\n * @returns An object containing all default values suitable for YAML serialization\n * \n * @example\n * ```typescript\n * const shape = z.object({\n * apiKey: z.string().describe('Your API key'),\n * timeout: z.number().default(5000).describe('Request timeout in milliseconds'),\n * features: z.array(z.string()).default(['auth', 'logging'])\n * }).shape;\n * \n * const config = generateDefaultConfig(shape, './config');\n * // Returns: { timeout: 5000, features: ['auth', 'logging'] }\n * // Note: apiKey is not included since it has no default\n * ```\n */\nexport const generateDefaultConfig = <T extends z.ZodRawShape>(\n configShape: T,\n configDirectory: string\n): Record<string, any> => {\n // Create the full schema by combining base and user schema\n const fullSchema = z.object({\n ...configShape,\n });\n\n // Extract defaults from the full schema using only explicit defaults\n const defaults = extractSchemaDefaults(fullSchema);\n\n // Don't include configDirectory in the generated file since it's runtime-specific\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { configDirectory: _, ...configDefaults } = defaults || {};\n\n return configDefaults || {};\n}; "],"names":["extractSchemaDefaults","schema","_def","typeName","defaultSchema","defaultValue","unwrappable","unwrapped","unwrap","undefined","objectSchema","result","key","subschema","Object","entries","shape","keys","length","arraySchema","elementDefaults","element","generateDefaultConfig","configShape","configDirectory","fullSchema","z","object","defaults","_","configDefaults"],"mappings":";;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA6BO,MAAMA,qBAAAA,GAAwB,CAACC,MAAAA,GAAAA;;IAElC,IAAIA,MAAAA,CAAOC,IAAI,IAAID,MAAAA,CAAOC,IAAI,CAACC,QAAQ,KAAK,YAAA,EAAc;AACtD,QAAA,MAAMC,aAAAA,GAAgBH,MAAAA;QACtB,OAAOG,aAAAA,CAAcF,IAAI,CAACG,YAAY,EAAA;AAC1C;;AAGA,IAAA,IAAIJ,OAAOC,IAAI,KAAKD,MAAAA,CAAOC,IAAI,CAACC,QAAQ,KAAK,aAAA,IAAiBF,OAAOC,IAAI,CAACC,QAAQ,KAAK,aAAY,CAAA,EAAI;AACnG,QAAA,MAAMG,WAAAA,GAAcL,MAAAA;QACpB,MAAMM,SAAAA,GAAYD,YAAYE,MAAM,EAAA;;;QAIpC,IAAID,SAAAA,CAAUL,IAAI,IAAIK,SAAAA,CAAUL,IAAI,CAACC,QAAQ,KAAK,YAAA,EAAc;AAC5D,YAAA,OAAOH,qBAAAA,CAAsBO,SAAAA,CAAAA;AACjC;;QAGA,OAAOE,SAAAA;AACX;;IAGA,IAAIR,MAAAA,CAAOC,IAAI,IAAID,MAAAA,CAAOC,IAAI,CAACC,QAAQ,KAAK,WAAA,EAAa;AACrD,QAAA,MAAMO,YAAAA,GAAeT,MAAAA;AACrB,QAAA,MAAMU,SAAc,EAAC;QAErB,KAAK,MAAM,CAACC,GAAAA,EAAKC,SAAAA,CAAU,IAAIC,OAAOC,OAAO,CAACL,YAAAA,CAAaM,KAAK,CAAA,CAAG;AAC/D,YAAA,MAAMX,eAAeL,qBAAAA,CAAsBa,SAAAA,CAAAA;AAC3C,YAAA,IAAIR,iBAAiBI,SAAAA,EAAW;gBAC5BE,MAAM,CAACC,IAAI,GAAGP,YAAAA;AAClB;AACJ;AAEA,QAAA,OAAOS,OAAOG,IAAI,CAACN,QAAQO,MAAM,GAAG,IAAIP,MAAAA,GAASF,SAAAA;AACrD;;IAGA,IAAIR,MAAAA,CAAOC,IAAI,IAAID,MAAAA,CAAOC,IAAI,CAACC,QAAQ,KAAK,UAAA,EAAY;AACpD,QAAA,MAAMgB,WAAAA,GAAclB,MAAAA;QACpB,MAAMmB,eAAAA,GAAkBpB,qBAAAA,CAAsBmB,WAAAA,CAAYE,OAAO,CAAA;;AAEjE,QAAA,OAAOD,oBAAoBX,SAAAA,GAAY;AAACW,YAAAA;AAAgB,SAAA,GAAG,EAAE;AACjE;;IAGA,IAAInB,MAAAA,CAAOC,IAAI,IAAID,MAAAA,CAAOC,IAAI,CAACC,QAAQ,KAAK,WAAA,EAAa;AACrD,QAAA,OAAO,EAAC;AACZ;;IAGA,OAAOM,SAAAA;AACX;AA0EA;;;;;;;;;;;;;;;;;;;;;;;;AAwBC,IACM,MAAMa,qBAAAA,GAAwB,CACjCC,WAAAA,EACAC,eAAAA,GAAAA;;IAGA,MAAMC,UAAAA,GAAaC,CAAAA,CAAEC,MAAM,CAAC;AACxB,QAAA,GAAGJ;AACP,KAAA,CAAA;;AAGA,IAAA,MAAMK,WAAW5B,qBAAAA,CAAsByB,UAAAA,CAAAA;;;IAIvC,MAAM,EAAED,iBAAiBK,CAAC,EAAE,GAAGC,cAAAA,EAAgB,GAAGF,YAAY,EAAC;AAE/D,IAAA,OAAOE,kBAAkB,EAAC;AAC9B;;;;"}
1
+ {"version":3,"file":"schema-defaults.js","sources":["../../src/util/schema-defaults.ts"],"sourcesContent":["import { z } from 'zod';\n\n/**\n * Extracts default values from a Zod schema recursively.\n * \n * This function traverses a Zod schema and builds an object containing\n * all the default values defined in the schema. It handles:\n * - ZodDefault types with explicit default values\n * - ZodOptional/ZodNullable types by unwrapping them\n * - ZodObject types by recursively processing their shape\n * - ZodArray types by providing an empty array as default\n * \n * @param schema - The Zod schema to extract defaults from\n * @returns An object containing all default values from the schema\n * \n * @example\n * ```typescript\n * const schema = z.object({\n * name: z.string().default('app'),\n * port: z.number().default(3000),\n * debug: z.boolean().default(false),\n * database: z.object({\n * host: z.string().default('localhost'),\n * port: z.number().default(5432)\n * })\n * });\n * \n * const defaults = extractSchemaDefaults(schema);\n * // Returns: { name: 'app', port: 3000, debug: false, database: { host: 'localhost', port: 5432 } }\n * ```\n */\nexport const extractSchemaDefaults = (schema: z.ZodTypeAny): any => {\n // Handle ZodDefault - extract the default value\n if (schema._def && schema._def.typeName === 'ZodDefault') {\n const defaultSchema = schema as z.ZodDefault<any>;\n return defaultSchema._def.defaultValue();\n }\n\n // Handle ZodOptional and ZodNullable - only recurse if there's an explicit default\n if (schema._def && (schema._def.typeName === 'ZodOptional' || schema._def.typeName === 'ZodNullable')) {\n const unwrappable = schema as z.ZodOptional<any> | z.ZodNullable<any>;\n const unwrapped = unwrappable.unwrap();\n\n // Only provide defaults if the unwrapped schema has explicit defaults\n // This prevents optional arrays/objects from automatically getting [] or {} defaults\n if (unwrapped._def && unwrapped._def.typeName === 'ZodDefault') {\n return extractSchemaDefaults(unwrapped);\n }\n\n // For optional fields without explicit defaults, return undefined\n return undefined;\n }\n\n // Handle ZodObject - recursively process shape\n if (schema._def && schema._def.typeName === 'ZodObject') {\n const objectSchema = schema as z.ZodObject<any>;\n const result: any = {};\n\n for (const [key, subschema] of Object.entries(objectSchema.shape)) {\n const defaultValue = extractSchemaDefaults(subschema as z.ZodTypeAny);\n if (defaultValue !== undefined) {\n result[key] = defaultValue;\n }\n }\n\n return Object.keys(result).length > 0 ? result : undefined;\n }\n\n // Handle ZodArray - provide empty array as default\n if (schema._def && schema._def.typeName === 'ZodArray') {\n const arraySchema = schema as z.ZodArray<any>;\n const elementDefaults = extractSchemaDefaults(arraySchema.element);\n // Return an empty array, or an array with one example element if it has defaults\n return elementDefaults !== undefined ? [elementDefaults] : [];\n }\n\n // Handle ZodRecord - provide empty object as default\n if (schema._def && schema._def.typeName === 'ZodRecord') {\n return {};\n }\n\n // For other types, return undefined (no default available)\n return undefined;\n};\n\n/**\n * Extracts meaningful defaults for config file generation, including sensible defaults for optional fields.\n * This is more generous than extractSchemaDefaults for the purpose of creating helpful config files.\n */\nexport const extractConfigFileDefaults = (schema: z.ZodTypeAny): any => {\n // Handle ZodDefault - extract the default value\n if (schema._def && schema._def.typeName === 'ZodDefault') {\n const defaultSchema = schema as z.ZodDefault<any>;\n return defaultSchema._def.defaultValue();\n }\n\n // Handle ZodOptional and ZodNullable - provide sensible defaults for config generation\n if (schema._def && (schema._def.typeName === 'ZodOptional' || schema._def.typeName === 'ZodNullable')) {\n const unwrappable = schema as z.ZodOptional<any> | z.ZodNullable<any>;\n const unwrapped = unwrappable.unwrap();\n\n // Recurse into the unwrapped schema to get its default or provide a sensible one\n const unwrappedDefault = extractConfigFileDefaults(unwrapped);\n if (unwrappedDefault !== undefined) {\n return unwrappedDefault;\n }\n\n // Provide sensible defaults for common types when generating config files\n if (unwrapped._def) {\n switch (unwrapped._def.typeName) {\n case 'ZodBoolean':\n return false;\n case 'ZodNumber':\n return 0;\n case 'ZodString':\n return '';\n case 'ZodArray':\n return [];\n case 'ZodRecord':\n return {};\n case 'ZodObject':\n return extractConfigFileDefaults(unwrapped);\n }\n }\n\n return undefined;\n }\n\n // Handle ZodObject - recursively process shape\n if (schema._def && schema._def.typeName === 'ZodObject') {\n const objectSchema = schema as z.ZodObject<any>;\n const result: any = {};\n\n for (const [key, subschema] of Object.entries(objectSchema.shape)) {\n const defaultValue = extractConfigFileDefaults(subschema as z.ZodTypeAny);\n if (defaultValue !== undefined) {\n result[key] = defaultValue;\n }\n }\n\n return Object.keys(result).length > 0 ? result : {};\n }\n\n // Handle ZodArray - provide empty array as default\n if (schema._def && schema._def.typeName === 'ZodArray') {\n return [];\n }\n\n // Handle ZodRecord - provide empty object as default\n if (schema._def && schema._def.typeName === 'ZodRecord') {\n return {};\n }\n\n // For other types, return undefined (no default available)\n return undefined;\n};\n\n/**\n * Generates a complete configuration object with all default values populated.\n * \n * This function combines the base ConfigSchema with a user-provided schema shape\n * and extracts all available default values to create a complete configuration\n * example that can be serialized to YAML.\n * \n * @template T - The Zod schema shape type\n * @param configShape - The user's configuration schema shape\n * @param configDirectory - The configuration directory to include in the defaults\n * @returns An object containing all default values suitable for YAML serialization\n * \n * @example\n * ```typescript\n * const shape = z.object({\n * apiKey: z.string().describe('Your API key'),\n * timeout: z.number().default(5000).describe('Request timeout in milliseconds'),\n * features: z.array(z.string()).default(['auth', 'logging'])\n * }).shape;\n * \n * const config = generateDefaultConfig(shape, './config');\n * // Returns: { timeout: 5000, features: ['auth', 'logging'] }\n * // Note: apiKey is not included since it has no default\n * ```\n */\nexport const generateDefaultConfig = <T extends z.ZodRawShape>(\n configShape: T,\n _configDirectory: string\n): Record<string, any> => {\n // Create the full schema by combining base and user schema\n const fullSchema = z.object({\n ...configShape,\n });\n\n // Extract defaults from the full schema using only explicit defaults\n const defaults = extractSchemaDefaults(fullSchema);\n\n // Don't include configDirectory in the generated file since it's runtime-specific\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { configDirectory: _, ...configDefaults } = defaults || {};\n\n return configDefaults || {};\n}; "],"names":["extractSchemaDefaults","schema","_def","typeName","defaultSchema","defaultValue","unwrappable","unwrapped","unwrap","undefined","objectSchema","result","key","subschema","Object","entries","shape","keys","length","arraySchema","elementDefaults","element","generateDefaultConfig","configShape","_configDirectory","fullSchema","z","object","defaults","configDirectory","_","configDefaults"],"mappings":";;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA6BO,MAAMA,qBAAAA,GAAwB,CAACC,MAAAA,GAAAA;;IAElC,IAAIA,MAAAA,CAAOC,IAAI,IAAID,MAAAA,CAAOC,IAAI,CAACC,QAAQ,KAAK,YAAA,EAAc;AACtD,QAAA,MAAMC,aAAAA,GAAgBH,MAAAA;QACtB,OAAOG,aAAAA,CAAcF,IAAI,CAACG,YAAY,EAAA;AAC1C;;AAGA,IAAA,IAAIJ,OAAOC,IAAI,KAAKD,MAAAA,CAAOC,IAAI,CAACC,QAAQ,KAAK,aAAA,IAAiBF,OAAOC,IAAI,CAACC,QAAQ,KAAK,aAAY,CAAA,EAAI;AACnG,QAAA,MAAMG,WAAAA,GAAcL,MAAAA;QACpB,MAAMM,SAAAA,GAAYD,YAAYE,MAAM,EAAA;;;QAIpC,IAAID,SAAAA,CAAUL,IAAI,IAAIK,SAAAA,CAAUL,IAAI,CAACC,QAAQ,KAAK,YAAA,EAAc;AAC5D,YAAA,OAAOH,qBAAAA,CAAsBO,SAAAA,CAAAA;AACjC;;QAGA,OAAOE,SAAAA;AACX;;IAGA,IAAIR,MAAAA,CAAOC,IAAI,IAAID,MAAAA,CAAOC,IAAI,CAACC,QAAQ,KAAK,WAAA,EAAa;AACrD,QAAA,MAAMO,YAAAA,GAAeT,MAAAA;AACrB,QAAA,MAAMU,SAAc,EAAC;QAErB,KAAK,MAAM,CAACC,GAAAA,EAAKC,SAAAA,CAAU,IAAIC,OAAOC,OAAO,CAACL,YAAAA,CAAaM,KAAK,CAAA,CAAG;AAC/D,YAAA,MAAMX,eAAeL,qBAAAA,CAAsBa,SAAAA,CAAAA;AAC3C,YAAA,IAAIR,iBAAiBI,SAAAA,EAAW;gBAC5BE,MAAM,CAACC,IAAI,GAAGP,YAAAA;AAClB;AACJ;AAEA,QAAA,OAAOS,OAAOG,IAAI,CAACN,QAAQO,MAAM,GAAG,IAAIP,MAAAA,GAASF,SAAAA;AACrD;;IAGA,IAAIR,MAAAA,CAAOC,IAAI,IAAID,MAAAA,CAAOC,IAAI,CAACC,QAAQ,KAAK,UAAA,EAAY;AACpD,QAAA,MAAMgB,WAAAA,GAAclB,MAAAA;QACpB,MAAMmB,eAAAA,GAAkBpB,qBAAAA,CAAsBmB,WAAAA,CAAYE,OAAO,CAAA;;AAEjE,QAAA,OAAOD,oBAAoBX,SAAAA,GAAY;AAACW,YAAAA;AAAgB,SAAA,GAAG,EAAE;AACjE;;IAGA,IAAInB,MAAAA,CAAOC,IAAI,IAAID,MAAAA,CAAOC,IAAI,CAACC,QAAQ,KAAK,WAAA,EAAa;AACrD,QAAA,OAAO,EAAC;AACZ;;IAGA,OAAOM,SAAAA;AACX;AA0EA;;;;;;;;;;;;;;;;;;;;;;;;AAwBC,IACM,MAAMa,qBAAAA,GAAwB,CACjCC,WAAAA,EACAC,gBAAAA,GAAAA;;IAGA,MAAMC,UAAAA,GAAaC,CAAAA,CAAEC,MAAM,CAAC;AACxB,QAAA,GAAGJ;AACP,KAAA,CAAA;;AAGA,IAAA,MAAMK,WAAW5B,qBAAAA,CAAsByB,UAAAA,CAAAA;;;IAIvC,MAAM,EAAEI,iBAAiBC,CAAC,EAAE,GAAGC,cAAAA,EAAgB,GAAGH,YAAY,EAAC;AAE/D,IAAA,OAAOG,kBAAkB,EAAC;AAC9B;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theunwalked/cardigantime",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "description": "cardigantime is a tool to help you time your cardigans.",
5
5
  "type": "module",
6
6
  "main": "./dist/cardigantime.cjs",
@@ -33,34 +33,34 @@
33
33
  "license": "Apache-2.0",
34
34
  "dependencies": {
35
35
  "commander": "^14.0.0",
36
- "dotenv": "^17.0.0",
36
+ "dotenv": "^17.0.1",
37
37
  "glob": "^11.0.3",
38
38
  "js-yaml": "^4.1.0",
39
39
  "winston": "^3.17.0",
40
- "zod": "^3.25.67"
40
+ "zod": "^3.25.71"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@eslint/eslintrc": "^3.3.1",
44
- "@eslint/js": "^9.30.0",
44
+ "@eslint/js": "^9.30.1",
45
45
  "@rollup/plugin-replace": "^6.0.2",
46
46
  "@swc/core": "^1.12.9",
47
47
  "@types/js-yaml": "^4.0.9",
48
48
  "@types/luxon": "^3.6.2",
49
- "@types/node": "^24.0.8",
49
+ "@types/node": "^24.0.10",
50
50
  "@typescript-eslint/eslint-plugin": "^8.35.1",
51
51
  "@typescript-eslint/parser": "^8.35.1",
52
52
  "@vitest/coverage-v8": "^3.2.4",
53
- "eslint": "^9.30.0",
53
+ "eslint": "^9.30.1",
54
54
  "eslint-plugin-import": "^2.32.0",
55
55
  "globals": "^16.3.0",
56
56
  "typescript": "^5.8.3",
57
- "vite": "^7.0.0",
57
+ "vite": "^7.0.1",
58
58
  "vite-plugin-dts": "^4.5.4",
59
- "vite-plugin-node": "^5.0.1",
59
+ "vite-plugin-node": "^7.0.0",
60
60
  "vitest": "^3.2.4"
61
61
  },
62
62
  "scripts": {
63
- "build": "tsc --noEmit && vite build",
63
+ "build": "pnpm run lint && tsc --noEmit && vite build",
64
64
  "start": "dist/main.js",
65
65
  "dev": "vite build --watch",
66
66
  "watch": "vite build --watch",