@anyme/anymejs
Version:
156 lines (153 loc) • 5.71 kB
JavaScript
import { CONFIG, ENV_KEY_VALUES } from './default.config.js';
import { extname, basename, resolve, join } from 'node:path';
import fg from '../_virtual/index.js';
import { isEmpty, deepMerge, all, importJson, importModule, isFunction, ctx, set, getAbsolutePath } from '../utils/index.js';
class Config {
#config = CONFIG;
fileGroups = new Map();
configs = new Map();
path = process.env.CONFIG_PATH || "./config";
env = process.env.NODE_ENV || "development";
ignore = ["**/node_modules/**", "**/dist/**", "**/*.d.ts"];
order = [".ts", ".js", ".mjs", ".cjs", ".json"];
constructor() {
this.fileGroups = this.groupConfigs(this.loadPaths());
}
async get(name) {
if (!name)
return await this.loadCore();
if (this.configs.has(name))
return this.configs.get(name);
if (this.fileGroups.has(name)) {
const module = await this.importConfig(this.fileGroups.get(name));
if (!isEmpty(module)) {
this.configs.set(name, module);
return module;
}
}
return undefined;
}
async loadCore() {
if (this.configs.has("core") || isEmpty(this.fileGroups))
return this.#config;
await this.loadAllConfigs();
this.#config = deepMerge(this.#config, ...this.getCoreConfigs());
this.loadEnvConfig();
this.resolveServerPaths();
this.validate();
this.configs.set("core", this.#config);
return this.#config;
}
getCoreConfigs() {
const configs = [];
if (this.configs.has("default")) {
configs.push(this.configs.get("default"));
}
if (this.env === "development" && this.configs.has("local")) {
configs.push(this.configs.get("local"));
}
else if (this.env === "production" && this.configs.has("prod")) {
configs.push(this.configs.get("prod"));
}
else if (this.env && this.configs.has(this.env)) {
configs.push(this.configs.get(this.env));
}
return configs;
}
loadAllConfigs() {
return all(this.fileGroups, async ([key, path]) => {
const module = await this.importConfig(path);
if (!isEmpty(module))
this.configs.set(key, module);
return module;
});
}
loadPaths() {
return fg.sync(this.getPattern(), {
onlyFiles: true,
ignore: this.ignore,
absolute: true,
});
}
groupConfigs(paths) {
const fileGroups = new Map();
for (const path of paths) {
const ext = extname(path);
const index = this.order.indexOf(ext);
if (index === -1)
continue;
const fileName = basename(path, ext).slice(0, -7);
if (!fileGroups.has(fileName))
fileGroups.set(fileName, path);
else {
const oldIndex = this.order.indexOf(extname(fileGroups.get(fileName)));
if (index < oldIndex)
fileGroups.set(fileName, path);
}
}
return fileGroups;
}
async importConfig(path) {
try {
if (extname(path) === ".json")
return importJson(path);
const module = await importModule(path);
const result = isFunction(module) ? module(ctx()) : module;
return isEmpty(result) ? {} : result;
}
catch (error) {
console.error("❌ Failed to load config:", error);
throw error;
}
}
async loadEnvConfig() {
ENV_KEY_VALUES.forEach((item) => {
if (process.env[item.value]) {
if (item.type === "number")
this.merge(item.key, parseInt(process.env[item.value]));
else if (item.type === "boolean")
this.merge(item.key, process.env[item.value] === "true");
else if (item.type === "resolve")
this.merge(item.key, resolve(process.env[item.value]));
else
this.merge(item.key, process.env[item.value]);
}
});
}
getPattern() {
const ext = this.order.join(",");
return join(this.path, `*.config{${ext}}`).replace(/\\/g, "/");
}
merge(str, value) {
this.#config = deepMerge(this.#config, set(str, value));
}
async validate() {
if (!this.#config.session?.client?.secret) {
console.warn("⚠️ Session secret is not set.");
}
if (this.env === "production") {
if (this.#config.session?.enable) {
if (!this.#config.session?.client?.cookie?.secure) {
console.warn("⚠️ Forcing secure cookies in production environment");
}
}
if (this.#config.db?.enable) {
if (this.#config.db?.client?.synchronize) {
console.warn("⚠️ Database synchronization is enabled in production environment");
}
}
}
}
resolveServerPaths() {
const serverPaths = ["controllers", "middlewares", "interceptors"];
serverPaths.forEach((key) => {
if (this.#config.server?.route?.[key]?.length === 1 &&
typeof this.#config.server?.route?.[key][0] === "string") {
const path = this.#config.server.route[key][0];
this.merge(`server.route.${key}`, [getAbsolutePath(path)]);
}
});
}
}
export { Config };
//# sourceMappingURL=index.js.map