cmpstr-cli
Version:
Simple CLI wrapper for the CmpStr package to normalize and compare strings directly via terminal
87 lines • 3.13 kB
JavaScript
/**
* @fileoverview
* Configuration utilities for CmpStr CLI
*
* Handles loading, merging, and resolving configuration from
* YAML/JSON files and CLI options.
*
* @author Paul Köhler (komed3)
* @license MIT
*/
;
import * as fs from 'node:fs/promises';
import { fileURLToPath } from 'url';
import path from 'path';
import yaml from 'yaml';
// Get the directory name of the current module (ESM-compatible)
const __dirname = path.dirname(fileURLToPath(import.meta.url));
/**
* Loads a configuration file (YAML, YML, or JSON).
* Falls back to the default config if no path is provided.
*
* @async
* @param {string} [cfgPath] - Path to the config file.
* @returns {Promise<Partial<Config>>} The loaded configuration object.
* @throws {Error} If loading or parsing fails.
*/
export async function loadCfg(cfgPath) {
const defaultConfigPath = path.resolve(__dirname, '../../default.yml');
const filePath = path.resolve(cfgPath || defaultConfigPath);
try {
const content = await fs.readFile(filePath, 'utf-8');
const ext = path.extname(filePath).toLowerCase();
switch (ext) {
case '.yaml':
case '.yml': return yaml.parse(content);
case '.json': return JSON.parse(content);
default: throw new Error(`Unsupported config format: ${ext}`);
}
}
catch (err) {
throw new Error(`Failed to load config from ${filePath}`);
}
}
/**
* Deeply merges two configuration objects.
*
* @param {Partial<Config>} t - The target config object.
* @param {Partial<Config>} o - The source config object to merge in.
* @returns {Partial<Config>} The merged config object.
*/
export function mergeCfg(t = Object.create(null), o = Object.create(null)) {
return Object.keys(o).forEach(k => {
const val = o[k];
// Prevent prototype pollution
if (k === '__proto__' || k === 'constructor')
return;
t[k] = typeof val === 'object' && !Array.isArray(val)
? mergeCfg(typeof t[k] === 'object' && !Array.isArray(t[k])
? t[k] : Object.create(null), val)
: val;
}), t;
}
/**
* Loads and merges configuration from file and CLI options.
*
* @async
* @param {Partial<Config>} [cfg] - The base config object (e.g., from CLI).
* @param {string} [cfgPath] - Path to the config file.
* @returns {Promise<Partial<Config>>} The resolved configuration object.
*/
export async function resolveCfg(cfg = Object.create(null), cfgPath) {
return mergeCfg((await loadCfg(cfgPath)) ?? Object.create(null), cfg);
}
/**
* Resolves the effective configuration for a command.
* Merges global options, command options, and config file.
*
* @async
* @param {Command} cmd - The Commander command instance.
* @param {Record<string, any>} [opt] - Additional options to merge.
* @returns {Promise<Partial<Config>>} The resolved configuration object.
*/
export async function cfg(cmd, opt) {
const { config, ...opts } = cmd.parent.opts() ?? {};
return await resolveCfg(mergeCfg(opts, opt), config);
}
//# sourceMappingURL=config.js.map