@cmmv/core
Version:
CMMV core module for contract and application management
177 lines (176 loc) • 7.55 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Config = void 0;
require("dotenv/config");
const path = require("node:path");
const fs = require("node:fs");
const abstracts_1 = require("../abstracts");
const logger_1 = require("./logger");
class Config extends abstracts_1.Singleton {
constructor() {
super(...arguments);
this.config = {};
}
static async loadConfig() {
const rootDir = process.cwd();
const configFiles = [
'.cmmv.config',
'.cmmv.test',
'config',
'config.test',
];
const extensions = ['.js', '.cjs', '.ts'];
await configFiles.forEach(async (configName) => {
for (const ext of extensions) {
const filePath = path.join(rootDir, `${configName}${ext}`);
if (fs.existsSync(filePath)) {
let configModule;
try {
if (ext === '.ts')
configModule = await Promise.resolve(`${filePath}`).then(s => require(s));
else
configModule = require(filePath);
if (configModule || configName.includes('config')) {
const instance = Config.getInstance();
instance.config =
configModule.default || configModule;
Config.assign(configModule.default || configModule);
}
else if (configName.includes('test')) {
Config.assign(configModule);
}
this.logger.log(`Loaded config: ${filePath}`);
break;
}
catch (error) {
this.logger.error(`Error loading config from ${filePath}:`, error);
}
}
}
});
}
static get(key, defaultValue) {
const config = Config.getInstance();
const value = key
.split('.')
.reduce((o, k) => o && o[k] !== undefined && o[k] !== null ? o[k] : null, config.config);
return value ? value : defaultValue;
}
static has(key) {
const config = Config.getInstance();
return (key
.split('.')
.reduce((o, k) => (o && k in o ? o[k] : undefined), config.config) !== undefined);
}
static set(key, value) {
const config = Config.getInstance();
const keys = key.split('.');
let obj = config.config;
while (keys.length > 1) {
const k = keys.shift();
obj[k] = obj[k] || {};
obj = obj[k];
}
obj[keys[0]] = value;
}
static delete(key) {
const config = Config.getInstance();
const keys = key.split('.');
let obj = config.config;
while (keys.length > 1) {
const k = keys.shift();
if (!(k in obj))
return;
obj = obj[k];
}
delete obj[keys[0]];
}
static getAll() {
return Config.getInstance().config;
}
static assign(config) {
const instance = Config.getInstance();
instance.config = { ...instance.config, ...config };
}
static clear() {
Config.getInstance().config = {};
}
static async validateConfigs(configs) {
const configInstance = Config.getInstance();
const loadedConfig = configInstance.config;
const validateSchema = (schema, config, path = '') => {
for (const key in schema) {
const schemaDefinition = schema[key];
const currentPath = path ? `${path}.${key}` : key;
const configValue = config[key];
if (schemaDefinition.required &&
(configValue === undefined || configValue === null)) {
throw new Error(`Configuration "${currentPath}" is required but missing.`);
}
if (configValue === undefined || configValue === null)
continue;
if (schemaDefinition.type !== 'any') {
let isTypeValid = false;
if (Array.isArray(schemaDefinition.type)) {
isTypeValid = schemaDefinition.type.some((type) => {
return ((type === 'array' &&
Array.isArray(configValue)) ||
type === typeof configValue);
});
if (!isTypeValid) {
throw new Error(`Configuration "${currentPath}" expects one of types [${schemaDefinition.type.join(', ')}] but received "${typeof configValue}".`);
}
}
else {
isTypeValid =
(schemaDefinition.type === 'array' &&
Array.isArray(configValue)) ||
schemaDefinition.type === typeof configValue;
if (!isTypeValid) {
throw new Error(`Configuration "${currentPath}" expects type "${schemaDefinition.type}" but received "${typeof configValue}".`);
}
}
}
if (((Array.isArray(schemaDefinition.type) &&
schemaDefinition.type.includes('array')) ||
schemaDefinition.type === 'array') &&
schemaDefinition.properties &&
Array.isArray(configValue)) {
configValue.forEach((item, index) => {
if (typeof item !== 'object' || item === null) {
throw new Error(`Configuration "${currentPath}[${index}]" expects an object but received "${typeof item}".`);
}
validateSchema(schemaDefinition.properties, item, `${currentPath}[${index}]`);
});
}
if (((Array.isArray(schemaDefinition.type) &&
schemaDefinition.type.includes('object')) ||
schemaDefinition.type === 'object') &&
schemaDefinition.properties) {
if (typeof configValue !== 'object' ||
Array.isArray(configValue)) {
throw new Error(`Configuration "${currentPath}" expects an object but received "${typeof configValue}".`);
}
validateSchema(schemaDefinition.properties, configValue, currentPath);
}
}
};
for (const schema of configs) {
for (const moduleKey in schema) {
const moduleSchema = schema[moduleKey];
const moduleConfig = loadedConfig[moduleKey];
if (moduleConfig !== undefined && moduleConfig !== null)
validateSchema(moduleSchema, moduleConfig, moduleKey);
}
}
}
static envMap(envConfig) {
const instance = Config.getInstance();
for (const key in envConfig) {
if (envConfig[key] === undefined)
instance.config[envConfig[key]] = process.env[key];
}
}
}
exports.Config = Config;
Config.logger = new logger_1.Logger('Config');