@deepkit/app
Version:
Deepkit App, CLI framework and service container
107 lines (85 loc) • 3.19 kB
text/typescript
/*
* Deepkit Framework
* Copyright (C) 2021 Deepkit UG, Marc J. Schmidt
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the MIT License.
*
* You should have received a copy of the MIT License along with this program.
*/
import { isAbsolute, join } from 'path';
import { existsSync, readFileSync } from 'fs';
class ConfigOptionNotFound extends Error {
}
export function resolveEnvFilePath(path: string): string | undefined {
const resolvedPath = isAbsolute(path) ? path : findFileUntilPackageRoot(path);
if (!resolvedPath || !existsSync(resolvedPath)) return undefined;
return resolvedPath;
}
function findFileUntilPackageRoot(fileName: string): string | undefined {
let dir = process.cwd();
while (true) {
const candidate = join(dir, fileName);
if (existsSync(candidate)) {
return candidate;
}
// reached root, so stop
if (existsSync(join(dir, 'package.json'))) return;
const next = join(dir, '../');
if (next === dir) return; //reached root
dir = next;
}
}
export class EnvConfiguration {
protected container: { [name: string]: any } = {};
/**
* Reads a .env file from given path, based to basePath.
*/
public loadEnvFile(path: string): boolean {
const resolvedPath = resolveEnvFilePath(path);
if (!resolvedPath) return false;
const RE_INI_KEY_VAL = /^\s*([\w.-]+)\s*=\s*(.*)?\s*$/;
const content = readFileSync(resolvedPath);
for (const line of content.toString('utf8').split('\n')) {
const keyValueArr = line.match(RE_INI_KEY_VAL);
if (!keyValueArr) continue;
const key = keyValueArr[1];
let value = keyValueArr[2] || '';
const end = value.length - 1;
const isDoubleQuoted = value[0] === '"' && value[end] === '"';
const isSingleQuoted = value[0] === '\'' && value[end] === '\'';
// if single or double quoted, remove quotes
if (isSingleQuoted) {
value = value.substring(1, end);
} else if (isDoubleQuoted) {
value = JSON.parse(value);
} else {
value = value.trim();
}
this.container[key] = value;
}
return true;
}
public getKeys(): string[] {
return Object.keys(this.container);
}
public getAll(): { [name: string]: any } {
return this.container;
}
/**
* Returns the value for a configuration option.
*
* Priority is first process.env, then manually set options, then values from the loaded env file.
*/
public get<T = any>(name: string): T {
if (process.env[name] !== undefined) return process.env[name] as any;
if (this.container[name] !== undefined) return this.container[name];
throw new ConfigOptionNotFound(`Config option ${name} not found.`);
}
/**
* Sets an option value. If a env file has been read, it will be overwritten.
*/
public set(name: string, value: any) {
this.container[name] = value;
}
}