| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338 |
69x
69x
69x
69x
69x
69x
69x
69x
69x
69x
69x
69x
69x
102x
36x
34x
39x
57x
47x
30x
47x
57x
80x
1x
79x
79x
25x
79x
79x
25x
19x
88x
3x
107x
259x
259x
37x
37x
259x
14x
14x
14x
9x
9x
14x
621x
46x
8x
46x
11x
46x
19x
19x
14x
2x
12x
5x
5x
5x
5x
3x
5x
5x
7x
7x
7x
1x
5x
6x
6x
6x
6x
6x
2x
3x
3x
| /**
* © 2014 Liferay, Inc. <https://liferay.com>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
import Module from './module';
/**
*
*/
export default class Config {
/**
* Creates an instance of Configuration class
* @constructor
* @param {object=} cfg configuration properties
*/
constructor(cfg = {}) {
this._modules = {};
this._maps = {};
this._paths = {};
this._config = {maps: {}, paths: {}};
this._parse(cfg, 'defaultURLParams', {});
this._parse(cfg, 'explainResolutions', false);
this._parse(cfg, 'showWarnings', false);
this._parse(cfg, 'waitTimeout', 7000);
this._parse(cfg, 'basePath', '/');
this._parse(cfg, 'resolvePath', '/o/js_resolve_modules');
this._parse(cfg, 'combine', false);
this._parse(cfg, 'url', '');
this._parse(cfg, 'urlMaxLength', 2000);
}
/**
* Whether to explain how require() calls are resolved
*/
get explainResolutions() {
return this._config.explainResolutions;
}
/**
* Whether to show development warnings
*/
get showWarnings() {
return this._config.showWarnings;
}
/**
* Time to wait for module script requests to load (in milliseconds)
*/
get waitTimeout() {
return this._config.waitTimeout;
}
/**
* The base path from where modules must be retrieved
*/
get basePath() {
return this._config.basePath;
}
/**
* The path to use when calling the server to resolve module dependencies
*/
get resolvePath() {
return this._config.resolvePath;
}
/**
* Whether to combine module requests into combo URLs
*/
get combine() {
return this._config.combine;
}
/**
* The URL of the server
*/
get url() {
return this._config.url;
}
/**
* The maximum length of a combo URL. If URL is larger than that it is split
* in as many requests as needed.
*/
get urlMaxLength() {
return this._config.urlMaxLength;
}
/**
* Default parameters to add to the module request URLs
*/
get defaultURLParams() {
return this._config.defaultURLParams;
}
/**
* An object with registered module paths
*/
get paths() {
return this._paths;
}
/**
* Adds a module to the configuration with default field values if it
* doesn't exist. Otherwise, throws an exception.
* @param {string} moduleName
* @param {object} moduleProperties initial properties to set on module in
* addition to its name
* @return {Object} the module
*/
addModule(moduleName, moduleProperties = {}) {
if (this._modules[moduleName]) {
throw new Error(`Module is already registered: ${moduleName}`);
}
const module = new Module(moduleName);
Object.entries(moduleProperties).forEach(([key, value]) => {
module[key] = value;
});
this._modules[moduleName] = module;
return module;
}
/**
* Add mappings to the current configuration
* @param {object} mappings an object with one or more mappings
*/
addMappings(mappings) {
Object.assign(this._maps, mappings);
}
/**
* Add path mappings to the current configuration
* @param {object} paths an object with one or more path mappings
*/
addPaths(paths) {
Object.assign(this._paths, paths);
}
/**
* Returns array with all registered modules or the requested subset of
* them.
* @param {?Array} moduleNames optional list of module names to retrieve
* @return {Array}
*/
getModules(moduleNames = undefined) {
if (moduleNames === undefined) {
return Object.values(this._modules);
}
return moduleNames.map(moduleName => this.getModule(moduleName));
}
/**
* Returns the registered module for the moduleName.
* @param {string} moduleName the module name
* @return {Object} the registed module object
*/
getModule(moduleName) {
let module = this._modules[moduleName];
if (!module) {
const mappedName = this._mapModule(moduleName);
module = this._modules[mappedName];
}
return module;
}
/**
* Returns the registered module for the dependency of moduleName.
* @param {string} moduleName the module name
* @param {string} dependencyName the dependencyName name
* @return {Object} the registed module object
*/
getDependency(moduleName, dependencyName) {
const module = this.getModule(moduleName);
let dependencyModule = this._modules[dependencyName];
if (!dependencyModule) {
const mappedName = this._mapModule(dependencyName, module.map);
dependencyModule = this._modules[mappedName];
}
return dependencyModule;
}
/**
* Parse a configuration property to store it in _config.
* @param {object} cfg
* @param {string} property
* @param {*} defaultValue
*/
_parse(cfg, property, defaultValue) {
this._config[property] = cfg.hasOwnProperty(property)
? cfg[property]
: defaultValue;
}
/**
* Maps module names to their aliases. Example:
* __CONFIG__.maps = {
* liferay: 'liferay@1.0.0'
* }
*
* When someone does require('liferay/html/js/ac.es',...),
* if the module 'liferay/html/js/ac.es' is not defined,
* then a corresponding alias will be searched. If found, the name will be
* replaced, so it will look like user did
* require('liferay@1.0.0/html/js/ac.es',...).
*
* Additionally, modules can define a custom map to alias module names just
* in the context of that module loading operation. When present, the
* contextual module mapping will take precedence over the general one.
* @param {string} moduleName The module which have to be mapped
* @param {?object} contextMap Contextual module mapping information
* relevant to the current load operation
* @return {array} The mapped module
*/
_mapModule(moduleName, contextMap) {
if (contextMap) {
moduleName = this._mapMatches(moduleName, contextMap);
}
if (Object.keys(this._maps).length > 0) {
moduleName = this._mapMatches(moduleName, this._maps);
}
return moduleName;
}
/**
* Creates a function that transforms module names based on a provided
* set of mappings.
* @param {string} moduleName module name
* @param {object} maps Mapping information.
* @return {function} The generated mapper function
*/
_mapMatches(moduleName, maps) {
let match = maps[moduleName];
if (match) {
if (typeof match === 'object') {
return match.value;
}
return match;
}
match = this._mapExactMatch(moduleName, maps);
// Apply partial mapping only if exactMatch hasn't been
// already applied for this mapping
Eif (!match) {
match = this._mapPartialMatch(moduleName, maps);
}
// Apply * mapping only if neither exactMatch nor
// partialMatch have been already applied for this mapping
if (!match) {
match = this._mapWildcardMatch(moduleName, maps);
}
return match || moduleName;
}
/**
* Transforms a module name using the exactMatch mappings
* in a provided mapping object.
* @param {string} module The module which have to be mapped.
* @param {object} maps Mapping information.
* @return {object} An object with a boolean `matched` field and a string
* `result` field containing the mapped module name
*/
_mapExactMatch(module, maps) {
for (const alias in maps) {
Eif (Object.prototype.hasOwnProperty.call(maps, alias)) {
const aliasValue = maps[alias];
if (aliasValue.value && aliasValue.exactMatch) {
Iif (module === alias) {
return aliasValue.value;
}
}
}
}
}
/**
* Transforms a module name using the partial mappings
* in a provided mapping object.
* @param {string} module The module which have to be mapped.
* @param {object} maps Mapping information.
* @return {object} An object with a boolean `matched` field and a string
* `result` field containing the mapped module name
*/
_mapPartialMatch(module, maps) {
for (const alias in maps) {
Eif (Object.prototype.hasOwnProperty.call(maps, alias)) {
let aliasValue = maps[alias];
Eif (!aliasValue.exactMatch) {
Iif (aliasValue.value) {
aliasValue = aliasValue.value;
}
if (module === alias || module.indexOf(alias + '/') === 0) {
return aliasValue + module.substring(alias.length);
}
}
}
}
}
/**
* Transforms a module name using the wildcard mapping in a provided mapping
* object.
* @param {string} module The module which have to be mapped.
* @param {object} maps Mapping information.
* @return {object} An object with a boolean `matched` field and a string
* `result` field containing the mapped module name
*/
_mapWildcardMatch(module, maps) {
Eif (typeof maps['*'] === 'function') {
return maps['*'](module);
}
}
}
|