UNPKG

@adjust/core

Version:

A framework for creating highly customisable open source software

205 lines 9.59 kB
Object.defineProperty(exports, "__esModule", { value: true }); const data_1 = require("../data"); const settingsManager_1 = require("./settingsManager"); const eventEmitter_1 = require("../../utils/eventEmitter"); const extendedObject_1 = require("../../utils/extendedObject"); const sortedList_1 = require("../../utils/sortedList"); class Settings extends eventEmitter_1.EventEmitter { /** * Creates settings for a specific module instance * @param target The module instance to target * @param config The configuration for the existing settings */ constructor(target, config) { super(); this.target = target; this.settingsFile = settingsManager_1.SettingsManager.getSettingsFile(target.getClass().getPath(), config); // Load the settings that apply to this target this.get = this.loadApplicableSettingsFromFile(); // Setup the listeners this.setupSettingsFileListener(); // Create the setters object this.set = this.setupSetters(); } // Disposal /** * Properly disposes the object */ destroy() { this.settingsFile.off("change", this.settingsFileListener); } // Setup methods /** * Gets the settings from the settings file and loads the ones that apply to this target * @returns The getter object for the settings */ loadApplicableSettingsFromFile() { this.settingsPriorities = {}; // Go through all the settingsSets and their conditions this.settingsFile.getAllSettings().forEach(settingsSet => { // Check if the conditions apply to this target const condition = settingsSet.condition; if (this.satisfiesCondition(condition)) { // Go through all the settings values extendedObject_1.ExtendedObject.forEach(settingsSet.data.get, (key, value, path, parentPath) => { // Get the list to store the value in const parent = extendedObject_1.ExtendedObject.getField(this.settingsPriorities, parentPath, true); let field = parent[key]; // Create the list if absent if (!field) field = parent[key] = new sortedList_1.SortedList((a, b) => a.condition.getPriority() - b.condition.getPriority()); // Store the value field.push({ condition: condition, value: value }); }, true, true); } }); // Retrieve all the highest priority settings const settings = {}; extendedObject_1.ExtendedObject.forEach(this.settingsPriorities, (key, value, path, parentPath) => { // Get the highest priority value, and store it const val = value.get(-1).value; const parent = extendedObject_1.ExtendedObject.getField(settings, parentPath, true); parent[key] = val; }, true); this.settings = new data_1.Data(settings); return this.settings.get; } /** * Adds the necessary listeners to the settings file, to keep the data in this bject synchronised */ setupSettingsFileListener() { this.settingsFileListener = (path, value, condition) => { if (this.satisfiesCondition(condition)) { // Keep track of whether or not the settings value has to be updated let updateValue = false; // Get the list to contain the value const list = extendedObject_1.ExtendedObject.getField(this.settingsPriorities, path); // Check if the value has been remvoed, change or inserted if (value === undefined) { // If the value has been removed, remove it from the list const oldIndex = list.pop(item => item.condition.equals(condition)); // Check if it was the highest priority element updateValue = list.length == oldIndex; } else { // Get the actual array from the sorted list const array = list.get(); // Get the item that contains the condition and value let item = array.find(item => item.condition.equals(condition)); // Check if the item actually exists if (item) { // If so, change its value item.value = value; } else { // If it didn't exist yet, create it item = { condition: condition, value: value }; list.push(item); } // Find the index of the setting const index = array.findIndex(item => item.condition.equals(condition)); // Check if it was the highest priority element updateValue = index == list.length - 1; } // If the value updated, emit a change if (updateValue) { const value = list.get(-1).value; // Retrieve the current value const oldValue = extendedObject_1.ExtendedObject.getField(this.settings.get, path); // Replace the setting by the new highest priority element this.settings.changeData(extendedObject_1.ExtendedObject.translatePathToObject(path, value)); // Send a change event this.emit("change", path, value, oldValue); } } }; this.settingsFile.on("change", this.settingsFileListener); } // Altering settings setup methods /** * Creates setter methods for all of the settings * @returns A setter object that takes a condition as a second argument */ setupSetters() { // Get the class const Class = this.__proto__.constructor; // Perform the static method 'createSetters' to turn the data structure intoa setters structure return Class.createSetters(this.settingsFile.getStucture(), this.changeData.bind(this)); } /** * Goes through the initial data in order to map all fields to setter methods on the set object * @param object The object for which to create setter functions * @param path The path of the given object from the root in this data * @returns The mapped object where all values are callable setter functions */ static createSetters(object, change, path = "") { return extendedObject_1.ExtendedObject.map(object, (value, key) => { // Create an object path from the string path, an leave the property value blank const top = {}; const propPath = extendedObject_1.ExtendedObject.translatePathToObject(path, top); // Create the set method const setter = (value, condition) => { // Change the top most part of the data path (the value) top[key] = value; // Emit the change return change(propPath, condition); }; // Add any subsetters to the setter if necessary by recursing if (value instanceof Object) { const p = (path ? path + "." : "") + key; // Assign the child setters Object.assign(setter, this.createSetters(value, change, p)); } // Map the data to the setter return setter; }); } // Data altering methods /** * Changes the data for a passed condition * @param data The fields to change * @param condition The condition to change them fore * @returns A promise that resolves when all listeners resolved */ changeData(data, condition) { // Check if the condition applies to this target, if not throw an error if (!this.satisfiesCondition(condition)) throw new Error("The target of these settings doesn't satisfy the given condition"); // Return the setter object from the settingsFile return this.settingsFile.getConditionData(condition).changeData(data); } /** * Checks whether the target of these settings satisfy the passed condition * @param condition The condition to check for * @returns Whether or not the target satisfies the condition */ satisfiesCondition(condition) { return !condition || condition.matches(this.target); } // Data retrieval methods /** * Retrieves the data object storing all the applicable settings * @returns The settings Data instance */ getSettings() { return this.settings; } // Saving /** * Stores all the settings (including the ones that do not apply to this target) in the corresponding file */ save() { return this.settingsFile.save(); } /** * Reloads all the settings (including the ones that do not apply to this target) from the corresponding file */ reload() { return this.settingsFile.reload(); } on(type, listener, name) { return super.on(type, listener, name); } } exports.Settings = Settings; //# sourceMappingURL=settings.js.map