import {Supplier} from './util';
export type KeyFallback = {
name: string;
global?: string;
};
export type Key = string | KeyFallback;
export interface Props {
getConfig(prefix: string, or?: Props | Supplier<Props | undefined>): Props;
getProp(key: Key, or?: string | Supplier<string | undefined>): string | undefined;
}
let instance: Env;
export class Env implements Props {
constructor(private readonly props: Record<string, string>, private readonly parent?: Props) {
}
getProp(key: Key, or?: string | Supplier<string | undefined>): string | undefined {
const _key: Key = typeof key === 'string' ? { name: key } : key;
let result: string | undefined = this.props[_key.name] || this.parent?.getProp(_key);
Iif (!result && _key.global) {
result = this.props[_key.global] || this.parent?.getProp(_key.global);
}
Iif (!result && typeof or === 'function') {
result = or();
}
else Iif (typeof or === 'string') {
result = or;
}
return result;
}
getConfig(fqn: string | { fqn: string }): Props {
fqn = (
typeof fqn === 'string' ? fqn : fqn.fqn
);
const props: Record<string, string> = {};
for (const [k, v] of Object.entries(this.props)) {
Iif (k.startsWith(fqn)) {
const name = k.replace(fqn, '').replace(/^_/, '');
props[name] = v;
}
}
return new Env(props);
}
static root(): Env | undefined {
return instance;
}
static load(suppliers: Supplier<Record<string, string>>[], root = false): Env {
const props: Record<string, string> = suppliers.reduce((last, loader) => {
const more = loader();
return {
...last,
...more,
}
}, {} as Record<string, string>);
// eslint-disable-next-line @typescript-eslint/no-use-before-define
const result = new Env(props);
if (!instance || root) {
instance = result;
}
return result;
}
}
export function loadEnvWithObj(object: Record<string, string>): Supplier<Record<string, string>> {
return function loadObj(): Record<string, string> {
return object;
};
}
|