| 
									
										
										
										
											2015-12-30 00:44:55 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2018-07-30 23:08:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-03 00:45:44 +08:00
										 |  |  | "use strict"; | 
					
						
							| 
									
										
										
										
											2015-12-30 00:44:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-17 06:04:01 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Gets the value at path of object | 
					
						
							| 
									
										
										
										
											2019-07-10 04:15:14 +08:00
										 |  |  |  * @param {object} obj object to query | 
					
						
							|  |  |  |  * @param {string} path query path | 
					
						
							| 
									
										
										
										
											2019-06-17 06:04:01 +08:00
										 |  |  |  * @returns {any} - if {@param path} requests element from array, then `undefined` will be returned | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const getProperty = (obj, path) => { | 
					
						
							|  |  |  | 	let name = path.split("."); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 	for (let i = 0; i < name.length - 1; i++) { | 
					
						
							| 
									
										
										
										
											2015-12-30 00:44:55 +08:00
										 |  |  | 		obj = obj[name[i]]; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (typeof obj !== "object" || !obj || Array.isArray(obj)) return; | 
					
						
							| 
									
										
										
										
											2015-12-30 00:44:55 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return obj[name.pop()]; | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2015-12-30 00:44:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-17 06:04:01 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Sets the value at path of object. Stops execution, if {@param path} requests element from array to be set | 
					
						
							| 
									
										
										
										
											2019-07-10 04:15:14 +08:00
										 |  |  |  * @param {object} obj object to query | 
					
						
							|  |  |  |  * @param {string} path query path | 
					
						
							|  |  |  |  * @param {any} value value to be set | 
					
						
							| 
									
										
										
										
											2019-06-17 06:04:01 +08:00
										 |  |  |  * @returns {void} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const setProperty = (obj, path, value) => { | 
					
						
							|  |  |  | 	let name = path.split("."); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 	for (let i = 0; i < name.length - 1; i++) { | 
					
						
							| 
									
										
										
										
											2018-08-21 08:26:50 +08:00
										 |  |  | 		if (typeof obj[name[i]] !== "object" && obj[name[i]] !== undefined) return; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (Array.isArray(obj[name[i]])) return; | 
					
						
							|  |  |  | 		if (!obj[name[i]]) obj[name[i]] = {}; | 
					
						
							| 
									
										
										
										
											2015-12-30 00:44:55 +08:00
										 |  |  | 		obj = obj[name[i]]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	obj[name.pop()] = value; | 
					
						
							| 
									
										
										
										
											2017-11-08 18:32:05 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2015-12-30 00:44:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-17 06:04:01 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @typedef {'call' | 'make' | 'append'} ConfigType | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {(options: object) => any} MakeConfigHandler | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {(value: any, options: object) => any} CallConfigHandler | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {any[]} AppendConfigValues | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-03 00:45:44 +08:00
										 |  |  | class OptionsDefaulter { | 
					
						
							|  |  |  | 	constructor() { | 
					
						
							| 
									
										
										
										
											2019-06-17 06:04:01 +08:00
										 |  |  | 		/** | 
					
						
							|  |  |  | 		 * Stores default options settings or functions for computing them | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2017-01-11 17:51:58 +08:00
										 |  |  | 		this.defaults = {}; | 
					
						
							| 
									
										
										
										
											2019-06-17 06:04:01 +08:00
										 |  |  | 		/** | 
					
						
							|  |  |  | 		 * Stores configuration for options | 
					
						
							|  |  |  | 		 * @type {{[key: string]: ConfigType}} | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2017-01-03 00:45:44 +08:00
										 |  |  | 		this.config = {}; | 
					
						
							| 
									
										
										
										
											2016-10-29 17:11:44 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-17 06:04:01 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * Enhancing {@param options} with default values | 
					
						
							| 
									
										
										
										
											2019-07-10 04:15:14 +08:00
										 |  |  | 	 * @param {object} options provided options | 
					
						
							| 
									
										
										
										
											2019-06-17 06:04:01 +08:00
										 |  |  | 	 * @returns {object} - enhanced options | 
					
						
							|  |  |  | 	 * @throws {Error} - will throw error, if configuration value is other then `undefined` or {@link ConfigType} | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2017-01-03 00:45:44 +08:00
										 |  |  | 	process(options) { | 
					
						
							| 
									
										
										
										
											2019-06-19 19:16:05 +08:00
										 |  |  | 		options = { ...options }; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for (let name in this.defaults) { | 
					
						
							|  |  |  | 			switch (this.config[name]) { | 
					
						
							| 
									
										
										
										
											2019-06-17 06:04:01 +08:00
										 |  |  | 				/** | 
					
						
							|  |  |  | 				 * If {@link ConfigType} doesn't specified and current value is `undefined`, then default value will be assigned | 
					
						
							|  |  |  | 				 */ | 
					
						
							| 
									
										
										
										
											2017-01-03 00:45:44 +08:00
										 |  |  | 				case undefined: | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					if (getProperty(options, name) === undefined) { | 
					
						
							| 
									
										
										
										
											2017-01-03 00:45:44 +08:00
										 |  |  | 						setProperty(options, name, this.defaults[name]); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-01-03 00:45:44 +08:00
										 |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2019-06-17 06:04:01 +08:00
										 |  |  | 				/** | 
					
						
							|  |  |  | 				 * Assign result of {@link CallConfigHandler} | 
					
						
							|  |  |  | 				 */ | 
					
						
							| 
									
										
										
										
											2017-01-03 00:45:44 +08:00
										 |  |  | 				case "call": | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					setProperty( | 
					
						
							|  |  |  | 						options, | 
					
						
							|  |  |  | 						name, | 
					
						
							| 
									
										
										
										
											2018-03-27 13:57:25 +08:00
										 |  |  | 						this.defaults[name].call(this, getProperty(options, name), options) | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					); | 
					
						
							| 
									
										
										
										
											2017-01-03 00:45:44 +08:00
										 |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2019-06-17 06:04:01 +08:00
										 |  |  | 				/** | 
					
						
							|  |  |  | 				 * Assign result of {@link MakeConfigHandler}, if current value is `undefined` | 
					
						
							|  |  |  | 				 */ | 
					
						
							| 
									
										
										
										
											2017-01-03 00:45:44 +08:00
										 |  |  | 				case "make": | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					if (getProperty(options, name) === undefined) { | 
					
						
							| 
									
										
										
										
											2018-03-27 16:19:13 +08:00
										 |  |  | 						setProperty(options, name, this.defaults[name].call(this, options)); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-01-03 00:45:44 +08:00
										 |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2019-06-17 06:04:01 +08:00
										 |  |  | 				/** | 
					
						
							|  |  |  | 				 * Adding {@link AppendConfigValues} at the end of the current array | 
					
						
							|  |  |  | 				 */ | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				case "append": { | 
					
						
							|  |  |  | 					let oldValue = getProperty(options, name); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					if (!Array.isArray(oldValue)) { | 
					
						
							|  |  |  | 						oldValue = []; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					oldValue.push(...this.defaults[name]); | 
					
						
							|  |  |  | 					setProperty(options, name, oldValue); | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-01-03 00:45:44 +08:00
										 |  |  | 				default: | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					throw new Error( | 
					
						
							|  |  |  | 						"OptionsDefaulter cannot process " + this.config[name] | 
					
						
							|  |  |  | 					); | 
					
						
							| 
									
										
										
										
											2017-01-03 00:45:44 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-12-30 00:44:55 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-09-14 15:22:29 +08:00
										 |  |  | 		return options; | 
					
						
							| 
									
										
										
										
											2015-12-30 00:44:55 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-17 06:04:01 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * Builds up default values | 
					
						
							| 
									
										
										
										
											2019-07-10 04:15:14 +08:00
										 |  |  | 	 * @param {string} name option path | 
					
						
							|  |  |  | 	 * @param {ConfigType | any} config if {@param def} is provided, then only {@link ConfigType} is allowed | 
					
						
							|  |  |  | 	 * @param {MakeConfigHandler | CallConfigHandler | AppendConfigValues} [def] defaults | 
					
						
							| 
									
										
										
										
											2019-06-17 06:04:01 +08:00
										 |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2017-01-03 00:45:44 +08:00
										 |  |  | 	set(name, config, def) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (def !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-01-03 00:45:44 +08:00
										 |  |  | 			this.defaults[name] = def; | 
					
						
							|  |  |  | 			this.config[name] = config; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			this.defaults[name] = config; | 
					
						
							|  |  |  | 			delete this.config[name]; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-12-30 00:44:55 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-03 00:45:44 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = OptionsDefaulter; |