monocart-coverage-reports 2.12.11 → 2.13.0

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.
@@ -220,18 +220,26 @@ const Util = {
220
220
  return;
221
221
  }
222
222
 
223
- // rangeList should be sorted by startKey, but seems useless here
224
- const list = rangeList.filter((it) => startPos >= it[startKey] && endPos <= it[endKey]);
225
- if (!list.length) {
226
- return;
223
+ // rangeList is sorted by startKey ascending.
224
+ // Binary search for the rightmost range where startKey <= startPos.
225
+ let low = 0;
226
+ let high = rangeList.length;
227
+ while (low < high) {
228
+ const mid = (low + high) >>> 1;
229
+ if (rangeList[mid][startKey] > startPos) {
230
+ high = mid;
231
+ } else {
232
+ low = mid + 1;
233
+ }
227
234
  }
228
235
 
229
- // could be multiple results, but seems no case for now
230
- // if (list.length > 1) {
231
- // console.log('==============', list);
232
- // }
233
-
234
- return list[0];
236
+ // Scan backwards from the insertion point; the first match is the answer.
237
+ for (let i = low - 1; i >= 0; i--) {
238
+ const it = rangeList[i];
239
+ if (endPos <= it[endKey]) {
240
+ return it;
241
+ }
242
+ }
235
243
  },
236
244
 
