141 lines
3.3 KiB
TypeScript
141 lines
3.3 KiB
TypeScript
import * as fs from 'fs-extra';
|
|
|
|
import { IEnvironment } from './environment';
|
|
|
|
/**
|
|
* Configuration object
|
|
*/
|
|
export class Configuration {
|
|
public config: any = {};
|
|
public loaded = false;
|
|
|
|
constructor(
|
|
private env: IEnvironment,
|
|
private file: string,
|
|
private defaults: any = {}
|
|
) {}
|
|
|
|
/**
|
|
* Load the configuration from its file.
|
|
*/
|
|
public async load(): Promise<void> {
|
|
this.loaded = true;
|
|
if (!await fs.pathExists(this.file)) {
|
|
this.saveDefaults();
|
|
return;
|
|
}
|
|
|
|
const json = await fs.readJson(this.file);
|
|
this.config = json;
|
|
|
|
// Assign default values to existing configuration and resave.
|
|
// Eliminates the need for plugins to overwrite the configuration file
|
|
// when exiting.
|
|
if (this.defaults) {
|
|
this.config = Object.assign({}, this.defaults, json);
|
|
await this.save();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save configuration to its file.
|
|
*/
|
|
public async save(): Promise<void> {
|
|
return fs.writeJson(this.file, this.config);
|
|
}
|
|
|
|
/**
|
|
* Get a configuration value by key.
|
|
* @param key JSON traverse key (foo.bar.one)
|
|
* @param defval Default value
|
|
* @param from Internal use only
|
|
* @returns Configuration value or default or null
|
|
*/
|
|
public get(key: string, defval?: any, from?: any): any {
|
|
if (!from) {
|
|
from = this.config;
|
|
}
|
|
|
|
// Recursive object traversal
|
|
if (key.indexOf('.') !== -1) {
|
|
const split = key.split('.');
|
|
const first = this.get(split[0], null, from);
|
|
if (first != null) {
|
|
return this.get(split.slice(1).join('.'), defval, first);
|
|
}
|
|
return defval;
|
|
}
|
|
|
|
// Array indexing
|
|
if (key.indexOf('[') !== -1 && key.indexOf(']') !== -1) {
|
|
const match = key.match(/\[(\d+)\]/i);
|
|
const realKey = key.substr(0, key.indexOf('['));
|
|
if (match != null) {
|
|
const index = parseInt(match[1], 10);
|
|
if (from[realKey]) {
|
|
return from[realKey][index];
|
|
}
|
|
}
|
|
return defval;
|
|
}
|
|
|
|
if (from[key] == null) {
|
|
return defval;
|
|
}
|
|
|
|
return from[key];
|
|
}
|
|
|
|
/**
|
|
* Set a configuration value by key.
|
|
* @returns true on success
|
|
*/
|
|
public set(key: string, value?: any, from?: any): boolean {
|
|
if (!from) {
|
|
from = this.config;
|
|
}
|
|
|
|
// Recursive object traversal
|
|
if (key.indexOf('.') !== -1) {
|
|
const split = key.split('.');
|
|
const first = this.get(split[0], null, from);
|
|
if (first != null) {
|
|
return this.set(split.slice(1).join('.'), value, first);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Array indexing
|
|
if (key.indexOf('[') !== -1 && key.indexOf(']') !== -1) {
|
|
const match = key.match(/\[(\d+)\]/i);
|
|
const realKey = key.substr(0, key.indexOf('['));
|
|
if (match != null) {
|
|
const index = parseInt(match[1], 10);
|
|
if (from[realKey]) {
|
|
from[realKey][index] = value;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
from[key] = value;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Set the default configuration before loading.
|
|
* @param defconf Default configuration
|
|
*/
|
|
public setDefaults(defconf: any): void {
|
|
this.defaults = defconf;
|
|
}
|
|
|
|
/**
|
|
* Save default values to configuration file
|
|
*/
|
|
public async saveDefaults(): Promise<void> {
|
|
this.config = this.defaults || {};
|
|
await this.save();
|
|
}
|
|
}
|