plumjs-config
Version:
A powerful Node.js configuration management library with YAML support and dynamic configuration loading
219 lines • 7.59 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigUtils = void 0;
const yaml = __importStar(require("js-yaml"));
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
/**
* Utility functions for configuration management
*/
class ConfigUtils {
/**
* Deep merge two configuration objects (alias for mergeDeep)
*/
static deepMerge(target, source) {
return ConfigUtils.mergeDeep(target, source);
}
/**
* Get value from configuration using dot notation (alias for getNestedValue)
*/
static getValue(obj, path, defaultValue) {
return ConfigUtils.getNestedValue(obj, path, defaultValue);
}
/**
* Check if a path exists in configuration
*/
static hasValue(obj, path) {
const keys = path.split('.');
let current = obj;
for (const key of keys) {
if (current && typeof current === 'object' && key in current) {
current = current[key];
}
else {
return false;
}
}
return true;
}
/**
* Parse environment variables into configuration object
*/
static parseEnvironmentVariables() {
const config = {};
Object.keys(process.env).forEach(key => {
const value = process.env[key];
if (value !== undefined) {
// Convert UPPER_SNAKE_CASE to lower.dot.case
const configPath = key.toLowerCase().replace(/_/g, '.');
ConfigUtils.setNestedValue(config, configPath, value);
}
});
return config;
}
/**
* Deep merge two configuration objects
*/
static mergeDeep(target, source) {
const isObject = (obj) => obj && typeof obj === 'object' && !Array.isArray(obj);
if (!isObject(target) || !isObject(source)) {
return source;
}
const result = { ...target };
Object.keys(source).forEach(key => {
const targetValue = result[key];
const sourceValue = source[key];
if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
result[key] = [...targetValue, ...sourceValue];
}
else if (isObject(targetValue) && isObject(sourceValue)) {
result[key] = ConfigUtils.mergeDeep(targetValue, sourceValue);
}
else {
result[key] = sourceValue;
}
});
return result;
}
/**
* Load and parse YAML content
*/
static loadYaml(yamlContent) {
try {
const documents = [];
yaml.loadAll(yamlContent, (doc) => {
if (doc) {
documents.push(doc);
}
});
return documents.reduce((merged, doc) => ConfigUtils.mergeDeep(merged, doc), {});
}
catch (error) {
throw new Error(`Failed to parse YAML: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Load configuration files from directory
*/
static async loadConfigFiles(dirPath, patterns = ['**/*.yml', '**/*.yaml']) {
if (!fs.existsSync(dirPath)) {
return {};
}
const files = fs.readdirSync(dirPath);
let mergedConfig = {};
for (const fileName of files) {
// 严格检查文件扩展名,只允许 .yml 或 .yaml 结尾的文件
if (fileName.endsWith('.yml') || fileName.endsWith('.yaml')) {
const filePath = path.join(dirPath, fileName);
const content = await fs.readFile(filePath, 'utf-8');
const fileConfig = ConfigUtils.loadYaml(content);
mergedConfig = ConfigUtils.mergeDeep(mergedConfig, fileConfig);
}
}
return mergedConfig;
}
/**
* Resolve variable interpolation in configuration values
*/
static resolveVariables(value, context, maxDepth = 10) {
if (typeof value !== 'string') {
return value;
}
let resolved = value;
let depth = 0;
const variableRegex = /\$\{([^}]+)\}/g;
while (variableRegex.test(resolved) && depth < maxDepth) {
resolved = resolved.replace(variableRegex, (match, variablePath) => {
const resolvedValue = ConfigUtils.getNestedValue(context, variablePath);
return resolvedValue !== undefined ? String(resolvedValue) : match;
});
depth++;
variableRegex.lastIndex = 0; // Reset regex
}
// Try to parse as JSON if it looks like a complex value
try {
return JSON.parse(resolved);
}
catch {
return resolved;
}
}
/**
* Get nested value from object using dot notation
*/
static getNestedValue(obj, path, defaultValue) {
const keys = path.split('.');
let current = obj;
for (const key of keys) {
if (current && typeof current === 'object' && key in current) {
current = current[key];
}
else {
return defaultValue;
}
}
return current;
}
/**
* Set nested value in object using dot notation
*/
static setNestedValue(obj, path, value) {
const keys = path.split('.');
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!(key in current) || typeof current[key] !== 'object') {
current[key] = {};
}
current = current[key];
}
current[keys[keys.length - 1]] = value;
}
/**
* Validate configuration object
*/
static validateConfig(config) {
return typeof config === 'object' && config !== null && !Array.isArray(config);
}
/**
* Clone configuration object deeply
*/
static cloneConfig(config) {
return JSON.parse(JSON.stringify(config));
}
}
exports.ConfigUtils = ConfigUtils;
//# sourceMappingURL=utils.js.map
;