Projekt

Obecné

Profil

Stáhnout (3.71 KB) Statistiky
| Větev: | Revize:
1
/*
2
	MIT License http://www.opensource.org/licenses/mit-license.php
3
	Author Tobias Koppers @sokra
4
*/
5
"use strict";
6

    
7
/**
8
 * Gets the value at path of object
9
 * @param {object} obj object to query
10
 * @param {string} path query path
11
 * @returns {any} - if {@param path} requests element from array, then `undefined` will be returned
12
 */
13
const getProperty = (obj, path) => {
14
	let name = path.split(".");
15
	for (let i = 0; i < name.length - 1; i++) {
16
		obj = obj[name[i]];
17
		if (typeof obj !== "object" || !obj || Array.isArray(obj)) return;
18
	}
19
	return obj[name.pop()];
20
};
21

    
22
/**
23
 * Sets the value at path of object. Stops execution, if {@param path} requests element from array to be set
24
 * @param {object} obj object to query
25
 * @param {string} path query path
26
 * @param {any} value value to be set
27
 * @returns {void}
28
 */
29
const setProperty = (obj, path, value) => {
30
	let name = path.split(".");
31
	for (let i = 0; i < name.length - 1; i++) {
32
		if (typeof obj[name[i]] !== "object" && obj[name[i]] !== undefined) return;
33
		if (Array.isArray(obj[name[i]])) return;
34
		if (!obj[name[i]]) obj[name[i]] = {};
35
		obj = obj[name[i]];
36
	}
37
	obj[name.pop()] = value;
38
};
39

    
40
/**
41
 * @typedef {'call' | 'make' | 'append'} ConfigType
42
 */
43
/**
44
 * @typedef {(options: object) => any} MakeConfigHandler
45
 */
46
/**
47
 * @typedef {(value: any, options: object) => any} CallConfigHandler
48
 */
49
/**
50
 * @typedef {any[]} AppendConfigValues
51
 */
52

    
53
class OptionsDefaulter {
54
	constructor() {
55
		/**
56
		 * Stores default options settings or functions for computing them
57
		 */
58
		this.defaults = {};
59
		/**
60
		 * Stores configuration for options
61
		 * @type {{[key: string]: ConfigType}}
62
		 */
63
		this.config = {};
64
	}
65

    
66
	/**
67
	 * Enhancing {@param options} with default values
68
	 * @param {object} options provided options
69
	 * @returns {object} - enhanced options
70
	 * @throws {Error} - will throw error, if configuration value is other then `undefined` or {@link ConfigType}
71
	 */
72
	process(options) {
73
		options = Object.assign({}, options);
74
		for (let name in this.defaults) {
75
			switch (this.config[name]) {
76
				/**
77
				 * If {@link ConfigType} doesn't specified and current value is `undefined`, then default value will be assigned
78
				 */
79
				case undefined:
80
					if (getProperty(options, name) === undefined) {
81
						setProperty(options, name, this.defaults[name]);
82
					}
83
					break;
84
				/**
85
				 * Assign result of {@link CallConfigHandler}
86
				 */
87
				case "call":
88
					setProperty(
89
						options,
90
						name,
91
						this.defaults[name].call(this, getProperty(options, name), options)
92
					);
93
					break;
94
				/**
95
				 * Assign result of {@link MakeConfigHandler}, if current value is `undefined`
96
				 */
97
				case "make":
98
					if (getProperty(options, name) === undefined) {
99
						setProperty(options, name, this.defaults[name].call(this, options));
100
					}
101
					break;
102
				/**
103
				 * Adding {@link AppendConfigValues} at the end of the current array
104
				 */
105
				case "append": {
106
					let oldValue = getProperty(options, name);
107
					if (!Array.isArray(oldValue)) {
108
						oldValue = [];
109
					}
110
					oldValue.push(...this.defaults[name]);
111
					setProperty(options, name, oldValue);
112
					break;
113
				}
114
				default:
115
					throw new Error(
116
						"OptionsDefaulter cannot process " + this.config[name]
117
					);
118
			}
119
		}
120
		return options;
121
	}
122

    
123
	/**
124
	 * Builds up default values
125
	 * @param {string} name option path
126
	 * @param {ConfigType | any} config if {@param def} is provided, then only {@link ConfigType} is allowed
127
	 * @param {MakeConfigHandler | CallConfigHandler | AppendConfigValues} [def] defaults
128
	 * @returns {void}
129
	 */
130
	set(name, config, def) {
131
		if (def !== undefined) {
132
			this.defaults[name] = def;
133
			this.config[name] = config;
134
		} else {
135
			this.defaults[name] = config;
136
			delete this.config[name];
137
		}
138
	}
139
}
140

    
141
module.exports = OptionsDefaulter;
(105-105/144)