@utilarium/cardigantime 0.0.24-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +65 -0
- package/README.md +398 -0
- package/dist/cardigantime.cjs +2169 -0
- package/dist/cardigantime.cjs.map +1 -0
- package/dist/cardigantime.d.ts +92 -0
- package/dist/cardigantime.js +198 -0
- package/dist/cardigantime.js.map +1 -0
- package/dist/config/executable-security.d.ts +32 -0
- package/dist/config/format-detector.d.ts +59 -0
- package/dist/configure.d.ts +55 -0
- package/dist/configure.js +125 -0
- package/dist/configure.js.map +1 -0
- package/dist/constants.d.ts +25 -0
- package/dist/constants.js +38 -0
- package/dist/constants.js.map +1 -0
- package/dist/discovery/discoverer.d.ts +62 -0
- package/dist/discovery/hierarchical-modes.d.ts +64 -0
- package/dist/discovery/index.d.ts +15 -0
- package/dist/discovery/patterns.d.ts +77 -0
- package/dist/discovery/root-detection.d.ts +100 -0
- package/dist/discovery/traversal-security.d.ts +106 -0
- package/dist/env/errors.d.ts +18 -0
- package/dist/env/index.d.ts +7 -0
- package/dist/env/naming.d.ts +38 -0
- package/dist/env/parser.d.ts +61 -0
- package/dist/env/reader.d.ts +45 -0
- package/dist/env/resolver.d.ts +25 -0
- package/dist/env/schema-utils.d.ts +33 -0
- package/dist/env/types.d.ts +43 -0
- package/dist/error/ArgumentError.d.ts +31 -0
- package/dist/error/ArgumentError.js +48 -0
- package/dist/error/ArgumentError.js.map +1 -0
- package/dist/error/ConfigParseError.d.ts +26 -0
- package/dist/error/ConfigurationError.d.ts +21 -0
- package/dist/error/ConfigurationError.js +46 -0
- package/dist/error/ConfigurationError.js.map +1 -0
- package/dist/error/FileSystemError.d.ts +30 -0
- package/dist/error/FileSystemError.js +58 -0
- package/dist/error/FileSystemError.js.map +1 -0
- package/dist/error/index.d.ts +4 -0
- package/dist/mcp/discovery.d.ts +105 -0
- package/dist/mcp/errors.d.ts +75 -0
- package/dist/mcp/index.d.ts +22 -0
- package/dist/mcp/integration.d.ts +184 -0
- package/dist/mcp/parser.d.ts +141 -0
- package/dist/mcp/resolver.d.ts +165 -0
- package/dist/mcp/tools/check-config-types.d.ts +208 -0
- package/dist/mcp/tools/check-config.d.ts +85 -0
- package/dist/mcp/tools/index.d.ts +12 -0
- package/dist/mcp/types.d.ts +210 -0
- package/dist/parsers/index.d.ts +25 -0
- package/dist/parsers/javascript-parser.d.ts +12 -0
- package/dist/parsers/json-parser.d.ts +6 -0
- package/dist/parsers/typescript-parser.d.ts +15 -0
- package/dist/parsers/yaml-parser.d.ts +6 -0
- package/dist/read.d.ts +56 -0
- package/dist/read.js +653 -0
- package/dist/read.js.map +1 -0
- package/dist/security/audit-logger.d.ts +135 -0
- package/dist/security/cli-validator.d.ts +73 -0
- package/dist/security/config-validator.d.ts +95 -0
- package/dist/security/defaults.d.ts +17 -0
- package/dist/security/index.d.ts +14 -0
- package/dist/security/numeric-guard.d.ts +111 -0
- package/dist/security/path-guard.d.ts +53 -0
- package/dist/security/profiles.d.ts +127 -0
- package/dist/security/security-validator.d.ts +109 -0
- package/dist/security/string-guard.d.ts +92 -0
- package/dist/security/types.d.ts +126 -0
- package/dist/security/zod-secure-enum.d.ts +20 -0
- package/dist/security/zod-secure-number.d.ts +39 -0
- package/dist/security/zod-secure-path.d.ts +24 -0
- package/dist/security/zod-secure-string.d.ts +38 -0
- package/dist/types.d.ts +584 -0
- package/dist/types.js +56 -0
- package/dist/types.js.map +1 -0
- package/dist/util/hierarchical.d.ts +136 -0
- package/dist/util/hierarchical.js +436 -0
- package/dist/util/hierarchical.js.map +1 -0
- package/dist/util/schema-defaults.d.ts +80 -0
- package/dist/util/schema-defaults.js +118 -0
- package/dist/util/schema-defaults.js.map +1 -0
- package/dist/util/storage.d.ts +31 -0
- package/dist/util/storage.js +154 -0
- package/dist/util/storage.js.map +1 -0
- package/dist/validate.d.ts +113 -0
- package/dist/validate.js +260 -0
- package/dist/validate.js.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hierarchical.js","sources":["../../src/util/hierarchical.ts"],"sourcesContent":["import * as path from 'node: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 isUnsafeKey(key: string): boolean {\n return key === '__proto__' || key === 'constructor' || key === 'prototype';\n}\n\nfunction setNestedValue(obj: any, path: string, value: any): void {\n const keys = path.split('.');\n const lastKey = keys.pop()!;\n\n // Prevent prototype pollution via special property names\n if (isUnsafeKey(lastKey) || keys.some(isUnsafeKey)) {\n return;\n }\n\n const target = keys.reduce((current, key) => {\n // Skip if this is an unsafe key (already checked above, but defensive)\n if (isUnsafeKey(key)) {\n return current;\n }\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 * Tries to find a config file with alternative extensions (.yaml or .yml).\n * \n * @param storage Storage instance to use for file operations\n * @param configDir The directory containing the config file\n * @param configFileName The base config file name (may have .yaml or .yml extension)\n * @param logger Optional logger for debugging\n * @returns Promise resolving to the found config file path or null if not found\n */\nasync function findConfigFileWithExtension(\n storage: any,\n configDir: string,\n configFileName: string,\n logger?: Logger\n): Promise<string | null> {\n const configFilePath = path.join(configDir, configFileName);\n \n // First try the exact filename as specified\n const exists = await storage.exists(configFilePath);\n if (exists) {\n const isReadable = await storage.isFileReadable(configFilePath);\n if (isReadable) {\n return configFilePath;\n }\n }\n \n // If the exact filename doesn't exist or isn't readable, try alternative extensions\n // Only do this if the filename has a .yaml or .yml extension\n const ext = path.extname(configFileName);\n if (ext === '.yaml' || ext === '.yml') {\n const baseName = path.basename(configFileName, ext);\n const alternativeExt = ext === '.yaml' ? '.yml' : '.yaml';\n const alternativePath = path.join(configDir, baseName + alternativeExt);\n \n logger?.debug(`Config file not found at ${configFilePath}, trying alternative: ${alternativePath}`);\n \n const altExists = await storage.exists(alternativePath);\n if (altExists) {\n const altIsReadable = await storage.isFileReadable(alternativePath);\n if (altIsReadable) {\n logger?.debug(`Found config file with alternative extension: ${alternativePath}`);\n return alternativePath;\n }\n }\n }\n \n return null;\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 \n try {\n logger?.verbose(`Attempting to load config file: ${path.join(configDir, configFileName)}`);\n\n // Try to find the config file with alternative extensions\n const configFilePath = await findConfigFileWithExtension(storage, configDir, configFileName, logger);\n \n if (!configFilePath) {\n logger?.debug(`Config file does not exist: ${path.join(configDir, configFileName)}`);\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 ${path.join(configDir, configFileName)}: ${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","isUnsafeKey","keys","lastKey","pop","some","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","findConfigFileWithExtension","configFileName","configFilePath","isFileReadable","ext","extname","baseName","basename","alternativeExt","alternativePath","altExists","altIsReadable","loadConfigFromDirectory","encoding","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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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Extracts default values from a Zod schema recursively using Zod v4's parsing mechanisms.
|
|
4
|
+
*
|
|
5
|
+
* This function leverages Zod's own parsing behavior to extract defaults rather than
|
|
6
|
+
* accessing internal properties. It works by:
|
|
7
|
+
* 1. For ZodDefault types: parsing undefined to trigger the default
|
|
8
|
+
* 2. For ZodObject types: creating a minimal object and parsing to get all defaults
|
|
9
|
+
* 3. For wrapped types: unwrapping and recursing
|
|
10
|
+
*
|
|
11
|
+
* @param schema - The Zod schema to extract defaults from
|
|
12
|
+
* @returns An object containing all default values from the schema
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const schema = z.object({
|
|
17
|
+
* name: z.string().default('app'),
|
|
18
|
+
* port: z.number().default(3000),
|
|
19
|
+
* debug: z.boolean().default(false),
|
|
20
|
+
* database: z.object({
|
|
21
|
+
* host: z.string().default('localhost'),
|
|
22
|
+
* port: z.number().default(5432)
|
|
23
|
+
* })
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* const defaults = extractSchemaDefaults(schema);
|
|
27
|
+
* // Returns: { name: 'app', port: 3000, debug: false, database: { host: 'localhost', port: 5432 } }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare const extractSchemaDefaults: (schema: z.ZodTypeAny) => any;
|
|
31
|
+
/**
|
|
32
|
+
* Extracts default values that should be included in generated config files.
|
|
33
|
+
*
|
|
34
|
+
* This function is similar to extractSchemaDefaults but filters out certain types
|
|
35
|
+
* of defaults that shouldn't appear in generated configuration files, such as
|
|
36
|
+
* computed defaults or system-specific values.
|
|
37
|
+
*
|
|
38
|
+
* @param schema - The Zod schema to extract config file defaults from
|
|
39
|
+
* @returns An object containing default values suitable for config files
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const schema = z.object({
|
|
44
|
+
* appName: z.string().default('my-app'),
|
|
45
|
+
* timestamp: z.number().default(() => Date.now()), // Excluded from config files
|
|
46
|
+
* port: z.number().default(3000)
|
|
47
|
+
* });
|
|
48
|
+
*
|
|
49
|
+
* const configDefaults = extractConfigFileDefaults(schema);
|
|
50
|
+
* // Returns: { appName: 'my-app', port: 3000 }
|
|
51
|
+
* // Note: timestamp is excluded because it's a function-based default
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export declare const extractConfigFileDefaults: (schema: z.ZodTypeAny) => any;
|
|
55
|
+
/**
|
|
56
|
+
* Generates a complete configuration object with all default values populated.
|
|
57
|
+
*
|
|
58
|
+
* This function combines the base ConfigSchema with a user-provided schema shape
|
|
59
|
+
* and extracts all available default values to create a complete configuration
|
|
60
|
+
* example that can be serialized to YAML.
|
|
61
|
+
*
|
|
62
|
+
* @template T - The Zod schema shape type
|
|
63
|
+
* @param configShape - The user's configuration schema shape
|
|
64
|
+
* @param configDirectory - The configuration directory to include in the defaults
|
|
65
|
+
* @returns An object containing all default values suitable for YAML serialization
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* const shape = z.object({
|
|
70
|
+
* apiKey: z.string().describe('Your API key'),
|
|
71
|
+
* timeout: z.number().default(5000).describe('Request timeout in milliseconds'),
|
|
72
|
+
* features: z.array(z.string()).default(['auth', 'logging'])
|
|
73
|
+
* }).shape;
|
|
74
|
+
*
|
|
75
|
+
* const config = generateDefaultConfig(shape, './config');
|
|
76
|
+
* // Returns: { timeout: 5000, features: ['auth', 'logging'] }
|
|
77
|
+
* // Note: apiKey is not included since it has no default
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare const generateDefaultConfig: <T extends z.ZodRawShape>(configShape: T, _configDirectory: string) => Record<string, any>;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Extracts default values from a Zod schema recursively using Zod v4's parsing mechanisms.
|
|
5
|
+
*
|
|
6
|
+
* This function leverages Zod's own parsing behavior to extract defaults rather than
|
|
7
|
+
* accessing internal properties. It works by:
|
|
8
|
+
* 1. For ZodDefault types: parsing undefined to trigger the default
|
|
9
|
+
* 2. For ZodObject types: creating a minimal object and parsing to get all defaults
|
|
10
|
+
* 3. For wrapped types: unwrapping and recursing
|
|
11
|
+
*
|
|
12
|
+
* @param schema - The Zod schema to extract defaults from
|
|
13
|
+
* @returns An object containing all default values from the schema
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const schema = z.object({
|
|
18
|
+
* name: z.string().default('app'),
|
|
19
|
+
* port: z.number().default(3000),
|
|
20
|
+
* debug: z.boolean().default(false),
|
|
21
|
+
* database: z.object({
|
|
22
|
+
* host: z.string().default('localhost'),
|
|
23
|
+
* port: z.number().default(5432)
|
|
24
|
+
* })
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* const defaults = extractSchemaDefaults(schema);
|
|
28
|
+
* // Returns: { name: 'app', port: 3000, debug: false, database: { host: 'localhost', port: 5432 } }
|
|
29
|
+
* ```
|
|
30
|
+
*/ const extractSchemaDefaults = (schema)=>{
|
|
31
|
+
// Handle ZodDefault - parse undefined to get the default value
|
|
32
|
+
if (schema instanceof z.ZodDefault) {
|
|
33
|
+
try {
|
|
34
|
+
return schema.parse(undefined);
|
|
35
|
+
} catch {
|
|
36
|
+
// If parsing undefined fails, return undefined
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Handle ZodOptional and ZodNullable by unwrapping
|
|
41
|
+
if (schema instanceof z.ZodOptional || schema instanceof z.ZodNullable) {
|
|
42
|
+
return extractSchemaDefaults(schema.unwrap());
|
|
43
|
+
}
|
|
44
|
+
// Handle ZodObject - create an object with defaults by parsing an empty object
|
|
45
|
+
if (schema instanceof z.ZodObject) {
|
|
46
|
+
const defaults = {};
|
|
47
|
+
const shape = schema.shape;
|
|
48
|
+
// First, try to extract defaults from individual fields
|
|
49
|
+
for (const [key, subschema] of Object.entries(shape)){
|
|
50
|
+
const defaultValue = extractSchemaDefaults(subschema);
|
|
51
|
+
if (defaultValue !== undefined) {
|
|
52
|
+
defaults[key] = defaultValue;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Then parse an empty object to trigger any schema-level defaults
|
|
56
|
+
const result = schema.safeParse({});
|
|
57
|
+
if (result.success) {
|
|
58
|
+
// Merge the parsed result with our extracted defaults
|
|
59
|
+
return {
|
|
60
|
+
...defaults,
|
|
61
|
+
...result.data
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return Object.keys(defaults).length > 0 ? defaults : undefined;
|
|
65
|
+
}
|
|
66
|
+
// Handle ZodArray - return empty array as a reasonable default
|
|
67
|
+
if (schema instanceof z.ZodArray) {
|
|
68
|
+
const elementDefaults = extractSchemaDefaults(schema.element);
|
|
69
|
+
return elementDefaults !== undefined ? [
|
|
70
|
+
elementDefaults
|
|
71
|
+
] : [];
|
|
72
|
+
}
|
|
73
|
+
// Handle ZodRecord - return empty object as default
|
|
74
|
+
if (schema instanceof z.ZodRecord) {
|
|
75
|
+
return {};
|
|
76
|
+
}
|
|
77
|
+
// No default available for other schema types
|
|
78
|
+
return undefined;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Generates a complete configuration object with all default values populated.
|
|
82
|
+
*
|
|
83
|
+
* This function combines the base ConfigSchema with a user-provided schema shape
|
|
84
|
+
* and extracts all available default values to create a complete configuration
|
|
85
|
+
* example that can be serialized to YAML.
|
|
86
|
+
*
|
|
87
|
+
* @template T - The Zod schema shape type
|
|
88
|
+
* @param configShape - The user's configuration schema shape
|
|
89
|
+
* @param configDirectory - The configuration directory to include in the defaults
|
|
90
|
+
* @returns An object containing all default values suitable for YAML serialization
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* const shape = z.object({
|
|
95
|
+
* apiKey: z.string().describe('Your API key'),
|
|
96
|
+
* timeout: z.number().default(5000).describe('Request timeout in milliseconds'),
|
|
97
|
+
* features: z.array(z.string()).default(['auth', 'logging'])
|
|
98
|
+
* }).shape;
|
|
99
|
+
*
|
|
100
|
+
* const config = generateDefaultConfig(shape, './config');
|
|
101
|
+
* // Returns: { timeout: 5000, features: ['auth', 'logging'] }
|
|
102
|
+
* // Note: apiKey is not included since it has no default
|
|
103
|
+
* ```
|
|
104
|
+
*/ const generateDefaultConfig = (configShape, _configDirectory)=>{
|
|
105
|
+
// Create the full schema by combining base and user schema
|
|
106
|
+
const fullSchema = z.object({
|
|
107
|
+
...configShape
|
|
108
|
+
});
|
|
109
|
+
// Extract defaults from the full schema using only explicit defaults
|
|
110
|
+
const defaults = extractSchemaDefaults(fullSchema);
|
|
111
|
+
// Don't include configDirectory in the generated file since it's runtime-specific
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
113
|
+
const { configDirectory: _, ...configDefaults } = defaults || {};
|
|
114
|
+
return configDefaults || {};
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export { extractSchemaDefaults, generateDefaultConfig };
|
|
118
|
+
//# sourceMappingURL=schema-defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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 using Zod v4's parsing mechanisms.\n *\n * This function leverages Zod's own parsing behavior to extract defaults rather than\n * accessing internal properties. It works by:\n * 1. For ZodDefault types: parsing undefined to trigger the default\n * 2. For ZodObject types: creating a minimal object and parsing to get all defaults\n * 3. For wrapped types: unwrapping and recursing\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 - parse undefined to get the default value\n if (schema instanceof z.ZodDefault) {\n try {\n return schema.parse(undefined);\n } catch {\n // If parsing undefined fails, return undefined\n return undefined;\n }\n }\n\n // Handle ZodOptional and ZodNullable by unwrapping\n if (schema instanceof z.ZodOptional || schema instanceof z.ZodNullable) {\n return extractSchemaDefaults(schema.unwrap() as any);\n }\n\n // Handle ZodObject - create an object with defaults by parsing an empty object\n if (schema instanceof z.ZodObject) {\n const defaults: any = {};\n const shape = schema.shape;\n\n // First, try to extract defaults from individual fields\n for (const [key, subschema] of Object.entries(shape)) {\n const defaultValue = extractSchemaDefaults(subschema as any);\n if (defaultValue !== undefined) {\n defaults[key] = defaultValue;\n }\n }\n\n // Then parse an empty object to trigger any schema-level defaults\n const result = schema.safeParse({});\n if (result.success) {\n // Merge the parsed result with our extracted defaults\n return { ...defaults, ...result.data };\n }\n\n return Object.keys(defaults).length > 0 ? defaults : undefined;\n }\n\n // Handle ZodArray - return empty array as a reasonable default\n if (schema instanceof z.ZodArray) {\n const elementDefaults = extractSchemaDefaults(schema.element as any);\n return elementDefaults !== undefined ? [elementDefaults] : [];\n }\n\n // Handle ZodRecord - return empty object as default\n if (schema instanceof z.ZodRecord) {\n return {};\n }\n\n // No default available for other schema types\n return undefined;\n};\n\n/**\n * Extracts default values that should be included in generated config files.\n *\n * This function is similar to extractSchemaDefaults but filters out certain types\n * of defaults that shouldn't appear in generated configuration files, such as\n * computed defaults or system-specific values.\n *\n * @param schema - The Zod schema to extract config file defaults from\n * @returns An object containing default values suitable for config files\n *\n * @example\n * ```typescript\n * const schema = z.object({\n * appName: z.string().default('my-app'),\n * timestamp: z.number().default(() => Date.now()), // Excluded from config files\n * port: z.number().default(3000)\n * });\n *\n * const configDefaults = extractConfigFileDefaults(schema);\n * // Returns: { appName: 'my-app', port: 3000 }\n * // Note: timestamp is excluded because it's a function-based default\n * ```\n */\nexport const extractConfigFileDefaults = (schema: z.ZodTypeAny): any => {\n // Handle ZodDefault - parse undefined to get the default value\n if (schema instanceof z.ZodDefault) {\n try {\n const defaultValue = schema.parse(undefined);\n // Exclude function-generated defaults from config files\n // These are typically runtime-computed values\n if (typeof defaultValue === 'function') {\n return undefined;\n }\n return defaultValue;\n } catch {\n return undefined;\n }\n }\n\n // Handle ZodOptional and ZodNullable by unwrapping\n if (schema instanceof z.ZodOptional || schema instanceof z.ZodNullable) {\n return extractConfigFileDefaults(schema.unwrap() as any);\n }\n\n // Handle ZodObject - extract defaults suitable for config files\n if (schema instanceof z.ZodObject) {\n const defaults: any = {};\n const shape = schema.shape;\n\n for (const [key, subschema] of Object.entries(shape)) {\n const defaultValue = extractConfigFileDefaults(subschema as any);\n if (defaultValue !== undefined) {\n defaults[key] = defaultValue;\n }\n }\n\n // Parse an empty object to get any schema-level defaults\n const result = schema.safeParse({});\n if (result.success) {\n // Filter out any function-based or computed values\n const filteredData: any = {};\n for (const [key, value] of Object.entries(result.data)) {\n if (typeof value !== 'function' && value !== null) {\n filteredData[key] = value;\n }\n }\n return { ...defaults, ...filteredData };\n }\n\n return Object.keys(defaults).length > 0 ? defaults : undefined;\n }\n\n // Handle ZodArray - typically don't include array defaults in config files\n if (schema instanceof z.ZodArray) {\n // For config files, we usually don't want to pre-populate arrays\n return undefined;\n }\n\n // Handle ZodRecord - return empty object as default for config files\n if (schema instanceof z.ZodRecord) {\n return {};\n }\n\n // No default available for other schema types\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};\n\n"],"names":["extractSchemaDefaults","schema","z","ZodDefault","parse","undefined","ZodOptional","ZodNullable","unwrap","ZodObject","defaults","shape","key","subschema","Object","entries","defaultValue","result","safeParse","success","data","keys","length","ZodArray","elementDefaults","element","ZodRecord","generateDefaultConfig","configShape","_configDirectory","fullSchema","object","configDirectory","_","configDefaults"],"mappings":";;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4BO,MAAMA,qBAAAA,GAAwB,CAACC,MAAAA,GAAAA;;IAElC,IAAIA,MAAAA,YAAkBC,CAAAA,CAAEC,UAAU,EAAE;QAChC,IAAI;YACA,OAAOF,MAAAA,CAAOG,KAAK,CAACC,SAAAA,CAAAA;AACxB,QAAA,CAAA,CAAE,OAAM;;YAEJ,OAAOA,SAAAA;AACX,QAAA;AACJ,IAAA;;AAGA,IAAA,IAAIJ,kBAAkBC,CAAAA,CAAEI,WAAW,IAAIL,MAAAA,YAAkBC,CAAAA,CAAEK,WAAW,EAAE;QACpE,OAAOP,qBAAAA,CAAsBC,OAAOO,MAAM,EAAA,CAAA;AAC9C,IAAA;;IAGA,IAAIP,MAAAA,YAAkBC,CAAAA,CAAEO,SAAS,EAAE;AAC/B,QAAA,MAAMC,WAAgB,EAAC;QACvB,MAAMC,KAAAA,GAAQV,OAAOU,KAAK;;QAG1B,KAAK,MAAM,CAACC,GAAAA,EAAKC,SAAAA,CAAU,IAAIC,MAAAA,CAAOC,OAAO,CAACJ,KAAAA,CAAAA,CAAQ;AAClD,YAAA,MAAMK,eAAehB,qBAAAA,CAAsBa,SAAAA,CAAAA;AAC3C,YAAA,IAAIG,iBAAiBX,SAAAA,EAAW;gBAC5BK,QAAQ,CAACE,IAAI,GAAGI,YAAAA;AACpB,YAAA;AACJ,QAAA;;AAGA,QAAA,MAAMC,MAAAA,GAAShB,MAAAA,CAAOiB,SAAS,CAAC,EAAC,CAAA;QACjC,IAAID,MAAAA,CAAOE,OAAO,EAAE;;YAEhB,OAAO;AAAE,gBAAA,GAAGT,QAAQ;AAAE,gBAAA,GAAGO,OAAOG;AAAK,aAAA;AACzC,QAAA;AAEA,QAAA,OAAON,OAAOO,IAAI,CAACX,UAAUY,MAAM,GAAG,IAAIZ,QAAAA,GAAWL,SAAAA;AACzD,IAAA;;IAGA,IAAIJ,MAAAA,YAAkBC,CAAAA,CAAEqB,QAAQ,EAAE;QAC9B,MAAMC,eAAAA,GAAkBxB,qBAAAA,CAAsBC,MAAAA,CAAOwB,OAAO,CAAA;AAC5D,QAAA,OAAOD,oBAAoBnB,SAAAA,GAAY;AAACmB,YAAAA;AAAgB,SAAA,GAAG,EAAE;AACjE,IAAA;;IAGA,IAAIvB,MAAAA,YAAkBC,CAAAA,CAAEwB,SAAS,EAAE;AAC/B,QAAA,OAAO,EAAC;AACZ,IAAA;;IAGA,OAAOrB,SAAAA;AACX;AAyFA;;;;;;;;;;;;;;;;;;;;;;;;AAwBC,IACM,MAAMsB,qBAAAA,GAAwB,CACjCC,WAAAA,EACAC,gBAAAA,GAAAA;;IAGA,MAAMC,UAAAA,GAAa5B,CAAAA,CAAE6B,MAAM,CAAC;AACxB,QAAA,GAAGH;AACP,KAAA,CAAA;;AAGA,IAAA,MAAMlB,WAAWV,qBAAAA,CAAsB8B,UAAAA,CAAAA;;;IAIvC,MAAM,EAAEE,iBAAiBC,CAAC,EAAE,GAAGC,cAAAA,EAAgB,GAAGxB,YAAY,EAAC;AAE/D,IAAA,OAAOwB,kBAAkB,EAAC;AAC9B;;;;"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
/**
|
|
3
|
+
* This module exists to isolate filesystem operations from the rest of the codebase.
|
|
4
|
+
* This makes testing easier by avoiding direct fs mocking in jest configuration.
|
|
5
|
+
*
|
|
6
|
+
* Additionally, abstracting storage operations allows for future flexibility -
|
|
7
|
+
* this export utility may need to work with storage systems other than the local filesystem
|
|
8
|
+
* (e.g. S3, Google Cloud Storage, etc).
|
|
9
|
+
*/
|
|
10
|
+
export interface Utility {
|
|
11
|
+
exists: (path: string) => Promise<boolean>;
|
|
12
|
+
isDirectory: (path: string) => Promise<boolean>;
|
|
13
|
+
isFile: (path: string) => Promise<boolean>;
|
|
14
|
+
isReadable: (path: string) => Promise<boolean>;
|
|
15
|
+
isWritable: (path: string) => Promise<boolean>;
|
|
16
|
+
isFileReadable: (path: string) => Promise<boolean>;
|
|
17
|
+
isDirectoryWritable: (path: string) => Promise<boolean>;
|
|
18
|
+
isDirectoryReadable: (path: string) => Promise<boolean>;
|
|
19
|
+
createDirectory: (path: string) => Promise<void>;
|
|
20
|
+
readFile: (path: string, encoding: string) => Promise<string>;
|
|
21
|
+
readStream: (path: string) => Promise<fs.ReadStream>;
|
|
22
|
+
writeFile: (path: string, data: string | Buffer, encoding: string) => Promise<void>;
|
|
23
|
+
forEachFileIn: (directory: string, callback: (path: string) => Promise<void>, options?: {
|
|
24
|
+
pattern: string;
|
|
25
|
+
}) => Promise<void>;
|
|
26
|
+
hashFile: (path: string, length: number) => Promise<string>;
|
|
27
|
+
listFiles: (directory: string) => Promise<string[]>;
|
|
28
|
+
}
|
|
29
|
+
export declare const create: (params: {
|
|
30
|
+
log?: (message: string, ...args: any[]) => void;
|
|
31
|
+
}) => Utility;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import { glob } from 'glob';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import * as crypto from 'node:crypto';
|
|
5
|
+
import { FileSystemError } from '../error/FileSystemError.js';
|
|
6
|
+
|
|
7
|
+
const create = (params)=>{
|
|
8
|
+
// eslint-disable-next-line no-console
|
|
9
|
+
const log = params.log || console.log;
|
|
10
|
+
const exists = async (path)=>{
|
|
11
|
+
try {
|
|
12
|
+
await fs.promises.stat(path);
|
|
13
|
+
return true;
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
15
|
+
} catch (error) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
const isDirectory = async (path)=>{
|
|
20
|
+
const stats = await fs.promises.stat(path);
|
|
21
|
+
if (!stats.isDirectory()) {
|
|
22
|
+
log(`${path} is not a directory`);
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
};
|
|
27
|
+
const isFile = async (path)=>{
|
|
28
|
+
const stats = await fs.promises.stat(path);
|
|
29
|
+
if (!stats.isFile()) {
|
|
30
|
+
log(`${path} is not a file`);
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
return true;
|
|
34
|
+
};
|
|
35
|
+
const isReadable = async (path)=>{
|
|
36
|
+
try {
|
|
37
|
+
await fs.promises.access(path, fs.constants.R_OK);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
log(`${path} is not readable: %s %s`, error.message, error.stack);
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
};
|
|
44
|
+
const isWritable = async (path)=>{
|
|
45
|
+
try {
|
|
46
|
+
await fs.promises.access(path, fs.constants.W_OK);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
log(`${path} is not writable: %s %s`, error.message, error.stack);
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return true;
|
|
52
|
+
};
|
|
53
|
+
const isFileReadable = async (path)=>{
|
|
54
|
+
return await exists(path) && await isFile(path) && await isReadable(path);
|
|
55
|
+
};
|
|
56
|
+
const isDirectoryWritable = async (path)=>{
|
|
57
|
+
return await exists(path) && await isDirectory(path) && await isWritable(path);
|
|
58
|
+
};
|
|
59
|
+
const isDirectoryReadable = async (path)=>{
|
|
60
|
+
return await exists(path) && await isDirectory(path) && await isReadable(path);
|
|
61
|
+
};
|
|
62
|
+
const createDirectory = async (path)=>{
|
|
63
|
+
try {
|
|
64
|
+
await fs.promises.mkdir(path, {
|
|
65
|
+
recursive: true
|
|
66
|
+
});
|
|
67
|
+
} catch (mkdirError) {
|
|
68
|
+
throw FileSystemError.directoryCreationFailed(path, mkdirError);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const readFile = async (path, encoding)=>{
|
|
72
|
+
// Validate encoding parameter
|
|
73
|
+
const validEncodings = [
|
|
74
|
+
'utf8',
|
|
75
|
+
'utf-8',
|
|
76
|
+
'ascii',
|
|
77
|
+
'latin1',
|
|
78
|
+
'base64',
|
|
79
|
+
'hex',
|
|
80
|
+
'utf16le',
|
|
81
|
+
'ucs2',
|
|
82
|
+
'ucs-2'
|
|
83
|
+
];
|
|
84
|
+
if (!validEncodings.includes(encoding.toLowerCase())) {
|
|
85
|
+
throw new Error('Invalid encoding specified');
|
|
86
|
+
}
|
|
87
|
+
// Check file size before reading to prevent DoS
|
|
88
|
+
try {
|
|
89
|
+
const stats = await fs.promises.stat(path);
|
|
90
|
+
const maxFileSize = 10 * 1024 * 1024; // 10MB limit
|
|
91
|
+
if (stats.size > maxFileSize) {
|
|
92
|
+
throw new Error('File too large to process');
|
|
93
|
+
}
|
|
94
|
+
} catch (error) {
|
|
95
|
+
if (error.code === 'ENOENT') {
|
|
96
|
+
throw FileSystemError.fileNotFound(path);
|
|
97
|
+
}
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
return await fs.promises.readFile(path, {
|
|
101
|
+
encoding: encoding
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
const writeFile = async (path, data, encoding)=>{
|
|
105
|
+
await fs.promises.writeFile(path, data, {
|
|
106
|
+
encoding: encoding
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
const forEachFileIn = async (directory, callback, options = {
|
|
110
|
+
pattern: '*.*'
|
|
111
|
+
})=>{
|
|
112
|
+
try {
|
|
113
|
+
const files = await glob(options.pattern, {
|
|
114
|
+
cwd: directory,
|
|
115
|
+
nodir: true
|
|
116
|
+
});
|
|
117
|
+
for (const file of files){
|
|
118
|
+
await callback(path.join(directory, file));
|
|
119
|
+
}
|
|
120
|
+
} catch (err) {
|
|
121
|
+
throw FileSystemError.operationFailed(`glob pattern ${options.pattern}`, directory, err);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
const readStream = async (path)=>{
|
|
125
|
+
return fs.createReadStream(path);
|
|
126
|
+
};
|
|
127
|
+
const hashFile = async (path, length)=>{
|
|
128
|
+
const file = await readFile(path, 'utf8');
|
|
129
|
+
return crypto.createHash('sha256').update(file).digest('hex').slice(0, length);
|
|
130
|
+
};
|
|
131
|
+
const listFiles = async (directory)=>{
|
|
132
|
+
return await fs.promises.readdir(directory);
|
|
133
|
+
};
|
|
134
|
+
return {
|
|
135
|
+
exists,
|
|
136
|
+
isDirectory,
|
|
137
|
+
isFile,
|
|
138
|
+
isReadable,
|
|
139
|
+
isWritable,
|
|
140
|
+
isFileReadable,
|
|
141
|
+
isDirectoryWritable,
|
|
142
|
+
isDirectoryReadable,
|
|
143
|
+
createDirectory,
|
|
144
|
+
readFile,
|
|
145
|
+
readStream,
|
|
146
|
+
writeFile,
|
|
147
|
+
forEachFileIn,
|
|
148
|
+
hashFile,
|
|
149
|
+
listFiles
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export { create };
|
|
154
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sources":["../../src/util/storage.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport { glob } from 'glob';\nimport * as path from 'node:path';\nimport * as crypto from 'node:crypto';\nimport { FileSystemError } from '../error/FileSystemError';\n/**\n * This module exists to isolate filesystem operations from the rest of the codebase.\n * This makes testing easier by avoiding direct fs mocking in jest configuration.\n * \n * Additionally, abstracting storage operations allows for future flexibility - \n * this export utility may need to work with storage systems other than the local filesystem\n * (e.g. S3, Google Cloud Storage, etc).\n */\n\nexport interface Utility {\n exists: (path: string) => Promise<boolean>;\n isDirectory: (path: string) => Promise<boolean>;\n isFile: (path: string) => Promise<boolean>;\n isReadable: (path: string) => Promise<boolean>;\n isWritable: (path: string) => Promise<boolean>;\n isFileReadable: (path: string) => Promise<boolean>;\n isDirectoryWritable: (path: string) => Promise<boolean>;\n isDirectoryReadable: (path: string) => Promise<boolean>;\n createDirectory: (path: string) => Promise<void>;\n readFile: (path: string, encoding: string) => Promise<string>;\n readStream: (path: string) => Promise<fs.ReadStream>;\n writeFile: (path: string, data: string | Buffer, encoding: string) => Promise<void>;\n forEachFileIn: (directory: string, callback: (path: string) => Promise<void>, options?: { pattern: string }) => Promise<void>;\n hashFile: (path: string, length: number) => Promise<string>;\n listFiles: (directory: string) => Promise<string[]>;\n}\n\nexport const create = (params: { log?: (message: string, ...args: any[]) => void }): Utility => {\n\n // eslint-disable-next-line no-console\n const log = params.log || console.log;\n\n const exists = async (path: string): Promise<boolean> => {\n try {\n await fs.promises.stat(path);\n return true;\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (error: any) {\n return false;\n }\n }\n\n const isDirectory = async (path: string): Promise<boolean> => {\n const stats = await fs.promises.stat(path);\n if (!stats.isDirectory()) {\n log(`${path} is not a directory`);\n return false;\n }\n return true;\n }\n\n const isFile = async (path: string): Promise<boolean> => {\n const stats = await fs.promises.stat(path);\n if (!stats.isFile()) {\n log(`${path} is not a file`);\n return false;\n }\n return true;\n }\n\n const isReadable = async (path: string): Promise<boolean> => {\n try {\n await fs.promises.access(path, fs.constants.R_OK);\n } catch (error: any) {\n log(`${path} is not readable: %s %s`, error.message, error.stack);\n return false;\n }\n return true;\n }\n\n const isWritable = async (path: string): Promise<boolean> => {\n try {\n await fs.promises.access(path, fs.constants.W_OK);\n } catch (error: any) {\n log(`${path} is not writable: %s %s`, error.message, error.stack);\n return false;\n }\n return true;\n }\n\n const isFileReadable = async (path: string): Promise<boolean> => {\n return await exists(path) && await isFile(path) && await isReadable(path);\n }\n\n const isDirectoryWritable = async (path: string): Promise<boolean> => {\n return await exists(path) && await isDirectory(path) && await isWritable(path);\n }\n\n const isDirectoryReadable = async (path: string): Promise<boolean> => {\n return await exists(path) && await isDirectory(path) && await isReadable(path);\n }\n\n const createDirectory = async (path: string): Promise<void> => {\n try {\n await fs.promises.mkdir(path, { recursive: true });\n } catch (mkdirError: any) {\n throw FileSystemError.directoryCreationFailed(path, mkdirError);\n }\n }\n\n const readFile = async (path: string, encoding: string): Promise<string> => {\n // Validate encoding parameter\n const validEncodings = ['utf8', 'utf-8', 'ascii', 'latin1', 'base64', 'hex', 'utf16le', 'ucs2', 'ucs-2'];\n if (!validEncodings.includes(encoding.toLowerCase())) {\n throw new Error('Invalid encoding specified');\n }\n\n // Check file size before reading to prevent DoS\n try {\n const stats = await fs.promises.stat(path);\n const maxFileSize = 10 * 1024 * 1024; // 10MB limit\n if (stats.size > maxFileSize) {\n throw new Error('File too large to process');\n }\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n throw FileSystemError.fileNotFound(path);\n }\n throw error;\n }\n\n return await fs.promises.readFile(path, { encoding: encoding as BufferEncoding });\n }\n\n const writeFile = async (path: string, data: string | Buffer, encoding: string): Promise<void> => {\n await fs.promises.writeFile(path, data, { encoding: encoding as BufferEncoding });\n }\n\n const forEachFileIn = async (directory: string, callback: (file: string) => Promise<void>, options: { pattern: string | string[] } = { pattern: '*.*' }): Promise<void> => {\n try {\n const files = await glob(options.pattern, { cwd: directory, nodir: true });\n for (const file of files) {\n await callback(path.join(directory, file));\n }\n } catch (err: any) {\n throw FileSystemError.operationFailed(`glob pattern ${options.pattern}`, directory, err);\n }\n }\n\n const readStream = async (path: string): Promise<fs.ReadStream> => {\n return fs.createReadStream(path);\n }\n\n const hashFile = async (path: string, length: number): Promise<string> => {\n const file = await readFile(path, 'utf8');\n return crypto.createHash('sha256').update(file).digest('hex').slice(0, length);\n }\n\n const listFiles = async (directory: string): Promise<string[]> => {\n return await fs.promises.readdir(directory);\n }\n\n return {\n exists,\n isDirectory,\n isFile,\n isReadable,\n isWritable,\n isFileReadable,\n isDirectoryWritable,\n isDirectoryReadable,\n createDirectory,\n readFile,\n readStream,\n writeFile,\n forEachFileIn,\n hashFile,\n listFiles,\n };\n}"],"names":["create","params","log","console","exists","path","fs","promises","stat","error","isDirectory","stats","isFile","isReadable","access","constants","R_OK","message","stack","isWritable","W_OK","isFileReadable","isDirectoryWritable","isDirectoryReadable","createDirectory","mkdir","recursive","mkdirError","FileSystemError","directoryCreationFailed","readFile","encoding","validEncodings","includes","toLowerCase","Error","maxFileSize","size","code","fileNotFound","writeFile","data","forEachFileIn","directory","callback","options","pattern","files","glob","cwd","nodir","file","join","err","operationFailed","readStream","createReadStream","hashFile","length","crypto","createHash","update","digest","slice","listFiles","readdir"],"mappings":"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"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { z, ZodObject } from 'zod';
|
|
2
|
+
import { ArgumentError } from './error/ArgumentError';
|
|
3
|
+
import { ConfigurationError } from './error/ConfigurationError';
|
|
4
|
+
import { FileSystemError } from './error/FileSystemError';
|
|
5
|
+
import { ConfigSchema, Logger, Options } from './types';
|
|
6
|
+
export { ArgumentError, ConfigurationError, FileSystemError };
|
|
7
|
+
/**
|
|
8
|
+
* Recursively extracts all keys from a Zod schema in dot notation.
|
|
9
|
+
*
|
|
10
|
+
* This function traverses a Zod schema structure and builds a flat list
|
|
11
|
+
* of all possible keys, using dot notation for nested objects. It handles
|
|
12
|
+
* optional/nullable types by unwrapping them and supports arrays by
|
|
13
|
+
* introspecting their element type.
|
|
14
|
+
*
|
|
15
|
+
* Special handling for:
|
|
16
|
+
* - ZodOptional/ZodNullable: Unwraps to get the underlying type
|
|
17
|
+
* - ZodAny/ZodRecord: Accepts any keys, returns the prefix or empty array
|
|
18
|
+
* - ZodArray: Introspects the element type
|
|
19
|
+
* - ZodObject: Recursively processes all shape properties
|
|
20
|
+
*
|
|
21
|
+
* @param schema - The Zod schema to introspect
|
|
22
|
+
* @param prefix - Internal parameter for building nested key paths
|
|
23
|
+
* @returns Array of strings representing all possible keys in dot notation
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const schema = z.object({
|
|
28
|
+
* user: z.object({
|
|
29
|
+
* name: z.string(),
|
|
30
|
+
* settings: z.object({ theme: z.string() })
|
|
31
|
+
* }),
|
|
32
|
+
* debug: z.boolean()
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* const keys = listZodKeys(schema);
|
|
36
|
+
* // Returns: ['user.name', 'user.settings.theme', 'debug']
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare const listZodKeys: (schema: z.ZodTypeAny, prefix?: string) => string[];
|
|
40
|
+
/**
|
|
41
|
+
* Generates a list of all keys within a JavaScript object, using dot notation for nested keys.
|
|
42
|
+
* Mimics the behavior of listZodKeys but operates on plain objects.
|
|
43
|
+
* For arrays, it inspects the first element that is a plain object to determine nested keys.
|
|
44
|
+
* If an array contains no plain objects, or is empty, the key for the array itself is listed.
|
|
45
|
+
*
|
|
46
|
+
* @param obj The object to introspect.
|
|
47
|
+
* @param prefix Internal use for recursion: the prefix for the current nesting level.
|
|
48
|
+
* @returns An array of strings representing all keys in dot notation.
|
|
49
|
+
*/
|
|
50
|
+
export declare const listObjectKeys: (obj: Record<string, unknown>, prefix?: string) => string[];
|
|
51
|
+
/**
|
|
52
|
+
* Validates that the configuration object contains only keys allowed by the schema.
|
|
53
|
+
*
|
|
54
|
+
* This function prevents configuration errors by detecting typos or extra keys
|
|
55
|
+
* that aren't defined in the Zod schema. It intelligently handles:
|
|
56
|
+
* - ZodRecord types that accept arbitrary keys
|
|
57
|
+
* - Nested objects and their key structures
|
|
58
|
+
* - Arrays and their element key structures
|
|
59
|
+
*
|
|
60
|
+
* The function throws a ConfigurationError if extra keys are found, providing
|
|
61
|
+
* helpful information about what keys are allowed vs. what was found.
|
|
62
|
+
*
|
|
63
|
+
* @param mergedSources - The merged configuration object to validate
|
|
64
|
+
* @param fullSchema - The complete Zod schema including base and user schemas
|
|
65
|
+
* @param logger - Logger for error reporting
|
|
66
|
+
* @throws {ConfigurationError} When extra keys are found that aren't in the schema
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const schema = z.object({ name: z.string(), age: z.number() });
|
|
71
|
+
* const config = { name: 'John', age: 30, typo: 'invalid' };
|
|
72
|
+
*
|
|
73
|
+
* checkForExtraKeys(config, schema, console);
|
|
74
|
+
* // Throws: ConfigurationError with details about 'typo' being an extra key
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export declare const checkForExtraKeys: (mergedSources: object, fullSchema: ZodObject<any>, logger: Logger | typeof console) => void;
|
|
78
|
+
/**
|
|
79
|
+
* Validates a configuration object against the combined Zod schema.
|
|
80
|
+
*
|
|
81
|
+
* This is the main validation function that:
|
|
82
|
+
* 1. Validates the configuration directory (if config feature enabled)
|
|
83
|
+
* 2. Combines the base ConfigSchema with user-provided schema shape
|
|
84
|
+
* 3. Checks for extra keys not defined in the schema
|
|
85
|
+
* 4. Validates all values against their schema definitions
|
|
86
|
+
* 5. Provides detailed error reporting for validation failures
|
|
87
|
+
*
|
|
88
|
+
* The validation is comprehensive and catches common configuration errors
|
|
89
|
+
* including typos, missing required fields, wrong types, and invalid values.
|
|
90
|
+
*
|
|
91
|
+
* @template T - The Zod schema shape type for configuration validation
|
|
92
|
+
* @param config - The merged configuration object to validate
|
|
93
|
+
* @param options - Cardigantime options containing schema, defaults, and logger
|
|
94
|
+
* @throws {ConfigurationError} When configuration validation fails
|
|
95
|
+
* @throws {FileSystemError} When configuration directory validation fails
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* const schema = z.object({
|
|
100
|
+
* apiKey: z.string().min(1),
|
|
101
|
+
* timeout: z.number().positive(),
|
|
102
|
+
* });
|
|
103
|
+
*
|
|
104
|
+
* await validate(config, {
|
|
105
|
+
* configShape: schema.shape,
|
|
106
|
+
* defaults: { configDirectory: './config', isRequired: true },
|
|
107
|
+
* logger: console,
|
|
108
|
+
* features: ['config']
|
|
109
|
+
* });
|
|
110
|
+
* // Throws detailed errors if validation fails
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
export declare const validate: <T extends z.ZodRawShape>(config: z.infer<ZodObject<T & typeof ConfigSchema.shape>>, options: Options<T>) => Promise<void>;
|