237
245
  getRangeLines: (sLoc, eLoc) => {
@@ -62,40 +62,7 @@ const getDetailsRows = (files, metrics, cdOptions, color) => {
62
62
  };
63
63
 
64
64
  const getFileFilter = (input) => {
65
- // for function handler
66
- if (typeof input === 'function') {
67
- return input;
68
- }
69
-
70
- // for single minimatch pattern
71
- if (input && typeof input === 'string') {
72
- // string to multiple patterns "{...}"
73
- // mcr npx mocha --entryFilter {'**/node_modules/**':false,'**/src/*.js':true}
74
- // mcr npx mocha --entryFilter "{'**/node_modules/**': false, '**/src/*.js': true}"
75
- const obj = Util.strToObj(input);
76
- if (obj) {
77
- input = obj;
78
- } else {
79
- return (file) => {
80
- return Util.betterMinimatch(file.sourcePath, input);
81
- };
82
- }
83
- }
84
-
85
- // for patterns
86
- if (input && typeof input === 'object') {
87
- const patterns = Object.keys(input);
88
- return (file) => {
89
- const sourcePath = file.sourcePath;
90
- for (const pattern of patterns) {
91
- if (Util.betterMinimatch(sourcePath, pattern)) {
92
- return input[pattern];
93
- }
94
- }
95
- // false if not matched
96
- };
97
- }
98
-
65
+ return Util.createFilterHandler(input, (file) => file.sourcePath);
99
66
  };
100
67
 
101
68
  const getFilteredFiles = (filter, files) => {
package/lib/utils/gc.js CHANGED
@@ -1,9 +1,18 @@
1
- const v8 = require('node:v8');
2
- const vm = require('node:vm');
1
+
2
+ const isBun = typeof Bun !== 'undefined' && Boolean(process.versions.bun);
3
3
 
4
4
  if (typeof global.gc !== 'function') {
5
- v8.setFlagsFromString('--expose_gc');
6
- global.gc = vm.runInNewContext('gc');
5
+
6
+ if (isBun) {
7
+ global.gc = () => {
8
+ Bun.gc(true);
9
+ };
10
+ } else {
11
+ const v8 = require('node:v8');
12
+ const vm = require('node:vm');
13
+ v8.setFlagsFromString('--expose_gc');
14
+ global.gc = vm.runInNewContext('gc');
15
+ }
7
16
  }
8
17
 
9
18
  module.exports = global.gc;
@@ -46,19 +46,15 @@ function fromSortedRanges(ranges) {
46
46
  }
47
47
  let parent;
48
48
  let parentCount;
49
- while (true) {
49
+ while (stack.length > 0) {
50
50
  [parent, parentCount] = stack[stack.length - 1];
51
- // assert: `top !== undefined` (the ranges are sorted)
52
51
  if (range.startOffset < parent.end) {
53
52
  break;
54
- } else {
55
- stack.pop();
56
- }
57
-
58
- // prevent crash when v8 incorrectly merges static_initializer's
59
- if (stack.length === 0) {
60
- break;
61
53
  }
54
+ stack.pop();
55
+ // parent / parentCount still hold the last popped values
56
+ // when v8 incorrectly merges static_initializer's, the stack
57
+ // may become empty; the while condition handles that.
62
58
  }
63
59
  node.delta -= parentCount;
64
60
  parent.children.push(node);
package/lib/utils/util.js CHANGED
@@ -39,6 +39,15 @@ const Util = {
39
39
  markdownGrid,
40
40
  mergeV8Coverage,
41
41
 
42
+ ensureDirSync: function(filePath) {
43
+ const p = path.dirname(filePath);
44
+ if (!fs.existsSync(p)) {
45
+ fs.mkdirSync(p, {
46
+ recursive: true
47
+ });
48
+ }
49
+ },
50
+
42
51
  forceGC: () => {
43
52
  gc();
44
53
  },
@@ -97,9 +106,9 @@ const Util = {
97
106
  }
98
107
  },
99
108
 
100
- calculateSha1: (buffer) => {
109
+ calculateSha1: (input) => {
101
110
  const hash = crypto.createHash('sha1');
102
- hash.update(buffer);
111
+ hash.update(input);
103
112
  return hash.digest('hex');
104
113
  },
105
114
 
@@ -132,6 +141,10 @@ const Util = {
132
141
  },
133
142
 
134
143
  resolveWatermarks: (defaultWatermarks, watermarks) => {
144
+ // clone to avoid mutating the input
145
+ defaultWatermarks = {
146
+ ... defaultWatermarks
147
+ };
135
148
  if (watermarks) {
136
149
  if (Array.isArray(watermarks)) {
137
150
  Object.keys(defaultWatermarks).forEach((k) => {
@@ -204,62 +217,54 @@ const Util = {
204
217
  return false;
205
218
  },
206
219
 
207
- // eslint-disable-next-line complexity
208
- getEntryFilter: (options) => {
209
- // for entry.url
210
-
211
- if (options.entryFilterHandler) {
212
- return options.entryFilterHandler;
213
- }
214
-
215
- let input = options.entryFilter || options.filter;
216
-
220
+ createFilterHandler: function(input, fieldAccessor) {
217
221
  // for function handler
218
222
  if (typeof input === 'function') {
219
- options.entryFilterHandler = input;
220
223
  return input;
221
224
  }
222
225
 
223
226
  // for single minimatch pattern
224
227
  if (input && typeof input === 'string') {
225
- // string to multiple patterns "{...}"
226
- // mcr npx mocha --entryFilter {'**/node_modules/**':false,'**/src/*.js':true}
227
- // mcr npx mocha --entryFilter "{'**/node_modules/**': false, '**/src/*.js': true}"
228
228
  const obj = Util.strToObj(input);
229
229
  if (obj) {
230
230
  input = obj;
231
231
  } else {
232
- const handler = (entry) => {
233
- return Util.betterMinimatch(entry.url, input);
232
+ return (item) => {
233
+ return Util.betterMinimatch(fieldAccessor(item), input);
234
234
  };
235
- options.entryFilterHandler = handler;
236
- return handler;
237
235
  }
238
236
  }
239
237
 
240
238
  // for patterns
241
239
  if (input && typeof input === 'object') {
242
240
  const patterns = Object.keys(input);
243
- const handler = (entry) => {
244
- const url = entry.url;
241
+ return (item) => {
242
+ const value = fieldAccessor(item);
245
243
  for (const pattern of patterns) {
246
- if (Util.betterMinimatch(url, pattern)) {
244
+ if (Util.betterMinimatch(value, pattern)) {
247
245
  return input[pattern];
248
246
  }
249
247
  }
250
- // false if not matched
251
248
  };
252
- options.entryFilterHandler = handler;
253
- return handler;
254
249
  }
255
250
 
256
251
  // default
257
- const handler = () => true;
252
+ return () => true;
253
+ },
254
+
255
+ getEntryFilter: (options) => {
256
+ // for entry.url
257
+
258
+ if (options.entryFilterHandler) {
259
+ return options.entryFilterHandler;
260
+ }
261
+
262
+ const input = options.entryFilter || options.filter;
263
+ const handler = Util.createFilterHandler(input, (entry) => entry.url);
258
264
  options.entryFilterHandler = handler;
259
265
  return handler;
260
266
  },
261
267
 
262
- // eslint-disable-next-line complexity
263
268
  getSourceFilter: (options) => {
264
269
  // for sourcePath
265
270
 
@@ -267,48 +272,8 @@ const Util = {
267
272
  return options.sourceFilterHandler;
268
273
  }
269
274
 
270
- let input = options.sourceFilter || options.filter;
271
-
272
- // for function handler
273
- if (typeof input === 'function') {
274
- options.sourceFilterHandler = input;
275
- return input;
276
- }
277
-
278
- // for single minimatch pattern
279
- if (input && typeof input === 'string') {
280
- // string to multiple patterns "{...}"
281
- // mcr npx mocha --sourceFilter {'**/node_modules/**':false,'**/src/*.js':true}
282
- // mcr npx mocha --sourceFilter "{'**/node_modules/**': false, '**/src/*.js': true}"
283
- const obj = Util.strToObj(input);
284
- if (obj) {
285
- input = obj;
286
- } else {
287
- const handler = (sourcePath) => {
288
- return Util.betterMinimatch(sourcePath, input);
289
- };
290
- options.sourceFilterHandler = handler;
291
- return handler;
292
- }
293
- }
294
-
295
- // for patterns
296
- if (input && typeof input === 'object') {
297
- const patterns = Object.keys(input);
298
- const handler = (sourcePath) => {
299
- for (const pattern of patterns) {
300
- if (Util.betterMinimatch(sourcePath, pattern)) {
301
- return input[pattern];
302
- }
303
- }
304
- // false if not matched
305
- };
306
- options.sourceFilterHandler = handler;
307
- return handler;
308
- }
309
-
310
- // default
311
- const handler = () => true;
275
+ const input = options.sourceFilter || options.filter;
276
+ const handler = Util.createFilterHandler(input, (sourcePath) => sourcePath);
312
277
  options.sourceFilterHandler = handler;
313
278
  return handler;
314
279
  },
@@ -524,26 +489,12 @@ const Util = {
524
489
  },
525
490
 
526
491
  writeFileSync: function(filePath, content) {
527
- if (!fs.existsSync(filePath)) {
528
- const p = path.dirname(filePath);
529
- if (!fs.existsSync(p)) {
530
- fs.mkdirSync(p, {
531
- recursive: true
532
- });
533
- }
534
- }
492
+ Util.ensureDirSync(filePath);
535
493
  fs.writeFileSync(filePath, content);
536
494
  },
537
495
 
538
496
  writeFile: async (filePath, content) => {
539
- if (!fs.existsSync(filePath)) {
540
- const p = path.dirname(filePath);
541
- if (!fs.existsSync(p)) {
542
- fs.mkdirSync(p, {
543
- recursive: true
544
- });
545
- }
546
- }
497
+ Util.ensureDirSync(filePath);
547
498
  await writeFile(filePath, content).catch((e) => {
548
499
  Util.logError(`write file: ${filePath} ${e.message || e}`);
549
500
  });
package/lib/v8/v8.js CHANGED
@@ -152,20 +152,19 @@ const initV8ListAndSourcemap = async (mcr, v8list) => {
152
152
 
153
153
  // ========================================================================================================
154
154
 
155
- // force to async
156
155
  const mergeCssRanges = (itemList) => {
157
- return new Promise((resolve) => {
158
-
159
- let concatRanges = [];
160
- itemList.forEach((item) => {
161
- concatRanges = concatRanges.concat(item.ranges);
162
- });
156
+ // Concatenate all ranges using push to avoid O(n²) array copying
157
+ const concatRanges = [];
158
+ for (const item of itemList) {
159
+ for (const range of item.ranges) {
160
+ concatRanges.push(range);
161
+ }
162
+ }
163
163
 
164
- // ranges: [ {start, end} ]
165
- const ranges = dedupeFlatRanges(concatRanges);
164
+ // ranges: [ {start, end} ]
165
+ const ranges = dedupeFlatRanges(concatRanges);
166
166
 
167
- resolve(ranges);
168
- });
167
+ return ranges;
169
168
  };
170
169
 
171
170
  const mergeJsFunctions = async (itemList) => {
@@ -212,7 +211,7 @@ const mergeV8DataList = async (dataList, options) => {
212
211
  const itemList = mergeMap[id];
213
212
  const item = itemMap[id];
214
213
  if (item.type === 'css') {
215
- item.ranges = await mergeCssRanges(itemList);
214
+ item.ranges = mergeCssRanges(itemList);
216
215
  } else {
217
216
  item.functions = await mergeJsFunctions(itemList);
218
217
  }