Skip to content

Commit 262f7e7

Browse files
authored
fix(middleware-code-coverage): Lazy evaluate exclude patterns (#528)
This prevents the initial evaluation of exclude patterns on middleware initialization, which is not necessary in case the middleware is not used. Calculating exclude patterns requires to read and parse all .library files of the project and its dependencies.
1 parent e680542 commit 262f7e7

File tree

4 files changed

+403
-111
lines changed

4 files changed

+403
-111
lines changed

packages/middleware-code-coverage/lib/middleware.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import {
33
createInstrumentationConfig,
44
shouldInstrumentResource,
55
getLatestSourceMap,
6-
readJsonFile} from "./util.js";
6+
readJsonFile,
7+
getLibraryCoverageExcludePatterns
8+
} from "./util.js";
79
import {createInstrumenter} from "istanbul-lib-instrument";
810
import reportCoverage from "./coverage-reporter.js";
911
import bodyParser from "body-parser";
@@ -33,10 +35,7 @@ import {promisify} from "node:util";
3335
* @returns {Function} Middleware function to use
3436
*/
3537
export default async function({log, middlewareUtil, options={}, resources}) {
36-
const config = await createInstrumentationConfig(
37-
options.configuration,
38-
resources.all
39-
);
38+
const config = await createInstrumentationConfig(options.configuration);
4039
const {
4140
report: reporterConfig,
4241
instrument: instrumenterConfig,
@@ -104,9 +103,22 @@ export default async function({log, middlewareUtil, options={}, resources}) {
104103
)
105104
);
106105

106+
let excludePatterns;
107+
107108
router.use(async (req, res, next) => {
109+
// Lazy initialize exclude patterns
110+
if (excludePatterns === undefined) {
111+
// Custom patterns take precedence over .library defined patterns (also when set to null)
112+
if (generalConfig.excludePatterns !== undefined) {
113+
excludePatterns = generalConfig.excludePatterns;
114+
} else {
115+
// Read patterns from .library files, this should only be done if needed and only once
116+
excludePatterns = await getLibraryCoverageExcludePatterns(resources.all);
117+
}
118+
}
119+
108120
// Skip files which should not be instrumented
109-
if (!shouldInstrumentResource(req, generalConfig)) {
121+
if (!shouldInstrumentResource(req, excludePatterns)) {
110122
next();
111123
return;
112124
}

packages/middleware-code-coverage/lib/util.js

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,15 @@ import {readFile} from "node:fs/promises";
77
*
88
* @public
99
* @param {object} configuration instrumentation configuration
10-
* @param {@ui5/fs/Resource[]} resources
1110
* @returns {Promise<object>} configuration
1211
*/
13-
export async function createInstrumentationConfig(configuration = {}, resources) {
14-
const excludedPatterns = resources ? await excludePatterns(resources) : [];
15-
12+
export async function createInstrumentationConfig(configuration = {}) {
1613
const {instrument, report, ...generalConfig} = configuration;
1714

1815
return {
1916
// General configuration
2017
cwd: "./",
21-
excludePatterns: excludedPatterns,
18+
2219
// General config overwrites
2320
...generalConfig,
2421

@@ -55,17 +52,17 @@ export function getLatestSourceMap(instrumenter) {
5552
*
5653
* @public
5754
* @param {object} request
58-
* @param {object} config
55+
* @param {Array<RegExp|string>} excludePatterns Patterns to exclude file from instrumentation (RegExp or string)
5956
* @returns {boolean}
6057
*/
61-
export function shouldInstrumentResource(request, config) {
58+
export function shouldInstrumentResource(request, excludePatterns) {
6259
return (
6360
request.path &&
6461
request.path.endsWith(".js") && // Only .js file requests
6562
!isFalsyValue(request.query.instrument) && // instrument only flagged files, ignore "falsy" values
66-
!(config && config.excludePatterns || []).some((pattern) => {
63+
!(excludePatterns || []).some((pattern) => {
6764
if (pattern instanceof RegExp) {
68-
// The ones comming from .library files are regular expressions
65+
// The ones coming from .library files are regular expressions
6966
return pattern.test(request.path);
7067
} else {
7168
return request.path.includes(pattern);
@@ -131,13 +128,13 @@ function isFalsyValue(value) {
131128
* Note: We might consider to move this utility into the @ui5/project
132129
*
133130
* @private
134-
* @param {@ui5/fs/Resource[]} resources
131+
* @param {@ui5/fs/AbstractReader} reader
135132
* @returns {Promise<RegExp[]>} exclude patterns
136133
*/
137-
async function excludePatterns(resources) {
134+
export async function getLibraryCoverageExcludePatterns(reader) {
138135
const aExcludes = [];
139136
// Read excludes from .library files
140-
const aDotLibrary = await resources.byGlob(["/resources/**/.library"]);
137+
const aDotLibrary = await reader.byGlob(["/resources/**/.library"]);
141138
for (const oDotLibrary of aDotLibrary) {
142139
const content = await oDotLibrary.getString();
143140
const result = await xml2js.parseStringPromise(content);

0 commit comments

Comments
 (0)