@theunwalked/cardigantime 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +136 -1
- package/dist/cardigantime.cjs +250 -29
- package/dist/cardigantime.cjs.map +1 -1
- package/dist/cardigantime.d.ts +17 -0
- package/dist/cardigantime.js +17 -0
- package/dist/cardigantime.js.map +1 -1
- package/dist/constants.js +2 -1
- package/dist/constants.js.map +1 -1
- package/dist/read.js +74 -3
- package/dist/read.js.map +1 -1
- package/dist/types.d.ts +42 -0
- package/dist/types.js.map +1 -1
- package/dist/util/hierarchical.d.ts +25 -11
- package/dist/util/hierarchical.js +157 -25
- package/dist/util/hierarchical.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,6 +2,62 @@ import path__default from 'path';
|
|
|
2
2
|
import * as yaml from 'js-yaml';
|
|
3
3
|
import { create } from './storage.js';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Resolves relative paths in configuration values relative to the configuration file's directory.
|
|
7
|
+
*/ function resolveConfigPaths(config, configDir, pathFields = [], resolvePathArray = []) {
|
|
8
|
+
if (!config || typeof config !== 'object' || pathFields.length === 0) {
|
|
9
|
+
return config;
|
|
10
|
+
}
|
|
11
|
+
const resolvedConfig = {
|
|
12
|
+
...config
|
|
13
|
+
};
|
|
14
|
+
for (const fieldPath of pathFields){
|
|
15
|
+
const value = getNestedValue(resolvedConfig, fieldPath);
|
|
16
|
+
if (value !== undefined) {
|
|
17
|
+
const shouldResolveArrayElements = resolvePathArray.includes(fieldPath);
|
|
18
|
+
const resolvedValue = resolvePathValue(value, configDir, shouldResolveArrayElements);
|
|
19
|
+
setNestedValue(resolvedConfig, fieldPath, resolvedValue);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return resolvedConfig;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Gets a nested value from an object using dot notation.
|
|
26
|
+
*/ function getNestedValue(obj, path) {
|
|
27
|
+
return path.split('.').reduce((current, key)=>current === null || current === void 0 ? void 0 : current[key], obj);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Sets a nested value in an object using dot notation.
|
|
31
|
+
*/ function setNestedValue(obj, path, value) {
|
|
32
|
+
const keys = path.split('.');
|
|
33
|
+
const lastKey = keys.pop();
|
|
34
|
+
const target = keys.reduce((current, key)=>{
|
|
35
|
+
if (!(key in current)) {
|
|
36
|
+
current[key] = {};
|
|
37
|
+
}
|
|
38
|
+
return current[key];
|
|
39
|
+
}, obj);
|
|
40
|
+
target[lastKey] = value;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Resolves a path value (string or array of strings) relative to the config directory.
|
|
44
|
+
*/ function resolvePathValue(value, configDir, resolveArrayElements) {
|
|
45
|
+
if (typeof value === 'string') {
|
|
46
|
+
return resolveSinglePath(value, configDir);
|
|
47
|
+
}
|
|
48
|
+
if (Array.isArray(value) && resolveArrayElements) {
|
|
49
|
+
return value.map((item)=>typeof item === 'string' ? resolveSinglePath(item, configDir) : item);
|
|
50
|
+
}
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Resolves a single path string relative to the config directory if it's a relative path.
|
|
55
|
+
*/ function resolveSinglePath(pathStr, configDir) {
|
|
56
|
+
if (!pathStr || path__default.isAbsolute(pathStr)) {
|
|
57
|
+
return pathStr;
|
|
58
|
+
}
|
|
59
|
+
return path__default.resolve(configDir, pathStr);
|
|
60
|
+
}
|
|
5
61
|
/**
|
|
6
62
|
* Discovers configuration directories by traversing up the directory tree.
|
|
7
63
|
*
|
|
@@ -80,8 +136,10 @@ import { create } from './storage.js';
|
|
|
80
136
|
* @param configFileName Name of the configuration file
|
|
81
137
|
* @param encoding File encoding
|
|
82
138
|
* @param logger Optional logger
|
|
139
|
+
* @param pathFields Optional array of field names that contain paths to be resolved
|
|
140
|
+
* @param resolvePathArray Optional array of field names whose array elements should all be resolved as paths
|
|
83
141
|
* @returns Promise resolving to parsed configuration object or null if not found
|
|
84
|
-
*/ async function loadConfigFromDirectory(configDir, configFileName, encoding = 'utf8', logger) {
|
|
142
|
+
*/ async function loadConfigFromDirectory(configDir, configFileName, encoding = 'utf8', logger, pathFields, resolvePathArray) {
|
|
85
143
|
const storage = create({
|
|
86
144
|
log: (logger === null || logger === void 0 ? void 0 : logger.debug) || (()=>{})
|
|
87
145
|
});
|
|
@@ -101,8 +159,13 @@ import { create } from './storage.js';
|
|
|
101
159
|
const yamlContent = await storage.readFile(configFilePath, encoding);
|
|
102
160
|
const parsedYaml = yaml.load(yamlContent);
|
|
103
161
|
if (parsedYaml !== null && typeof parsedYaml === 'object') {
|
|
162
|
+
let config = parsedYaml;
|
|
163
|
+
// Apply path resolution if configured
|
|
164
|
+
if (pathFields && pathFields.length > 0) {
|
|
165
|
+
config = resolveConfigPaths(config, configDir, pathFields, resolvePathArray || []);
|
|
166
|
+
}
|
|
104
167
|
logger === null || logger === void 0 ? void 0 : logger.verbose(`Successfully loaded config from: ${configFilePath}`);
|
|
105
|
-
return
|
|
168
|
+
return config;
|
|
106
169
|
} else {
|
|
107
170
|
logger === null || logger === void 0 ? void 0 : logger.debug(`Config file contains invalid format: ${configFilePath}`);
|
|
108
171
|
return null;
|
|
@@ -113,24 +176,26 @@ import { create } from './storage.js';
|
|
|
113
176
|
}
|
|
114
177
|
}
|
|
115
178
|
/**
|
|
116
|
-
* Deep merges multiple configuration objects with proper precedence.
|
|
179
|
+
* Deep merges multiple configuration objects with proper precedence and configurable array overlap behavior.
|
|
117
180
|
*
|
|
118
181
|
* Objects are merged from lowest precedence to highest precedence,
|
|
119
182
|
* meaning that properties in later objects override properties in earlier objects.
|
|
120
|
-
* Arrays
|
|
183
|
+
* Arrays can be merged using different strategies based on the fieldOverlaps configuration.
|
|
121
184
|
*
|
|
122
185
|
* @param configs Array of configuration objects, ordered from lowest to highest precedence
|
|
186
|
+
* @param fieldOverlaps Configuration for how array fields should be merged (optional)
|
|
123
187
|
* @returns Merged configuration object
|
|
124
188
|
*
|
|
125
189
|
* @example
|
|
126
190
|
* ```typescript
|
|
127
191
|
* const merged = deepMergeConfigs([
|
|
128
|
-
* { api: { timeout: 5000 },
|
|
129
|
-
* { api: { retries: 3 }, features: ['
|
|
130
|
-
* ]
|
|
131
|
-
* //
|
|
192
|
+
* { api: { timeout: 5000 }, features: ['auth'] }, // Lower precedence
|
|
193
|
+
* { api: { retries: 3 }, features: ['analytics'] }, // Higher precedence
|
|
194
|
+
* ], {
|
|
195
|
+
* 'features': 'append' // Results in features: ['auth', 'analytics']
|
|
196
|
+
* });
|
|
132
197
|
* ```
|
|
133
|
-
*/ function deepMergeConfigs(configs) {
|
|
198
|
+
*/ function deepMergeConfigs(configs, fieldOverlaps) {
|
|
134
199
|
if (configs.length === 0) {
|
|
135
200
|
return {};
|
|
136
201
|
}
|
|
@@ -140,16 +205,18 @@ import { create } from './storage.js';
|
|
|
140
205
|
};
|
|
141
206
|
}
|
|
142
207
|
return configs.reduce((merged, current)=>{
|
|
143
|
-
return deepMergeTwo(merged, current);
|
|
208
|
+
return deepMergeTwo(merged, current, fieldOverlaps);
|
|
144
209
|
}, {});
|
|
145
210
|
}
|
|
146
211
|
/**
|
|
147
|
-
* Deep merges two objects with proper precedence.
|
|
212
|
+
* Deep merges two objects with proper precedence and configurable array overlap behavior.
|
|
148
213
|
*
|
|
149
214
|
* @param target Target object (lower precedence)
|
|
150
215
|
* @param source Source object (higher precedence)
|
|
216
|
+
* @param fieldOverlaps Configuration for how array fields should be merged (optional)
|
|
217
|
+
* @param currentPath Current field path for nested merging (used internally)
|
|
151
218
|
* @returns Merged object
|
|
152
|
-
*/ function deepMergeTwo(target, source) {
|
|
219
|
+
*/ function deepMergeTwo(target, source, fieldOverlaps, currentPath = '') {
|
|
153
220
|
// Handle null/undefined
|
|
154
221
|
if (source == null) return target;
|
|
155
222
|
if (target == null) return source;
|
|
@@ -157,11 +224,17 @@ import { create } from './storage.js';
|
|
|
157
224
|
if (typeof source !== 'object' || typeof target !== 'object') {
|
|
158
225
|
return source; // Source takes precedence
|
|
159
226
|
}
|
|
160
|
-
// Handle arrays
|
|
227
|
+
// Handle arrays with configurable overlap behavior
|
|
161
228
|
if (Array.isArray(source)) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
229
|
+
if (Array.isArray(target) && fieldOverlaps) {
|
|
230
|
+
const overlapMode = getOverlapModeForPath(currentPath, fieldOverlaps);
|
|
231
|
+
return mergeArrays(target, source, overlapMode);
|
|
232
|
+
} else {
|
|
233
|
+
// Default behavior: replace entirely
|
|
234
|
+
return [
|
|
235
|
+
...source
|
|
236
|
+
];
|
|
237
|
+
}
|
|
165
238
|
}
|
|
166
239
|
if (Array.isArray(target)) {
|
|
167
240
|
return source; // Source object replaces target array
|
|
@@ -172,17 +245,72 @@ import { create } from './storage.js';
|
|
|
172
245
|
};
|
|
173
246
|
for(const key in source){
|
|
174
247
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
248
|
+
const fieldPath = currentPath ? `${currentPath}.${key}` : key;
|
|
175
249
|
if (Object.prototype.hasOwnProperty.call(result, key) && typeof result[key] === 'object' && typeof source[key] === 'object' && !Array.isArray(source[key]) && !Array.isArray(result[key])) {
|
|
176
250
|
// Recursively merge nested objects
|
|
177
|
-
result[key] = deepMergeTwo(result[key], source[key]);
|
|
251
|
+
result[key] = deepMergeTwo(result[key], source[key], fieldOverlaps, fieldPath);
|
|
178
252
|
} else {
|
|
179
|
-
//
|
|
180
|
-
|
|
253
|
+
// Handle arrays and primitives with overlap consideration
|
|
254
|
+
if (Array.isArray(source[key]) && Array.isArray(result[key]) && fieldOverlaps) {
|
|
255
|
+
const overlapMode = getOverlapModeForPath(fieldPath, fieldOverlaps);
|
|
256
|
+
result[key] = mergeArrays(result[key], source[key], overlapMode);
|
|
257
|
+
} else {
|
|
258
|
+
// Replace with source value (higher precedence)
|
|
259
|
+
result[key] = source[key];
|
|
260
|
+
}
|
|
181
261
|
}
|
|
182
262
|
}
|
|
183
263
|
}
|
|
184
264
|
return result;
|
|
185
265
|
}
|
|
266
|
+
/**
|
|
267
|
+
* Determines the overlap mode for a given field path.
|
|
268
|
+
*
|
|
269
|
+
* @param fieldPath The current field path (dot notation)
|
|
270
|
+
* @param fieldOverlaps Configuration mapping field paths to overlap modes
|
|
271
|
+
* @returns The overlap mode to use for this field path
|
|
272
|
+
*/ function getOverlapModeForPath(fieldPath, fieldOverlaps) {
|
|
273
|
+
// Check for exact match first
|
|
274
|
+
if (fieldPath in fieldOverlaps) {
|
|
275
|
+
return fieldOverlaps[fieldPath];
|
|
276
|
+
}
|
|
277
|
+
// Check for any parent path matches (for nested configurations)
|
|
278
|
+
const pathParts = fieldPath.split('.');
|
|
279
|
+
for(let i = pathParts.length - 1; i > 0; i--){
|
|
280
|
+
const parentPath = pathParts.slice(0, i).join('.');
|
|
281
|
+
if (parentPath in fieldOverlaps) {
|
|
282
|
+
return fieldOverlaps[parentPath];
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
// Default to override if no specific configuration found
|
|
286
|
+
return 'override';
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Merges two arrays based on the specified overlap mode.
|
|
290
|
+
*
|
|
291
|
+
* @param targetArray The lower precedence array
|
|
292
|
+
* @param sourceArray The higher precedence array
|
|
293
|
+
* @param mode The overlap mode to use
|
|
294
|
+
* @returns The merged array
|
|
295
|
+
*/ function mergeArrays(targetArray, sourceArray, mode) {
|
|
296
|
+
switch(mode){
|
|
297
|
+
case 'append':
|
|
298
|
+
return [
|
|
299
|
+
...targetArray,
|
|
300
|
+
...sourceArray
|
|
301
|
+
];
|
|
302
|
+
case 'prepend':
|
|
303
|
+
return [
|
|
304
|
+
...sourceArray,
|
|
305
|
+
...targetArray
|
|
306
|
+
];
|
|
307
|
+
case 'override':
|
|
308
|
+
default:
|
|
309
|
+
return [
|
|
310
|
+
...sourceArray
|
|
311
|
+
];
|
|
312
|
+
}
|
|
313
|
+
}
|
|
186
314
|
/**
|
|
187
315
|
* Loads configurations from multiple directories and merges them with proper precedence.
|
|
188
316
|
*
|
|
@@ -201,15 +329,19 @@ import { create } from './storage.js';
|
|
|
201
329
|
* configDirName: '.kodrdriv',
|
|
202
330
|
* configFileName: 'config.yaml',
|
|
203
331
|
* startingDir: '/project/subdir',
|
|
204
|
-
* maxLevels: 5
|
|
332
|
+
* maxLevels: 5,
|
|
333
|
+
* fieldOverlaps: {
|
|
334
|
+
* 'features': 'append',
|
|
335
|
+
* 'excludePatterns': 'prepend'
|
|
336
|
+
* }
|
|
205
337
|
* });
|
|
206
338
|
*
|
|
207
|
-
* // result.config contains merged configuration
|
|
339
|
+
* // result.config contains merged configuration with custom array merging
|
|
208
340
|
* // result.discoveredDirs shows where configs were found
|
|
209
341
|
* // result.errors contains any non-fatal errors
|
|
210
342
|
* ```
|
|
211
343
|
*/ async function loadHierarchicalConfig(options) {
|
|
212
|
-
const { configFileName, encoding = 'utf8', logger } = options;
|
|
344
|
+
const { configFileName, encoding = 'utf8', logger, pathFields, resolvePathArray, fieldOverlaps } = options;
|
|
213
345
|
logger === null || logger === void 0 ? void 0 : logger.verbose('Starting hierarchical configuration loading');
|
|
214
346
|
// Discover all configuration directories
|
|
215
347
|
const discoveredDirs = await discoverConfigDirectories(options);
|
|
@@ -230,7 +362,7 @@ import { create } from './storage.js';
|
|
|
230
362
|
].sort((a, b)=>b.level - a.level);
|
|
231
363
|
for (const dir of sortedDirs){
|
|
232
364
|
try {
|
|
233
|
-
const config = await loadConfigFromDirectory(dir.path, configFileName, encoding, logger);
|
|
365
|
+
const config = await loadConfigFromDirectory(dir.path, configFileName, encoding, logger, pathFields, resolvePathArray);
|
|
234
366
|
if (config !== null) {
|
|
235
367
|
configs.push(config);
|
|
236
368
|
logger === null || logger === void 0 ? void 0 : logger.debug(`Loaded config from level ${dir.level}: ${dir.path}`);
|
|
@@ -243,8 +375,8 @@ import { create } from './storage.js';
|
|
|
243
375
|
logger === null || logger === void 0 ? void 0 : logger.debug(errorMsg);
|
|
244
376
|
}
|
|
245
377
|
}
|
|
246
|
-
// Merge all configurations with proper precedence
|
|
247
|
-
const mergedConfig = deepMergeConfigs(configs);
|
|
378
|
+
// Merge all configurations with proper precedence and configurable array overlap
|
|
379
|
+
const mergedConfig = deepMergeConfigs(configs, fieldOverlaps);
|
|
248
380
|
logger === null || logger === void 0 ? void 0 : logger.verbose(`Hierarchical loading complete. Merged ${configs.length} configurations`);
|
|
249
381
|
return {
|
|
250
382
|
config: mergedConfig,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hierarchical.js","sources":["../../src/util/hierarchical.ts"],"sourcesContent":["import path from 'path';\nimport * as yaml from 'js-yaml';\nimport { create as createStorage } from './storage';\nimport { Logger } from '../types';\n\n/**\n * 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}\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 * @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): 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 logger?.verbose(`Successfully loaded config from: ${configFilePath}`);\n return parsedYaml as object;\n } else {\n logger?.debug(`Config file contains invalid format: ${configFilePath}`);\n return null;\n }\n } catch (error: any) {\n logger?.debug(`Error loading config from ${configFilePath}: ${error.message}`);\n return null;\n }\n}\n\n/**\n * Deep merges multiple configuration objects with proper precedence.\n * \n * Objects are merged from lowest precedence to highest precedence,\n * meaning that properties in later objects override properties in earlier objects.\n * Arrays are replaced entirely (not merged).\n * \n * @param configs Array of configuration objects, ordered from lowest to highest precedence\n * @returns Merged configuration object\n * \n * @example\n * ```typescript\n * const merged = deepMergeConfigs([\n * { api: { timeout: 5000 }, debug: true }, // Lower precedence\n * { api: { retries: 3 }, features: ['auth'] }, // Higher precedence\n * ]);\n * // Result: { api: { timeout: 5000, retries: 3 }, debug: true, features: ['auth'] }\n * ```\n */\nexport function deepMergeConfigs(configs: object[]): object {\n if (configs.length === 0) {\n return {};\n }\n\n if (configs.length === 1) {\n return { ...configs[0] };\n }\n\n return configs.reduce((merged, current) => {\n return deepMergeTwo(merged, current);\n }, {});\n}\n\n/**\n * Deep merges two objects with proper precedence.\n * \n * @param target Target object (lower precedence)\n * @param source Source object (higher precedence)\n * @returns Merged object\n */\nfunction deepMergeTwo(target: any, source: any): any {\n // Handle null/undefined\n if (source == null) return target;\n if (target == null) return source;\n\n // Handle non-objects (primitives, arrays, functions, etc.)\n if (typeof source !== 'object' || typeof target !== 'object') {\n return source; // Source takes precedence\n }\n\n // Handle arrays - replace entirely, don't merge\n if (Array.isArray(source)) {\n return [...source];\n }\n\n if (Array.isArray(target)) {\n return source; // Source object replaces target array\n }\n\n // Deep merge objects\n const result = { ...target };\n\n for (const key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n if (Object.prototype.hasOwnProperty.call(result, key) &&\n typeof result[key] === 'object' &&\n typeof source[key] === 'object' &&\n !Array.isArray(source[key]) &&\n !Array.isArray(result[key])) {\n // Recursively merge nested objects\n result[key] = deepMergeTwo(result[key], source[key]);\n } else {\n // Replace with source value (higher precedence)\n result[key] = source[key];\n }\n }\n }\n\n return result;\n}\n\n/**\n * Loads configurations from multiple directories and merges them with proper precedence.\n * \n * This is the main function for hierarchical configuration loading. It:\n * 1. Discovers configuration directories up the directory tree\n * 2. Loads configuration files from each discovered directory\n * 3. Merges them with proper precedence (closer directories win)\n * 4. Returns the merged configuration with metadata\n * \n * @param options Configuration options for hierarchical loading\n * @returns Promise resolving to hierarchical configuration result\n * \n * @example\n * ```typescript\n * const result = await loadHierarchicalConfig({\n * configDirName: '.kodrdriv',\n * configFileName: 'config.yaml',\n * startingDir: '/project/subdir',\n * maxLevels: 5\n * });\n * \n * // result.config contains merged configuration\n * // result.discoveredDirs shows where configs were found\n * // result.errors contains any non-fatal errors\n * ```\n */\nexport async function loadHierarchicalConfig(\n options: HierarchicalDiscoveryOptions\n): Promise<HierarchicalConfigResult> {\n const { configFileName, encoding = 'utf8', logger } = 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 );\n\n if (config !== null) {\n configs.push(config);\n logger?.debug(`Loaded config from level ${dir.level}: ${dir.path}`);\n } else {\n logger?.debug(`No valid config found at level ${dir.level}: ${dir.path}`);\n }\n } catch (error: any) {\n const errorMsg = `Failed to load config from ${dir.path}: ${error.message}`;\n errors.push(errorMsg);\n logger?.debug(errorMsg);\n }\n }\n\n // Merge all configurations with proper precedence\n const mergedConfig = deepMergeConfigs(configs);\n\n logger?.verbose(`Hierarchical loading complete. Merged ${configs.length} configurations`);\n\n return {\n config: mergedConfig,\n discoveredDirs,\n errors\n };\n} "],"names":["discoverConfigDirectories","options","configDirName","maxLevels","startingDir","process","cwd","logger","storage","createStorage","log","debug","discoveredDirs","currentDir","path","resolve","level","visited","Set","realPath","has","add","configDirPath","join","exists","isReadable","isDirectoryReadable","push","error","message","parentDir","dirname","verbose","length","loadConfigFromDirectory","configDir","configFileName","encoding","configFilePath","isFileReadable","yamlContent","readFile","parsedYaml","yaml","load","deepMergeConfigs","configs","reduce","merged","current","deepMergeTwo","target","source","Array","isArray","result","key","Object","prototype","hasOwnProperty","call","loadHierarchicalConfig","config","errors","sortedDirs","sort","a","b","dir","errorMsg","mergedConfig"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hierarchical.js","sources":["../../src/util/hierarchical.ts"],"sourcesContent":["import path from 'path';\nimport * as yaml from 'js-yaml';\nimport { create as createStorage } from './storage';\nimport { Logger, FieldOverlapOptions, ArrayOverlapMode } from '../types';\n\n/**\n * Resolves relative paths in configuration values relative to the configuration file's directory.\n */\nfunction resolveConfigPaths(\n config: any,\n configDir: string,\n pathFields: string[] = [],\n resolvePathArray: string[] = []\n): any {\n if (!config || typeof config !== 'object' || pathFields.length === 0) {\n return config;\n }\n\n const resolvedConfig = { ...config };\n\n for (const fieldPath of pathFields) {\n const value = getNestedValue(resolvedConfig, fieldPath);\n if (value !== undefined) {\n const shouldResolveArrayElements = resolvePathArray.includes(fieldPath);\n const resolvedValue = resolvePathValue(value, configDir, shouldResolveArrayElements);\n setNestedValue(resolvedConfig, fieldPath, resolvedValue);\n }\n }\n\n return resolvedConfig;\n}\n\n/**\n * Gets a nested value from an object using dot notation.\n */\nfunction getNestedValue(obj: any, path: string): any {\n return path.split('.').reduce((current, key) => current?.[key], obj);\n}\n\n/**\n * Sets a nested value in an object using dot notation.\n */\nfunction setNestedValue(obj: any, path: string, value: any): void {\n const keys = path.split('.');\n const lastKey = keys.pop()!;\n const target = keys.reduce((current, key) => {\n if (!(key in current)) {\n current[key] = {};\n }\n return current[key];\n }, obj);\n target[lastKey] = value;\n}\n\n/**\n * Resolves a path value (string or array of strings) relative to the config directory.\n */\nfunction resolvePathValue(value: any, configDir: string, resolveArrayElements: boolean): any {\n if (typeof value === 'string') {\n return resolveSinglePath(value, configDir);\n }\n\n if (Array.isArray(value) && resolveArrayElements) {\n return value.map(item =>\n typeof item === 'string' ? resolveSinglePath(item, configDir) : item\n );\n }\n\n return value;\n}\n\n/**\n * Resolves a single path string relative to the config directory if it's a relative path.\n */\nfunction resolveSinglePath(pathStr: string, configDir: string): string {\n if (!pathStr || path.isAbsolute(pathStr)) {\n return pathStr;\n }\n\n return path.resolve(configDir, pathStr);\n}\n\n/**\n * Represents a discovered configuration directory with its path and precedence level.\n */\nexport interface DiscoveredConfigDir {\n /** Absolute path to the configuration directory */\n path: string;\n /** Distance from the starting directory (0 = closest/highest precedence) */\n level: number;\n}\n\n/**\n * Options for hierarchical configuration discovery.\n */\nexport interface HierarchicalDiscoveryOptions {\n /** Name of the configuration directory to look for (e.g., '.kodrdriv') */\n configDirName: string;\n /** Name of the configuration file within each directory */\n configFileName: string;\n /** Maximum number of parent directories to traverse (default: 10) */\n maxLevels?: number;\n /** Starting directory for discovery (default: process.cwd()) */\n startingDir?: string;\n /** File encoding for reading configuration files */\n encoding?: string;\n /** Logger for debugging */\n logger?: Logger;\n /** Array of field names that contain paths to be resolved */\n pathFields?: string[];\n /** Array of field names whose array elements should all be resolved as paths */\n resolvePathArray?: string[];\n /** Configuration for how array fields should be merged in hierarchical mode */\n fieldOverlaps?: FieldOverlapOptions;\n}\n\n/**\n * Result of loading configurations from multiple directories.\n */\nexport interface HierarchicalConfigResult {\n /** Merged configuration object with proper precedence */\n config: object;\n /** Array of directories where configuration was found */\n discoveredDirs: DiscoveredConfigDir[];\n /** Array of any errors encountered during loading (non-fatal) */\n errors: string[];\n}\n\n/**\n * Discovers configuration directories by traversing up the directory tree.\n * \n * Starting from the specified directory (or current working directory),\n * this function searches for directories with the given name, continuing\n * up the directory tree until it reaches the filesystem root or the\n * maximum number of levels.\n * \n * @param options Configuration options for discovery\n * @returns Promise resolving to array of discovered configuration directories\n * \n * @example\n * ```typescript\n * const dirs = await discoverConfigDirectories({\n * configDirName: '.kodrdriv',\n * configFileName: 'config.yaml',\n * maxLevels: 5\n * });\n * // Returns: [\n * // { path: '/project/.kodrdriv', level: 0 },\n * // { path: '/project/parent/.kodrdriv', level: 1 }\n * // ]\n * ```\n */\nexport async function discoverConfigDirectories(\n options: HierarchicalDiscoveryOptions\n): Promise<DiscoveredConfigDir[]> {\n const {\n configDirName,\n maxLevels = 10,\n startingDir = process.cwd(),\n logger\n } = options;\n\n const storage = createStorage({ log: logger?.debug || (() => { }) });\n const discoveredDirs: DiscoveredConfigDir[] = [];\n\n let currentDir = path.resolve(startingDir);\n let level = 0;\n const visited = new Set<string>(); // Prevent infinite loops with symlinks\n\n logger?.debug(`Starting hierarchical discovery from: ${currentDir}`);\n\n while (level < maxLevels) {\n // Prevent infinite loops with symlinks\n const realPath = path.resolve(currentDir);\n if (visited.has(realPath)) {\n logger?.debug(`Already visited ${realPath}, stopping discovery`);\n break;\n }\n visited.add(realPath);\n\n const configDirPath = path.join(currentDir, configDirName);\n logger?.debug(`Checking for config directory: ${configDirPath}`);\n\n try {\n const exists = await storage.exists(configDirPath);\n const isReadable = exists && await storage.isDirectoryReadable(configDirPath);\n\n if (exists && isReadable) {\n discoveredDirs.push({\n path: configDirPath,\n level\n });\n logger?.debug(`Found config directory at level ${level}: ${configDirPath}`);\n } else if (exists && !isReadable) {\n logger?.debug(`Config directory exists but is not readable: ${configDirPath}`);\n }\n } catch (error: any) {\n logger?.debug(`Error checking config directory ${configDirPath}: ${error.message}`);\n }\n\n // Move up one directory level\n const parentDir = path.dirname(currentDir);\n\n // Check if we've reached the root directory\n if (parentDir === currentDir) {\n logger?.debug('Reached filesystem root, stopping discovery');\n break;\n }\n\n currentDir = parentDir;\n level++;\n }\n\n logger?.verbose(`Discovery complete. Found ${discoveredDirs.length} config directories`);\n return discoveredDirs;\n}\n\n/**\n * Loads and parses a configuration file from a directory.\n * \n * @param configDir Path to the configuration directory\n * @param configFileName Name of the configuration file\n * @param encoding File encoding\n * @param logger Optional logger\n * @param pathFields Optional array of field names that contain paths to be resolved\n * @param resolvePathArray Optional array of field names whose array elements should all be resolved as paths\n * @returns Promise resolving to parsed configuration object or null if not found\n */\nexport async function loadConfigFromDirectory(\n configDir: string,\n configFileName: string,\n encoding: string = 'utf8',\n logger?: Logger,\n pathFields?: string[],\n resolvePathArray?: string[]\n): Promise<object | null> {\n const storage = createStorage({ log: logger?.debug || (() => { }) });\n const configFilePath = path.join(configDir, configFileName);\n\n try {\n logger?.verbose(`Attempting to load config file: ${configFilePath}`);\n\n const exists = await storage.exists(configFilePath);\n if (!exists) {\n logger?.debug(`Config file does not exist: ${configFilePath}`);\n return null;\n }\n\n const isReadable = await storage.isFileReadable(configFilePath);\n if (!isReadable) {\n logger?.debug(`Config file exists but is not readable: ${configFilePath}`);\n return null;\n }\n\n const yamlContent = await storage.readFile(configFilePath, encoding);\n const parsedYaml = yaml.load(yamlContent);\n\n if (parsedYaml !== null && typeof parsedYaml === 'object') {\n let config = parsedYaml as object;\n\n // Apply path resolution if configured\n if (pathFields && pathFields.length > 0) {\n config = resolveConfigPaths(config, configDir, pathFields, resolvePathArray || []);\n }\n\n logger?.verbose(`Successfully loaded config from: ${configFilePath}`);\n return config;\n } else {\n logger?.debug(`Config file contains invalid format: ${configFilePath}`);\n return null;\n }\n } catch (error: any) {\n logger?.debug(`Error loading config from ${configFilePath}: ${error.message}`);\n return null;\n }\n}\n\n/**\n * Deep merges multiple configuration objects with proper precedence and configurable array overlap behavior.\n * \n * Objects are merged from lowest precedence to highest precedence,\n * meaning that properties in later objects override properties in earlier objects.\n * Arrays can be merged using different strategies based on the fieldOverlaps configuration.\n * \n * @param configs Array of configuration objects, ordered from lowest to highest precedence\n * @param fieldOverlaps Configuration for how array fields should be merged (optional)\n * @returns Merged configuration object\n * \n * @example\n * ```typescript\n * const merged = deepMergeConfigs([\n * { api: { timeout: 5000 }, features: ['auth'] }, // Lower precedence\n * { api: { retries: 3 }, features: ['analytics'] }, // Higher precedence\n * ], {\n * 'features': 'append' // Results in features: ['auth', 'analytics']\n * });\n * ```\n */\nexport function deepMergeConfigs(configs: object[], fieldOverlaps?: FieldOverlapOptions): object {\n if (configs.length === 0) {\n return {};\n }\n\n if (configs.length === 1) {\n return { ...configs[0] };\n }\n\n return configs.reduce((merged, current) => {\n return deepMergeTwo(merged, current, fieldOverlaps);\n }, {});\n}\n\n/**\n * Deep merges two objects with proper precedence and configurable array overlap behavior.\n * \n * @param target Target object (lower precedence)\n * @param source Source object (higher precedence)\n * @param fieldOverlaps Configuration for how array fields should be merged (optional)\n * @param currentPath Current field path for nested merging (used internally)\n * @returns Merged object\n */\nfunction deepMergeTwo(target: any, source: any, fieldOverlaps?: FieldOverlapOptions, currentPath: string = ''): any {\n // Handle null/undefined\n if (source == null) return target;\n if (target == null) return source;\n\n // Handle non-objects (primitives, arrays, functions, etc.)\n if (typeof source !== 'object' || typeof target !== 'object') {\n return source; // Source takes precedence\n }\n\n // Handle arrays with configurable overlap behavior\n if (Array.isArray(source)) {\n if (Array.isArray(target) && fieldOverlaps) {\n const overlapMode = getOverlapModeForPath(currentPath, fieldOverlaps);\n return mergeArrays(target, source, overlapMode);\n } else {\n // Default behavior: replace entirely\n return [...source];\n }\n }\n\n if (Array.isArray(target)) {\n return source; // Source object replaces target array\n }\n\n // Deep merge objects\n const result = { ...target };\n\n for (const key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n const fieldPath = currentPath ? `${currentPath}.${key}` : key;\n\n if (Object.prototype.hasOwnProperty.call(result, key) &&\n typeof result[key] === 'object' &&\n typeof source[key] === 'object' &&\n !Array.isArray(source[key]) &&\n !Array.isArray(result[key])) {\n // Recursively merge nested objects\n result[key] = deepMergeTwo(result[key], source[key], fieldOverlaps, fieldPath);\n } else {\n // Handle arrays and primitives with overlap consideration\n if (Array.isArray(source[key]) && Array.isArray(result[key]) && fieldOverlaps) {\n const overlapMode = getOverlapModeForPath(fieldPath, fieldOverlaps);\n result[key] = mergeArrays(result[key], source[key], overlapMode);\n } else {\n // Replace with source value (higher precedence)\n result[key] = source[key];\n }\n }\n }\n }\n\n return result;\n}\n\n/**\n * Determines the overlap mode for a given field path.\n * \n * @param fieldPath The current field path (dot notation)\n * @param fieldOverlaps Configuration mapping field paths to overlap modes\n * @returns The overlap mode to use for this field path\n */\nfunction getOverlapModeForPath(fieldPath: string, fieldOverlaps: FieldOverlapOptions): ArrayOverlapMode {\n // Check for exact match first\n if (fieldPath in fieldOverlaps) {\n return fieldOverlaps[fieldPath];\n }\n\n // Check for any parent path matches (for nested configurations)\n const pathParts = fieldPath.split('.');\n for (let i = pathParts.length - 1; i > 0; i--) {\n const parentPath = pathParts.slice(0, i).join('.');\n if (parentPath in fieldOverlaps) {\n return fieldOverlaps[parentPath];\n }\n }\n\n // Default to override if no specific configuration found\n return 'override';\n}\n\n/**\n * Merges two arrays based on the specified overlap mode.\n * \n * @param targetArray The lower precedence array\n * @param sourceArray The higher precedence array\n * @param mode The overlap mode to use\n * @returns The merged array\n */\nfunction mergeArrays(targetArray: any[], sourceArray: any[], mode: ArrayOverlapMode): any[] {\n switch (mode) {\n case 'append':\n return [...targetArray, ...sourceArray];\n case 'prepend':\n return [...sourceArray, ...targetArray];\n case 'override':\n default:\n return [...sourceArray];\n }\n}\n\n/**\n * Loads configurations from multiple directories and merges them with proper precedence.\n * \n * This is the main function for hierarchical configuration loading. It:\n * 1. Discovers configuration directories up the directory tree\n * 2. Loads configuration files from each discovered directory\n * 3. Merges them with proper precedence (closer directories win)\n * 4. Returns the merged configuration with metadata\n * \n * @param options Configuration options for hierarchical loading\n * @returns Promise resolving to hierarchical configuration result\n * \n * @example\n * ```typescript\n * const result = await loadHierarchicalConfig({\n * configDirName: '.kodrdriv',\n * configFileName: 'config.yaml',\n * startingDir: '/project/subdir',\n * maxLevels: 5,\n * fieldOverlaps: {\n * 'features': 'append',\n * 'excludePatterns': 'prepend'\n * }\n * });\n * \n * // result.config contains merged configuration with custom array merging\n * // result.discoveredDirs shows where configs were found\n * // result.errors contains any non-fatal errors\n * ```\n */\nexport async function loadHierarchicalConfig(\n options: HierarchicalDiscoveryOptions\n): Promise<HierarchicalConfigResult> {\n const { configFileName, encoding = 'utf8', logger, pathFields, resolvePathArray, fieldOverlaps } = options;\n\n logger?.verbose('Starting hierarchical configuration loading');\n\n // Discover all configuration directories\n const discoveredDirs = await discoverConfigDirectories(options);\n\n if (discoveredDirs.length === 0) {\n logger?.verbose('No configuration directories found');\n return {\n config: {},\n discoveredDirs: [],\n errors: []\n };\n }\n\n // Load configurations from each directory\n const configs: object[] = [];\n const errors: string[] = [];\n\n // Sort by level (highest level first = lowest precedence first)\n const sortedDirs = [...discoveredDirs].sort((a, b) => b.level - a.level);\n\n for (const dir of sortedDirs) {\n try {\n const config = await loadConfigFromDirectory(\n dir.path,\n configFileName,\n encoding,\n logger,\n pathFields,\n resolvePathArray\n );\n\n if (config !== null) {\n configs.push(config);\n logger?.debug(`Loaded config from level ${dir.level}: ${dir.path}`);\n } else {\n logger?.debug(`No valid config found at level ${dir.level}: ${dir.path}`);\n }\n } catch (error: any) {\n const errorMsg = `Failed to load config from ${dir.path}: ${error.message}`;\n errors.push(errorMsg);\n logger?.debug(errorMsg);\n }\n }\n\n // Merge all configurations with proper precedence and configurable array overlap\n const mergedConfig = deepMergeConfigs(configs, fieldOverlaps);\n\n logger?.verbose(`Hierarchical loading complete. Merged ${configs.length} configurations`);\n\n return {\n config: mergedConfig,\n discoveredDirs,\n errors\n };\n} "],"names":["resolveConfigPaths","config","configDir","pathFields","resolvePathArray","length","resolvedConfig","fieldPath","value","getNestedValue","undefined","shouldResolveArrayElements","includes","resolvedValue","resolvePathValue","setNestedValue","obj","path","split","reduce","current","key","keys","lastKey","pop","target","resolveArrayElements","resolveSinglePath","Array","isArray","map","item","pathStr","isAbsolute","resolve","discoverConfigDirectories","options","configDirName","maxLevels","startingDir","process","cwd","logger","storage","createStorage","log","debug","discoveredDirs","currentDir","level","visited","Set","realPath","has","add","configDirPath","join","exists","isReadable","isDirectoryReadable","push","error","message","parentDir","dirname","verbose","loadConfigFromDirectory","configFileName","encoding","configFilePath","isFileReadable","yamlContent","readFile","parsedYaml","yaml","load","deepMergeConfigs","configs","fieldOverlaps","merged","deepMergeTwo","source","currentPath","overlapMode","getOverlapModeForPath","mergeArrays","result","Object","prototype","hasOwnProperty","call","pathParts","i","parentPath","slice","targetArray","sourceArray","mode","loadHierarchicalConfig","errors","sortedDirs","sort","a","b","dir","errorMsg","mergedConfig"],"mappings":"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"}
|