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 { 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 { 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 { this.config = this.defaults || {}; await this.save(); } }