monocart-coverage-reports 2.5.9 → 2.6.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.
- package/LICENSE +21 -21
- package/README.md +791 -778
- package/lib/cli.js +250 -215
- package/lib/converter/ast-visitor.js +675 -666
- package/lib/converter/ast.js +353 -353
- package/lib/converter/collect-source-maps.js +201 -201
- package/lib/converter/converter.js +1487 -1429
- package/lib/converter/find-original-range.js +737 -737
- package/lib/converter/ignore.js +163 -163
- package/lib/converter/info-branch.js +93 -93
- package/lib/converter/info-function.js +63 -63
- package/lib/converter/info-statement.js +43 -43
- package/lib/default/options.js +84 -84
- package/lib/default/template.html +47 -47
- package/lib/generate.js +720 -532
- package/lib/index.d.ts +360 -324
- package/lib/index.js +187 -180
- package/lib/index.mjs +5 -3
- package/lib/istanbul/istanbul-summary.js +70 -63
- package/lib/istanbul/istanbul.js +146 -146
- package/lib/packages/monocart-coverage-v8.js +1 -1
- package/lib/platform/concurrency.js +74 -74
- package/lib/platform/share.js +484 -484
- package/lib/utils/dedupe.js +118 -118
- package/lib/utils/request.js +62 -62
- package/lib/utils/snapshot.js +381 -0
- package/lib/utils/source-path.js +179 -179
- package/lib/utils/util.js +526 -526
- package/lib/v8/v8-summary.js +138 -138
- package/lib/v8/v8.js +400 -630
- package/package.json +81 -80
package/lib/converter/ast.js
CHANGED
|
@@ -1,353 +1,353 @@
|
|
|
1
|
-
const {
|
|
2
|
-
acorn, acornLoose, parseCss
|
|
3
|
-
} = require('../packages/monocart-coverage-vendor.js');
|
|
4
|
-
const Util = require('../utils/util.js');
|
|
5
|
-
|
|
6
|
-
const { collectAstInfo } = require('./ast-visitor.js');
|
|
7
|
-
|
|
8
|
-
const getCoverageInfo = (coverageList) => {
|
|
9
|
-
const functionMap = new Map();
|
|
10
|
-
const functionNameMap = new Map();
|
|
11
|
-
const functionUncoveredRanges = [];
|
|
12
|
-
let rootRange;
|
|
13
|
-
coverageList.forEach((block) => {
|
|
14
|
-
const {
|
|
15
|
-
functionName, ranges, root
|
|
16
|
-
} = block;
|
|
17
|
-
|
|
18
|
-
let functionRange;
|
|
19
|
-
const blockRanges = [];
|
|
20
|
-
|
|
21
|
-
ranges.forEach((range, i) => {
|
|
22
|
-
if (i === 0) {
|
|
23
|
-
// function range
|
|
24
|
-
functionRange = range;
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
blockRanges.push(range);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
functionRange.functionName = functionName;
|
|
31
|
-
|
|
32
|
-
// blocks
|
|
33
|
-
if (blockRanges.length) {
|
|
34
|
-
const blockMap = new Map();
|
|
35
|
-
blockRanges.forEach((item) => {
|
|
36
|
-
blockMap.set(item.startOffset, item);
|
|
37
|
-
});
|
|
38
|
-
functionRange.blockMap = blockMap;
|
|
39
|
-
// uncovered is unique
|
|
40
|
-
const blockUncoveredRanges = blockRanges.filter((it) => it.count === 0);
|
|
41
|
-
blockUncoveredRanges.sort((a, b) => {
|
|
42
|
-
return a.startOffset - b.startOffset;
|
|
43
|
-
});
|
|
44
|
-
functionRange.blockUncoveredRanges = blockUncoveredRanges;
|
|
45
|
-
functionRange.blockCoveredRanges = blockRanges.filter((it) => it.count > 0);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// root function from vm
|
|
49
|
-
if (root) {
|
|
50
|
-
rootRange = functionRange;
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// root function from first range
|
|
55
|
-
if (!rootRange) {
|
|
56
|
-
rootRange = functionRange;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
functionMap.set(functionRange.startOffset, functionRange);
|
|
60
|
-
if (functionName) {
|
|
61
|
-
functionNameMap.set(functionRange.startOffset + functionName.length, functionRange);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// uncovered is unique
|
|
65
|
-
if (functionRange.count === 0) {
|
|
66
|
-
functionUncoveredRanges.push(functionRange);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
// sort ranges
|
|
72
|
-
functionUncoveredRanges.sort((a, b) => {
|
|
73
|
-
return a.startOffset - b.startOffset;
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
return {
|
|
77
|
-
functionMap,
|
|
78
|
-
functionNameMap,
|
|
79
|
-
functionUncoveredRanges,
|
|
80
|
-
rootRange
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const getFakeAstInfo = (coverageList) => {
|
|
86
|
-
const functions = [];
|
|
87
|
-
const branches = [];
|
|
88
|
-
const statements = [];
|
|
89
|
-
coverageList.forEach((block) => {
|
|
90
|
-
const {
|
|
91
|
-
isBlockCoverage, functionName, ranges, root
|
|
92
|
-
} = block;
|
|
93
|
-
|
|
94
|
-
ranges.forEach((range, i) => {
|
|
95
|
-
|
|
96
|
-
const {
|
|
97
|
-
startOffset, endOffset, count
|
|
98
|
-
} = range;
|
|
99
|
-
|
|
100
|
-
if (i === 0 && root) {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
statements.push({
|
|
105
|
-
start: startOffset,
|
|
106
|
-
end: endOffset,
|
|
107
|
-
count
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
if (isBlockCoverage) {
|
|
111
|
-
// branches
|
|
112
|
-
branches.push({
|
|
113
|
-
type: 'branch',
|
|
114
|
-
start: startOffset,
|
|
115
|
-
end: endOffset,
|
|
116
|
-
locations: [{
|
|
117
|
-
start: startOffset,
|
|
118
|
-
end: endOffset,
|
|
119
|
-
count
|
|
120
|
-
}]
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (i === 0) {
|
|
125
|
-
// function range
|
|
126
|
-
functions.push({
|
|
127
|
-
start: startOffset,
|
|
128
|
-
end: endOffset,
|
|
129
|
-
bodyStart: startOffset,
|
|
130
|
-
bodyEnd: endOffset,
|
|
131
|
-
count,
|
|
132
|
-
functionName
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
// console.log('fake functions', functions.map((it) => it));
|
|
141
|
-
|
|
142
|
-
return {
|
|
143
|
-
functions,
|
|
144
|
-
branches,
|
|
145
|
-
statements
|
|
146
|
-
};
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
const getJsAstInfo = (item, coverageList) => {
|
|
150
|
-
|
|
151
|
-
const {
|
|
152
|
-
source, fake, empty
|
|
153
|
-
} = item;
|
|
154
|
-
|
|
155
|
-
if (fake) {
|
|
156
|
-
return getFakeAstInfo(coverageList);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const options = {
|
|
160
|
-
ecmaVersion: 'latest',
|
|
161
|
-
// most time for node.js file
|
|
162
|
-
allowReturnOutsideFunction: true,
|
|
163
|
-
allowImportExportEverywhere: true,
|
|
164
|
-
allowAwaitOutsideFunction: true,
|
|
165
|
-
allowSuperOutsideMethod: true,
|
|
166
|
-
// first line: #!/usr/bin/env node
|
|
167
|
-
allowHashBang: true
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
let err;
|
|
171
|
-
let ast;
|
|
172
|
-
try {
|
|
173
|
-
ast = acorn.parse(source, options);
|
|
174
|
-
} catch (e) {
|
|
175
|
-
err = e;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (err) {
|
|
179
|
-
|
|
180
|
-
// empty = untested file
|
|
181
|
-
// could be .ts, .vue and so on, that can not be parsed normally
|
|
182
|
-
if (empty) {
|
|
183
|
-
return {
|
|
184
|
-
functions: [],
|
|
185
|
-
branches: [],
|
|
186
|
-
statements: []
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// runtime code should be parsed successful
|
|
191
|
-
Util.logInfo(`failed to parse source file: ${item.sourcePath} ${err.message}`);
|
|
192
|
-
|
|
193
|
-
// https://github.com/acornjs/acorn/tree/master/acorn-loose
|
|
194
|
-
// It is recommended to always try a parse with the regular acorn parser first,
|
|
195
|
-
// and only fall back to this parser when that one finds syntax errors.
|
|
196
|
-
ast = acornLoose.parse(source, options);
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const coverageInfo = getCoverageInfo(coverageList);
|
|
201
|
-
coverageInfo.item = item;
|
|
202
|
-
|
|
203
|
-
return collectAstInfo(ast, coverageInfo);
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
// =========================================================================================================
|
|
207
|
-
|
|
208
|
-
const addRule = (item, coverageList, coveredRanges, count = 0) => {
|
|
209
|
-
|
|
210
|
-
const { source } = item;
|
|
211
|
-
const { start, end } = source;
|
|
212
|
-
const startOffset = start.offset;
|
|
213
|
-
const endOffset = end.offset;
|
|
214
|
-
|
|
215
|
-
if (!count) {
|
|
216
|
-
const coveredRange = Util.findInRanges(startOffset, endOffset, coveredRanges, 'startOffset', 'endOffset');
|
|
217
|
-
if (coveredRange) {
|
|
218
|
-
count = 1;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
coverageList.push({
|
|
223
|
-
start: startOffset,
|
|
224
|
-
end: endOffset,
|
|
225
|
-
count
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
return count;
|
|
229
|
-
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
const addAtRule = (item, coverageList, coveredRanges, empty) => {
|
|
233
|
-
const { name, nodes } = item;
|
|
234
|
-
|
|
235
|
-
const defaultCount = empty ? 0 : 1;
|
|
236
|
-
|
|
237
|
-
if (['charset', 'import', 'namespace'].includes(name)) {
|
|
238
|
-
addRule(item, coverageList, coveredRanges, defaultCount);
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (['media', 'supports', 'container', 'layer'].includes(name)) {
|
|
243
|
-
|
|
244
|
-
const childCoverageList = [];
|
|
245
|
-
const count = addCssRules(nodes, childCoverageList, coveredRanges, empty);
|
|
246
|
-
if (count) {
|
|
247
|
-
|
|
248
|
-
coverageList.push({
|
|
249
|
-
start: item.source.start.offset,
|
|
250
|
-
end: childCoverageList[0].start,
|
|
251
|
-
count: 1
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
let end;
|
|
255
|
-
childCoverageList.forEach((it) => {
|
|
256
|
-
coverageList.push(it);
|
|
257
|
-
end = it.end;
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
coverageList.push({
|
|
261
|
-
start: end,
|
|
262
|
-
end: item.source.end.offset,
|
|
263
|
-
count: 1
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
addRule(item, coverageList, coveredRanges);
|
|
272
|
-
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
const addCssRules = (list, coverageList, coveredRanges, empty) => {
|
|
276
|
-
|
|
277
|
-
let count = 0;
|
|
278
|
-
|
|
279
|
-
// line and line is 1-base
|
|
280
|
-
list.forEach((item) => {
|
|
281
|
-
|
|
282
|
-
const { type } = item;
|
|
283
|
-
|
|
284
|
-
if (type === 'comment') {
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
if (type === 'rule') {
|
|
289
|
-
count += addRule(item, coverageList, coveredRanges);
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// console.log('=============================================================================');
|
|
294
|
-
// Object.keys(item).forEach((k) => {
|
|
295
|
-
// if (k === 'parent') {
|
|
296
|
-
// return;
|
|
297
|
-
// }
|
|
298
|
-
// if (k === 'raws') {
|
|
299
|
-
// return;
|
|
300
|
-
// }
|
|
301
|
-
// if (k === 'nodes') {
|
|
302
|
-
// console.log(k, item[k].length);
|
|
303
|
-
// return;
|
|
304
|
-
// }
|
|
305
|
-
// if (k === 'source') {
|
|
306
|
-
// console.log(k, item[k].start, item[k].end);
|
|
307
|
-
// return;
|
|
308
|
-
// }
|
|
309
|
-
// console.log(k, item[k]);
|
|
310
|
-
// });
|
|
311
|
-
|
|
312
|
-
if (type === 'atrule') {
|
|
313
|
-
addAtRule(item, coverageList, coveredRanges, empty);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
return count;
|
|
319
|
-
};
|
|
320
|
-
|
|
321
|
-
const getCssAstInfo = (item, coverageList) => {
|
|
322
|
-
|
|
323
|
-
const {
|
|
324
|
-
source, ranges, empty
|
|
325
|
-
} = item;
|
|
326
|
-
|
|
327
|
-
// sort covered ranges
|
|
328
|
-
ranges.sort((a, b) => a.start - b.start);
|
|
329
|
-
|
|
330
|
-
// to offset covered ranges
|
|
331
|
-
const coveredRanges = ranges.map((it) => {
|
|
332
|
-
return {
|
|
333
|
-
startOffset: it.start,
|
|
334
|
-
endOffset: it.end
|
|
335
|
-
};
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
const ast = parseCss(source);
|
|
339
|
-
|
|
340
|
-
addCssRules(ast.nodes, coverageList, coveredRanges, empty);
|
|
341
|
-
|
|
342
|
-
return {
|
|
343
|
-
functions: [],
|
|
344
|
-
branches: [],
|
|
345
|
-
statements: []
|
|
346
|
-
};
|
|
347
|
-
};
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
module.exports = {
|
|
351
|
-
getJsAstInfo,
|
|
352
|
-
getCssAstInfo
|
|
353
|
-
};
|
|
1
|
+
const {
|
|
2
|
+
acorn, acornLoose, parseCss
|
|
3
|
+
} = require('../packages/monocart-coverage-vendor.js');
|
|
4
|
+
const Util = require('../utils/util.js');
|
|
5
|
+
|
|
6
|
+
const { collectAstInfo } = require('./ast-visitor.js');
|
|
7
|
+
|
|
8
|
+
const getCoverageInfo = (coverageList) => {
|
|
9
|
+
const functionMap = new Map();
|
|
10
|
+
const functionNameMap = new Map();
|
|
11
|
+
const functionUncoveredRanges = [];
|
|
12
|
+
let rootRange;
|
|
13
|
+
coverageList.forEach((block) => {
|
|
14
|
+
const {
|
|
15
|
+
functionName, ranges, root
|
|
16
|
+
} = block;
|
|
17
|
+
|
|
18
|
+
let functionRange;
|
|
19
|
+
const blockRanges = [];
|
|
20
|
+
|
|
21
|
+
ranges.forEach((range, i) => {
|
|
22
|
+
if (i === 0) {
|
|
23
|
+
// function range
|
|
24
|
+
functionRange = range;
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
blockRanges.push(range);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
functionRange.functionName = functionName;
|
|
31
|
+
|
|
32
|
+
// blocks
|
|
33
|
+
if (blockRanges.length) {
|
|
34
|
+
const blockMap = new Map();
|
|
35
|
+
blockRanges.forEach((item) => {
|
|
36
|
+
blockMap.set(item.startOffset, item);
|
|
37
|
+
});
|
|
38
|
+
functionRange.blockMap = blockMap;
|
|
39
|
+
// uncovered is unique
|
|
40
|
+
const blockUncoveredRanges = blockRanges.filter((it) => it.count === 0);
|
|
41
|
+
blockUncoveredRanges.sort((a, b) => {
|
|
42
|
+
return a.startOffset - b.startOffset;
|
|
43
|
+
});
|
|
44
|
+
functionRange.blockUncoveredRanges = blockUncoveredRanges;
|
|
45
|
+
functionRange.blockCoveredRanges = blockRanges.filter((it) => it.count > 0);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// root function from vm
|
|
49
|
+
if (root) {
|
|
50
|
+
rootRange = functionRange;
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// root function from first range
|
|
55
|
+
if (!rootRange) {
|
|
56
|
+
rootRange = functionRange;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
functionMap.set(functionRange.startOffset, functionRange);
|
|
60
|
+
if (functionName) {
|
|
61
|
+
functionNameMap.set(functionRange.startOffset + functionName.length, functionRange);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// uncovered is unique
|
|
65
|
+
if (functionRange.count === 0) {
|
|
66
|
+
functionUncoveredRanges.push(functionRange);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// sort ranges
|
|
72
|
+
functionUncoveredRanges.sort((a, b) => {
|
|
73
|
+
return a.startOffset - b.startOffset;
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
functionMap,
|
|
78
|
+
functionNameMap,
|
|
79
|
+
functionUncoveredRanges,
|
|
80
|
+
rootRange
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const getFakeAstInfo = (coverageList) => {
|
|
86
|
+
const functions = [];
|
|
87
|
+
const branches = [];
|
|
88
|
+
const statements = [];
|
|
89
|
+
coverageList.forEach((block) => {
|
|
90
|
+
const {
|
|
91
|
+
isBlockCoverage, functionName, ranges, root
|
|
92
|
+
} = block;
|
|
93
|
+
|
|
94
|
+
ranges.forEach((range, i) => {
|
|
95
|
+
|
|
96
|
+
const {
|
|
97
|
+
startOffset, endOffset, count
|
|
98
|
+
} = range;
|
|
99
|
+
|
|
100
|
+
if (i === 0 && root) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
statements.push({
|
|
105
|
+
start: startOffset,
|
|
106
|
+
end: endOffset,
|
|
107
|
+
count
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
if (isBlockCoverage) {
|
|
111
|
+
// branches
|
|
112
|
+
branches.push({
|
|
113
|
+
type: 'branch',
|
|
114
|
+
start: startOffset,
|
|
115
|
+
end: endOffset,
|
|
116
|
+
locations: [{
|
|
117
|
+
start: startOffset,
|
|
118
|
+
end: endOffset,
|
|
119
|
+
count
|
|
120
|
+
}]
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (i === 0) {
|
|
125
|
+
// function range
|
|
126
|
+
functions.push({
|
|
127
|
+
start: startOffset,
|
|
128
|
+
end: endOffset,
|
|
129
|
+
bodyStart: startOffset,
|
|
130
|
+
bodyEnd: endOffset,
|
|
131
|
+
count,
|
|
132
|
+
functionName
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// console.log('fake functions', functions.map((it) => it));
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
functions,
|
|
144
|
+
branches,
|
|
145
|
+
statements
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const getJsAstInfo = (item, coverageList) => {
|
|
150
|
+
|
|
151
|
+
const {
|
|
152
|
+
source, fake, empty
|
|
153
|
+
} = item;
|
|
154
|
+
|
|
155
|
+
if (fake) {
|
|
156
|
+
return getFakeAstInfo(coverageList);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const options = {
|
|
160
|
+
ecmaVersion: 'latest',
|
|
161
|
+
// most time for node.js file
|
|
162
|
+
allowReturnOutsideFunction: true,
|
|
163
|
+
allowImportExportEverywhere: true,
|
|
164
|
+
allowAwaitOutsideFunction: true,
|
|
165
|
+
allowSuperOutsideMethod: true,
|
|
166
|
+
// first line: #!/usr/bin/env node
|
|
167
|
+
allowHashBang: true
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
let err;
|
|
171
|
+
let ast;
|
|
172
|
+
try {
|
|
173
|
+
ast = acorn.parse(source, options);
|
|
174
|
+
} catch (e) {
|
|
175
|
+
err = e;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (err) {
|
|
179
|
+
|
|
180
|
+
// empty = untested file
|
|
181
|
+
// could be .ts, .vue and so on, that can not be parsed normally
|
|
182
|
+
if (empty) {
|
|
183
|
+
return {
|
|
184
|
+
functions: [],
|
|
185
|
+
branches: [],
|
|
186
|
+
statements: []
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// runtime code should be parsed successful
|
|
191
|
+
Util.logInfo(`failed to parse source file: ${item.sourcePath} ${err.message}`);
|
|
192
|
+
|
|
193
|
+
// https://github.com/acornjs/acorn/tree/master/acorn-loose
|
|
194
|
+
// It is recommended to always try a parse with the regular acorn parser first,
|
|
195
|
+
// and only fall back to this parser when that one finds syntax errors.
|
|
196
|
+
ast = acornLoose.parse(source, options);
|
|
197
|
+
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const coverageInfo = getCoverageInfo(coverageList);
|
|
201
|
+
coverageInfo.item = item;
|
|
202
|
+
|
|
203
|
+
return collectAstInfo(ast, coverageInfo);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// =========================================================================================================
|
|
207
|
+
|
|
208
|
+
const addRule = (item, coverageList, coveredRanges, count = 0) => {
|
|
209
|
+
|
|
210
|
+
const { source } = item;
|
|
211
|
+
const { start, end } = source;
|
|
212
|
+
const startOffset = start.offset;
|
|
213
|
+
const endOffset = end.offset;
|
|
214
|
+
|
|
215
|
+
if (!count) {
|
|
216
|
+
const coveredRange = Util.findInRanges(startOffset, endOffset, coveredRanges, 'startOffset', 'endOffset');
|
|
217
|
+
if (coveredRange) {
|
|
218
|
+
count = 1;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
coverageList.push({
|
|
223
|
+
start: startOffset,
|
|
224
|
+
end: endOffset,
|
|
225
|
+
count
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
return count;
|
|
229
|
+
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const addAtRule = (item, coverageList, coveredRanges, empty) => {
|
|
233
|
+
const { name, nodes } = item;
|
|
234
|
+
|
|
235
|
+
const defaultCount = empty ? 0 : 1;
|
|
236
|
+
|
|
237
|
+
if (['charset', 'import', 'namespace'].includes(name)) {
|
|
238
|
+
addRule(item, coverageList, coveredRanges, defaultCount);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (['media', 'supports', 'container', 'layer'].includes(name)) {
|
|
243
|
+
|
|
244
|
+
const childCoverageList = [];
|
|
245
|
+
const count = addCssRules(nodes, childCoverageList, coveredRanges, empty);
|
|
246
|
+
if (count) {
|
|
247
|
+
|
|
248
|
+
coverageList.push({
|
|
249
|
+
start: item.source.start.offset,
|
|
250
|
+
end: childCoverageList[0].start,
|
|
251
|
+
count: 1
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
let end;
|
|
255
|
+
childCoverageList.forEach((it) => {
|
|
256
|
+
coverageList.push(it);
|
|
257
|
+
end = it.end;
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
coverageList.push({
|
|
261
|
+
start: end,
|
|
262
|
+
end: item.source.end.offset,
|
|
263
|
+
count: 1
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
addRule(item, coverageList, coveredRanges);
|
|
272
|
+
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
const addCssRules = (list, coverageList, coveredRanges, empty) => {
|
|
276
|
+
|
|
277
|
+
let count = 0;
|
|
278
|
+
|
|
279
|
+
// line and line is 1-base
|
|
280
|
+
list.forEach((item) => {
|
|
281
|
+
|
|
282
|
+
const { type } = item;
|
|
283
|
+
|
|
284
|
+
if (type === 'comment') {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (type === 'rule') {
|
|
289
|
+
count += addRule(item, coverageList, coveredRanges);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// console.log('=============================================================================');
|
|
294
|
+
// Object.keys(item).forEach((k) => {
|
|
295
|
+
// if (k === 'parent') {
|
|
296
|
+
// return;
|
|
297
|
+
// }
|
|
298
|
+
// if (k === 'raws') {
|
|
299
|
+
// return;
|
|
300
|
+
// }
|
|
301
|
+
// if (k === 'nodes') {
|
|
302
|
+
// console.log(k, item[k].length);
|
|
303
|
+
// return;
|
|
304
|
+
// }
|
|
305
|
+
// if (k === 'source') {
|
|
306
|
+
// console.log(k, item[k].start, item[k].end);
|
|
307
|
+
// return;
|
|
308
|
+
// }
|
|
309
|
+
// console.log(k, item[k]);
|
|
310
|
+
// });
|
|
311
|
+
|
|
312
|
+
if (type === 'atrule') {
|
|
313
|
+
addAtRule(item, coverageList, coveredRanges, empty);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
return count;
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const getCssAstInfo = (item, coverageList) => {
|
|
322
|
+
|
|
323
|
+
const {
|
|
324
|
+
source, ranges, empty
|
|
325
|
+
} = item;
|
|
326
|
+
|
|
327
|
+
// sort covered ranges
|
|
328
|
+
ranges.sort((a, b) => a.start - b.start);
|
|
329
|
+
|
|
330
|
+
// to offset covered ranges
|
|
331
|
+
const coveredRanges = ranges.map((it) => {
|
|
332
|
+
return {
|
|
333
|
+
startOffset: it.start,
|
|
334
|
+
endOffset: it.end
|
|
335
|
+
};
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
const ast = parseCss(source);
|
|
339
|
+
|
|
340
|
+
addCssRules(ast.nodes, coverageList, coveredRanges, empty);
|
|
341
|
+
|
|
342
|
+
return {
|
|
343
|
+
functions: [],
|
|
344
|
+
branches: [],
|
|
345
|
+
statements: []
|
|
346
|
+
};
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
module.exports = {
|
|
351
|
+
getJsAstInfo,
|
|
352
|
+
getCssAstInfo
|
|
353
|
+
};
|