@sap-ux/jest-environment-ui5 5.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3323 @@
1
+ /*!
2
+ * ${copyright}
3
+ */
4
+
5
+ // This file is a copy from the ui5 ui5loader.js file with some modifications to make it work in the jest enviorment
6
+ /*
7
+ * IMPORTANT NOTICE
8
+ * With 1.54, ui5loader.js and its new features are not yet a public API.
9
+ * The loader must only be used via the well-known and documented UI5 APIs
10
+ * such as sap.ui.define, sap.ui.require, etc.
11
+ * Any direct usage of ui5loader.js or its features is not supported and
12
+ * might break in future releases.
13
+ */
14
+
15
+ /*global sap:true, Blob, console, document, Promise, URL, XMLHttpRequest */
16
+
17
+ (function(__global) {
18
+ "use strict";
19
+
20
+ /*
21
+ * Helper function that removes any query and/or hash parts from the given URL.
22
+ *
23
+ * @param {string} href URL to remove query and hash from
24
+ * @returns {string}
25
+ */
26
+ function pathOnly(href) {
27
+ const p = href.search(/[?#]/);
28
+ return p < 0 ? href : href.slice(0, p);
29
+ }
30
+
31
+ /**
32
+ * Resolve a given URL, either against the base URL of the current document or against a given base URL.
33
+ *
34
+ * If no base URL is given, the URL will be resolved relative to the baseURI of the current document.
35
+ * If a base URL is given, that base will first be resolved relative to the document's baseURI,
36
+ * then the URL will be resolved relative to the resolved base.
37
+ *
38
+ * Search parameters or a hash of the chosen base will be ignored.
39
+ *
40
+ * @param {string} sURI Relative or absolute URL that should be resolved
41
+ * @param {string} [sBase=document.baseURI] Base URL relative to which the URL should be resolved
42
+ * @returns {string} Resolved URL
43
+ */
44
+ function resolveURL(sURI, sBase) {
45
+ sBase = pathOnly(sBase ? resolveURL(sBase) : document.baseURI);
46
+ return new URL(sURI, sBase).href;
47
+ }
48
+
49
+ // ---- helpers -------------------------------------------------------------------------------
50
+
51
+ function noop() {}
52
+
53
+ function forEach(obj, callback) {
54
+ Object.keys(obj).forEach((key) => callback(key, obj[key]));
55
+ }
56
+
57
+ function executeInSeparateTask(fn) {
58
+ setTimeout(fn, 0);
59
+ }
60
+
61
+ function executeInMicroTask(fn) {
62
+ Promise.resolve().then(fn);
63
+ }
64
+
65
+ // ---- hooks & configuration -----------------------------------------------------------------
66
+
67
+ const aEarlyLogs = [];
68
+
69
+ function earlyLog(level, message) {
70
+ aEarlyLogs.push({
71
+ level,
72
+ message
73
+ });
74
+ }
75
+
76
+ /**
77
+ * Log functionality.
78
+ *
79
+ * Can be set to an object with the methods shown below (subset of sap/base/Log).
80
+ * Logging methods never must fail. Should they ever throw errors, then the internal state
81
+ * of the loader will be broken.
82
+ *
83
+ * By default, all methods are implemented as NOOPs.
84
+ *
85
+ * @type {{debug:function(),info:function(),warning:function(),error:function(),isLoggable:function():boolean}}
86
+ * @private
87
+ */
88
+
89
+ let log = {
90
+ debug: earlyLog.bind(this, 'debug'),
91
+ info: earlyLog.bind(this, 'info'),
92
+ warning: earlyLog.bind(this, 'warning'),
93
+ error: earlyLog.bind(this, 'error'),
94
+ isLoggable: noop
95
+ };
96
+
97
+ /**
98
+ * Basic assert functionality.
99
+ *
100
+ * Can be set to a function that gets a value (the expression to be asserted) as first
101
+ * parameter and a message as second parameter. When the expression coerces to false,
102
+ * the assertion is violated and the message should be emitted (logged, thrown, whatever).
103
+ *
104
+ * By default, this is implemented as a NOOP.
105
+ * @type {function(any,string)}
106
+ * @private
107
+ */
108
+ let assert = noop; // Null Object pattern: dummy assert which is used as long as no assert is injected
109
+
110
+ /**
111
+ * Callback for performance measurement.
112
+ *
113
+ * When set, it must be an object with methods <code>start</code> and <code>end</code>.
114
+ * @type {{start:function(string,any),end:function(string)}}
115
+ * @private
116
+ */
117
+ let measure;
118
+
119
+ /**
120
+ * Source code transformation hook.
121
+ *
122
+ * To be used by code coverage, only supported in sync mode.
123
+ * @private
124
+ */
125
+ let translate;
126
+
127
+ /**
128
+ * Method used by sap.ui.require to simulate asynchronous behavior.
129
+ *
130
+ * The default executes the given function in a separate browser task.
131
+ * Can be changed to execute in a micro task to save idle time in case of
132
+ * many nested sap.ui.require calls.
133
+ */
134
+ let simulateAsyncCallback = executeInSeparateTask;
135
+
136
+ /*
137
+ * Activates strictest possible compliance with AMD spec
138
+ * - no multiple executions of the same module
139
+ * - at most one anonymous module definition per file, zero for adhoc definitions
140
+ */
141
+ const strictModuleDefinitions = true;
142
+
143
+ /**
144
+ * Whether asynchronous loading can be used at all.
145
+ * When activated, require will load asynchronously, else synchronously.
146
+ * @type {boolean}
147
+ * @private
148
+ */
149
+ let bGlobalAsyncMode = false;
150
+
151
+
152
+ /**
153
+ * Whether ui5loader currently exposes its AMD implementation as global properties
154
+ * <code>define</code> and <code>require</code>. Defaults to <code>false</code>.
155
+ * @type {boolean}
156
+ * @private
157
+ */
158
+ let bExposeAsAMDLoader = false;
159
+
160
+ /**
161
+ * How the loader should react to calls of sync APIs or when global names are accessed:
162
+ * 0: tolerate
163
+ * 1: warn
164
+ * 2: reject
165
+ * @type {int}
166
+ * @private
167
+ */
168
+ let syncCallBehavior = 0;
169
+
170
+ /**
171
+ * Default base URL for modules, used when no other configuration is provided.
172
+ * In case the base url is removed via <code>registerResourcePath("", null)</code>
173
+ * it will be reset to this URL instead.
174
+ * @const
175
+ * @type {string}
176
+ * @private
177
+ */
178
+ const DEFAULT_BASE_URL = "";
179
+
180
+ /**
181
+ * Temporarily saved reference to the original value of the global define variable.
182
+ *
183
+ * @type {any}
184
+ * @private
185
+ */
186
+ let vOriginalDefine;
187
+
188
+ /**
189
+ * Temporarily saved reference to the original value of the global require variable.
190
+ *
191
+ * @type {any}
192
+ * @private
193
+ */
194
+ let vOriginalRequire;
195
+
196
+ let currentModuleName;
197
+
198
+
199
+ /**
200
+ * A map of URL prefixes keyed by the corresponding module name prefix.
201
+ *
202
+ * Note that the empty prefix ('') will always match and thus serves as a fallback.
203
+ * See {@link sap.ui.loader.config}, option <code>paths</code>.
204
+ * @type {Object<string,{url:string,absoluteUrl:string}>}
205
+ * @private
206
+ */
207
+ const mUrlPrefixes = Object.create(null);
208
+ mUrlPrefixes[''] = {
209
+ url: DEFAULT_BASE_URL,
210
+ absoluteUrl: resolveURL(DEFAULT_BASE_URL)
211
+ };
212
+
213
+ /**
214
+ * Mapping of module IDs.
215
+ *
216
+ * Each entry is a map of its own, keyed by the module ID prefix for which it should be
217
+ * applied. Each contained map maps module ID prefixes to module ID prefixes.
218
+ *
219
+ * All module ID prefixes must not have extensions.
220
+ * @type {Object.<string,Object.<string,string>>}
221
+ * @private
222
+ */
223
+ const mMaps = Object.create(null);
224
+
225
+ /**
226
+ * Information about third party modules, keyed by the module's resource name (including extension '.js').
227
+ *
228
+ * Each module shim object can have the following properties:
229
+ * <ul>
230
+ * <li><i>boolean</i>: [amd=false] Whether the module uses an AMD loader if present. If set to <code>true</code>,
231
+ * UI5 will disable an AMD loader while loading such a module to force the module to expose its content
232
+ * via global names.</li>
233
+ * <li><i>string[]|string</i>: [exports=undefined] Global name (or names) that are exported by the module.
234
+ * If one ore multiple names are defined, the first one will be read from the global object and will be
235
+ * used as value of the module. Each name can be a dot separated hierarchical name (will be resolved with
236
+ * <code>getGlobalProperty</code>)</li>
237
+ * <li><i>string[]</i>: [deps=undefined] List of modules that the module depends on. The modules will be loaded
238
+ * first before loading the module itself. Note that the stored dependencies also include the extension '.js'
239
+ * for easier evaluation, but <code>config({shim:...})</code> expects them without the extension for
240
+ * compatibility with the AMD-JS specification.</li>
241
+ * </ul>
242
+ *
243
+ * @see config method
244
+ * @type {Object.<string,{amd:boolean,exports:(string|string[]),deps:string[]}>}
245
+ * @private
246
+ */
247
+ const mShims = Object.create(null);
248
+
249
+ /**
250
+ * Dependency Cache information.
251
+ * Maps the name of a module to a list of its known dependencies.
252
+ * @type {Object.<string,string[]>}
253
+ * @private
254
+ */
255
+ const mDepCache = Object.create(null);
256
+
257
+ /**
258
+ * Whether the loader should try to load debug sources.
259
+ * @type {boolean}
260
+ * @private
261
+ */
262
+ let bDebugSources = false;
263
+
264
+ /**
265
+ * Indicates partial or total debug mode.
266
+ *
267
+ * Can be set to a function which checks whether preloads should be ignored for the given module.
268
+ * If undefined, all preloads will be used.
269
+ * @type {function(string):boolean|undefined}
270
+ * @private
271
+ */
272
+ let fnIgnorePreload;
273
+
274
+
275
+ // ---- internal state ------------------------------------------------------------------------
276
+
277
+ /**
278
+ * Map of modules that have been loaded or required so far, keyed by their name.
279
+ *
280
+ * @type {Object<string,Module>}
281
+ * @private
282
+ */
283
+ const mModules = Object.create(null);
284
+
285
+ /**
286
+ * Whether (sap.ui.)define calls must be executed synchronously in the current context.
287
+ *
288
+ * The initial value is <code>null</code>. During the execution of a module loading operation
289
+ * ((sap.ui.)require or (sap.ui.)define etc.), it is set to true or false depending on the
290
+ * legacy synchronicity behavior of the operation.
291
+ *
292
+ * Problem: when AMD modules are loaded with hard coded script tags and when some later inline
293
+ * script expects the module export synchronously, then the (sap.ui.)define must be executed
294
+ * synchronously.
295
+ * Most prominent example: unit tests that include QUnitUtils as a script tag and use qutils
296
+ * in one of their inline scripts.
297
+ * @type {boolean|null}
298
+ * @private
299
+ */
300
+ let bForceSyncDefines = null;
301
+
302
+ /**
303
+ * Stack of modules that are currently being executed in case of synchronous processing.
304
+ *
305
+ * Allows to identify the executing module (e.g. when resolving dependencies or in case of
306
+ * bundles like sap-ui-core).
307
+ *
308
+ * @type {Array.<{name:string,used:boolean}>}
309
+ * @private
310
+ */
311
+ const _execStack = [ ];
312
+
313
+ /**
314
+ * A prefix that will be added to module loading log statements and which reflects the nesting of module executions.
315
+ * @type {string}
316
+ * @private
317
+ */
318
+ let sLogPrefix = "";
319
+
320
+ /**
321
+ * Counter used to give anonymous modules a unique module ID.
322
+ * @type {int}
323
+ * @private
324
+ */
325
+ let iAnonymousModuleCount = 0;
326
+
327
+ // ---- break preload execution into tasks ----------------------------------------------------
328
+
329
+ /**
330
+ * Default value for `iMaxTaskDuration`.
331
+ *
332
+ * A value of -1 switched the scheduling off, a value of zero postpones each execution
333
+ */
334
+ const DEFAULT_MAX_TASK_DURATION = -1; // off
335
+
336
+ /**
337
+ * Maximum accumulated task execution time (threshold)
338
+ * Can be configured via the private API property `maxTaskDuration`.
339
+ */
340
+ let iMaxTaskDuration = DEFAULT_MAX_TASK_DURATION;
341
+
342
+ /**
343
+ * The earliest elapsed time at which a new browser task will be enforced.
344
+ * Will be updated when a new task starts.
345
+ */
346
+ let iMaxTaskTime = Date.now() + iMaxTaskDuration;
347
+
348
+ /**
349
+ * A promise that fulfills when the new browser task has been reached.
350
+ * All postponed callback executions will be executed after this promise.
351
+ * `null` as long as the elapsed time threshold is not reached.
352
+ */
353
+ let pWaitForNextTask;
354
+
355
+ /**
356
+ * Message channel which will be used to create a new browser task
357
+ * without being subject to timer throttling.
358
+ * Will be created lazily on first usage.
359
+ */
360
+ let oNextTaskMessageChannel;
361
+
362
+ /**
363
+ * Update elapsed time threshold.
364
+ *
365
+ * The threshold will be updated only if executions currently are not postponed.
366
+ * Otherwise, the next task will anyhow update the threshold.
367
+ */
368
+ function updateMaxTaskTime() {
369
+ if ( pWaitForNextTask == null ) {
370
+ iMaxTaskTime = Date.now() + iMaxTaskDuration;
371
+ }
372
+ }
373
+
374
+ /**
375
+ * Update duration limit and elapsed time threshold.
376
+ */
377
+ function updateMaxTaskDuration(v) {
378
+ v = Number(v);
379
+
380
+ const iBeginOfCurrentTask = iMaxTaskTime - iMaxTaskDuration;
381
+
382
+ // limit to range [-1 ... Infinity], any other value incl. NaN restores the default
383
+ iMaxTaskDuration = v >= -1 ? v : DEFAULT_MAX_TASK_DURATION;
384
+
385
+ // Update the elapsed time threshold only if executions currently are not postponed.
386
+ // Otherwise, the next task will be the first to honor the new maximum duration.
387
+ if ( pWaitForNextTask == null ) {
388
+ iMaxTaskTime = iBeginOfCurrentTask + iMaxTaskDuration;
389
+ }
390
+ }
391
+
392
+ function waitForNextTask() {
393
+ if ( pWaitForNextTask == null ) {
394
+ /**
395
+ * Post a message to a MessageChannel to create a new task, without suffering from timer throttling
396
+ * In the new task, use a setTimeout(,0) to allow for better queuing of other events (like CSS loading)
397
+ */
398
+ pWaitForNextTask = new Promise(function(resolve) {
399
+ if ( oNextTaskMessageChannel == null ) {
400
+ oNextTaskMessageChannel = new MessageChannel();
401
+ oNextTaskMessageChannel.port2.start();
402
+ }
403
+ oNextTaskMessageChannel.port2.addEventListener("message", function() {
404
+ setTimeout(function() {
405
+ pWaitForNextTask = null;
406
+ iMaxTaskTime = Date.now() + iMaxTaskDuration;
407
+ resolve();
408
+ }, 0);
409
+ }, {
410
+ once: true
411
+ });
412
+ oNextTaskMessageChannel.port1.postMessage(null);
413
+ });
414
+ }
415
+ return pWaitForNextTask;
416
+ }
417
+
418
+ /**
419
+ * Creates a function which schedules the execution of the given callback.
420
+ *
421
+ * The scheduling tries to limit the duration of browser tasks. When the configurable
422
+ * limit is reached, the creation of a new browser task is triggered and all subsequently
423
+ * scheduled callbacks will be postponed until the new browser task starts executing.
424
+ * In the new browser task, scheduling starts anew.
425
+ *
426
+ * The limit for the duration of browser tasks is configured via `iMaxTaskDuration`.
427
+ * By setting `iMaxTaskDuration` to a negative value, the whole scheduling mechanism is
428
+ * switched off. In that case, the returned function will execute the callback immediately.
429
+ *
430
+ * If a value of zero is set, each callback will be executed in a separate browser task.
431
+ * For preloaded modules, this essentially mimics the browser behavior of single file loading,
432
+ * but without the network and server delays.
433
+ *
434
+ * For larger values, at least one callback will be executed in each new browser task. When,
435
+ * after the execution of the callback, the configured threshold has been reached, all further
436
+ * callbacks will be postponed.
437
+ *
438
+ * Note: This is a heuristic only. Neither is the measurement of the task duration accurate,
439
+ * nor is there a way to know in advance the execution time of a callback.
440
+ *
441
+ * @param {function(any):void} fnCallback
442
+ * Function to schedule
443
+ * @returns {function(any):void}
444
+ * A function to call instead of the original callback; it takes care of scheduling
445
+ * and executing the original callback.
446
+ * @private
447
+ */
448
+ function scheduleExecution(fnCallback) {
449
+ if ( iMaxTaskDuration < 0 ) {
450
+ return fnCallback;
451
+ }
452
+ return function() {
453
+ if ( pWaitForNextTask == null ) {
454
+ fnCallback.call(undefined, arguments[0]);
455
+
456
+ // if time limit is reached now, postpone future task
457
+ if ( Date.now() >= iMaxTaskTime ) {
458
+ waitForNextTask();
459
+ }
460
+ return;
461
+ }
462
+ pWaitForNextTask.then(scheduleExecution(fnCallback).bind(undefined, arguments[0]));
463
+ };
464
+ }
465
+
466
+ // ---- Names and Paths -----------------------------------------------------------------------
467
+
468
+ /**
469
+ * Name conversion function that converts a name in unified resource name syntax to a name in UI5 module name syntax.
470
+ * If the name cannot be converted (e.g. doesn't end with '.js'), then <code>undefined</code> is returned.
471
+ *
472
+ * @param {string} sName Name in unified resource name syntax
473
+ * @returns {string|undefined} Name in UI5 (legacy) module name syntax (dot separated)
474
+ * or <code>undefined</code> when the name can't be converted
475
+ * @private
476
+ */
477
+ function urnToUI5(sName) {
478
+ // UI5 module name syntax is only defined for JS resources
479
+ if ( !/\.js$/.test(sName) ) {
480
+ return undefined;
481
+ }
482
+
483
+ sName = sName.slice(0, -3);
484
+ if ( /^jquery\.sap\./.test(sName) ) {
485
+ return sName; // do nothing
486
+ }
487
+ return sName.replace(/\//g, ".");
488
+ }
489
+
490
+ function urnToIDAndType(sResourceName) {
491
+ const basenamePos = sResourceName.lastIndexOf('/');
492
+ const dotPos = sResourceName.lastIndexOf('.');
493
+
494
+ if ( dotPos > basenamePos ) {
495
+ return {
496
+ id: sResourceName.slice(0, dotPos),
497
+ type: sResourceName.slice(dotPos)
498
+ };
499
+ }
500
+ return {
501
+ id: sResourceName,
502
+ type: ''
503
+ };
504
+ }
505
+
506
+ const rJSSubTypes = /(\.controller|\.fragment|\.view|\.designtime|\.support)?.js$/;
507
+
508
+ function urnToBaseIDAndSubType(sResourceName) {
509
+ const m = rJSSubTypes.exec(sResourceName);
510
+ if ( m ) {
511
+ return {
512
+ baseID: sResourceName.slice(0, m.index),
513
+ subType: m[0]
514
+ };
515
+ }
516
+ }
517
+
518
+ const rDotSegmentAnywhere = /(?:^|\/)\.+(?=\/|$)/;
519
+ const rDotSegment = /^\.*$/;
520
+
521
+ /**
522
+ * Normalizes a resource name by resolving any relative name segments.
523
+ *
524
+ * A segment consisting of a single dot <code>./</code>, when used at the beginning of a name refers
525
+ * to the containing package of the <code>sBaseName</code>. When used inside a name, it is ignored.
526
+ *
527
+ * A segment consisting of two dots <code>../</code> refers to the parent package. It can be used
528
+ * anywhere in a name, but the resolved name prefix up to that point must not be empty.
529
+ *
530
+ * Example: A name <code>../common/validation.js</code> defined in <code>sap/myapp/controller/mycontroller.controller.js</code>
531
+ * will resolve to <code>sap/myapp/common/validation.js</code>.
532
+ *
533
+ * When <code>sBaseName</code> is <code>null</code> (e.g. for a <code>sap.ui.require</code> call),
534
+ * the resource name must not start with a relative name segment or an error will be thrown.
535
+ *
536
+ * @param {string} sResourceName Name to resolve
537
+ * @param {string|null} sBaseName Name of a reference module relative to which the name will be resolved
538
+ * @returns {string} Resolved name
539
+ * @throws {Error} When a relative name should be resolved but not basename is given;
540
+ * or when upward navigation (../) is requested on the root level
541
+ * or when a name segment consists of 3 or more dots only
542
+ * @private
543
+ */
544
+ function normalize(sResourceName, sBaseName) {
545
+
546
+ const p = sResourceName.search(rDotSegmentAnywhere);
547
+
548
+ // check whether the name needs to be resolved at all - if not, just return the sModuleName as it is.
549
+ if ( p < 0 ) {
550
+ return sResourceName;
551
+ }
552
+
553
+ // if the name starts with a relative segment then there must be a base name (a global sap.ui.require doesn't support relative names)
554
+ if ( p === 0 ) {
555
+ if ( sBaseName == null ) {
556
+ throw new Error("relative name not supported ('" + sResourceName + "'");
557
+ }
558
+ // prefix module name with the parent package
559
+ sResourceName = sBaseName.slice(0, sBaseName.lastIndexOf('/') + 1) + sResourceName;
560
+ }
561
+
562
+ const aSegments = sResourceName.split('/');
563
+
564
+ // process path segments
565
+ let j = 0;
566
+ const l = aSegments.length;
567
+ for (let i = 0; i < l; i++) {
568
+
569
+ const sSegment = aSegments[i];
570
+
571
+ if ( rDotSegment.test(sSegment) ) {
572
+ if (sSegment === '.' || sSegment === '') {
573
+ // ignore '.' as it's just a pointer to current package. ignore '' as it results from double slashes (ignored by browsers as well)
574
+ continue;
575
+ } else if (sSegment === '..') {
576
+ // move to parent directory
577
+ if ( j === 0 ) {
578
+ throw new Error("Can't navigate to parent of root ('" + sResourceName + "')");
579
+ }
580
+ j--;
581
+ } else {
582
+ throw new Error("Illegal path segment '" + sSegment + "' ('" + sResourceName + "')");
583
+ }
584
+ } else {
585
+ aSegments[j++] = sSegment;
586
+ }
587
+
588
+ }
589
+
590
+ aSegments.length = j;
591
+
592
+ return aSegments.join('/');
593
+ }
594
+
595
+ /**
596
+ * Adds a resource path to the resources map.
597
+ *
598
+ * @param {string} sResourceNamePrefix prefix is used as map key
599
+ * @param {string} sUrlPrefix path to the resource
600
+ */
601
+ function registerResourcePath(sResourceNamePrefix, sUrlPrefix) {
602
+ sResourceNamePrefix = String(sResourceNamePrefix || "");
603
+
604
+ if ( sUrlPrefix == null ) {
605
+
606
+ // remove a registered URL prefix, if it wasn't for the empty resource name prefix
607
+ if ( sResourceNamePrefix ) {
608
+ if ( mUrlPrefixes[sResourceNamePrefix] ) {
609
+ delete mUrlPrefixes[sResourceNamePrefix];
610
+ log.info(`registerResourcePath ('${sResourceNamePrefix}') (registration removed)`);
611
+ }
612
+ return;
613
+ }
614
+
615
+ // otherwise restore the default
616
+ sUrlPrefix = DEFAULT_BASE_URL;
617
+ log.info(`registerResourcePath ('${sResourceNamePrefix}') (default registration restored)`);
618
+
619
+ }
620
+
621
+ // cast to string and remove query parameters and/or hash
622
+ sUrlPrefix = pathOnly(String(sUrlPrefix));
623
+
624
+ // ensure that the prefix ends with a '/'
625
+ if ( sUrlPrefix.slice(-1) !== '/' ) {
626
+ sUrlPrefix += '/';
627
+ }
628
+
629
+ mUrlPrefixes[sResourceNamePrefix] = {
630
+ url: sUrlPrefix,
631
+ // calculate absolute URL, only to be used by 'guessResourceName'
632
+ absoluteUrl: resolveURL(sUrlPrefix)
633
+ };
634
+ }
635
+
636
+ /**
637
+ * Retrieves path to a given resource by finding the longest matching prefix for the resource name
638
+ *
639
+ * @param {string} sResourceName name of the resource stored in the resources map
640
+ * @param {string} sSuffix url suffix
641
+ *
642
+ * @returns {string} resource path
643
+ */
644
+ function getResourcePath(sResourceName, sSuffix) {
645
+ const startsWithSlash = sResourceName.startsWith("/")
646
+ let sNamePrefix = sResourceName;
647
+ let p = sResourceName.length;
648
+
649
+ // search for a registered name prefix, starting with the full name and successively removing one segment
650
+ while ( p > 0 && !mUrlPrefixes[sNamePrefix] ) {
651
+ p = sNamePrefix.lastIndexOf('/');
652
+ // Note: an empty segment at p = 0 (leading slash) will be ignored
653
+ sNamePrefix = p > 0 ? sNamePrefix.slice(0, p) : '';
654
+ }
655
+
656
+ assert((p > 0 || sNamePrefix === '') && mUrlPrefixes[sNamePrefix], "there always must be a mapping");
657
+
658
+ let sPath = mUrlPrefixes[sNamePrefix].url + sResourceName.slice(p + 1); // also skips a leading slash!
659
+
660
+ //remove trailing slash
661
+ if ( sPath.slice(-1) === '/' ) {
662
+ sPath = sPath.slice(0, -1);
663
+ }
664
+ if(startsWithSlash) {
665
+ sPath = `/${sPath}`
666
+ }
667
+ return sPath + (sSuffix || '');
668
+
669
+ }
670
+
671
+ /**
672
+ * Returns the reporting mode for synchronous calls
673
+ *
674
+ * @returns {int} sync call behavior
675
+ */
676
+ function getSyncCallBehavior() {
677
+ return syncCallBehavior;
678
+ }
679
+
680
+ /**
681
+ * Try to find a resource name that would be mapped to the given URL.
682
+ *
683
+ * If multiple path mappings would create a match, the returned name is not necessarily
684
+ * the best (longest) match. The first match which is found, will be returned.
685
+ *
686
+ * When <code>bLoadedResourcesOnly</code> is set, only those resources will be taken
687
+ * into account for which content has been loaded already.
688
+ *
689
+ * @param {string} sURL URL to guess the resource name for
690
+ * @param {boolean} [bLoadedResourcesOnly=false] Whether the guess should be limited to already loaded resources
691
+ * @returns {string|undefined} Resource name or <code>undefined</code> if no matching name could be found
692
+ * @private
693
+ */
694
+ function guessResourceName(sURL, bLoadedResourcesOnly) {
695
+ // Make sure to have an absolute URL without query parameters or hash
696
+ // to check against absolute prefix URLs
697
+ sURL = pathOnly(resolveURL(sURL));
698
+
699
+ for (const sNamePrefix in mUrlPrefixes) {
700
+
701
+ // Note: configured URL prefixes are guaranteed to end with a '/'
702
+ // But to support the legacy scenario promoted by the application tools ( "registerModulePath('Application','Application')" )
703
+ // the prefix check here has to be done without the slash
704
+ const sUrlPrefix = mUrlPrefixes[sNamePrefix].absoluteUrl.slice(0, -1);
705
+
706
+ if ( sURL.startsWith(sUrlPrefix) ) {
707
+
708
+ // calc resource name
709
+ let sResourceName = sNamePrefix + sURL.slice(sUrlPrefix.length);
710
+ // remove a leading '/' (occurs if name prefix is empty and if match was a full segment match
711
+ if ( sResourceName.charAt(0) === '/' ) {
712
+ sResourceName = sResourceName.slice(1);
713
+ }
714
+
715
+ if ( !bLoadedResourcesOnly || mModules[sResourceName]?.data != undefined ) {
716
+ return sResourceName;
717
+ }
718
+ }
719
+ }
720
+ }
721
+
722
+ /**
723
+ * Find the most specific map config that matches the given context resource
724
+ * @param {string} sContext Resource name to be used as context
725
+ * @returns {Object<string,string>|undefined} Most specific map or <code>undefined</code>
726
+ */
727
+ function findMapForContext(sContext) {
728
+ let p, mMap;
729
+ if ( sContext != null ) {
730
+ // maps are defined on module IDs, reduce URN to module ID
731
+ sContext = urnToIDAndType(sContext).id;
732
+ p = sContext.length;
733
+ mMap = mMaps[sContext];
734
+ while ( p > 0 && mMap == null ) {
735
+ p = sContext.lastIndexOf('/');
736
+ if ( p > 0 ) { // Note: an empty segment at p = 0 (leading slash) will be ignored
737
+ sContext = sContext.slice(0, p);
738
+ mMap = mMaps[sContext];
739
+ }
740
+ }
741
+ }
742
+ // if none is found, fallback to '*' map
743
+ return mMap || mMaps['*'];
744
+ }
745
+
746
+ function getMappedName(sResourceName, sRequestingResourceName) {
747
+ var addSlash = false
748
+ if(sRequestingResourceName?.startsWith("/") && sResourceName.startsWith(".")) {
749
+ addSlash = true
750
+ }
751
+ const mMap = findMapForContext(sRequestingResourceName);
752
+
753
+ // resolve relative names
754
+ sResourceName = normalize(sResourceName, sRequestingResourceName);
755
+ if(addSlash) {
756
+ sResourceName = `/${sResourceName}`
757
+ }
758
+ // if there's a map, search for the most specific matching entry
759
+ if ( mMap != null ) {
760
+ // start with the full ID and successively remove one segment
761
+ let sPrefix = urnToIDAndType(sResourceName).id;
762
+ let p = sPrefix.length;
763
+ while ( p > 0 && mMap[sPrefix] == null ) {
764
+ p = sPrefix.lastIndexOf('/');
765
+ // Note: an empty segment at p = 0 (leading slash) will be ignored
766
+ sPrefix = p > 0 ? sPrefix.slice(0, p) : '';
767
+ }
768
+
769
+ if ( p > 0 ) {
770
+ const sMappedResourceName = mMap[sPrefix] + sResourceName.slice(p);
771
+ if ( log.isLoggable() ) {
772
+ log.debug(`module ID ${sResourceName} mapped to ${sMappedResourceName}`);
773
+ }
774
+ return sMappedResourceName; // also skips a leading slash!
775
+ }
776
+ }
777
+
778
+ return sResourceName;
779
+ }
780
+
781
+ function getGlobalObject(oObject, aNames, l, bCreate) {
782
+ for (let i = 0; oObject && i < l; i++) {
783
+ if (!oObject[aNames[i]] && bCreate ) {
784
+ oObject[aNames[i]] = {};
785
+ }
786
+ oObject = oObject[aNames[i]];
787
+ }
788
+ return oObject;
789
+ }
790
+
791
+ function getGlobalProperty(sName) {
792
+ const aNames = sName ? sName.split(".") : [];
793
+
794
+ if ( syncCallBehavior && aNames.length > 1 ) {
795
+ log.error("[nosync] getGlobalProperty called to retrieve global name '" + sName + "'");
796
+ }
797
+
798
+ return getGlobalObject(__global, aNames, aNames.length);
799
+ }
800
+
801
+ function setGlobalProperty(sName, vValue) {
802
+ const aNames = sName ? sName.split(".") : [];
803
+
804
+ if ( aNames.length > 0 ) {
805
+ const oObject = getGlobalObject(__global, aNames, aNames.length - 1, true);
806
+ oObject[aNames[aNames.length - 1]] = vValue;
807
+ }
808
+ }
809
+
810
+ // ---- Modules -------------------------------------------------------------------------------
811
+
812
+ function wrapExport(value) {
813
+ return { moduleExport: value };
814
+ }
815
+
816
+ function unwrapExport(wrapper) {
817
+ return wrapper.moduleExport;
818
+ }
819
+
820
+ /**
821
+ * Module neither has been required nor preloaded nor declared, but someone asked for it.
822
+ */
823
+ const INITIAL = 0,
824
+
825
+ /**
826
+ * Module has been preloaded, but not required or declared.
827
+ */
828
+ PRELOADED = -1,
829
+
830
+ /**
831
+ * Module has been declared.
832
+ */
833
+ LOADING = 1,
834
+
835
+ /**
836
+ * Module has been loaded, but not yet executed.
837
+ */
838
+ LOADED = 2,
839
+
840
+ /**
841
+ * Module is currently being executed
842
+ */
843
+ EXECUTING = 3,
844
+
845
+ /**
846
+ * Module has been loaded and executed without errors.
847
+ */
848
+ READY = 4,
849
+
850
+ /**
851
+ * Module either could not be loaded or execution threw an error
852
+ */
853
+ FAILED = 5,
854
+
855
+ /**
856
+ * Special content value used internally until the content of a module has been determined
857
+ */
858
+ NOT_YET_DETERMINED = {};
859
+
860
+ /**
861
+ * A module/resource as managed by the module system.
862
+ *
863
+ * Each module has the following properties
864
+ * <ul>
865
+ * <li>{int} state one of the module states defined in this function</li>
866
+ * <li>{string} url URL where the module has been loaded from</li>
867
+ * <li>{any} data temp. raw content of the module (between loaded and ready or when preloaded)</li>
868
+ * <li>{string} group the bundle with which a resource was loaded or null</li>
869
+ * <li>{string} error an error description for state <code>FAILED</code></li>
870
+ * <li>{any} content the content of the module as exported via define()<(li>
871
+ * </ul>
872
+ */
873
+ class Module {
874
+
875
+ /**
876
+ * Creates a new Module.
877
+ *
878
+ * @param {string} name Name of the module, including extension
879
+ */
880
+ constructor(name) {
881
+ this.name = name;
882
+ this.state = INITIAL;
883
+ /*
884
+ * Whether processing of the module is complete.
885
+ * This is very similar to, but not the same as state >= READY because declareModule() sets state=READY very early.
886
+ * That state transition is 'legacy' from the library-all files; it needs to be checked whether it can be removed.
887
+ */
888
+ this.settled = false;
889
+ this.url =
890
+ this._deferred =
891
+ this.data =
892
+ this.group =
893
+ this.error =
894
+ this.pending = null;
895
+ this.content = NOT_YET_DETERMINED;
896
+ }
897
+
898
+ deferred() {
899
+ if ( this._deferred == null ) {
900
+ const deferred = this._deferred = {};
901
+ deferred.promise = new Promise(function(resolve,reject) {
902
+ deferred.resolve = resolve;
903
+ deferred.reject = reject;
904
+ });
905
+ // avoid 'Uncaught (in promise)' log entries
906
+ deferred.promise.catch(noop);
907
+ }
908
+ return this._deferred;
909
+ }
910
+
911
+ api() {
912
+ this._api ??= {
913
+ id: this.name.slice(0,-3),
914
+ exports: this._exports = {},
915
+ url: this.url,
916
+ config: noop
917
+ };
918
+ return this._api;
919
+ }
920
+
921
+ /**
922
+ * Sets the module state to READY and either determines the value or sets
923
+ * it from the given parameter.
924
+ * @param {any} value Module value
925
+ */
926
+ ready(value) {
927
+ // should throw, but some tests and apps would fail
928
+ assert(!this.settled, `Module ${this.name} is already settled`);
929
+ this.state = READY;
930
+ this.settled = true;
931
+ if ( arguments.length > 0 ) {
932
+ // check arguments.length to allow a value of undefined
933
+ this.content = value;
934
+ }
935
+ this.deferred().resolve(wrapExport(this.value()));
936
+ if ( this.aliases ) {
937
+ value = this.value();
938
+ this.aliases.forEach((alias) => Module.get(alias).ready(value));
939
+ }
940
+ }
941
+
942
+ failWith(msg, cause) {
943
+ const err = makeModuleError(msg, this, cause);
944
+ this.fail(err);
945
+ return err;
946
+ }
947
+
948
+ fail(err) {
949
+ // should throw, but some tests and apps would fail
950
+ assert(!this.settled, `Module ${this.name} is already settled`);
951
+ this.settled = true;
952
+ if ( this.state !== FAILED ) {
953
+ this.state = FAILED;
954
+ this.error = err;
955
+ this.deferred().reject(err);
956
+ this.aliases?.forEach((alias) => Module.get(alias).fail(err));
957
+ }
958
+ }
959
+
960
+ addPending(sDependency) {
961
+ (this.pending ??= []).push(sDependency);
962
+ }
963
+
964
+ addAlias(sAliasName) {
965
+ (this.aliases ??= []).push(sAliasName);
966
+ // add this module as pending dependency to the original
967
+ Module.get(sAliasName).addPending(this.name);
968
+ }
969
+
970
+ preload(url, data, bundle) {
971
+ if ( this.state === INITIAL && !fnIgnorePreload?.(this.name) ) {
972
+ this.state = PRELOADED;
973
+ this.url = url;
974
+ this.data = data;
975
+ this.group = bundle;
976
+ }
977
+ return this;
978
+ }
979
+
980
+ /**
981
+ * Determines the value of this module.
982
+ *
983
+ * If the module hasn't been loaded or executed yet, <code>undefined</code> will be returned.
984
+ *
985
+ * @returns {any} Export of the module or <code>undefined</code>
986
+ * @private
987
+ */
988
+ value() {
989
+ if ( this.state === READY ) {
990
+ if ( this.content === NOT_YET_DETERMINED ) {
991
+ // Determine the module value lazily.
992
+ // For AMD modules this has already been done on execution of the factory function.
993
+ // For other modules that are required synchronously, it has been done after execution.
994
+ // For the few remaining scenarios (like global scripts), it is done here
995
+ const oShim = mShims[this.name],
996
+ sExport = oShim && (Array.isArray(oShim.exports) ? oShim.exports[0] : oShim.exports);
997
+ // best guess for thirdparty modules or legacy modules that don't use sap.ui.define
998
+ if(this.name === "sap/ui/thirdparty/crossroads.js") {
999
+ this.content = window.crossroads;
1000
+ } else {
1001
+ this.content = getGlobalProperty( sExport || urnToUI5(this.name) );
1002
+ }
1003
+
1004
+ }
1005
+ return this.content;
1006
+ }
1007
+
1008
+ return undefined;
1009
+ }
1010
+
1011
+ /**
1012
+ * Checks whether this module depends on the given module.
1013
+ *
1014
+ * When a module definition (define) is executed, the requested dependencies are added
1015
+ * as 'pending' to the Module instance. This function checks if the oDependantModule is
1016
+ * reachable from this module when following the pending dependency information.
1017
+ *
1018
+ * Note: when module aliases are introduced (all module definitions in a file use an ID that differs
1019
+ * from the request module ID), then the alias module is also added as a "pending" dependency.
1020
+ *
1021
+ * @param {Module} oDependantModule Module which has a dependency to <code>oModule</code>
1022
+ * @returns {boolean} Whether this module depends on the given one.
1023
+ * @private
1024
+ */
1025
+ dependsOn(oDependantModule) {
1026
+ const dependant = oDependantModule.name,
1027
+ visited = Object.create(null);
1028
+
1029
+ // log.debug("checking for a cycle between", this.name, "and", dependant);
1030
+ function visit(mod) {
1031
+ if ( !visited[mod] ) {
1032
+ // log.debug(" ", mod);
1033
+ visited[mod] = true;
1034
+ const pending = mModules[mod]?.pending;
1035
+ return Array.isArray(pending) &&
1036
+ (pending.indexOf(dependant) >= 0 || pending.some(visit));
1037
+ }
1038
+ return false;
1039
+ }
1040
+
1041
+ return this.name === dependant || visit(this.name);
1042
+ }
1043
+
1044
+ /**
1045
+ * Find or create a module by its unified resource name.
1046
+ *
1047
+ * If the module doesn't exist yet, a new one is created in state INITIAL.
1048
+ *
1049
+ * @param {string} sModuleName Name of the module in URN syntax
1050
+ * @returns {Module} Module with that name, newly created if it didn't exist yet
1051
+ */
1052
+ static get(sModuleName) {
1053
+ const oModule = mModules[sModuleName] ??= new Module(sModuleName);
1054
+ return oModule;
1055
+ }
1056
+
1057
+ }
1058
+
1059
+ /*
1060
+ * Determines the currently executing module.
1061
+ */
1062
+ function getExecutingModule() {
1063
+ if ( _execStack.length > 0 ) {
1064
+ return _execStack[_execStack.length - 1].name;
1065
+ }
1066
+ return document.currentScript?.getAttribute("data-sap-ui-module");
1067
+ }
1068
+
1069
+ // --------------------------------------------------------------------------------------------
1070
+
1071
+ let _globalDefine = () => {
1072
+ },
1073
+ _globalDefineAMD;
1074
+
1075
+ function updateDefineAndInterceptAMDFlag(newDefine) {
1076
+
1077
+ // no change, do nothing
1078
+ if ( _globalDefine === newDefine ) {
1079
+ return;
1080
+ }
1081
+
1082
+ // first cleanup on an old loader
1083
+ if ( _globalDefine ) {
1084
+ _globalDefine.amd = _globalDefineAMD;
1085
+ _globalDefine =
1086
+ _globalDefineAMD = undefined;
1087
+ }
1088
+
1089
+ // remember the new define
1090
+ _globalDefine = newDefine;
1091
+
1092
+ // intercept access to the 'amd' property of the new define, if it's not our own define
1093
+ if ( newDefine && !newDefine.ui5 ) {
1094
+ _globalDefineAMD = _globalDefine.amd;
1095
+
1096
+ Object.defineProperty(_globalDefine, "amd", {
1097
+ get: function() {
1098
+ const sCurrentModule = getExecutingModule();
1099
+ if ( sCurrentModule && mShims[sCurrentModule]?.amd ) {
1100
+ log.debug(`suppressing define.amd for ${sCurrentModule}`);
1101
+ return undefined;
1102
+ }
1103
+ return _globalDefineAMD;
1104
+ },
1105
+ set: function(newDefineAMD) {
1106
+ _globalDefineAMD = newDefineAMD;
1107
+ log.debug(`define.amd became ${newDefineAMD ? "active" : "unset"}`);
1108
+ },
1109
+ configurable: true // we have to allow a redefine for debug mode or restart from CDN etc.
1110
+ });
1111
+ }
1112
+ }
1113
+
1114
+ try {
1115
+ Object.defineProperty(__global, "define", {
1116
+ get: function() {
1117
+
1118
+ return global.__globalDefine;
1119
+ //return _globalDefine;
1120
+ },
1121
+ set: function(newDefine) {
1122
+ global.__globalDefine = newDefine;
1123
+ this.__globalDefine = newDefine;
1124
+ updateDefineAndInterceptAMDFlag(newDefine);
1125
+ log.debug(`define became ${newDefine ? "active" : "unset"}`);
1126
+ },
1127
+ configurable: true // we have to allow a redefine for debug mode or restart from CDN etc.
1128
+ });
1129
+ } catch (e) {
1130
+ log.warning("could not intercept changes to window.define, ui5loader won't be able to a change of the AMD loader");
1131
+ }
1132
+
1133
+ updateDefineAndInterceptAMDFlag(__global.define);
1134
+
1135
+ // --------------------------------------------------------------------------------------------
1136
+
1137
+ function isModuleError(err) {
1138
+ return err?.name === "ModuleError";
1139
+ }
1140
+
1141
+ /**
1142
+ * Wraps the given 'cause' in a new error with the given message and with name 'ModuleError'.
1143
+ *
1144
+ * The new message and the message of the cause are combined. The stacktrace of the
1145
+ * new error and of the cause are combined (with a separating 'Caused by').
1146
+ *
1147
+ * Instead of the final message string, a template is provided which can contain placeholders
1148
+ * for the module ID ({id}) and module URL ({url}). Providing a template without concrete
1149
+ * values allows to detect the repeated nesting of the same error. In such a case, only
1150
+ * the innermost cause will be kept (affects both, stack trace as well as the cause property).
1151
+ * The message, however, will contain the full chain of module IDs.
1152
+ *
1153
+ * @param {string} template Message string template with placeholders
1154
+ * @param {Module} module Module for which the error occurred
1155
+ * @param {Error} cause original error
1156
+ * @returns {Error} New module error
1157
+ */
1158
+ function makeModuleError(template, module, cause) {
1159
+ let modules = `'${module.name}'`;
1160
+
1161
+ if (isModuleError(cause)) {
1162
+ // update the chain of modules (increasing the indent)
1163
+ modules += `\n -> ${cause._modules.replace(/ -> /g, " -> ")}`;
1164
+ // omit repeated occurrences of the same kind of error
1165
+ if ( template === cause._template ) {
1166
+ cause = cause.cause;
1167
+ }
1168
+ }
1169
+
1170
+ // create the message string from the template and the cause's message
1171
+ const message =
1172
+ template.replace(/\{id\}/, modules).replace(/\{url\}/, module.url)
1173
+ + (cause ? ": " + cause.message : "");
1174
+ //console.log(cause.stack);
1175
+ const error = new Error(message);
1176
+ error.name = "ModuleError";
1177
+ error.cause = cause;
1178
+ if ( cause?.stack ) {
1179
+ error.stack = error.stack + "\nCaused by: " + cause.stack;
1180
+ }
1181
+ // the following properties are only for internal usage
1182
+ error._template = template;
1183
+ error._modules = modules;
1184
+ return error;
1185
+ }
1186
+
1187
+ function declareModule(sModuleName) {
1188
+ // sModuleName must be a unified resource name of type .js
1189
+ assert(/\.js$/.test(sModuleName), "must be a Javascript module");
1190
+
1191
+ const oModule = Module.get(sModuleName);
1192
+
1193
+ if ( oModule.state > INITIAL ) {
1194
+ return oModule;
1195
+ }
1196
+
1197
+ if ( log.isLoggable() ) {
1198
+ log.debug(`${sLogPrefix}declare module '${sModuleName}'`);
1199
+ }
1200
+
1201
+ // avoid cycles
1202
+ oModule.state = READY;
1203
+
1204
+ return oModule;
1205
+ }
1206
+
1207
+ /**
1208
+ * Define an already loaded module synchronously.
1209
+ * Finds or creates a module by its unified resource name and resolves it with the given value.
1210
+ *
1211
+ * @param {string} sResourceName Name of the module in URN syntax
1212
+ * @param {any} vValue Content of the module
1213
+ */
1214
+ function defineModuleSync(sResourceName, vValue) {
1215
+ Module.get(sResourceName).ready(vValue);
1216
+ }
1217
+
1218
+ /**
1219
+ * Queue of modules for which sap.ui.define has been called (in async mode), but which have not been executed yet.
1220
+ * When loading modules via script tag, only the onload handler knows the relationship between executed sap.ui.define calls and
1221
+ * module name. It then resolves the pending modules in the queue. Only one entry can get the name of the module
1222
+ * if there are more entries, then this is an error
1223
+ *
1224
+ * @param {boolean} [nested] Whether this is a nested queue used during sync execution of a module
1225
+ */
1226
+ function ModuleDefinitionQueue(nested) {
1227
+ let aQueue = [],
1228
+ iRun = 0,
1229
+ vTimer;
1230
+
1231
+ this.push = function(name, deps, factory, _export) {
1232
+ if ( log.isLoggable() ) {
1233
+ log.debug(sLogPrefix + "pushing define() call"
1234
+ + (document.currentScript ? " from " + document.currentScript.src : "")
1235
+ + " to define queue #" + iRun);
1236
+ }
1237
+
1238
+ const sModule = document.currentScript?.getAttribute('data-sap-ui-module');
1239
+ aQueue.push({
1240
+ name: name,
1241
+ deps: deps,
1242
+ factory: factory,
1243
+ _export: _export,
1244
+ guess: sModule
1245
+ });
1246
+
1247
+ // trigger queue processing via a timer in case the currently executing script is not managed by the loader
1248
+ if ( !vTimer && !nested && sModule == null ) {
1249
+ vTimer = setTimeout(this.process.bind(this, null, "timer"));
1250
+ }
1251
+ };
1252
+
1253
+ this.clear = function() {
1254
+ aQueue = [];
1255
+ if ( vTimer ) {
1256
+ clearTimeout(vTimer);
1257
+ vTimer = null;
1258
+ }
1259
+ };
1260
+
1261
+ /**
1262
+ * Process the queue of module definitions, assuming that the original request was for
1263
+ * <code>oRequestedModule</code>. If there is an unnamed module definition, it is assumed to be
1264
+ * the one for the requested module.
1265
+ *
1266
+ * When called via timer, <code>oRequestedModule</code> will be undefined.
1267
+ *
1268
+ * @param {Module} [oRequestedModule] Module for which the current script was loaded.
1269
+ * @param {string} [sInitiator] A string describing the caller of <code>process</code>
1270
+ */
1271
+ this.process = function(oRequestedModule, sInitiator) {
1272
+ const bLoggable = log.isLoggable();
1273
+ const aQueueCopy = aQueue;
1274
+ const iCurrentRun = iRun++;
1275
+ let sModuleName = null;
1276
+
1277
+ // clear the queue and timer early, we've already taken a copy of the queue
1278
+ this.clear();
1279
+
1280
+
1281
+ // if a module execution error was detected, stop processing the queue
1282
+ if ( oRequestedModule?.execError ) {
1283
+ if ( bLoggable ) {
1284
+ log.debug(`module execution error detected, ignoring queued define calls (${aQueueCopy.length})`);
1285
+ }
1286
+ oRequestedModule.fail(oRequestedModule.execError);
1287
+ return;
1288
+ }
1289
+
1290
+ /*
1291
+ * Name of the requested module, null when unknown or already consumed.
1292
+ *
1293
+ * - when no module request is known (e.g. script was embedded in the page as an unmanaged script tag),
1294
+ * then no name is known and unnamed module definitions will be reported as an error
1295
+ * - multiple unnamed module definitions also are reported as an error
1296
+ * - when the name of a named module definition matches the name of requested module, the name is 'consumed'.
1297
+ * Any later unnamed module definition will be reported as an error, too
1298
+ */
1299
+ sModuleName = oRequestedModule?.name;
1300
+
1301
+ // check whether there's a module definition for the requested module
1302
+ aQueueCopy.forEach((oEntry) => {
1303
+ if ( oEntry.name == null ) {
1304
+ if ( sModuleName != null ) {
1305
+ oEntry.name = sModuleName;
1306
+ sModuleName = null;
1307
+ } else {
1308
+ // multiple modules have been queued, but only one module can inherit the name from the require call
1309
+ if ( strictModuleDefinitions ) {
1310
+ const oError = new Error(
1311
+ "Modules that use an anonymous define() call must be loaded with a require() call; " +
1312
+ "they must not be executed via script tag or nested into other modules. ");
1313
+ if ( oRequestedModule ) {
1314
+ oRequestedModule.fail(oError);
1315
+ } else {
1316
+ throw oError;
1317
+ }
1318
+ }
1319
+ // give anonymous modules a unique pseudo ID
1320
+ oEntry.name = `~anonymous~${++iAnonymousModuleCount}.js`;
1321
+ log.error(
1322
+ "Modules that use an anonymous define() call must be loaded with a require() call; " +
1323
+ "they must not be executed via script tag or nested into other modules. " +
1324
+ "All other usages will fail in future releases or when standard AMD loaders are used. " +
1325
+ "Now using substitute name " + oEntry.name);
1326
+ }
1327
+ } else if ( oRequestedModule && oEntry.name === oRequestedModule.name ) {
1328
+ if ( sModuleName == null && !strictModuleDefinitions ) {
1329
+ // if 'strictModuleDefinitions' is active, double execution will be reported anyhow
1330
+ log.error(
1331
+ "Duplicate module definition: both, an unnamed module and a module with the expected name exist." +
1332
+ "This use case will fail in future releases or when standard AMD loaders are used. ");
1333
+ }
1334
+ sModuleName = null;
1335
+ }
1336
+ });
1337
+
1338
+ // if not, assign an alias if there's at least one queued module definition
1339
+ if ( sModuleName && aQueueCopy.length > 0 ) {
1340
+ if ( bLoggable ) {
1341
+ log.debug(
1342
+ "No queued module definition matches the ID of the request. " +
1343
+ `Now assuming that the first definition '${aQueueCopy[0].name}' is an alias of '${sModuleName}'`);
1344
+ }
1345
+ Module.get(aQueueCopy[0].name).addAlias(sModuleName);
1346
+ sModuleName = null;
1347
+ }
1348
+
1349
+ if ( bLoggable ) {
1350
+ log.debug(sLogPrefix + "[" + sInitiator + "] "
1351
+ + "processing define queue #" + iCurrentRun
1352
+ + (oRequestedModule ? " for '" + oRequestedModule.name + "'" : "")
1353
+ + ` with entries [${aQueueCopy.map((entry) => `'${entry.name}'`)}]`);
1354
+ }
1355
+
1356
+ aQueueCopy.forEach((oEntry) => {
1357
+ // start to resolve the dependencies
1358
+ executeModuleDefinition(oEntry.name, oEntry.deps, oEntry.factory, oEntry._export, /* bAsync = */ true);
1359
+ });
1360
+
1361
+ if ( sModuleName != null && !oRequestedModule.settled ) {
1362
+ // module name still not consumed, might be a non-UI5 module (e.g. in 'global' format)
1363
+ if ( bLoggable ) {
1364
+ log.debug(sLogPrefix + "no queued module definition for the requested module found, assume the module to be ready");
1365
+ }
1366
+ oRequestedModule.data = undefined; // allow GC
1367
+ oRequestedModule.ready(); // no export known, has to be retrieved via global name
1368
+ }
1369
+
1370
+ if ( bLoggable ) {
1371
+ log.debug(sLogPrefix + `processing define queue #${iCurrentRun} done`);
1372
+ }
1373
+ };
1374
+ }
1375
+
1376
+ let queue = new ModuleDefinitionQueue();
1377
+
1378
+ /**
1379
+ * Loads the source for the given module with a sync XHR.
1380
+ * @param {Module} oModule Module to load the source for
1381
+ * @throws {Error} When loading failed for some reason.
1382
+ */
1383
+ function loadSyncXHR(oModule) {
1384
+ const xhr = new XMLHttpRequest();
1385
+
1386
+ function createXHRLoadError(error) {
1387
+ error = new Error(xhr.statusText ? xhr.status + " - " + xhr.statusText : xhr.status);
1388
+ error.name = "XHRLoadError";
1389
+ error.status = xhr.status;
1390
+ error.statusText = xhr.statusText;
1391
+ return error;
1392
+ }
1393
+
1394
+ xhr.addEventListener('load', function(e) {
1395
+ // File protocol (file://) always has status code 0
1396
+ if ( xhr.status === 200 || xhr.status === 0 ) {
1397
+ oModule.state = LOADED;
1398
+ oModule.data = xhr.responseText;
1399
+ } else {
1400
+ oModule.error = createXHRLoadError();
1401
+ }
1402
+ });
1403
+ // Note: according to whatwg spec, error event doesn't fire for sync send(), instead an error is thrown
1404
+ // we register a handler, in case a browser doesn't follow the spec
1405
+ xhr.addEventListener('error', function(e) {
1406
+ oModule.error = createXHRLoadError();
1407
+ });
1408
+ xhr.open('GET', oModule.url, false);
1409
+ try {
1410
+ xhr.send();
1411
+ } catch (error) {
1412
+ oModule.error = error;
1413
+ }
1414
+ }
1415
+
1416
+ /**
1417
+ * Global event handler to detect script execution errors.
1418
+ * @private
1419
+ */
1420
+ window.addEventListener('error', function onUncaughtError(errorEvent) {
1421
+ var sModuleName = document.currentScript?.getAttribute('data-sap-ui-module');
1422
+ var oModule = sModuleName && Module.get(sModuleName);
1423
+ if ( oModule && oModule.execError == null ) {
1424
+ // if a currently executing module can be identified, attach the error to it and suppress reporting
1425
+ if ( log.isLoggable() ) {
1426
+ log.debug(`unhandled exception occurred while executing ${sModuleName}: ${errorEvent.message}`);
1427
+ }
1428
+ oModule.execError = errorEvent.error || {
1429
+ name: 'Error',
1430
+ message: errorEvent.message
1431
+ };
1432
+ return false;
1433
+ }
1434
+ });
1435
+
1436
+ function loadScript(oModule, sAlternativeURL) {
1437
+
1438
+ const oScript = document.createElement('SCRIPT');
1439
+ // Accessing the 'src' property of the script in this strange way prevents Safari 12 (or WebKit) from
1440
+ // wrongly optimizing access. SF12 seems to check at optimization time whether there's a setter for the
1441
+ // property and optimize accordingly. When a setter is defined or changed at a later point in time (e.g.
1442
+ // by the AppCacheBuster), then the optimization seems not to be updated and the new setter is ignored
1443
+ // BCP 1970035485
1444
+ oScript["s" + "rc"] = oModule.url;
1445
+ //oScript.src = oModule.url;
1446
+ oScript.setAttribute("data-sap-ui-module", oModule.name);
1447
+
1448
+ function onload(e) {
1449
+ updateMaxTaskTime();
1450
+ if ( log.isLoggable() ) {
1451
+ log.debug(`JavaScript resource loaded: ${oModule.name}`);
1452
+ }
1453
+ oScript.removeEventListener('load', onload);
1454
+ oScript.removeEventListener('error', onerror);
1455
+ queue.process(oModule, "onload");
1456
+ }
1457
+
1458
+ function onerror(e) {
1459
+ updateMaxTaskTime();
1460
+ oScript.removeEventListener('load', onload);
1461
+ oScript.removeEventListener('error', onerror);
1462
+ if (sAlternativeURL) {
1463
+ log.warning(`retry loading JavaScript resource: ${oModule.name}`);
1464
+ oScript?.parentNode?.removeChild(oScript);
1465
+ oModule.url = sAlternativeURL;
1466
+ loadScript(oModule, /* sAlternativeURL= */ null);
1467
+ return;
1468
+ }
1469
+
1470
+ log.error(`failed to load JavaScript resource: ${oModule.name}`);
1471
+ oModule.failWith("failed to load {id} from {url}", new Error("script load error"));
1472
+ }
1473
+
1474
+ if ( sAlternativeURL !== undefined ) {
1475
+ if ( mShims[oModule.name]?.amd ) {
1476
+ oScript.setAttribute("data-sap-ui-module-amd", "true");
1477
+ }
1478
+ oScript.addEventListener('load', onload);
1479
+ oScript.addEventListener('error', onerror);
1480
+ }
1481
+ document.head.appendChild(oScript);
1482
+
1483
+ }
1484
+
1485
+ function preloadDependencies(sModuleName) {
1486
+ const knownDependencies = mDepCache[sModuleName];
1487
+ if ( Array.isArray(knownDependencies) ) {
1488
+ log.debug(`preload dependencies for ${sModuleName}: ${knownDependencies}`);
1489
+ knownDependencies.forEach((dep) => {
1490
+ dep = getMappedName(dep, sModuleName);
1491
+ if ( /\.js$/.test(dep) ) {
1492
+ requireModule(null, dep, /* always async */ true);
1493
+ } // else: TODO handle non-JS resources, e.g. link rel=prefetch
1494
+ });
1495
+ }
1496
+ }
1497
+
1498
+ /**
1499
+ * Loads the given module if needed and returns the module export or a promise on it.
1500
+ *
1501
+ * If loading is still ongoing for the requested module and if there is a cycle detected between
1502
+ * the requesting module and the module to be loaded, then <code>undefined</code> (or a promise on
1503
+ * <code>undefined</code>) will be returned as intermediate module export to resolve the cycle.
1504
+ *
1505
+ * @param {Module} oRequestingModule The module in whose context the new module has to be loaded;
1506
+ * this is needed to detect cycles
1507
+ * @param {string} sModuleName Name of the module to be loaded, in URN form and with '.js' extension
1508
+ * @param {boolean} bAsync Whether the operation can be executed asynchronously
1509
+ * @param {boolean} [bSkipShimDeps=false] Whether shim dependencies should be ignored (used by recursive calls)
1510
+ * @param {boolean} [bSkipBundle=false] Whether bundle information should be ignored (used by recursive calls)
1511
+ * @returns {any|Promise} Returns the module export in sync mode or a promise on it in async mode
1512
+ * @throws {Error} When loading failed in sync mode
1513
+ *
1514
+ * @private
1515
+ */
1516
+ function requireModule(oRequestingModule, sModuleName, bAsync, bSkipShimDeps, bSkipBundle) {
1517
+
1518
+ // only for robustness, should not be possible by design (all callers append '.js')
1519
+ const oSplitName = urnToBaseIDAndSubType(sModuleName);
1520
+ if ( !oSplitName ) {
1521
+ throw new Error(`can only require Javascript module, not ${sModuleName}`);
1522
+ }
1523
+
1524
+ // Module names should not start with a "/"
1525
+ if (sModuleName[0] == "/") {
1526
+ log.debug("Module names that start with a slash should not be used, as they are reserved for future use.");
1527
+ }
1528
+
1529
+ const bLoggable = log.isLoggable();
1530
+
1531
+ const oModule = Module.get(sModuleName);
1532
+ const oShim = mShims[sModuleName];
1533
+
1534
+ // when there's a shim with dependencies for the module
1535
+ // resolve them first before requiring the module again with bSkipShimDeps = true
1536
+ if ( oShim?.deps && !bSkipShimDeps ) {
1537
+ if ( bLoggable ) {
1538
+ log.debug("require dependencies of raw module " + sModuleName);
1539
+ }
1540
+ return requireAll(oModule, oShim.deps, function() {
1541
+ // set bSkipShimDeps to true to prevent endless recursion
1542
+ return requireModule(oRequestingModule, sModuleName, bAsync, /* bSkipShimDeps = */ true, bSkipBundle);
1543
+ }, function(oErr) {
1544
+ // Note: in async mode, this 'throw' will reject the promise returned by requireAll
1545
+ throw oModule.failWith("Failed to resolve dependencies of {id}", oErr);
1546
+ }, bAsync);
1547
+ }
1548
+
1549
+ // when there's bundle information for the module
1550
+ // require the bundle first before requiring the module again with bSkipBundle = true
1551
+ if ( oModule.state === INITIAL && oModule.group && oModule.group !== sModuleName && !bSkipBundle ) {
1552
+ if ( bLoggable ) {
1553
+ log.debug(`${sLogPrefix}require bundle '${oModule.group}' containing '${sModuleName}'`);
1554
+ }
1555
+ if ( bAsync ) {
1556
+ return requireModule(null, oModule.group, bAsync).catch(noop).then(function() {
1557
+ // set bSkipBundle to true to prevent endless recursion
1558
+ return requireModule(oRequestingModule, sModuleName, bAsync, bSkipShimDeps, /* bSkipBundle = */ true);
1559
+ });
1560
+ } else {
1561
+ try {
1562
+ requireModule(null, oModule.group, bAsync);
1563
+ } catch (oError) {
1564
+ if ( bLoggable ) {
1565
+ log.error(sLogPrefix + "require bundle '" + oModule.group + "' failed (ignored)");
1566
+ }
1567
+ }
1568
+ }
1569
+ }
1570
+
1571
+ if ( bLoggable ) {
1572
+ log.debug(sLogPrefix + "require '" + sModuleName + "'"
1573
+ + (oRequestingModule ? " (dependency of '" + oRequestingModule.name + "')" : ""));
1574
+ }
1575
+ if(oModule.name === "sap/ui/thirdparty/hasher.js" && oModule.state === PRELOADED) {
1576
+ oModule.state = INITIAL
1577
+ }
1578
+ if(oModule.name === "sap/ui/fl/library.js") {
1579
+ bAsync = false;
1580
+ }
1581
+ // check if module has been loaded already
1582
+ if ( oModule.state !== INITIAL ) {
1583
+
1584
+ let bExecutedNow = false;
1585
+
1586
+ if ( oModule.state === EXECUTING && oModule.data != null && !bAsync && oModule.async ) {
1587
+ oModule.state = PRELOADED;
1588
+ oModule.async = bAsync;
1589
+ oModule.pending = null; // TODO or is this still needed ?
1590
+ }
1591
+
1592
+ if ( oModule.state === PRELOADED ) {
1593
+ oModule.state = LOADED;
1594
+ oModule.async = bAsync;
1595
+ bExecutedNow = true;
1596
+ measure && measure.start(sModuleName, "Require module " + sModuleName + " (preloaded)", ["require"]);
1597
+ execModule(sModuleName, bAsync);
1598
+ measure && measure.end(sModuleName);
1599
+ }
1600
+
1601
+ if ( oModule.state === READY ) {
1602
+ if ( !bExecutedNow && bLoggable ) {
1603
+ log.debug(sLogPrefix + "module '" + sModuleName + "' has already been loaded (skipped).");
1604
+ }
1605
+ // Note: this intentionally does not return oModule.promise() as the export might be temporary in case of cycles
1606
+ // or it might have changed after repeated module execution
1607
+ return bAsync ? Promise.resolve(wrapExport(oModule.value())) : wrapExport(oModule.value());
1608
+ } else if ( oModule.state === FAILED ) {
1609
+ if ( bAsync ) {
1610
+ return oModule.deferred().promise;
1611
+ } else {
1612
+ throw oModule.error;
1613
+ }
1614
+ } else {
1615
+ // currently loading or executing
1616
+ if ( bAsync ) {
1617
+ // break up cyclic dependencies
1618
+ if ( oRequestingModule && oModule.dependsOn(oRequestingModule) ) {
1619
+ if ( log.isLoggable() ) {
1620
+ log.debug("cycle detected between '" + oRequestingModule.name + "' and '" + sModuleName + "', returning undefined for '" + sModuleName + "'");
1621
+ }
1622
+ // Note: this must be a separate promise as the fulfillment is not the final one
1623
+ return Promise.resolve(wrapExport(undefined));
1624
+ }
1625
+ return oModule.deferred().promise;
1626
+ }
1627
+ if ( !bAsync && !oModule.async ) {
1628
+ // sync pending, return undefined
1629
+ if ( log.isLoggable() ) {
1630
+ log.debug("cycle detected between '" + (oRequestingModule ? oRequestingModule.name : "unknown") + "' and '" + sModuleName + "', returning undefined for '" + sModuleName + "'");
1631
+ }
1632
+ return wrapExport(undefined);
1633
+ }
1634
+ // async pending, load sync again
1635
+ log.warning("Sync request triggered for '" + sModuleName + "' while async request was already pending." +
1636
+ " Loading a module twice might cause issues and should be avoided by fully migrating to async APIs.");
1637
+ }
1638
+ }
1639
+
1640
+ measure && measure.start(sModuleName, "Require module " + sModuleName, ["require"]);
1641
+
1642
+ // set marker for loading modules (to break cycles)
1643
+ oModule.state = LOADING;
1644
+ oModule.async = bAsync;
1645
+
1646
+ // if debug is enabled, try to load debug module first
1647
+ const aExtensions = bDebugSources ? ["-dbg", ""] : [""];
1648
+ if ( !bAsync ) {
1649
+
1650
+ for (let i = 0; i < aExtensions.length && oModule.state !== LOADED; i++) {
1651
+ // create module URL for the current extension
1652
+ oModule.url = getResourcePath(oSplitName.baseID, aExtensions[i] + oSplitName.subType);
1653
+ if ( bLoggable ) {
1654
+ log.debug(sLogPrefix + "loading " + (aExtensions[i] ? aExtensions[i] + " version of " : "") + "'" + sModuleName + "' from '" + oModule.url + "' (using sync XHR)");
1655
+ }
1656
+
1657
+ if ( syncCallBehavior ) {
1658
+ const sMsg = "[nosync] loading module '" + oModule.url + "'";
1659
+ if ( syncCallBehavior === 1 ) {
1660
+ log.error(sMsg);
1661
+ } else {
1662
+ throw new Error(sMsg);
1663
+ }
1664
+ }
1665
+
1666
+ // call notification hook
1667
+ ui5Require.load({ completeLoad:noop, async: false }, oModule.url, oSplitName.baseID);
1668
+
1669
+ loadSyncXHR(oModule);
1670
+ }
1671
+
1672
+ if ( oModule.state === LOADING ) {
1673
+ // transition to FAILED
1674
+ oModule.failWith("failed to load {id} from {url}", oModule.error);
1675
+ } else if ( oModule.state === LOADED ) {
1676
+ // execute module __after__ loading it, this reduces the required stack space!
1677
+ execModule(sModuleName, bAsync);
1678
+ }
1679
+
1680
+ measure && measure.end(sModuleName);
1681
+
1682
+ if ( oModule.state !== READY ) {
1683
+ throw oModule.error;
1684
+ }
1685
+
1686
+ return wrapExport(oModule.value());
1687
+
1688
+ } else {
1689
+
1690
+ oModule.url = getResourcePath(oSplitName.baseID, aExtensions[0] + oSplitName.subType);
1691
+ // in debug mode, fall back to the non-dbg source, otherwise try the same source again (for SSO re-connect)
1692
+ const sAltUrl = bDebugSources ? getResourcePath(oSplitName.baseID, aExtensions[1] + oSplitName.subType) : oModule.url;
1693
+
1694
+ if ( log.isLoggable() ) {
1695
+ log.debug(sLogPrefix + "loading '" + sModuleName + "' from '" + oModule.url + "' (using <script>)");
1696
+ }
1697
+
1698
+ // call notification hook only once
1699
+ const filePath = global.pathMappingFn(sModuleName);
1700
+
1701
+ ui5Require.load({ completeLoad:noop, async: true }, sAltUrl, oSplitName.baseID);
1702
+ try {
1703
+ currentModuleName = sModuleName;
1704
+ _execStack.push({
1705
+ name: sModuleName,
1706
+ used: false
1707
+ });
1708
+ const requireOutput = global.requireFn(filePath)
1709
+ currentModuleName = undefined;
1710
+ queue.process(oModule, "onload");
1711
+ } catch(e) {
1712
+ oModule.failWith("failed to load {id} from {url}", new Error("script load error"));
1713
+ } finally {
1714
+ _execStack.pop();
1715
+ }
1716
+
1717
+
1718
+ //loadScript(oModule, /* sAlternativeURL= */ sAltUrl);
1719
+
1720
+ // process dep cache info
1721
+ preloadDependencies(sModuleName);
1722
+
1723
+ return oModule.deferred().promise;
1724
+ }
1725
+ }
1726
+
1727
+ // sModuleName must be a normalized resource name of type .js
1728
+ function execModule(sModuleName, bAsync) {
1729
+
1730
+ const oModule = mModules[sModuleName];
1731
+
1732
+ if ( oModule && oModule.state === LOADED && typeof oModule.data !== "undefined" ) {
1733
+
1734
+ const bLoggable = log.isLoggable();
1735
+ const bOldForceSyncDefines = bForceSyncDefines;
1736
+ const oOldQueue = queue;
1737
+ let sOldPrefix, sScript;
1738
+
1739
+ try {
1740
+
1741
+ bForceSyncDefines = !bAsync;
1742
+ queue = new ModuleDefinitionQueue(true);
1743
+
1744
+ if ( bLoggable ) {
1745
+ if ( typeof oModule.data === "string" ) {
1746
+ log.warning(sLogPrefix + "executing '" + sModuleName + "' (using eval)");
1747
+ } else {
1748
+ log.debug(sLogPrefix + "executing '" + sModuleName + "'");
1749
+ }
1750
+ sOldPrefix = sLogPrefix;
1751
+ sLogPrefix = sLogPrefix + ": ";
1752
+ }
1753
+
1754
+ // execute the script in the __global context
1755
+ oModule.state = EXECUTING;
1756
+ _execStack.push({
1757
+ name: sModuleName,
1758
+ used: false
1759
+ });
1760
+ if ( typeof oModule.data === "function" ) {
1761
+ const args = [];
1762
+ if( mShims[oModule.name] && mShims[oModule.name].deps) {
1763
+ mShims[oModule.name].deps.forEach((depName) => {
1764
+ args.push(Module.get(depName+ ".js").value())
1765
+ })
1766
+ }
1767
+ const output = oModule.data.call(__global);
1768
+ if(output && mShims[oModule.name] && mShims[oModule.name].exports && Object.keys(output).length > 0 && !global[mShims[oModule.name].exports]) {
1769
+ // if(global[mShims[oModule.name].exports] ) {
1770
+ // global[mShims[oModule.name].exports] = {...global[mShims[oModule.name].exports], ...output}
1771
+ // } else {
1772
+ global[mShims[oModule.name].exports] = output;
1773
+ //}
1774
+
1775
+ }
1776
+ else if(output && Object.keys(output).length > 0) {
1777
+ if( Object.keys(oModule.content).length === 0) {
1778
+ oModule.content = output;
1779
+ } else {
1780
+ oModule.content = {...oModule.content, ...output};
1781
+ }
1782
+
1783
+ }
1784
+ } else if ( Array.isArray(oModule.data) ) {
1785
+ ui5Define.apply(null, oModule.data);
1786
+ } else {
1787
+
1788
+ sScript = oModule.data;
1789
+
1790
+ // sourceURL: Firebug, Chrome and Safari debugging help, appending the string seems to cost ZERO performance
1791
+ // Note: make URL absolute so Chrome displays the file tree correctly
1792
+ // Note: do not append if there is already a sourceURL / sourceMappingURL
1793
+ // Note: Safari fails, if sourceURL is the same as an existing XHR URL
1794
+ // Note: Chrome ignores debug files when the same URL has already been load via sourcemap of the bootstrap file (sap-ui-core)
1795
+ // Note: sourcemap annotations URLs in eval'ed sources are resolved relative to the page, not relative to the source
1796
+ if (sScript ) {
1797
+ const oMatch = /\/\/[#@] source(Mapping)?URL=(.*)$/.exec(sScript);
1798
+ if ( oMatch && oMatch[1] && /^[^/]+\.js\.map$/.test(oMatch[2]) ) {
1799
+ // found a sourcemap annotation with a typical UI5 generated relative URL
1800
+ sScript = sScript.slice(0, oMatch.index) + oMatch[0].slice(0, -oMatch[2].length) + resolveURL(oMatch[2], oModule.url);
1801
+ }
1802
+ // @evo-todo use only sourceMappingURL, sourceURL or both?
1803
+ if ( !oMatch || oMatch[1] ) {
1804
+ // write sourceURL if no annotation was there or when it was a sourceMappingURL
1805
+ sScript += "\n//# sourceURL=" + resolveURL(oModule.url) + "?eval";
1806
+ }
1807
+ }
1808
+
1809
+ // framework internal hook to intercept the loaded script and modify
1810
+ // it before executing the script - e.g. useful for client side coverage
1811
+ if (typeof translate === "function") {
1812
+ sScript = translate(sScript, sModuleName);
1813
+ }
1814
+
1815
+ // eval the source in the global context (preventing access to the closure of this function)
1816
+ __global.eval(sScript);
1817
+ }
1818
+ queue.process(oModule, "after eval");
1819
+
1820
+ } catch (err) {
1821
+ oModule.data = undefined;
1822
+ if (isModuleError(err)) {
1823
+ // don't wrap a ModuleError again
1824
+ oModule.fail(err);
1825
+ } else {
1826
+ if (err instanceof SyntaxError && sScript) {
1827
+ // Module execution failed with a syntax error.
1828
+ // If in debug mode, load the script code again via script tag for better error reporting
1829
+ // (but without reacting to load/error events)
1830
+ if (fnIgnorePreload) {
1831
+ oModule.url = URL.createObjectURL(new Blob([sScript], {type: 'text/javascript'}));
1832
+ loadScript(oModule);
1833
+ } else {
1834
+ log.error("A syntax error occurred while evaluating '" + sModuleName + "'"
1835
+ + ", restarting the app with sap-ui-debug=x might reveal the error location");
1836
+ }
1837
+ }
1838
+ oModule.failWith("Failed to execute {id}", err);
1839
+ }
1840
+ } finally {
1841
+
1842
+ _execStack.pop();
1843
+
1844
+ if ( bLoggable ) {
1845
+ sLogPrefix = sOldPrefix;
1846
+ log.debug(sLogPrefix + "finished executing '" + sModuleName + "'");
1847
+ }
1848
+
1849
+ queue = oOldQueue;
1850
+ bForceSyncDefines = bOldForceSyncDefines;
1851
+ }
1852
+ }
1853
+ }
1854
+
1855
+ function requireAll(oRequestingModule, aDependencies, fnCallback, fnErrCallback, bAsync) {
1856
+
1857
+ const aModules = [];
1858
+ let sBaseName,
1859
+ oError;
1860
+
1861
+ try {
1862
+ // calculate the base name for relative module names
1863
+ if ( oRequestingModule instanceof Module ) {
1864
+ sBaseName = oRequestingModule.name;
1865
+ } else {
1866
+ sBaseName = oRequestingModule;
1867
+ oRequestingModule = null;
1868
+ }
1869
+ aDependencies = aDependencies.slice();
1870
+ for (let i = 0; i < aDependencies.length; i++) {
1871
+ aDependencies[i] = getMappedName(aDependencies[i] + '.js', sBaseName);
1872
+ }
1873
+ if ( oRequestingModule ) {
1874
+ // remember outgoing dependencies to be able to detect cycles, but ignore pseudo-dependencies
1875
+ aDependencies.forEach((dep) => {
1876
+ if ( !/^(require|exports|module)\.js$/.test(dep) ) {
1877
+ oRequestingModule.addPending(dep);
1878
+ }
1879
+ });
1880
+ }
1881
+
1882
+ for (let i = 0; i < aDependencies.length; i++) {
1883
+ const sDepModName = aDependencies[i];
1884
+ if ( oRequestingModule ) {
1885
+ switch ( sDepModName ) {
1886
+ case 'require.js':
1887
+ // the injected local require should behave like the Standard require (2nd argument = true)
1888
+ aModules[i] = wrapExport(createContextualRequire(sBaseName, true));
1889
+ break;
1890
+ case 'module.js':
1891
+ aModules[i] = wrapExport(oRequestingModule.api());
1892
+ break;
1893
+ case 'exports.js':
1894
+ oRequestingModule.api();
1895
+ aModules[i] = wrapExport(oRequestingModule._exports);
1896
+ break;
1897
+ default:
1898
+ break;
1899
+ }
1900
+ }
1901
+ if ( !aModules[i] ) {
1902
+ aModules[i] = requireModule(oRequestingModule, sDepModName, bAsync);
1903
+ }
1904
+ }
1905
+
1906
+ } catch (err) {
1907
+ oError = err;
1908
+ }
1909
+
1910
+ if ( bAsync ) {
1911
+ const oPromise = oError ? Promise.reject(oError) : Promise.all(aModules);
1912
+ return oPromise.then(fnCallback, fnErrCallback);
1913
+ } else {
1914
+ if ( oError ) {
1915
+ fnErrCallback(oError);
1916
+ } else {
1917
+ return fnCallback(aModules);
1918
+ }
1919
+ }
1920
+ }
1921
+
1922
+ function executeModuleDefinition(sResourceName, aDependencies, vFactory, bExport, bAsync) {
1923
+ const bLoggable = log.isLoggable();
1924
+ sResourceName = normalize(sResourceName);
1925
+
1926
+ if ( bLoggable ) {
1927
+ log.debug(sLogPrefix + "define('" + sResourceName + "', " + "['" + aDependencies.join("','") + "']" + ")");
1928
+ }
1929
+
1930
+ const oModule = declareModule(sResourceName);
1931
+
1932
+ let repeatedExecutionReported = false;
1933
+
1934
+ function shouldSkipExecution() {
1935
+ if ( oModule.settled ) {
1936
+ // avoid double execution of the module, e.g. when async/sync conflict occurred before queue processing
1937
+ if ( oModule.state >= READY && bAsync && oModule.async === false ) {
1938
+ log.warning("Repeated module execution skipped after async/sync conflict for " + oModule.name);
1939
+ return true;
1940
+ }
1941
+
1942
+ // when an inline module definition is executed repeatedly, this is reported but not prevented
1943
+ // Standard AMD loaders don't support this scenario, it needs to be fixed on caller side
1944
+ if ( strictModuleDefinitions && bAsync ) {
1945
+ log.warning("Module '" + oModule.name + "' has been defined more than once. " +
1946
+ "All but the first definition will be ignored, don't try to define the same module again.");
1947
+ return true;
1948
+ }
1949
+
1950
+ if ( !repeatedExecutionReported ) {
1951
+ log.error(
1952
+ "Module '" + oModule.name + "' is executed more than once. " +
1953
+ "This is an unsupported scenario and will fail in future versions of UI5 or " +
1954
+ "when a standard AMD loader is used. Don't define the same module again.");
1955
+ repeatedExecutionReported = true;
1956
+ }
1957
+ }
1958
+ }
1959
+
1960
+ if ( shouldSkipExecution() ) {
1961
+ return;
1962
+ }
1963
+
1964
+ // avoid early evaluation of the module value
1965
+ oModule.content = undefined;
1966
+
1967
+ function onSuccess(aModules) {
1968
+
1969
+ // avoid double execution of the module, e.g. when async/sync conflict occurred while waiting for dependencies
1970
+ if ( shouldSkipExecution() ) {
1971
+ return;
1972
+ }
1973
+
1974
+ // factory
1975
+ if ( bLoggable ) {
1976
+ log.debug(sLogPrefix + "define('" + sResourceName + "'): dependencies resolved, calling factory " + typeof vFactory);
1977
+ }
1978
+
1979
+ if ( bExport && syncCallBehavior !== 2 ) {
1980
+ // ensure parent namespace
1981
+ const aPackages = sResourceName.split('/');
1982
+ if ( aPackages.length > 1 ) {
1983
+ getGlobalObject(__global, aPackages, aPackages.length - 1, true);
1984
+ }
1985
+ }
1986
+
1987
+ if ( typeof vFactory === 'function' ) {
1988
+ // from https://github.com/amdjs/amdjs-api/blob/master/AMD.md
1989
+ // "If the factory function returns a value (an object, function, or any value that coerces to true),
1990
+ // then that value should be assigned as the exported value for the module."
1991
+ try {
1992
+ aModules = aModules.map(unwrapExport);
1993
+ let exports = vFactory.apply(__global, aModules);
1994
+ if ( oModule._api?.exports !== undefined && oModule._api.exports !== oModule._exports ) {
1995
+ exports = oModule._api.exports;
1996
+ } else if ( exports === undefined && oModule._exports ) {
1997
+ exports = oModule._exports;
1998
+ }
1999
+ oModule.content = exports;
2000
+ } catch (error) {
2001
+ const wrappedError = oModule.failWith("failed to execute module factory for '{id}'", error);
2002
+ if ( bAsync ) {
2003
+ // Note: in async mode, the error is reported via the oModule's promise
2004
+ return;
2005
+ }
2006
+ throw wrappedError;
2007
+ }
2008
+ } else {
2009
+ oModule.content = vFactory;
2010
+ }
2011
+
2012
+ // HACK: global export
2013
+ if ( bExport && syncCallBehavior !== 2 ) {
2014
+ if ( oModule.content == null ) {
2015
+ log.error(`Module '${sResourceName}' returned no content, but should export to global?`);
2016
+ } else {
2017
+ if ( bLoggable ) {
2018
+ log.debug(`exporting content of '${sResourceName}': as global object`);
2019
+ }
2020
+ // convert module name to UI5 module name syntax (might fail!)
2021
+ const sModuleName = urnToUI5(sResourceName);
2022
+ setGlobalProperty(sModuleName, oModule.content);
2023
+ }
2024
+ }
2025
+
2026
+ oModule.ready();
2027
+
2028
+ }
2029
+
2030
+ // Note: dependencies will be resolved and converted from RJS to URN inside requireAll
2031
+ requireAll(oModule, aDependencies, bAsync && oModule.data ? scheduleExecution(onSuccess) : onSuccess, function(oErr) {
2032
+ const oWrappedError = oModule.failWith("Failed to resolve dependencies of {id}", oErr);
2033
+ if ( !bAsync ) {
2034
+ throw oWrappedError;
2035
+ }
2036
+ // Note: in async mode, the error is reported via the oModule's promise
2037
+ }, /* bAsync = */ bAsync);
2038
+
2039
+ }
2040
+
2041
+ function ui5Define(sModuleName, aDependencies, vFactory, bExport) {
2042
+ let sResourceName;
2043
+
2044
+ // optional id
2045
+ if ( typeof sModuleName === 'string' ) {
2046
+ sResourceName = sModuleName + '.js';
2047
+ } else {
2048
+ // shift parameters
2049
+ bExport = vFactory;
2050
+ vFactory = aDependencies;
2051
+ aDependencies = sModuleName;
2052
+ sResourceName = null;
2053
+ }
2054
+
2055
+ // optional array of dependencies
2056
+ if ( !Array.isArray(aDependencies) ) {
2057
+ // shift parameters
2058
+ bExport = vFactory;
2059
+ vFactory = aDependencies;
2060
+ if ( typeof vFactory === 'function' && vFactory.length > 0 ) {
2061
+ aDependencies = ['require', 'exports', 'module'].slice(0, vFactory.length);
2062
+ } else {
2063
+ aDependencies = [];
2064
+ }
2065
+ }
2066
+
2067
+ // if ( bForceSyncDefines === false || (bForceSyncDefines == null && bGlobalAsyncMode) ) {
2068
+ // queue.push(sResourceName, aDependencies, vFactory, bExport);
2069
+ // if ( sResourceName != null ) {
2070
+ // const oModule = Module.get(sResourceName);
2071
+ // if ( oModule.state === INITIAL ) {
2072
+ // oModule.state = EXECUTING;
2073
+ // oModule.async = true;
2074
+ // }
2075
+ // }
2076
+ // return;
2077
+ // }
2078
+
2079
+ // immediate, synchronous execution
2080
+ const oCurrentExecInfo = _execStack.length > 0 ? _execStack[_execStack.length - 1] : null;
2081
+ if ( !sResourceName ) {
2082
+
2083
+ if ( oCurrentExecInfo && !oCurrentExecInfo.used ) {
2084
+ sResourceName = oCurrentExecInfo.name;
2085
+ oCurrentExecInfo.used = true;
2086
+ } else {
2087
+ // give anonymous modules a unique pseudo ID
2088
+ if(!oCurrentExecInfo) {
2089
+ sResourceName = global.testPath;
2090
+ } else if(currentModuleName) {
2091
+ sResourceName = currentModuleName;
2092
+ } else {
2093
+ sResourceName = `~anonymous~${++iAnonymousModuleCount}.js`;
2094
+ }
2095
+
2096
+ if ( oCurrentExecInfo ) {
2097
+ sResourceName = oCurrentExecInfo.name.slice(0, oCurrentExecInfo.name.lastIndexOf('/') + 1) + sResourceName;
2098
+ }
2099
+ log.error(
2100
+ "Modules that use an anonymous define() call must be loaded with a require() call; " +
2101
+ "they must not be executed via script tag or nested into other modules. " +
2102
+ "All other usages will fail in future releases or when standard AMD loaders are used " +
2103
+ "or when ui5loader runs in async mode. Now using substitute name " + sResourceName);
2104
+ }
2105
+ } else if ( oCurrentExecInfo?.used && sResourceName !== oCurrentExecInfo.name ) {
2106
+ log.debug(`module names don't match: requested: ${sModuleName}, defined: ${oCurrentExecInfo.name}`);
2107
+ Module.get(oCurrentExecInfo.name).addAlias(sModuleName);
2108
+ }
2109
+ executeModuleDefinition(sResourceName, aDependencies, vFactory, bExport, /* bAsync = */ false);
2110
+
2111
+ }
2112
+
2113
+ /**
2114
+ * The amdDefine() function is closer to the AMD spec, as opposed to sap.ui.define.
2115
+ * It's later assigned as the global define() if the loader is running in amd=true
2116
+ * mode (has to be configured explicitly).
2117
+ */
2118
+ function amdDefine(sModuleName, aDependencies, vFactory) {
2119
+ let oArgs = arguments;
2120
+ const bExportIsSet = typeof oArgs[oArgs.length - 1] === "boolean";
2121
+
2122
+ // bExport parameter is proprietary and should not be used for an AMD compliant define()
2123
+ if (bExportIsSet) {
2124
+ oArgs = Array.prototype.slice.call(oArgs, 0, oArgs.length - 1);
2125
+ }
2126
+
2127
+ ui5Define.apply(this, oArgs);
2128
+ }
2129
+ amdDefine.amd = {}; // identify as AMD-spec compliant loader
2130
+ amdDefine.ui5 = {}; // identify as ui5loader
2131
+
2132
+
2133
+ /**
2134
+ * Create a require() function which acts in the context of the given resource.
2135
+ *
2136
+ * @param {string|null} sContextName Name of the context resource (module) in URN syntax, incl. extension
2137
+ * @param {boolean} bAMDCompliance If set to true, the behavior of the require() function is closer to the AMD specification.
2138
+ * @returns {function} Require function.
2139
+ */
2140
+ function createContextualRequire(sContextName, bAMDCompliance) {
2141
+ const fnRequire = function(vDependencies, fnCallback, fnErrCallback) {
2142
+ assert(typeof vDependencies === 'string' || Array.isArray(vDependencies), "dependency param either must be a single string or an array of strings");
2143
+ assert(fnCallback == null || typeof fnCallback === 'function', "callback must be a function or null/undefined");
2144
+ assert(fnErrCallback == null || typeof fnErrCallback === 'function', "error callback must be a function or null/undefined");
2145
+
2146
+ // Probing for existing module
2147
+ if ( typeof vDependencies === 'string' ) {
2148
+ const sModuleName = getMappedName(vDependencies + '.js', sContextName);
2149
+ const oModule = Module.get(sModuleName);
2150
+
2151
+ // check the modules internal state
2152
+ // everything from PRELOADED to LOADED (incl. FAILED) is considered erroneous
2153
+ if (bAMDCompliance && oModule.state !== EXECUTING && oModule.state !== READY) {
2154
+ throw new Error(
2155
+ "Module '" + sModuleName + "' has not been loaded yet. " +
2156
+ "Use require(['" + sModuleName + "']) to load it."
2157
+ );
2158
+ }
2159
+
2160
+ // Module is in state READY or EXECUTING; or require() was called from sap.ui.require().
2161
+ // A modules value might be undefined (no return statement) even though the state is READY.
2162
+ return oModule.value();
2163
+ }
2164
+
2165
+ requireAll(sContextName, vDependencies, function(aModules) {
2166
+ aModules = aModules.map(unwrapExport);
2167
+ if ( typeof fnCallback === 'function' ) {
2168
+ if ( bGlobalAsyncMode ) {
2169
+ fnCallback.apply(__global, aModules);
2170
+ } else {
2171
+ // enforce asynchronous execution of callback even in sync mode
2172
+ simulateAsyncCallback(function() {
2173
+ fnCallback.apply(__global, aModules);
2174
+ });
2175
+ }
2176
+ }
2177
+ }, function(oErr) {
2178
+ if ( typeof fnErrCallback === 'function' ) {
2179
+ if ( bGlobalAsyncMode ) {
2180
+ fnErrCallback.call(__global, oErr);
2181
+ } else {
2182
+ simulateAsyncCallback(function() {
2183
+ fnErrCallback.call(__global, oErr);
2184
+ });
2185
+ }
2186
+ } else {
2187
+ throw oErr;
2188
+ }
2189
+ }, /* bAsync = */ bGlobalAsyncMode);
2190
+
2191
+ // return undefined;
2192
+ };
2193
+ fnRequire.toUrl = function(sName) {
2194
+ const sMappedName = ensureTrailingSlash(getMappedName(sName, sContextName), sName);
2195
+ return toUrl(sMappedName);
2196
+ };
2197
+ return fnRequire;
2198
+ }
2199
+
2200
+ function ensureTrailingSlash(sName, sInput) {
2201
+ //restore trailing slash
2202
+ if (sInput.slice(-1) === "/" && sName.slice(-1) !== "/") {
2203
+ return sName + "/";
2204
+ }
2205
+ return sName;
2206
+ }
2207
+
2208
+ function toUrl(sName) {
2209
+ if (sName.indexOf("/") === 0) {
2210
+ throw new Error(`The provided argument '${sName}' may not start with a slash`);
2211
+ }
2212
+ return ensureTrailingSlash(getResourcePath(sName), sName);
2213
+ }
2214
+
2215
+ /*
2216
+ * UI5 version of require (sap.ui.require)
2217
+ */
2218
+ const ui5Require = createContextualRequire(null, false);
2219
+
2220
+ /*
2221
+ * AMD version of require (window.require)
2222
+ *
2223
+ * Difference between require (sap.ui.require) and amdRequire (window.require):
2224
+ * - require("my/module"), returns undefined if the module was not loaded yet
2225
+ * - amdRequire("my/module"), throws an error if the module was not loaded yet
2226
+ */
2227
+ const amdRequire = createContextualRequire(null, true);
2228
+
2229
+ function requireSync(sModuleName) {
2230
+ sModuleName = getMappedName(sModuleName + '.js');
2231
+ if ( log.isLoggable() ) {
2232
+ log.warning(`sync require of '${sModuleName}'`);
2233
+ }
2234
+ return unwrapExport(requireModule(null, sModuleName, /* bAsync = */ false));
2235
+ }
2236
+
2237
+ function predefine(sModuleName, aDependencies, vFactory, bExport) {
2238
+ if ( typeof sModuleName !== 'string' ) {
2239
+ throw new Error("predefine requires a module name");
2240
+ }
2241
+ sModuleName = normalize(sModuleName);
2242
+ Module.get(sModuleName + '.js').preload("<unknown>/" + sModuleName, [sModuleName, aDependencies, vFactory, bExport], null);
2243
+ }
2244
+
2245
+ function preload(modules, group, url) {
2246
+ group = group || null;
2247
+ url = url || "<unknown>";
2248
+ for ( let name in modules ) {
2249
+ name = normalize(name);
2250
+ Module.get(name).preload(url + "/" + name, modules[name], group);
2251
+ }
2252
+ }
2253
+
2254
+ /**
2255
+ * Dumps information about the current set of modules and their state.
2256
+ *
2257
+ * @param {int} [iThreshold=-1] Earliest module state for which odules should be reported
2258
+ * @private
2259
+ */
2260
+ function dumpInternals(iThreshold) {
2261
+
2262
+ const states = [PRELOADED, INITIAL, LOADED, READY, FAILED, EXECUTING, LOADING];
2263
+ const stateNames = {
2264
+ [PRELOADED]: 'PRELOADED',
2265
+ [INITIAL]:'INITIAL',
2266
+ [LOADING]: 'LOADING',
2267
+ [LOADED]: 'LOADED',
2268
+ [EXECUTING]: 'EXECUTING',
2269
+ [READY]: 'READY',
2270
+ [FAILED]: 'FAILED'
2271
+ };
2272
+
2273
+ if ( iThreshold == null ) {
2274
+ iThreshold = PRELOADED;
2275
+ }
2276
+
2277
+ /*eslint-disable no-console */
2278
+ const info = log.isLoggable('INFO') ? log.info.bind(log) : console.info.bind(console);
2279
+ /*eslint-enable no-console */
2280
+
2281
+ const aModuleNames = Object.keys(mModules).sort();
2282
+ states.forEach((state) => {
2283
+ if ( state < iThreshold ) {
2284
+ return;
2285
+ }
2286
+ let count = 0;
2287
+ info(stateNames[state] + ":");
2288
+ aModuleNames.forEach((sModule, idx) => {
2289
+ const oModule = mModules[sModule];
2290
+ if ( oModule.state === state ) {
2291
+ let addtlInfo;
2292
+ if ( oModule.state === LOADING ) {
2293
+ const pending = oModule.pending?.reduce((acc, dep) => {
2294
+ const oDepModule = Module.get(dep);
2295
+ if ( oDepModule.state !== READY ) {
2296
+ acc.push( dep + "(" + stateNames[oDepModule.state] + ")");
2297
+ }
2298
+ return acc;
2299
+ }, []);
2300
+ if ( pending?.length > 0 ) {
2301
+ addtlInfo = "waiting for " + pending.join(", ");
2302
+ }
2303
+ } else if ( oModule.state === FAILED ) {
2304
+ addtlInfo = (oModule.error.name || "Error") + ": " + oModule.error.message;
2305
+ }
2306
+ info(" " + (idx + 1) + " " + sModule + (addtlInfo ? " (" + addtlInfo + ")" : ""));
2307
+ count++;
2308
+ }
2309
+ });
2310
+ if ( count === 0 ) {
2311
+ info(" none");
2312
+ }
2313
+ });
2314
+
2315
+ }
2316
+
2317
+ /**
2318
+ * Returns a flat copy of the current set of URL prefixes.
2319
+ *
2320
+ * @private
2321
+ */
2322
+ function getUrlPrefixes() {
2323
+ const mUrlPrefixesCopy = Object.create(null);
2324
+ forEach(mUrlPrefixes, function(sNamePrefix, oUrlInfo) {
2325
+ mUrlPrefixesCopy[sNamePrefix] = oUrlInfo.url;
2326
+ });
2327
+ return mUrlPrefixesCopy;
2328
+ }
2329
+
2330
+ /**
2331
+ * Removes a set of resources from the resource cache.
2332
+ *
2333
+ * @param {string} sName unified resource name of a resource or the name of a preload group to be removed
2334
+ * @param {boolean} [bPreloadGroup=true] whether the name specifies a preload group, defaults to true
2335
+ * @param {boolean} [bUnloadAll] Whether all matching resources should be unloaded, even if they have been executed already.
2336
+ * @param {boolean} [bDeleteExports] Whether exports (global variables) should be destroyed as well. Will be done for UI5 module names only.
2337
+ * @experimental Since 1.16.3 API might change completely, apps must not develop against it.
2338
+ * @private
2339
+ */
2340
+ function unloadResources(sName, bPreloadGroup, bUnloadAll, bDeleteExports) {
2341
+ const aModules = [];
2342
+
2343
+ if ( bPreloadGroup == null ) {
2344
+ bPreloadGroup = true;
2345
+ }
2346
+
2347
+ if ( bPreloadGroup ) {
2348
+ // collect modules that belong to the given group
2349
+ for ( const sURN in mModules ) {
2350
+ const oModule = mModules[sURN];
2351
+ if ( oModule && oModule.group === sName ) {
2352
+ aModules.push(sURN);
2353
+ }
2354
+ }
2355
+ } else {
2356
+ // single module
2357
+ if ( mModules[sName] ) {
2358
+ aModules.push(sName);
2359
+ }
2360
+ }
2361
+
2362
+ aModules.forEach((sURN) => {
2363
+ const oModule = mModules[sURN];
2364
+ if ( oModule && bDeleteExports && sURN.match(/\.js$/) ) {
2365
+ // @evo-todo move to compat layer?
2366
+ setGlobalProperty(urnToUI5(sURN), undefined);
2367
+ }
2368
+ if ( oModule && (bUnloadAll || oModule.state === PRELOADED) ) {
2369
+ delete mModules[sURN];
2370
+ }
2371
+ });
2372
+ }
2373
+
2374
+ function getModuleContent(name, url) {
2375
+ if ( name ) {
2376
+ name = getMappedName(name);
2377
+ } else {
2378
+ name = guessResourceName(url, true);
2379
+ }
2380
+ const oModule = name && mModules[name];
2381
+ if ( oModule ) {
2382
+ oModule.state = LOADED;
2383
+ return oModule.data;
2384
+ } else {
2385
+ return undefined;
2386
+ }
2387
+ }
2388
+
2389
+ /**
2390
+ * Returns an info about all known resources keyed by their URN.
2391
+ *
2392
+ * If the URN can be converted to a UI5 module name, then the value in the map
2393
+ * will be that name. Otherwise it will be null or undefined.
2394
+ *
2395
+ * @return {Object.<string,string>} Map of all module names keyed by their resource name
2396
+ * @see isDeclared
2397
+ * @private
2398
+ */
2399
+ function getAllModules() {
2400
+ const mSnapshot = Object.create(null);
2401
+ forEach(mModules, function(sURN, oModule) {
2402
+ mSnapshot[sURN] = {
2403
+ state: oModule.state,
2404
+ ui5: urnToUI5(sURN)
2405
+ };
2406
+ });
2407
+ return mSnapshot;
2408
+ }
2409
+
2410
+ function loadJSResourceAsync(sResource, bIgnoreErrors) {
2411
+ sResource = getMappedName(sResource);
2412
+ const promise = requireModule(null, sResource, /* bAsync = */ true).then(unwrapExport);
2413
+ return bIgnoreErrors ? promise.catch(noop) : promise;
2414
+ }
2415
+
2416
+ // ---- config --------------------------------------------------------------------------------
2417
+
2418
+ const mUI5ConfigHandlers = {
2419
+ baseUrl(url) {
2420
+ registerResourcePath("", url);
2421
+ },
2422
+ paths: registerResourcePath, // has length 2
2423
+ shim(module, shim) {
2424
+ if ( Array.isArray(shim) ) {
2425
+ shim = { deps : shim };
2426
+ }
2427
+ mShims[module + '.js'] = shim;
2428
+ },
2429
+ amd(bValue) {
2430
+ bValue = !!bValue;
2431
+ if ( bExposeAsAMDLoader !== bValue ) {
2432
+ bExposeAsAMDLoader = bValue;
2433
+ if (bValue) {
2434
+ vOriginalDefine = __global.define;
2435
+ vOriginalRequire = __global.require;
2436
+ __global.define = amdDefine;
2437
+ __global.require = amdRequire;
2438
+
2439
+ // Enable async loading behaviour implicitly when switching to amd mode
2440
+ bGlobalAsyncMode = true;
2441
+ } else {
2442
+ __global.define = vOriginalDefine;
2443
+ __global.require = vOriginalRequire;
2444
+ // NOTE: Do not set async mode back to false when amd mode gets deactivated
2445
+ }
2446
+ }
2447
+ },
2448
+ async(async) {
2449
+ if (bGlobalAsyncMode && !async) {
2450
+ throw new Error("Changing the ui5loader config from async to sync is not supported. Only a change from sync to async is allowed.");
2451
+ }
2452
+ bGlobalAsyncMode = !!async;
2453
+ },
2454
+ bundles(bundle, modules) {
2455
+ bundle += '.js';
2456
+ modules.forEach(
2457
+ (module) => { Module.get(module + '.js').group = bundle; }
2458
+ );
2459
+ },
2460
+ bundlesUI5(bundle, resources) {
2461
+ resources.forEach(
2462
+ (module) => { Module.get(module).group = bundle; }
2463
+ );
2464
+ },
2465
+ debugSources(debug) {
2466
+ bDebugSources = !!debug;
2467
+ },
2468
+ depCache(module, deps) {
2469
+ mDepCache[module + '.js'] = deps.map((dep) => dep + '.js');
2470
+ },
2471
+ depCacheUI5(module, deps) {
2472
+ mDepCache[module] = deps;
2473
+ },
2474
+ ignoreBundledResources(filter) {
2475
+ if(global["sap-ui-no-preload"] === true ) {
2476
+ fnIgnorePreload = () => true;
2477
+ }
2478
+ else if ( filter == null || typeof filter === 'function' ) {
2479
+ fnIgnorePreload = filter;
2480
+ }
2481
+ },
2482
+ map(context, map) {
2483
+ // @evo-todo ignore empty context, empty prefix?
2484
+ if ( map == null ) {
2485
+ delete mMaps[context];
2486
+ } else if ( typeof map === 'string' ) {
2487
+ // SystemJS style config
2488
+ mMaps['*'][context] = map;
2489
+ } else {
2490
+ mMaps[context] ||= Object.create(null);
2491
+ forEach(map, function(alias, name) {
2492
+ mMaps[context][alias] = name;
2493
+ });
2494
+ }
2495
+ },
2496
+ reportSyncCalls(report) {
2497
+ if ( report === 0 || report === 1 || report === 2 ) {
2498
+ syncCallBehavior = report;
2499
+ }
2500
+ },
2501
+ noConflict(bValue) {
2502
+ log.warning("Config option 'noConflict' has been deprecated, use option 'amd' instead, if still needed.");
2503
+ mUI5ConfigHandlers.amd(!bValue);
2504
+ }
2505
+ };
2506
+
2507
+ /**
2508
+ * Config handlers used when amd mode is enabled.
2509
+ * References only methods defined in the AMD spec.
2510
+ */
2511
+ const mAMDConfigHandlers = {
2512
+ baseUrl: mUI5ConfigHandlers.baseUrl,
2513
+ paths(module, url) {
2514
+ registerResourcePath(module, resolveURL(url, getResourcePath("") + "/"));
2515
+ },
2516
+ map: mUI5ConfigHandlers.map,
2517
+ shim: mUI5ConfigHandlers.shim
2518
+ };
2519
+
2520
+ /**
2521
+ * Executes all available handlers which are defined in the config object
2522
+ *
2523
+ * @param {object} oCfg config to handle
2524
+ * @param {Object<string,function>} mHandlers all available handlers
2525
+ */
2526
+ function handleConfigObject(oCfg, mHandlers) {
2527
+
2528
+ function processConfig(key, value) {
2529
+ const handler = mHandlers[key];
2530
+ if ( typeof handler === 'function' ) {
2531
+ if ( handler.length === 1) {
2532
+ handler(value);
2533
+ } else if ( value != null ) {
2534
+ forEach(value, handler);
2535
+ }
2536
+ } else {
2537
+ log.warning(`configuration option ${key} not supported (ignored)`);
2538
+ }
2539
+ }
2540
+
2541
+ // Make sure the 'baseUrl' handler is called first as
2542
+ // other handlers (e.g. paths) depend on it
2543
+ if (oCfg.baseUrl) {
2544
+ processConfig("baseUrl", oCfg.baseUrl);
2545
+ }
2546
+
2547
+ forEach(oCfg, function(key, value) {
2548
+ // Ignore "baseUrl" here as it will be handled above
2549
+ if (key !== "baseUrl") {
2550
+ processConfig(key, value);
2551
+ }
2552
+ });
2553
+ }
2554
+
2555
+ function ui5Config(cfg) {
2556
+ if ( cfg === undefined ) {
2557
+ return {
2558
+ amd: bExposeAsAMDLoader,
2559
+ async: bGlobalAsyncMode,
2560
+ noConflict: !bExposeAsAMDLoader // TODO needed?
2561
+ };
2562
+ }
2563
+ handleConfigObject(cfg, mUI5ConfigHandlers);
2564
+ }
2565
+
2566
+ function amdConfig(cfg) {
2567
+ if ( cfg === undefined ) {
2568
+ return undefined;
2569
+ }
2570
+ handleConfigObject(cfg, mAMDConfigHandlers);
2571
+ }
2572
+
2573
+ // expose preload function as property of sap.ui.require
2574
+ ui5Require.preload = preload;
2575
+
2576
+ // @evo-todo really use this hook for loading. But how to differentiate between sync and async?
2577
+ // for now, it is only a notification hook to attach load tests
2578
+ ui5Require.load = function(context, url, id) {
2579
+ };
2580
+
2581
+ const privateAPI = {
2582
+
2583
+ // properties
2584
+ get assert() {
2585
+ return assert;
2586
+ },
2587
+ set assert(v) {
2588
+ assert = v;
2589
+ },
2590
+ get logger() {
2591
+ return log;
2592
+ },
2593
+ set logger(v) {
2594
+ log = v;
2595
+ aEarlyLogs.forEach(({level, message}) => log[level](message));
2596
+ },
2597
+ get measure() {
2598
+ return measure;
2599
+ },
2600
+ set measure(v) {
2601
+ measure = v;
2602
+ },
2603
+ get translate() {
2604
+ return translate;
2605
+ },
2606
+ set translate(v) {
2607
+ translate = v;
2608
+ },
2609
+ get callbackInMicroTask() {
2610
+ return simulateAsyncCallback === executeInMicroTask;
2611
+ },
2612
+ set callbackInMicroTask(v) {
2613
+ simulateAsyncCallback = v ? executeInMicroTask : executeInSeparateTask;
2614
+ },
2615
+ get maxTaskDuration() {
2616
+ return iMaxTaskDuration;
2617
+ },
2618
+ set maxTaskDuration(v) {
2619
+ updateMaxTaskDuration(v);
2620
+ },
2621
+
2622
+ // methods
2623
+ amdDefine,
2624
+ amdRequire,
2625
+ config: ui5Config,
2626
+ declareModule(sResourceName) {
2627
+ /* void */ declareModule( normalize(sResourceName) );
2628
+ },
2629
+ defineModuleSync,
2630
+ dump: dumpInternals,
2631
+ getAllModules,
2632
+ getModuleContent,
2633
+ getModuleState(sResourceName) {
2634
+ return mModules[sResourceName] ? mModules[sResourceName].state : INITIAL;
2635
+ },
2636
+ getResourcePath,
2637
+ getSyncCallBehavior,
2638
+ getUrlPrefixes,
2639
+ loadJSResourceAsync,
2640
+ resolveURL,
2641
+ guessResourceName,
2642
+ toUrl,
2643
+ unloadResources
2644
+ };
2645
+
2646
+
2647
+ // establish APIs in the sap.ui namespace
2648
+
2649
+ __global.sap = __global.sap || {};
2650
+ sap.ui = sap.ui || {};
2651
+
2652
+ /**
2653
+ * Provides access to UI5 loader configuration.
2654
+ *
2655
+ * The configuration is used by {@link sap.ui.require} and {@link sap.ui.define}.
2656
+ *
2657
+ * @public
2658
+ * @namespace
2659
+ * @ui5-global-only
2660
+ */
2661
+ sap.ui.loader = {
2662
+
2663
+ /**
2664
+ * Sets the configuration for the UI5 loader. The configuration can be updated multiple times.
2665
+ * Later changes do not impact modules that have been loaded before.
2666
+ *
2667
+ * If no parameter is given, a partial copy of UI5 loader configuration in use is returned.
2668
+ *
2669
+ * The configuration options are aligned with the "Common Config" draft of the AMD spec
2670
+ * (https://github.com/amdjs/amdjs-api/blob/master/CommonConfig.md).
2671
+ *
2672
+ * The following code shows an example of what a UI5 loader configuration might look like:
2673
+ * <pre>
2674
+ *
2675
+ * sap.ui.loader.config({
2676
+ *
2677
+ * // location from where to load all modules by default
2678
+ * baseUrl: '../../resources/',
2679
+ *
2680
+ * paths: {
2681
+ * // load modules whose ID equals to or starts with 'my/module' from example.com
2682
+ * 'my/module': 'https://example.com/resources/my/module'
2683
+ * },
2684
+ *
2685
+ * map: {
2686
+ * // if any module requires 'sinon', load module 'sap/ui/thirdparty/sinon-4'
2687
+ * '*': {
2688
+ * 'sinon': 'sap/ui/thirdparty/sinon-4'
2689
+ * },
2690
+ * // but if a module whose ID equals to or starts with 'app' requires 'sinon'
2691
+ * // then load a legacy version instead
2692
+ * "app": {
2693
+ * 'sinon': 'sap/ui/legacy/sinon'
2694
+ * }
2695
+ * },
2696
+ *
2697
+ * // define two bundles that consists of JS modules only
2698
+ * bundles: {
2699
+ * bundle1: ['module1', 'module2'],
2700
+ * bundle2: ['moduleX', 'moduleY']
2701
+ * },
2702
+ *
2703
+ * // define a bundle that also contains non-JS resources
2704
+ * bundlesUI5: {
2705
+ * 'all.js': ['Component.js', 'manifest.json',
2706
+ * 'App.controller.js', 'App.view.xml']
2707
+ * },
2708
+ *
2709
+ * // activate real async loading and module definitions
2710
+ * async: true,
2711
+ *
2712
+ * // provide dependency and export metadata for non-UI5 modules
2713
+ * shim: {
2714
+ * 'sap/ui/thirdparty/blanket': {
2715
+ * amd: true,
2716
+ * exports: 'blanket'
2717
+ * }
2718
+ * }
2719
+ *
2720
+ * });
2721
+ *
2722
+ * </pre>
2723
+ *
2724
+ * @param {object} [cfg]
2725
+ * The provided configuration gets merged with the UI5 loader configuration in use.
2726
+ * If <code>cfg</code> is omitted or <code>undefined</code>, a copy of the current configuration
2727
+ * gets returned, containing at least the properties <code>amd</code> and <code>async</code>.
2728
+ *
2729
+ * @param {string} [cfg.baseUrl='./']
2730
+ * Default location to load modules from. If none of the configured <code>paths</code> prefixes
2731
+ * matches a module ID, the module will be loaded from the concatenation of the <code>baseUrl</code>
2732
+ * and the module ID.
2733
+ *
2734
+ * If the <code>baseUrl</code> itself is a relative URL, it is evaluated relative to <code>document.baseURI</code>.
2735
+ *
2736
+ * @param {Object.<string, string>} [cfg.paths]
2737
+ * A map of resource locations keyed by a corresponding module ID prefix.
2738
+ * When a module is to be loaded, the longest key in <code>paths</code> is searched that is a
2739
+ * prefix of the module ID. The module will be loaded from the concatenation of the corresponding
2740
+ * value in <code>paths</code> and the remainder of the module ID (after the prefix). If no entry
2741
+ * in <code>paths</code> matches, then the module will be loaded from the <code>baseUrl</code>.
2742
+ *
2743
+ * The prefixes (keys) must not contain relative segments (./ or ../), a trailing slash will be
2744
+ * removed, and only full name segment matches are considered a match (prefix 'sap/m' does not
2745
+ * match a module ID 'sap/main').
2746
+ *
2747
+ * <b>Note</b>: In contrast to the "Common Config" of the AMD spec, the paths (values in the map)
2748
+ * are interpreted relative to <code>document.baseURI</code>, not relative to <code>cfg.baseUrl</code>.
2749
+ *
2750
+ * @param {Object.<string, Object.<string, string>>} [cfg.map]
2751
+ * A map of maps that defines how to map module IDs to other module IDs (inner maps)
2752
+ * in the context of a specific set of modules (keys of outer map).
2753
+ *
2754
+ * Each key of the outer map represents a module ID prefix that describes the context for which
2755
+ * its value (inner map) has to be used. The special key <code>*</code> describes the default
2756
+ * context which applies for any module. Only the most specific matching context will be taken
2757
+ * into account.
2758
+ *
2759
+ * Each inner map maps a module ID or module ID prefix to another module ID or module ID prefix.
2760
+ * Again, only the most specific match is taken into account and only one mapping is evaluated
2761
+ * (the evaluation of the mappings is not done recursively).
2762
+ *
2763
+ * Matches are always complete matches, a prefix 'a/b/c' does not match the module ID 'a/b/com'.
2764
+ *
2765
+ * @param {Object.<string, {amd: boolean, deps: string[], exports: (string|string[])}>} [cfg.shim]
2766
+ * Defines additional metadata for modules for which the normal behavior of the AMD APIs is
2767
+ * not sufficient.
2768
+ *
2769
+ * A typical example are scripts that don't use <code>define</code> or <code>sap.ui.define</code>,
2770
+ * but export to a global name. With the <code>exports</code> property, one or more export
2771
+ * names can be specified, and the loader can retrieve the exported value after executing the
2772
+ * corresponding module. If such a module has dependencies, they can be specified in the
2773
+ * <code>deps</code> array and are loaded and executed before executing the module.
2774
+ *
2775
+ * The <code>amd</code> flag of a shim is a ui5loader-specific extension of the standard AMD shims.
2776
+ * If set, the ui5loader hides a currently active AMD loader before executing the module
2777
+ * and restores it afterwards. Otherwise, it might miss the export of third party modules that
2778
+ * check for an AMD loader and register with it instead of exporting to a global name. A future
2779
+ * version of the ui5loader might ignore this flag when it acts as an AMD loader by itself.
2780
+ *
2781
+ * <b>Note:</b> The ui5loader does not support the <code>init</code> option described by the
2782
+ * "Common Config" section of the AMD spec.
2783
+ *
2784
+ * @param {Object.<string, string[]>} [cfg.bundles]
2785
+ * A map of arrays that each define the modules contained in a bundle.
2786
+ *
2787
+ * Each key of the map represents the module ID of a bundle file. The array value represents
2788
+ * the set of JavaScript modules (their module IDs) that are contained in the bundle.
2789
+ *
2790
+ * When a module is required that has not been loaded yet, and for which a containing bundle is
2791
+ * known, that bundle will be required first. Only then the original module will be required
2792
+ * again and usually be taken from the just loaded bundle.
2793
+ *
2794
+ * A bundle will be loaded asynchronously only when the loader is in asynchronous mode and when
2795
+ * the request for the contained module originates from an asynchronous API. In all other cases,
2796
+ * the bundle has to be loaded synchronously to fulfill API contracts.
2797
+ *
2798
+ * <b>Note:</b> The loader only supports one containing bundle per module. If a module is declared
2799
+ * to be part of multiple bundles, only the last one will be taken into account.
2800
+ *
2801
+ * This configuration option is basically provided to be compatible with requireJS or SystemJS
2802
+ * configuration.
2803
+ *
2804
+ * @param {Object.<string, string[]>} [cfg.bundlesUI5]
2805
+ * A map of arrays that each define the resources contained in a bundle.
2806
+ *
2807
+ * This is similar to <code>bundles</code>, but all strings are unified resource names including
2808
+ * a file type extension, not only module IDs. This allows to represent more than just JavaScript
2809
+ * modules.
2810
+ *
2811
+ * Each key of the map represents the resource name (in unified resource name syntax) of a bundle
2812
+ * file. The array value represents the set of resources (also in unified resource name syntax)
2813
+ * that are contained in the bundle. The array can contain JavaScript as well as other textual
2814
+ * resource types (e.g. *.xml or *.json resources).
2815
+ *
2816
+ * When a module is required that has not been loaded yet, and for which a containing bundle is
2817
+ * known, that bundle will be required first. Only then the original module will be required
2818
+ * again and usually be taken from the just loaded bundle.
2819
+ *
2820
+ * A bundle will be loaded asynchronously only when the loader is in asynchronous mode and when
2821
+ * the request for the contained module originates from an asynchronous API. In all other cases,
2822
+ * the bundle has to be loaded synchronously to fulfill API contracts.
2823
+ *
2824
+ * <b>Note:</b> The loader only supports one containing bundle per module. If a module is declared
2825
+ * to be part of multiple bundles, only the last one will be taken into account.
2826
+ *
2827
+ * <b>Note:</b> Although non-JS resources can be declared to be part of a bundle, only requests for
2828
+ * JavaScript modules will currently trigger the loading of a bundle.
2829
+ *
2830
+ * @param {boolean} [cfg.async=false]
2831
+ * When set to true, <code>sap.ui.require</code> loads modules asynchronously via script tags and
2832
+ * <code>sap.ui.define</code> executes asynchronously. To enable this feature, it is recommended to
2833
+ * set the attribute <code>data-sap-ui-async="true"</code> on the application bootstrap tag.
2834
+ *
2835
+ * <b>Note:</b> Switching back from async to sync is not supported and trying to do so will throw
2836
+ * an <code>Error</code>
2837
+ *
2838
+ * @param {boolean} [cfg.amd=false]
2839
+ * When set to true, the ui5loader will overwrite the global properties <code>define</code>
2840
+ * and <code>require</code> with its own implementations. Any previously active AMD loader will
2841
+ * be remembered internally and can be restored by setting <code>amd</code> to false again.
2842
+ *
2843
+ * <b>Note:</b> Switching to the <code>amd</code> mode, the ui5loader will set <code>async</code>
2844
+ * to true implicitly for activating asynchronous loading. Once the loading behaviour has been
2845
+ * defined to be asynchronous, it can not be changed to synchronous behaviour again, also not
2846
+ * via setting <code>amd</code> to false.
2847
+ *
2848
+ * @returns {{amd: boolean, async: boolean, noConflict: boolean}|undefined} UI5 loader configuration in use.
2849
+ * @throws {Error} When trying to switch back from async mode to sync mode.
2850
+ * @public
2851
+ * @since 1.56.0
2852
+ * @function
2853
+ * @ui5-global-only
2854
+ */
2855
+ config: ui5Config,
2856
+
2857
+ /**
2858
+ * Internal API of the UI5 loader.
2859
+ *
2860
+ * Must not be used by code outside sap.ui.core.
2861
+ * @private
2862
+ * @ui5-restricted sap.ui.core
2863
+ */
2864
+ _: privateAPI
2865
+ };
2866
+
2867
+ /**
2868
+ * Sets the configuration of the ui5loader. The configuration can be updated multiple times.
2869
+ * Later changes do not impact modules that have been loaded before.
2870
+ *
2871
+ * Setting the <code>amd</code> option of the sap.ui.loader.config to <code>true</code> is a
2872
+ * prerequisite to use the <code>require.config</code> function
2873
+ * (see {@link sap.ui.loader.config sap.ui.loader.config option amd}).
2874
+ *
2875
+ * The ui5loader acts more AMD compliant in relation to resolution of paths defined as
2876
+ * part of the <code>paths</code> configuration option.
2877
+ *
2878
+ * @param {object} cfg The provided configuration gets merged with the UI5 loader configuration in use.
2879
+ *
2880
+ * @param {string} [cfg.baseUrl='./']
2881
+ * Default location to load modules from. If none of the configured <code>paths</code> prefixes
2882
+ * matches a module ID, the module will be loaded from the concatenation of the <code>baseUrl</code>
2883
+ * and the module ID.
2884
+ *
2885
+ * If the <code>baseUrl</code> itself is a relative URL, it is evaluated relative to <code>document.baseURI</code>.
2886
+ *
2887
+ * @param {object} [cfg.paths]
2888
+ * A map of resource locations keyed by a corresponding module ID prefix.
2889
+ * When a module is to be loaded, the longest key in <code>paths</code> is searched that is a
2890
+ * prefix of the module ID. The module will be loaded from the concatenation of the corresponding
2891
+ * value in <code>paths</code> and the remainder of the module ID (after the prefix). If no entry
2892
+ * in <code>paths</code> matches, then the module will be loaded from the <code>baseUrl</code>.
2893
+ *
2894
+ * The prefixes (keys) must not contain relative segments (./ or ../), a trailing slash will be
2895
+ * removed, and only full name segment matches are considered a match (prefix 'sap/m' does not
2896
+ * match a module ID 'sap/main').
2897
+ *
2898
+ * <b>Note</b>: In contrast to the {@link sap.ui.loader.config sap.ui.loader.config option paths},
2899
+ * the paths (values in the map) are interpreted relative to <code>cfg.baseUrl</code>,
2900
+ * not relative to <code>document.baseURI</code>. The behaviour is exactly as described in the "Common Config" draft
2901
+ * of the AMD spec (https://github.com/amdjs/amdjs-api/blob/master/CommonConfig.md).
2902
+ *
2903
+ * @param {Object.<string, Object.<string, string>>} [cfg.map]
2904
+ * A map of maps that defines how to map module IDs to other module IDs (inner maps)
2905
+ * in the context of a specific set of modules (keys of outer map).
2906
+ *
2907
+ * Each key of the outer map represents a module ID prefix that describes the context for which
2908
+ * its value (inner map) has to be used. The special key <code>*</code> describes the default
2909
+ * context which applies for any module. Only the most specific matching context will be taken
2910
+ * into account.
2911
+ *
2912
+ * Each inner map maps a module ID or module ID prefix to another module ID or module ID prefix.
2913
+ * Again, only the most specific match is taken into account and only one mapping is evaluated
2914
+ * (the evaluation of the mappings is not done recursively).
2915
+ *
2916
+ * Matches are always complete matches, a prefix 'a/b/c' does not match the module ID 'a/b/com'.
2917
+ *
2918
+ * @param {Object.<string, {deps: string[], exports: (string|string[])}>} [cfg.shim]
2919
+ * Defines additional metadata for modules for which the normal behavior of the AMD APIs is
2920
+ * not sufficient.
2921
+ *
2922
+ * A typical example are scripts that don't use <code>define</code> or <code>sap.ui.define</code>,
2923
+ * but export to a global name. With the <code>exports</code> property, one or more export
2924
+ * names can be specified, and the loader can retrieve the exported value after executing the
2925
+ * corresponding module. If such a module has dependencies, they can be specified in the
2926
+ * <code>deps</code> array and are loaded and executed before executing the module.
2927
+ *
2928
+ * <b>Note:</b> The ui5loader does not support the <code>init</code> option described by the
2929
+ * "Common Config" section of the AMD spec.
2930
+ *
2931
+ * @returns {undefined}
2932
+ * @public
2933
+ * @name require_config
2934
+ * @function
2935
+ */
2936
+ amdRequire.config = amdConfig;
2937
+
2938
+ /**
2939
+ * Defines a JavaScript module with its ID, its dependencies and a module export value or factory.
2940
+ *
2941
+ * The typical and only suggested usage of this method is to have one single, top level call to
2942
+ * <code>sap.ui.define</code> in one JavaScript resource (file). When a module is requested by its
2943
+ * module ID for the first time, the corresponding resource is determined from the ID and the current
2944
+ * {@link sap.ui.loader.config configuration}. The resource will be loaded and executed
2945
+ * which in turn will execute the top level <code>sap.ui.define</code> call.
2946
+ *
2947
+ * If the module ID was omitted from that call, it will be substituted by the ID that was used to
2948
+ * request the module. As a preparation step, the dependencies as well as their transitive dependencies,
2949
+ * will be loaded. Then, the module value (its export) will be determined: if a static value (object, literal)
2950
+ * was given as <code>vFactory</code>, that value will be the module value. If a function was given, that
2951
+ * function will be called (providing the module exports of the declared dependencies as parameters
2952
+ * to the function) and its return value will be used as module export value. The framework internally
2953
+ * associates the resulting value with the module ID and provides it to the original requester of the module.
2954
+ * Whenever the module is requested again, the same export value will be returned (modules are executed only once).
2955
+ *
2956
+ * <i>Example:</i><br>
2957
+ * The following example defines a module, but doesn't hard code the module ID.
2958
+ * If stored in a file 'sap/mylib/SomeClass.js', it can be requested with the ID 'sap/mylib/SomeClass'.
2959
+ * <pre>
2960
+ * sap.ui.define(['./Helper', 'sap/m/Bar'], function(Helper,Bar) {
2961
+ *
2962
+ * // create a new class
2963
+ * var SomeClass = function() {};
2964
+ *
2965
+ * // add methods to its prototype
2966
+ * SomeClass.prototype.foo = function() {
2967
+ *
2968
+ * // use a function from the dependency 'Helper' in the same package (e.g. 'sap/mylib/Helper' )
2969
+ * var mSettings = Helper.foo();
2970
+ *
2971
+ * // create and return an sap.m.Bar (using its local name 'Bar')
2972
+ * return new Bar(mSettings);
2973
+ *
2974
+ * }
2975
+ *
2976
+ * // return the class as module value
2977
+ * return SomeClass;
2978
+ *
2979
+ * });
2980
+ * </pre>
2981
+ *
2982
+ * In another module or in an application HTML page, the {@link sap.ui.require} API can be used
2983
+ * to load the sap/mylib/Something module and to work with it:
2984
+ *
2985
+ * <pre>
2986
+ * sap.ui.require(['sap/mylib/Something'], function(Something) {
2987
+ *
2988
+ * // instantiate a Something and call foo() on it
2989
+ * new Something().foo();
2990
+ *
2991
+ * });
2992
+ * </pre>
2993
+ *
2994
+ *
2995
+ * <h3>Module Name Syntax</h3>
2996
+ *
2997
+ * <code>sap.ui.define</code> uses a simplified variant of the {@link jQuery.sap.getResourcePath
2998
+ * unified resource name} syntax for the module's own name as well as for its dependencies.
2999
+ * The only difference to that syntax is, that for <code>sap.ui.define</code> and
3000
+ * <code>sap.ui.require</code>, the extension (which always would be '.js') has to be omitted.
3001
+ * Both methods always add this extension internally.
3002
+ *
3003
+ * As a convenience, the name of a dependency can start with the segment './' which will be
3004
+ * replaced by the name of the package that contains the currently defined module (relative name).
3005
+ *
3006
+ * It is best practice to omit the name of the defined module (first parameter) and to use
3007
+ * relative names for the dependencies whenever possible. This reduces the necessary configuration,
3008
+ * simplifies renaming of packages and allows to map them to a different namespace.
3009
+ *
3010
+ *
3011
+ * <h3>Dependency to Modules</h3>
3012
+ *
3013
+ * If a dependencies array is given, each entry represents the name of another module that
3014
+ * the currently defined module depends on. All dependency modules are loaded before the export
3015
+ * of the currently defined module is determined. The module export of each dependency module
3016
+ * will be provided as a parameter to a factory function, the order of the parameters will match
3017
+ * the order of the modules in the dependencies array.
3018
+ *
3019
+ * <b>Note:</b> The order in which the dependency modules are <i>executed</i> is <b>not</b>
3020
+ * defined by the order in the dependencies array! The execution order is affected by dependencies
3021
+ * <i>between</i> the dependency modules as well as by their current state (whether a module
3022
+ * already has been loaded or not). Neither module implementations nor dependents that require
3023
+ * a module set must make any assumption about the execution order (other than expressed by
3024
+ * their dependencies).
3025
+ *
3026
+ * <b>Note:</b> A static module export (a literal provided to <code>sap.ui.define</code>) cannot
3027
+ * depend on the module exports of the dependency modules as it has to be calculated before
3028
+ * the dependencies are resolved. As an alternative, modules can define a factory function,
3029
+ * calculate a static export value in that function, potentially based on the dependencies, and
3030
+ * return the result as module export value. The same approach must be taken when the module
3031
+ * export is supposed to be a function.
3032
+ *
3033
+ *
3034
+ * <h3>Asynchronous Contract</h3>
3035
+ *
3036
+ * <code>sap.ui.define</code> is designed to support real Asynchronous Module Definitions (AMD)
3037
+ * in future, although it internally still might use synchronous module loading, depending on
3038
+ * configuration and context. However, callers of <code>sap.ui.define</code> must never rely on
3039
+ * any synchronous behavior that they might observe in a specific test scenario.
3040
+ *
3041
+ * For example, callers of <code>sap.ui.define</code> must not use the module export value
3042
+ * immediately after invoking <code>sap.ui.define</code>:
3043
+ *
3044
+ * <pre>
3045
+ * // COUNTER EXAMPLE HOW __NOT__ TO DO IT
3046
+ *
3047
+ * // define a class Something as AMD module
3048
+ * sap.ui.define('Something', [], function() {
3049
+ * var Something = function() {};
3050
+ * return Something;
3051
+ * });
3052
+ *
3053
+ * // DON'T DO THAT!
3054
+ * // accessing the class _synchronously_ after sap.ui.define was called
3055
+ * new Something();
3056
+ *
3057
+ * </pre>
3058
+ *
3059
+ * Applications that need to ensure synchronous module definition or synchronous loading of dependencies
3060
+ * <b>MUST</b> use the deprecated legacy APIs {@link jQuery.sap.declare} and {@link jQuery.sap.require}.
3061
+ *
3062
+ *
3063
+ * <h3>(No) Global References</h3>
3064
+ *
3065
+ * To be in line with AMD best practices, modules defined with <code>sap.ui.define</code>
3066
+ * should not make any use of global variables if those variables are also available as module
3067
+ * exports. Instead, they should add dependencies to those modules and use the corresponding parameter
3068
+ * of the factory function to access the module exports.
3069
+ *
3070
+ * As the current programming model and the documentation of UI5 heavily rely on global names,
3071
+ * there will be a transition phase where UI5 enables AMD modules and local references to module
3072
+ * exports in parallel to the old global names. The fourth parameter of <code>sap.ui.define</code>
3073
+ * has been added to support that transition phase. When this parameter is set to true, the framework
3074
+ * provides two additional features
3075
+ *
3076
+ * <ol>
3077
+ * <li>Before the factory function is called, the existence of the global parent namespace for
3078
+ * the current module is ensured</li>
3079
+ * <li>The module export returned by the module's factory function will be automatically exported
3080
+ * under the global name which is derived from the ID of the module</li>
3081
+ * </ol>
3082
+ *
3083
+ * The parameter lets the framework know whether any of those two operations is needed or not.
3084
+ * In future versions of UI5, a central configuration option is planned to suppress those 'exports'.
3085
+ *
3086
+ *
3087
+ * <h3>Third Party Modules</h3>
3088
+ * Although third party modules don't use UI5 APIs, they still can be listed as dependencies in
3089
+ * a <code>sap.ui.define</code> call. They will be requested and executed like UI5 modules, but to
3090
+ * make their exports available, so called <em>shims</em> have to be defined.
3091
+ *
3092
+ * Note that UI5 temporarily deactivates an existing AMD loader while it executes third party modules
3093
+ * known to support AMD. This sounds contradictorily at a first glance as UI5 wants to support AMD,
3094
+ * but for now it is necessary to fully support UI5 applications that rely on global names for such modules.
3095
+ *
3096
+ * For third-party modules that UI5 delivers (e.g. those in namespace <code>sap/ui/thirdparty/</code>),
3097
+ * the necessary shims are defined by UI5 itself by executing the private module <code>ui5loader-autoconfig.js</code>
3098
+ * during bootstrap.
3099
+ *
3100
+ * Example:
3101
+ * <pre>
3102
+ * // module 'Something' wants to use third party library 'URI.js'
3103
+ * // It is packaged by UI5 as non-UI5-module 'sap/ui/thirdparty/URI'
3104
+ * // the following shim helps UI5 to correctly load URI.js and to retrieve the module's export value
3105
+ * // Apps don't have to define that shim, it is already applied by ui5loader-autconfig.js
3106
+ * sap.ui.loader.config({
3107
+ * shim: {
3108
+ * 'sap/ui/thirdparty/URI': {
3109
+ * amd: true, // URI.js reacts on an AMD loader, this flag lets UI5 temp. disable such loaders
3110
+ * exports: 'URI' // name of the global variable under which URI.js exports its module value
3111
+ * }
3112
+ * }
3113
+ * });
3114
+ *
3115
+ * // now the module can be retrieved like other modules
3116
+ * sap.ui.define('Something', ['sap/ui/thirdparty/URI'], function(URIModuleValue) {
3117
+ *
3118
+ * new URIModuleValue(...); // same as the global 'URI' name: new URI(...)
3119
+ *
3120
+ * ...
3121
+ * });
3122
+ * </pre>
3123
+ *
3124
+ *
3125
+ * <h3>Differences to Standard AMD</h3>
3126
+ *
3127
+ * The current implementation of <code>sap.ui.define</code> differs from the AMD specification
3128
+ * (https://github.com/amdjs/amdjs-api) or from concrete AMD loaders like <code>requireJS</code>
3129
+ * in several aspects:
3130
+ * <ul>
3131
+ * <li>The name <code>sap.ui.define</code> is different from the plain <code>define</code>.
3132
+ * This has two reasons: first, it avoids the impression that <code>sap.ui.define</code> is
3133
+ * an exact implementation of an AMD loader. And second, it allows the coexistence of an AMD
3134
+ * loader (e.g. requireJS) and <code>sap.ui.define</code> in one application as long as UI5 or
3135
+ * applications using UI5 are not fully prepared to run with an AMD loader.
3136
+ * Note that the difference of the API names also implies that the UI5 loader can't be used
3137
+ * to load 'real' AMD modules as they expect methods <code>define</code> and <code>require</code>
3138
+ * to be available. Modules that use Unified Module Definition (UMD) syntax, can be loaded,
3139
+ * but only when no AMD loader is present or when they expose their export also to the global
3140
+ * namespace, even when an AMD loader is present (as e.g. jQuery does) or when a shim is
3141
+ * defined for them using the <code>amd:true</code> flag (see example above)</li>
3142
+ * <li>Depending on configuration and the current context, <code>sap.ui.define</code> loads
3143
+ * the dependencies of a module either synchronously using a sync XHR call + eval or asynchronously
3144
+ * via script tags. The sync loading is basically a tribute to the synchronous history of UI5.
3145
+ * There's no way for a module developer to enforce synchronous loading of the dependencies and
3146
+ * on the long run, sync loading will be faded out.
3147
+ * Applications that need to ensure synchronous loading of dependencies <b>MUST</b> use the
3148
+ * deprecated legacy APIs like {@link jQuery.sap.require}.</li>
3149
+ * <li><code>sap.ui.define</code> does not support plugins to use other file types, formats or
3150
+ * protocols. It is not planned to support this in future</li>
3151
+ * <li><code>sap.ui.define</code> does not support absolute URLs as module names (dependencies)
3152
+ * nor does it allow module names that start with a slash. To refer to a module at an absolute
3153
+ * URL, a resource root can be registered that points to that URL (or to a prefix of it).</li>
3154
+ * <li><code>sap.ui.define</code> does <b>not</b> support the 'sugar' of requireJS where CommonJS
3155
+ * style dependency declarations using <code>sap.ui.require("something")</code> are automagically
3156
+ * converted into <code>sap.ui.define</code> dependencies before executing the factory function.</li>
3157
+ * </ul>
3158
+ *
3159
+ *
3160
+ * <h3>Restrictions, Design Considerations</h3>
3161
+ * <ul>
3162
+ * <li><b>Restriction</b>: as dependency management is not supported for Non-UI5 modules, the only way
3163
+ * to ensure proper execution order for such modules currently is to rely on the order in the
3164
+ * dependency array. Obviously, this only works as long as <code>sap.ui.define</code> uses
3165
+ * synchronous loading. It will be enhanced when asynchronous loading is implemented.</li>
3166
+ * <li>It was discussed to enforce asynchronous execution of the module factory function (e.g. with a
3167
+ * timeout of 0). But this would have invalidated the current migration scenario where a
3168
+ * sync <code>jQuery.sap.require</code> call can load a <code>sap.ui.define</code>'ed module.
3169
+ * If the module definition would not execute synchronously, the synchronous contract of the
3170
+ * require call would be broken (default behavior in existing UI5 applications)</li>
3171
+ * <li>A single file must not contain multiple calls to <code>sap.ui.define</code>. Multiple calls
3172
+ * currently are only supported in the so called 'preload' files that the UI5 merge tooling produces.
3173
+ * The exact details of how this works might be changed in future implementations and are not
3174
+ * part of the API contract</li>
3175
+ * </ul>
3176
+ * @param {string} [sModuleName] ID of the module in simplified resource name syntax.
3177
+ * When omitted, the loader determines the ID from the request.
3178
+ * @param {string[]} [aDependencies] List of dependencies of the module
3179
+ * @param {function(...any):any|any} vFactory The module export value or a function that calculates that value
3180
+ * @param {boolean} [bExport] Whether an export to global names is required - should be used by SAP-owned code only
3181
+ * @since 1.27.0
3182
+ * @public
3183
+ * @see https://github.com/amdjs/amdjs-api
3184
+ * @function
3185
+ * @ui5-global-only
3186
+ */
3187
+ sap.ui.define = ui5Define;
3188
+
3189
+ /**
3190
+ * @private
3191
+ * @ui5-restricted bundles created with UI5 tooling
3192
+ * @function
3193
+ * @ui5-global-only
3194
+ */
3195
+ sap.ui.predefine = predefine;
3196
+
3197
+ /**
3198
+ * Resolves one or more module dependencies.
3199
+ *
3200
+ * <h3>Synchronous Retrieval of a Single Module Export Value (Probing)</h3>
3201
+ *
3202
+ * When called with a single string, that string is assumed to be the ID of an already loaded
3203
+ * module and the export of that module is returned. If the module has not been loaded yet,
3204
+ * or if it is a Non-UI5 module (e.g. third-party module) without a shim, <code>undefined</code>
3205
+ * is returned.
3206
+ *
3207
+ * This signature variant allows synchronous access to module exports without initiating module loading.
3208
+ *
3209
+ * Sample:
3210
+ * <pre>
3211
+ * var JSONModel = sap.ui.require("sap/ui/model/json/JSONModel");
3212
+ * </pre>
3213
+ *
3214
+ * For modules that are known to be UI5 modules, this signature variant can be used to check whether
3215
+ * the module has been loaded.
3216
+ *
3217
+ *
3218
+ * <h3>Asynchronous Loading of Multiple Modules</h3>
3219
+ *
3220
+ * If an array of strings is given and (optionally) a callback function, then the strings
3221
+ * are interpreted as module IDs and the corresponding modules (and their transitive
3222
+ * dependencies) are loaded. Then the callback function will be called asynchronously.
3223
+ * The module exports of the specified modules will be provided as parameters to the callback
3224
+ * function in the same order in which they appeared in the dependencies array.
3225
+ *
3226
+ * The return value for the asynchronous use case is <code>undefined</code>.
3227
+ *
3228
+ * <pre>
3229
+ * sap.ui.require(['sap/ui/model/json/JSONModel', 'sap/ui/core/UIComponent'], function(JSONModel,UIComponent) {
3230
+ *
3231
+ * var MyComponent = UIComponent.extend('MyComponent', {
3232
+ * ...
3233
+ * });
3234
+ * ...
3235
+ *
3236
+ * });
3237
+ * </pre>
3238
+ *
3239
+ * This method uses the same variation of the {@link jQuery.sap.getResourcePath unified resource name}
3240
+ * syntax that {@link sap.ui.define} uses: module names are specified without the implicit extension '.js'.
3241
+ * Relative module names are not supported.
3242
+ *
3243
+ * @param {string|string[]} vDependencies Dependency (dependencies) to resolve
3244
+ * @param {function(...any)} [fnCallback] Callback function to execute after resolving an array of dependencies
3245
+ * @param {function(Error)} [fnErrback] Callback function to execute if an error was detected while loading the
3246
+ * dependencies or executing the factory function. Note that due to browser restrictions
3247
+ * not all errors will be reported via this callback. In general, module loading is
3248
+ * designed for the non-error case. Error handling is not complete.
3249
+ * @returns {any|undefined} A single module export value (sync probing variant) or <code>undefined</code> (async loading variant)
3250
+ * @public
3251
+ * @function
3252
+ * @ui5-global-only
3253
+ */
3254
+ sap.ui.require = ui5Require;
3255
+
3256
+ /**
3257
+ * Calculates a URL from the provided resource name.
3258
+ *
3259
+ * The calculation takes any configured ID mappings or resource paths into account
3260
+ * (see {@link sap.ui.loader.config config options map and paths}. It also supports relative
3261
+ * segments such as <code>./</code> and <code>../</code> within the path, but not at its beginning.
3262
+ * If relative navigation would cross the root namespace (e.g. <code>sap.ui.require.toUrl("../")</code>)
3263
+ * or when the resource name starts with a slash or with a relative segment, an error is thrown.
3264
+ *
3265
+ * <b>Note:</b> <code>toUrl</code> does not resolve the returned URL; whether it is an absolute
3266
+ * URL or a relative URL depends on the configured <code>baseUrl</code> and <code>paths</code>.
3267
+ *
3268
+ * @example
3269
+ * sap.ui.loader.config({
3270
+ * baseUrl: "/home"
3271
+ * });
3272
+ *
3273
+ * sap.ui.require.toUrl("app/data") === "/home/app/data"
3274
+ * sap.ui.require.toUrl("app/data.json") === "/home/app/data.json"
3275
+ * sap.ui.require.toUrl("app/data/") === "/home/app/data/"
3276
+ * sap.ui.require.toUrl("app/.config") === "/home/app/.config"
3277
+ * sap.ui.require.toUrl("app/test/../data.json") === "/home/data.json"
3278
+ * sap.ui.require.toUrl("app/test/./data.json") === "/home/test/data.json"
3279
+ * sap.ui.require.toUrl("app/../../data") throws Error because root namespace is left
3280
+ * sap.ui.require.toUrl("/app") throws Error because first character is a slash
3281
+ *
3282
+ * @param {string} sName Name of a resource e.g. <code>'app/data.json'</code>
3283
+ * @returns {string} Path to the resource, e.g. <code>'/home/app/data.json'</code>
3284
+ * @see https://github.com/amdjs/amdjs-api/wiki/require#requiretourlstring-
3285
+ * @throws {Error} If the input name is absolute (starts with a slash character <code>'/'</code>),
3286
+ * starts with a relative segment or if resolving relative segments would cross the root
3287
+ * namespace
3288
+ * @public
3289
+ * @name sap.ui.require.toUrl
3290
+ * @function
3291
+ * @ui5-global-only
3292
+ */
3293
+
3294
+ /**
3295
+ * Load a single module synchronously and return its module value.
3296
+ *
3297
+ * Basically, this method is a combination of {@link jQuery.sap.require} and {@link sap.ui.require}.
3298
+ * Its main purpose is to simplify the migration of modules to AMD style in those cases where some dependencies
3299
+ * have to be loaded late (lazy) and synchronously.
3300
+ *
3301
+ * The method accepts a single module name in the same syntax that {@link sap.ui.define} and {@link sap.ui.require}
3302
+ * already use (a simplified variation of the {@link jQuery.sap.getResourcePath unified resource name}:
3303
+ * slash separated names without the implicit extension '.js'). As for <code>sap.ui.require</code>,
3304
+ * relative names (using <code>./</code> or <code>../</code>) are not supported.
3305
+ * If not loaded yet, the named module will be loaded synchronously and the export value of the module will be returned.
3306
+ * While a module is executing, a value of <code>undefined</code> will be returned in case it is required again during
3307
+ * that period of time (e.g. in case of cyclic dependencies).
3308
+ *
3309
+ * <b>Note:</b> the scope of this method is limited to the sap.ui.core library. Callers are strongly encouraged to use
3310
+ * this method only when synchronous loading is unavoidable. Any code that uses this method won't benefit from future
3311
+ * performance improvements that require asynchronous module loading (e.g. HTTP/2). And such code never can comply with
3312
+ * a content security policies (CSP) that forbids 'eval'.
3313
+ *
3314
+ * @param {string} sModuleName Module name in requireJS syntax
3315
+ * @returns {any} Export value of the loaded module (can be <code>undefined</code>)
3316
+ * @private
3317
+ * @ui5-restricted sap.ui.core
3318
+ * @function
3319
+ * @ui5-global-only
3320
+ */
3321
+ sap.ui.requireSync = requireSync;
3322
+
3323
+ }(globalThis));