• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SAP / karma-ui5 / 10095551812

25 Jul 2024 02:01PM UTC coverage: 55.823%. Remained the same
10095551812

Pull #693

github

web-flow
Merge f3606e089 into 36addfd45
Pull Request #693: [DEPENDENCY] Bump UI5 Tooling dependencies

197 of 350 branches covered (56.29%)

Branch coverage included in aggregate %.

359 of 646 relevant lines covered (55.57%)

10.32 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.84
/lib/framework.js
1
import {parse as parseUrl} from "node:url";
2
import http from "node:http";
3
import https from "node:https";
4
import httpProxy from "http-proxy";
5
import {statSync, readFileSync} from "node:fs";
6
import path from "node:path";
7
import {fileURLToPath} from "node:url";
8
import yaml from "js-yaml";
9
import {Router} from "express";
10
import {ErrorMessage} from "./errors.js";
11

12
const __dirname = path.dirname(fileURLToPath(import.meta.url));
62✔
13

14
export default class Framework {
15
        constructor() {
16
                this.config = {};
70✔
17
        }
18

19
        createPluginFilesPattern(pattern) {
20
                return {pattern, included: true, served: true, watched: false};
52✔
21
        }
22

23
        createProjectFilesPattern(pattern) {
24
                return {pattern, included: false, served: true, watched: true};
49✔
25
        }
26

27
        /**
28
         * Checks if a list of paths exists
29
         *
30
         * @private
31
         * @param {Array} paths List of paths to check
32
         *
33
         * @returns {boolean[]} array if path exist
34
         */
35
        pathsExist(paths) {
36
                return paths.map((folderName) => this.exists(path.join(this.config.basePath, folderName)));
107✔
37
        }
38

39
        /**
40
         * Checks if a file or path exists
41
         *
42
         * @private
43
         * @param {string} filePath Path to check
44
         * @returns {boolean} true if the file or path exists
45
         */
46
        exists(filePath) {
47
                try {
15✔
48
                        return statSync(filePath).isDirectory();
15✔
49
                } catch (err) {
50
                        // "File or directory does not exist"
51
                        if (err.code === "ENOENT") {
12!
52
                                return false;
12✔
53
                        } else {
54
                                throw err;
×
55
                        }
56
                }
57
        }
58

59
        /**
60
         * Mutates config and auto set type if not defined
61
         */
62
        detectTypeFromFolder() {
63
                const webappFolder = this.config.ui5.paths.webapp;
31✔
64
                const srcFolder = this.config.ui5.paths.src;
31✔
65
                const testFolder = this.config.ui5.paths.test;
31✔
66
                const [hasWebapp, hasSrc, hasTest] = this.pathsExist([webappFolder, srcFolder, testFolder]);
31✔
67
                if (hasWebapp) return "application";
31✔
68
                if (hasSrc && hasTest) return "library";
4!
69
        }
70

71
        replaceLast(path, replacement) {
72
                return path.split("/").slice(0, -1).concat(replacement).join("/");
45✔
73
        }
74

75
        checkLegacy(config) {
76
                if (config.openui5 || config.client.openui5) {
68✔
77
                        this.logger.log("error", ErrorMessage.migrateConfig());
1✔
78
                        throw new Error(ErrorMessage.failure());
1✔
79
                }
80
        }
81

82
        initScriptMode(config) {
83
                let url;
84
                if (config.ui5.url) {
5✔
85
                        url = config.ui5.url + "/resources/sap-ui-core.js";
2✔
86
                } else {
87
                        // Uses middleware if no url has been specified
88
                        // Need to use an absolute URL as the file doesn't exist physically but will be
89
                        // resolved via our middleware
90
                        url = `${config.protocol}//${config.hostname}:${config.port}/base/`;
3✔
91
                        if (config.ui5.type === "application") {
3✔
92
                                url += `${config.ui5.paths.webapp}/resources/sap-ui-core.js`;
2✔
93
                        } else if (config.ui5.type === "library") {
1!
94
                                url += `${this.replaceLast(config.ui5.paths.src, "resources")}/sap-ui-core.js`;
1✔
95
                        }
96
                }
97
                config.client.ui5.config = config.ui5.config;
5✔
98
                config.client.ui5.tests = config.ui5.tests;
5✔
99
                if (config.ui5.tests) {
5✔
100
                        config.files.unshift(this.createPluginFilesPattern(`${__dirname}/client/autorun.js`));
1✔
101
                }
102
                config.files.unshift(this.createPluginFilesPattern(url));
5✔
103
                config.files.unshift(this.createPluginFilesPattern(`${__dirname}/client/sap-ui-config.js`));
5✔
104
        }
105

106
        async init({config, logger}) {
107
                this.config = config;
68✔
108
                this.logger = logger.create("ui5.framework");
68✔
109
                this.config.basePath = config.basePath || "";
68✔
110
                this.config.client = config.client || {};
68✔
111
                this.config.client.clearContext = false;
68✔
112
                // Always override client ui5 config. It should not be used by consumers.
113
                // Relevant options (e.g. testpage, config, tests) will be written to the client section.
114
                this.config.client.ui5 = {};
68✔
115
                this.config.client.ui5.useIframe = true; // for now only allow using iframes in HTML mode
68✔
116
                this.config.ui5 = config.ui5 || {};
68✔
117
                this.config.middleware = config.middleware || [];
68✔
118
                this.config.files = config.files || [];
68✔
119
                this.config.beforeMiddleware = config.beforeMiddleware || [];
68✔
120
                this.config.reporters = this.config.reporters || [];
68✔
121

122
                if (!this.config.ui5.mode) {
68✔
123
                        this.config.ui5.mode = "html";
60✔
124
                }
125
                if (typeof this.config.ui5.failOnEmptyTestPage === "undefined") {
68✔
126
                        // TODO 3.0: Enable by default
127
                        this.config.ui5.failOnEmptyTestPage = false;
63✔
128
                }
129

130
                this.checkLegacy(config);
68✔
131

132
                if (this.config.ui5.mode && ["script", "html"].indexOf(this.config.ui5.mode) === -1) {
67✔
133
                        this.logger.log("error", ErrorMessage.invalidMode(this.config.ui5.mode));
1✔
134
                        throw new Error(ErrorMessage.failure());
1✔
135
                }
136

137
                const incompatibleFrameworks = ["qunit", "sinon"];
66✔
138
                const hasIncompatibleFrameworks =
139
                        (frameworks) => frameworks.some((fwk) => incompatibleFrameworks.includes(fwk));
66✔
140
                if (this.config.ui5.mode === "html" && hasIncompatibleFrameworks(this.config.frameworks || [])) {
66✔
141
                        this.logger.log("error", ErrorMessage.incompatibleFrameworks(this.config.frameworks) );
2✔
142
                        throw new Error(ErrorMessage.failure());
2✔
143
                }
144

145
                if (this.config.ui5.mode === "html" && this.config.files.length > 0) {
64✔
146
                        this.logger.log("error", ErrorMessage.containsFilesDefinition() );
1✔
147
                        throw new Error(ErrorMessage.failure());
1✔
148
                }
149

150
                if (this.config.ui5.paths && !this.config.ui5.type) {
63✔
151
                        this.logger.log("error", ErrorMessage.customPathWithoutType() );
1✔
152
                        throw new Error(ErrorMessage.failure());
1✔
153
                }
154

155
                if (this.config.ui5.mode !== "html" && this.config.ui5.urlParameters) {
62✔
156
                        this.logger.log("error", ErrorMessage.urlParametersConfigInNonHtmlMode(this.config.ui5.mode,
1✔
157
                                this.config.ui5.urlParameters));
158
                        throw new Error(ErrorMessage.failure());
1✔
159
                }
160

161
                if (this.config.ui5.urlParameters !== undefined && !Array.isArray(this.config.ui5.urlParameters)) {
61✔
162
                        this.logger.log("error", ErrorMessage.urlParametersNotAnArray(this.config.ui5.urlParameters));
1✔
163
                        throw new Error(ErrorMessage.failure());
1✔
164
                }
165

166
                if (this.config.ui5.urlParameters) {
60✔
167
                        this.config.ui5.urlParameters.forEach((urlParameter) => {
3✔
168
                                if (typeof urlParameter !== "object") {
6✔
169
                                        this.logger.log("error", ErrorMessage.urlParameterNotObject(urlParameter));
1✔
170
                                        throw new Error(ErrorMessage.failure());
1✔
171
                                }
172
                                if (urlParameter.key === undefined || urlParameter.value === undefined) {
5✔
173
                                        this.logger.log("error", ErrorMessage.urlParameterMissingKeyOrValue(urlParameter));
1✔
174
                                        throw new Error(ErrorMessage.failure());
1✔
175
                                }
176
                        });
177
                }
178

179
                if (this.config.ui5.urlParameters !== undefined && !Array.isArray(this.config.ui5.urlParameters)) {
58!
180
                        this.logger.log("error", ErrorMessage.urlParametersNotAnArray(this.config.ui5.urlParameters));
×
181
                        throw new Error(ErrorMessage.failure());
×
182
                }
183

184
                if (typeof this.config.ui5.failOnEmptyTestPage !== "boolean") {
58✔
185
                        this.logger.log(
2✔
186
                                "error",
187
                                ErrorMessage.failOnEmptyTestPageNotTypeBoolean(this.config.ui5.failOnEmptyTestPage)
188
                        );
189
                        throw new Error(ErrorMessage.failure());
2✔
190
                }
191
                if (this.config.ui5.mode !== "html" && this.config.ui5.failOnEmptyTestPage === true) {
56✔
192
                        this.logger.log("error", ErrorMessage.failOnEmptyTestPageInNonHtmlMode(this.config.ui5.mode));
1✔
193
                        throw new Error(ErrorMessage.failure());
1✔
194
                }
195

196
                if (this.config.reporters.includes("ui5--fileExport")) {
55✔
197
                        this.logger.log("error", ErrorMessage.invalidFileExportReporterUsage());
1✔
198
                        throw new Error(ErrorMessage.failure());
1✔
199
                }
200
                if (this.config.ui5.fileExport === true || typeof this.config.ui5.fileExport === "object") {
54✔
201
                        this.config.reporters.push("ui5--fileExport");
2✔
202
                        if (this.config.ui5.fileExport === true) {
2✔
203
                                this.config.ui5.fileExport = {};
1✔
204
                        }
205
                }
206

207
                this.config.ui5.paths = this.config.ui5.paths || {
54✔
208
                        webapp: "webapp",
209
                        src: "src",
210
                        test: "test"
211
                };
212

213
                ["webapp", "src", "test"].forEach((pathName) => {
54✔
214
                        let pathValue = this.config.ui5.paths[pathName];
158✔
215
                        if (!pathValue) {
158✔
216
                                return;
12✔
217
                        }
218

219
                        let absolutePathValue;
220
                        const absoluteBasePath = path.resolve(this.config.basePath);
146✔
221

222
                        // Make sure paths are relative to the basePath
223
                        if (path.isAbsolute(pathValue)) {
146✔
224
                                absolutePathValue = pathValue;
4✔
225
                                pathValue = path.relative(this.config.basePath, pathValue);
4✔
226
                        } else {
227
                                absolutePathValue = path.resolve(this.config.basePath, pathValue);
142✔
228
                        }
229

230
                        // Paths must be within basePath
231
                        if (!absolutePathValue.startsWith(absoluteBasePath)) {
146✔
232
                                this.logger.log("error", ErrorMessage.pathNotWithinBasePath({
2✔
233
                                        pathName,
234
                                        pathValue: this.config.ui5.paths[pathName], // use value given in config here
235
                                        absolutePathValue,
236
                                        basePath: absoluteBasePath
237
                                }));
238
                                throw new Error(ErrorMessage.failure());
2✔
239
                        }
240

241
                        this.config.ui5.paths[pathName] = pathValue;
144✔
242
                });
243

244
                this.autoDetectType();
52✔
245

246
                if (this.config.ui5.mode === "script") {
46✔
247
                        this.initScriptMode(config);
5✔
248
                } else {
249
                        // Add browser bundle including third-party dependencies
250
                        this.config.files.unshift(this.createPluginFilesPattern(__dirname + "/../dist/browser-bundle.js"));
41✔
251
                }
252

253
                // Make testpage url available to the client
254
                this.config.client.ui5.testpage = this.config.ui5.testpage;
46✔
255
                // Make failOnEmptyTestPage option available to the client
256
                this.config.client.ui5.failOnEmptyTestPage = this.config.ui5.failOnEmptyTestPage;
46✔
257
                // Pass configured urlParameters to client
258
                this.config.client.ui5.urlParameters = this.config.ui5.urlParameters;
46✔
259
                // Pass fileExport parameter to client
260
                this.config.client.ui5.fileExport = this.config.reporters.includes("ui5--fileExport");
46✔
261

262

263
                if (this.config.ui5.type === "application") {
46✔
264
                        const webappFolder = this.config.ui5.paths.webapp;
38✔
265
                        if (!this.exists(path.join(this.config.basePath, webappFolder))) {
38✔
266
                                this.logger.log("error", ErrorMessage.applicationFolderNotFound(webappFolder));
1✔
267
                                throw new Error(ErrorMessage.failure());
1✔
268
                        }
269

270
                        // Match all files (including dotfiles)
271
                        this.config.files.push(
37✔
272
                                this.createProjectFilesPattern(config.basePath + `/{${webappFolder}/**,${webappFolder}/**/.*}`)
273
                        );
274
                } else if (config.ui5.type === "library") {
8✔
275
                        const srcFolder = this.config.ui5.paths.src;
7✔
276
                        const testFolder = this.config.ui5.paths.test;
7✔
277

278
                        const [hasSrc, hasTest] = this.pathsExist([srcFolder, testFolder]);
7✔
279
                        if (!hasSrc || !hasTest) {
7✔
280
                                this.logger.log("error", ErrorMessage.libraryFolderNotFound({
1✔
281
                                        srcFolder, testFolder, hasSrc, hasTest
282
                                }));
283
                                throw new Error(ErrorMessage.failure());
1✔
284
                        }
285

286
                        this.config.files.push(
6✔
287
                                // Match all files (including dotfiles)
288
                                this.createProjectFilesPattern(`${config.basePath}/{${srcFolder}/**,${srcFolder}/**/.*}`),
289
                                this.createProjectFilesPattern(`${config.basePath}/{${testFolder}/**,${testFolder}/**/.*}`),
290
                        );
291
                } else {
292
                        this.logger.log("error", ErrorMessage.invalidProjectType(config.ui5.type) );
1✔
293
                        throw new Error(ErrorMessage.failure());
1✔
294
                }
295

296
                // this.addPreprocessor();
297
                await this.setupMiddleware();
43✔
298
                return this;
43✔
299
        }
300

301
        autoDetectType() {
302
                if (this.config.ui5.type) {
52✔
303
                        return;
15✔
304
                }
305
                const {ui5: {configPath}, basePath} = this.config;
37✔
306
                const filePath = configPath ?
37✔
307
                        path.resolve(basePath, configPath) : path.join(basePath, "ui5.yaml");
308
                let fileContent;
309
                try {
37✔
310
                        fileContent = readFileSync(filePath);
37✔
311
                } catch (err) {
312
                        if (err.code !== "ENOENT") {
31!
313
                                throw err;
×
314
                        }
315
                }
316

317
                if (fileContent) {
37✔
318
                        let configs;
319
                        try {
6✔
320
                                configs = yaml.loadAll(fileContent, {
6✔
321
                                        filename: filePath
322
                                });
323
                        } catch (err) {
324
                                if (err.name === "YAMLException") {
1!
325
                                        this.logger.log("error", ErrorMessage.invalidUI5Yaml({
1✔
326
                                                filePath, yamlException: err
327
                                        }));
328
                                        throw Error(ErrorMessage.failure());
1✔
329
                                } else {
330
                                        throw err;
×
331
                                }
332
                        }
333

334
                        if (!configs[0] || !configs[0].type) {
5✔
335
                                this.logger.log("error", ErrorMessage.missingTypeInYaml());
1✔
336
                                throw Error(ErrorMessage.failure());
1✔
337
                        }
338

339
                        this.config.ui5.type = configs[0].type;
4✔
340
                } else {
341
                        this.config.ui5.type = this.detectTypeFromFolder();
31✔
342
                }
343
                if (!this.config.ui5.type) {
35✔
344
                        let errorText = "";
4✔
345

346
                        if (this.config.basePath.endsWith("/webapp")) {
4✔
347
                                errorText = ErrorMessage.invalidBasePath();
1✔
348
                        } else {
349
                                errorText = ErrorMessage.invalidFolderStructure();
3✔
350
                        }
351

352
                        this.logger.log("error", errorText);
4✔
353
                        throw new Error(ErrorMessage.failure());
4✔
354
                }
355
        }
356

357
        // Adding coverage preprocessor is currently not supported
358
        // /**
359
        //  * Adds preprocessors dynamically in case if no preprocessors have been defined in the config
360
        //  */
361
        // addPreprocessor() {
362
        //         const type = this.config.ui5.type,
363
        //                 cwd = process.cwd(),
364
        //                 srcFolder = this.config.ui5.paths.src,
365
        //                 webappFolder = this.config.ui5.paths.webapp;
366

367
        //         if (this.config.preprocessors && type && Object.keys(this.config.preprocessors).length === 0) {
368
        //                 if (type === "library") {
369
        //                         this.config.preprocessors[`${cwd}/${srcFolder}/**/*.js`] = ['coverage'];
370
        //                 } else if (type === "application") {
371
        //                         this.config.preprocessors[`${cwd}/{${webappFolder},${webappFolder}/!(test)}/*.js`] = ['coverage'];
372
        //                 }
373
        //         }
374
        // }
375

376
        /**
377
         * Rewrites the given url to use a virtual path that can be resolved
378
         * by the UI5 Tooling middleware or to conform with the UI5 CDN.
379
         *
380
         * Example (application):
381
         * /base/webapp/resources/sap-ui-core.js -> /resources/sap-ui-core.js
382
         *
383
         * Example (library):
384
         * /base/src/resources/sap-ui-core.js -> /resources/sap-ui-core.js
385
         * /base/test/test-resources/sap-ui-core.js -> /test-resources/sap-ui-core.js
386
         *
387
         * @param {string} url
388
         * @returns {string}
389
         */
390
        rewriteUrl(url) {
391
                const type = this.config.ui5.type;
27✔
392
                const webappFolder = this.config.ui5.paths.webapp;
27✔
393
                const srcFolder = this.config.ui5.paths.src;
27✔
394
                const testFolder = this.config.ui5.paths.test;
27✔
395
                if (!type) {
27✔
396
                        // TODO: do we want no type to be allowed?
397
                        return url;
6✔
398
                } else if (type === "application") {
21✔
399
                        const webappPattern = new RegExp(`^/base/${webappFolder}/`);
10✔
400
                        if (webappPattern.test(url)) {
10✔
401
                                return url.replace(webappPattern, "/");
3✔
402
                        }
403
                } else if (type === "library") {
11✔
404
                        const srcPattern = new RegExp(`^/base/${srcFolder}/`);
10✔
405
                        const testPattern = new RegExp(`^/base/${testFolder}/`);
10✔
406
                        // const basePattern = /^\/base\//; // TODO: is this expected?
407
                        if (srcPattern.test(url)) {
10✔
408
                                return url.replace(srcPattern, "/resources/");
1✔
409
                        } else if (testPattern.test(url)) {
9✔
410
                                return url.replace(testPattern, "/test-resources/");
1✔
411
                        } /* else if (basePattern.test(url)) {
412
                                return url.replace(basePattern, "/");
413
                        }*/
414
                } else {
415
                        this.logger.log("error", ErrorMessage.urlRewriteFailed(type));
1✔
416
                        return;
1✔
417
                }
418

419
                return url;
15✔
420
        }
421

422
        /**
423
         * Rewrites the given url from a virtual path (resources / test-resources)
424
         * to a filesystem path so that the request can be handled by the karma
425
         * middleware that serves the project files.
426
         *
427
         * This is only relevant for type "library", as it has two separate folders (src / test).
428
         *
429
         * Example:
430
         * /base/resources/sap-ui-core.js -> /base/src/sap-ui-core.js
431
         * /base/test-resources/sap/ui/test/ -> /base/test/sap/ui/test/
432
         *
433
         * @param {string} url
434
         * @returns {string}
435
         */
436
        rewriteUrlBefore(url) {
437
                const type = this.config.ui5.type;
23✔
438
                if (type !== "library") {
23✔
439
                        // Only rewrite "before" for type library
440
                        return url;
12✔
441
                }
442
                const srcFolder = this.config.ui5.paths.src;
11✔
443
                const testFolder = this.config.ui5.paths.test;
11✔
444
                const resourcesSrcPattern = new RegExp(
11✔
445
                        `/base/${this.replaceLast(srcFolder, "resources")}/`
446
                );
447
                const resourcesTestPattern = new RegExp(
11✔
448
                        `/base/${this.replaceLast(testFolder, "resources")}/`
449
                );
450
                const testResourcesSrcPattern = new RegExp(
11✔
451
                        `/base/${this.replaceLast(srcFolder, "test-resources")}/`
452
                );
453
                const testResourcesTestPattern = new RegExp(
11✔
454
                        `/base/${this.replaceLast(testFolder, "test-resources")}/`
455
                );
456
                if (resourcesSrcPattern.test(url)) {
11✔
457
                        return url.replace(resourcesSrcPattern, `/base/${srcFolder}/`);
2✔
458
                } else if (resourcesTestPattern.test(url)) {
9✔
459
                        return url.replace(resourcesTestPattern, `/base/${srcFolder}/`);
1✔
460
                } else if (testResourcesSrcPattern.test(url)) {
8✔
461
                        return url.replace(testResourcesSrcPattern, `/base/${testFolder}/`);
2✔
462
                } else if (testResourcesTestPattern.test(url)) {
6✔
463
                        return url.replace(testResourcesTestPattern, `/base/${testFolder}/`);
1✔
464
                }
465
                return url;
5✔
466
        }
467

468
        async applyUI5Middleware(router, {basePath, configPath}) {
469
                const graphOptions = {
2✔
470
                        cwd: basePath
471
                };
472
                if (configPath) {
2✔
473
                        graphOptions.rootConfigPath = path.resolve(basePath, configPath);
1✔
474
                }
475

476
                const {graphFromPackageDependencies} = await import("@ui5/project/graph");
2✔
477
                const {createReaderCollection} = await import("@ui5/fs/resourceFactory");
2✔
478
                const ReaderCollectionPrioritized = (await import("@ui5/fs/ReaderCollectionPrioritized")).default;
2✔
479

480
                const graph = await graphFromPackageDependencies(graphOptions);
2✔
481

482
                const rootProject = graph.getRoot();
2✔
483

484
                const readers = [];
2✔
485
                await graph.traverseBreadthFirst(async function({project: dep}) {
2✔
486
                        if (dep.getName() === rootProject.getName()) {
4✔
487
                                // Ignore root project
488
                                return;
2✔
489
                        }
490
                        readers.push(dep.getReader({style: "runtime"}));
2✔
491
                });
492

493
                const dependencies = createReaderCollection({
2✔
494
                        name: `Dependency reader collection for project ${rootProject.getName()}`,
495
                        readers
496
                });
497

498
                const rootReader = rootProject.getReader({style: "runtime"});
2✔
499

500
                const combo = new ReaderCollectionPrioritized({
2✔
501
                        name: "server - prioritize workspace over dependencies",
502
                        readers: [rootReader, dependencies]
503
                });
504
                const resources = {
2✔
505
                        rootProject: rootReader,
506
                        dependencies: dependencies,
507
                        all: combo
508
                };
509

510
                const MiddlewareManager = (await import("@ui5/server/internal/MiddlewareManager")).default;
2✔
511
                const middlewareManager = new MiddlewareManager({
2✔
512
                        graph,
513
                        rootProject,
514
                        resources,
515
                });
516

517
                await middlewareManager.applyMiddleware(router);
2✔
518
        }
519

520
        async setupUI5Server({basePath, configPath}) {
521
                const router = new Router();
33✔
522
                await this.applyUI5Middleware(router, {basePath, configPath});
33✔
523
                return router;
33✔
524
        }
525

526
        setupProxy({url}) {
527
                const {protocol} = parseUrl(url);
9✔
528
                const Agent = protocol === "https:" ? https.Agent : http.Agent;
9✔
529
                const agent = new Agent({keepAlive: true});
9✔
530
                const proxy = httpProxy.createProxyServer({
9✔
531
                        target: url,
532
                        changeOrigin: true,
533
                        agent
534
                });
535
                proxy.on("error", (err, req /* , res*/) => {
9✔
536
                        this.logger.warn(`Failed to proxy ${req.url} (${err.code}: ${err.message})`);
×
537
                });
538
                return (req, res) => proxy.web(req, res);
9✔
539
        }
540

541
        beforeMiddlewareRewriteUrl(req, res, next) {
542
                req.url = this.rewriteUrlBefore(req.url);
1✔
543
                next();
1✔
544
        }
545

546
        middlewareRewriteUrl(req, res, next) {
547
                req.url = this.rewriteUrl(req.url);
1✔
548
                next();
1✔
549
        }
550

551
        async setupMiddleware() {
552
                const config = this.config;
43✔
553

554
                if (config.ui5.type === "library") {
43✔
555
                        config.ui5._beforeMiddleware = new Router();
6✔
556
                        config.ui5._beforeMiddleware.use(this.beforeMiddlewareRewriteUrl.bind(this));
6✔
557
                        config.beforeMiddleware.push("ui5--beforeMiddleware");
6✔
558
                }
559

560
                let middleware;
561
                if (config.ui5.url) {
43✔
562
                        middleware = this.setupProxy(config.ui5);
7✔
563
                } else if (config.ui5.useMiddleware !== false) {
36✔
564
                        middleware = await this.setupUI5Server({
33✔
565
                                basePath: config.basePath,
566
                                configPath: config.ui5.configPath
567
                        });
568
                }
569

570
                if (middleware) {
43✔
571
                        config.ui5._middleware = new Router();
40✔
572
                        config.ui5._middleware.use(this.middlewareRewriteUrl.bind(this));
40✔
573
                        config.ui5._middleware.use(middleware);
40✔
574
                        config.middleware.push("ui5--middleware");
40✔
575
                }
576
        }
577
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc