escover 1.12.0 → 1.16.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.
- package/ChangeLog +27 -0
- package/README.md +14 -1
- package/lib/coverage-file/coverage-file.js +10 -13
- package/lib/coverage-file/lcov.js +38 -3
- package/lib/formatters/files.js +2 -0
- package/lib/formatters/lines.js +4 -7
- package/lib/instrument/index.js +0 -1
- package/lib/instrument/plugin-mark/{return.js → argument.js} +1 -1
- package/lib/instrument/plugin-mark/index.js +58 -52
- package/package.json +1 -1
- package/lib/instrument/plugin-mark/continue.js +0 -10
- package/lib/instrument/plugin-mark/throw.js +0 -17
package/ChangeLog
CHANGED
|
@@ -1,3 +1,30 @@
|
|
|
1
|
+
2022.01.27, v1.16.0
|
|
2
|
+
|
|
3
|
+
feature:
|
|
4
|
+
- escover: add support of ternary
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
2022.01.26, v1.15.0
|
|
8
|
+
|
|
9
|
+
fix:
|
|
10
|
+
- escover: logical: find up
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
2022.01.21, v1.14.0
|
|
14
|
+
|
|
15
|
+
feature:
|
|
16
|
+
- escover: instrument: integrate with putout with crawling enabled
|
|
17
|
+
- escover: format: files: add align center
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
2022.01.20, v1.13.0
|
|
21
|
+
|
|
22
|
+
feature:
|
|
23
|
+
- escover: add ability to read lcov
|
|
24
|
+
- coverage-file: add ability to parse lcov
|
|
25
|
+
- escover: mark: add support of break
|
|
26
|
+
|
|
27
|
+
|
|
1
28
|
2022.01.19, v1.12.0
|
|
2
29
|
|
|
3
30
|
feature:
|
package/README.md
CHANGED
|
@@ -31,7 +31,11 @@ which are needed to load module again, and apply mocks.
|
|
|
31
31
|
|
|
32
32
|
### 🤷 How to get coverage when mocks are used?
|
|
33
33
|
|
|
34
|
-
☝️ Use
|
|
34
|
+
☝️ Use 🎩`ESCover`! It supports loaders, `ESM` and collects coverage as a loader!
|
|
35
|
+
|
|
36
|
+
### 🤷 What with [`coveralls`](https://coveralls.io/)? Does [`lcov`](https://github.com/StevenLooman/mocha-lcov-reporter) supported?
|
|
37
|
+
|
|
38
|
+
☝️ Sure! `coverage/lcov.info` is main coverage file for 🎩`ESCover`.
|
|
35
39
|
|
|
36
40
|
## Install
|
|
37
41
|
|
|
@@ -55,6 +59,15 @@ When everything is covered:
|
|
|
55
59
|
|
|
56
60
|

|
|
57
61
|
|
|
62
|
+
## What formatters exists?
|
|
63
|
+
|
|
64
|
+
There is two types of formatters:
|
|
65
|
+
|
|
66
|
+
- `lines` adds links to each line;
|
|
67
|
+
- `files` shows information in table;
|
|
68
|
+
|
|
69
|
+
You can choose formatter with `ESCOVER_FORMAT` env variable.
|
|
70
|
+
|
|
58
71
|
## What if I want to use 🎩`ESCover` with `mock-import`?
|
|
59
72
|
|
|
60
73
|
Experimental `loaders` supports only one, for now. So [zenload](https://github.com/coderaiser/zenload) should be used.
|
|
@@ -8,15 +8,13 @@ import {getFileEntries} from '../c4.js';
|
|
|
8
8
|
import {transform} from '../transform.js';
|
|
9
9
|
import {merge} from '../merge.js';
|
|
10
10
|
import {findCacheDir} from './find-cache-dir.js';
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
parse,
|
|
16
|
-
} = JSON;
|
|
11
|
+
import {
|
|
12
|
+
generateLcov,
|
|
13
|
+
parseLcov,
|
|
14
|
+
} from './lcov.js';
|
|
17
15
|
|
|
18
16
|
const NAME = 'escover';
|
|
19
|
-
const
|
|
17
|
+
const LCOV = 'lcov.info';
|
|
20
18
|
|
|
21
19
|
export const writeCoverage = () => {
|
|
22
20
|
const files = getFileEntries();
|
|
@@ -26,27 +24,26 @@ export const writeCoverage = () => {
|
|
|
26
24
|
|
|
27
25
|
const parsed = transform(files);
|
|
28
26
|
const merged = merge(parsed);
|
|
29
|
-
const lcov =
|
|
27
|
+
const lcov = generateLcov(merged);
|
|
30
28
|
|
|
31
29
|
const dir = findCacheDir({
|
|
32
30
|
name: NAME,
|
|
33
31
|
create: true,
|
|
34
32
|
});
|
|
35
33
|
|
|
36
|
-
writeFileSync(join(dir,
|
|
37
|
-
writeFileSync(buildName(dir), stringify(merged, null, 4));
|
|
34
|
+
writeFileSync(join(dir, LCOV), lcov);
|
|
38
35
|
};
|
|
39
36
|
|
|
40
37
|
export const readCoverage = () => {
|
|
41
|
-
const
|
|
38
|
+
const dir = findCacheDir({
|
|
42
39
|
name: NAME,
|
|
43
40
|
});
|
|
44
41
|
|
|
45
|
-
const [error, data] = tryCatch(readFileSync,
|
|
42
|
+
const [error, data] = tryCatch(readFileSync, join(dir, LCOV), 'utf8');
|
|
46
43
|
|
|
47
44
|
if (error)
|
|
48
45
|
return [];
|
|
49
46
|
|
|
50
|
-
return
|
|
47
|
+
return parseLcov(data);
|
|
51
48
|
};
|
|
52
49
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const {entries} = Object;
|
|
2
2
|
|
|
3
|
-
export const
|
|
3
|
+
export const generateLcov = (files) => {
|
|
4
4
|
const result = [];
|
|
5
5
|
|
|
6
6
|
for (const {name, lines} of files) {
|
|
@@ -9,9 +9,44 @@ export const createLcov = (files) => {
|
|
|
9
9
|
const count = covered ? 1 : 0;
|
|
10
10
|
result.push(`DA:${line},${count}`);
|
|
11
11
|
}
|
|
12
|
+
|
|
13
|
+
result.push('end_of_record');
|
|
12
14
|
}
|
|
13
15
|
|
|
14
|
-
result.push('end_of_record');
|
|
15
|
-
|
|
16
16
|
return result.join('\n');
|
|
17
17
|
};
|
|
18
|
+
|
|
19
|
+
const isEnd = (a) => a === 'end_of_record';
|
|
20
|
+
|
|
21
|
+
export const parseLcov = (lcov) => {
|
|
22
|
+
const files = [];
|
|
23
|
+
let name = '';
|
|
24
|
+
let lines = {};
|
|
25
|
+
|
|
26
|
+
for (const current of lcov.split('\n')) {
|
|
27
|
+
const [cmd, arg] = current.split(':');
|
|
28
|
+
|
|
29
|
+
if (cmd === 'SF') {
|
|
30
|
+
name = arg;
|
|
31
|
+
lines = {};
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (cmd === 'DA') {
|
|
36
|
+
const [line, covered] = arg.split(',');
|
|
37
|
+
lines[line] = Boolean(Number(covered));
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (isEnd(cmd)) {
|
|
42
|
+
files.push({
|
|
43
|
+
name,
|
|
44
|
+
lines,
|
|
45
|
+
});
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return files;
|
|
51
|
+
};
|
|
52
|
+
|
package/lib/formatters/files.js
CHANGED
package/lib/formatters/lines.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
const {entries} = Object;
|
|
3
2
|
|
|
3
|
+
const {entries} = Object;
|
|
4
4
|
const createOut = (output) => (a) => output.push(a);
|
|
5
|
+
|
|
5
6
|
export default (coverageFile) => {
|
|
6
7
|
const output = [];
|
|
7
8
|
const out = createOut(output);
|
|
@@ -56,19 +57,15 @@ export default (coverageFile) => {
|
|
|
56
57
|
out(`1..${files.length}`);
|
|
57
58
|
out(`# files: ${files.length}`);
|
|
58
59
|
out(`# covered: ${coverage.coveredCount}`);
|
|
59
|
-
|
|
60
60
|
out('');
|
|
61
61
|
|
|
62
|
-
if (!coverage.uncoveredCount)
|
|
62
|
+
if (!coverage.uncoveredCount)
|
|
63
63
|
out('#️ 🌴 ok');
|
|
64
|
-
}
|
|
65
64
|
|
|
66
|
-
if (coverage.uncoveredCount)
|
|
65
|
+
if (coverage.uncoveredCount)
|
|
67
66
|
out(`# 🧨 fail: ${coverage.uncoveredCount}`);
|
|
68
|
-
}
|
|
69
67
|
|
|
70
68
|
out('');
|
|
71
69
|
|
|
72
70
|
return output.join('\n');
|
|
73
71
|
};
|
|
74
|
-
|
package/lib/instrument/index.js
CHANGED
|
@@ -4,10 +4,8 @@ import {
|
|
|
4
4
|
operator,
|
|
5
5
|
} from 'putout';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {addMarkToArgument} from './argument.js';
|
|
8
8
|
import {addMarkToArrowFunction} from './arrow.js';
|
|
9
|
-
import {addMarkToThrow} from './throw.js';
|
|
10
|
-
import {addMarkToContinue} from './continue.js';
|
|
11
9
|
|
|
12
10
|
const {
|
|
13
11
|
NumericLiteral,
|
|
@@ -19,6 +17,7 @@ const {
|
|
|
19
17
|
replaceWith,
|
|
20
18
|
compareAny,
|
|
21
19
|
compare,
|
|
20
|
+
replaceWithMultiple,
|
|
22
21
|
} = operator;
|
|
23
22
|
|
|
24
23
|
const LINE = `__c4['🧨'](__l, __c)`;
|
|
@@ -39,12 +38,10 @@ export const report = () => 'Mark line';
|
|
|
39
38
|
|
|
40
39
|
export const fix = (path, {options}) => {
|
|
41
40
|
const {node} = path;
|
|
42
|
-
|
|
43
41
|
const {start} = path.node.loc;
|
|
44
42
|
|
|
45
43
|
const {
|
|
46
44
|
c4 = {
|
|
47
|
-
mark: () => {},
|
|
48
45
|
init: () => {},
|
|
49
46
|
},
|
|
50
47
|
} = options;
|
|
@@ -56,8 +53,9 @@ export const fix = (path, {options}) => {
|
|
|
56
53
|
return;
|
|
57
54
|
}
|
|
58
55
|
|
|
59
|
-
if (path.isCallExpression()) {
|
|
56
|
+
if (path.isCallExpression() || path.isNewExpression()) {
|
|
60
57
|
const {node} = path;
|
|
58
|
+
|
|
61
59
|
replaceWith(path, SequenceExpression([
|
|
62
60
|
lineNode.expression,
|
|
63
61
|
node,
|
|
@@ -65,17 +63,11 @@ export const fix = (path, {options}) => {
|
|
|
65
63
|
return;
|
|
66
64
|
}
|
|
67
65
|
|
|
68
|
-
if (path.isLogicalExpression())
|
|
69
|
-
replaceWith(path
|
|
66
|
+
if (path.parentPath.isLogicalExpression())
|
|
67
|
+
return replaceWith(path, SequenceExpression([
|
|
70
68
|
lineNode.expression,
|
|
71
|
-
path.node
|
|
69
|
+
path.node,
|
|
72
70
|
]));
|
|
73
|
-
replaceWith(path.get('right'), SequenceExpression([
|
|
74
|
-
getLineNode(c4, path.node.right.loc.start).expression,
|
|
75
|
-
path.node.right,
|
|
76
|
-
]));
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
71
|
|
|
80
72
|
if (path.isAssignmentPattern() || path.isAssignmentExpression()) {
|
|
81
73
|
replaceWith(path.get('right'), SequenceExpression([
|
|
@@ -85,25 +77,18 @@ export const fix = (path, {options}) => {
|
|
|
85
77
|
return;
|
|
86
78
|
}
|
|
87
79
|
|
|
88
|
-
if (path.isNewExpression()) {
|
|
89
|
-
replaceWith(path, SequenceExpression([
|
|
90
|
-
lineNode.expression,
|
|
91
|
-
node,
|
|
92
|
-
]));
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (path.isReturnStatement())
|
|
97
|
-
return addMarkToReturn(path, lineNode);
|
|
98
|
-
|
|
99
80
|
if (path.isArrowFunctionExpression())
|
|
100
81
|
return addMarkToArrowFunction(path, lineNode);
|
|
101
82
|
|
|
102
|
-
if (path.isThrowStatement())
|
|
103
|
-
return
|
|
83
|
+
if (path.isReturnStatement() || path.isThrowStatement())
|
|
84
|
+
return addMarkToArgument(path, lineNode);
|
|
104
85
|
|
|
105
|
-
if (path.isContinueStatement())
|
|
106
|
-
return
|
|
86
|
+
if (path.isContinueStatement() || path.isBreakStatement()) {
|
|
87
|
+
return replaceWithMultiple(path, [
|
|
88
|
+
lineNode,
|
|
89
|
+
path.node,
|
|
90
|
+
]);
|
|
91
|
+
}
|
|
107
92
|
|
|
108
93
|
replaceWith(path, BlockStatement([
|
|
109
94
|
node,
|
|
@@ -112,51 +97,68 @@ export const fix = (path, {options}) => {
|
|
|
112
97
|
|
|
113
98
|
const EXCLUDE = [
|
|
114
99
|
LINE,
|
|
115
|
-
`(${LINE}, __z)`,
|
|
116
100
|
`return (${LINE}, __z)`,
|
|
117
101
|
`return ${LINE}`,
|
|
118
102
|
`throw (${LINE}, __z)`,
|
|
119
103
|
];
|
|
120
104
|
|
|
121
|
-
|
|
105
|
+
const SEQUENCE = `(${LINE}, __z)`;
|
|
106
|
+
const isExclude = (node) => {
|
|
107
|
+
const templates = [
|
|
108
|
+
...EXCLUDE,
|
|
109
|
+
SEQUENCE,
|
|
110
|
+
];
|
|
111
|
+
return compareAny(node, templates, {
|
|
112
|
+
findUp: false,
|
|
113
|
+
});
|
|
114
|
+
};
|
|
122
115
|
|
|
123
|
-
export const
|
|
124
|
-
'CallExpression',
|
|
125
|
-
'NewExpression',
|
|
126
|
-
'ReturnStatement',
|
|
127
|
-
'ThrowStatement',
|
|
128
|
-
];
|
|
116
|
+
export const exclude = () => EXCLUDE;
|
|
129
117
|
|
|
130
118
|
export const traverse = ({push}) => ({
|
|
131
|
-
'
|
|
132
|
-
|
|
119
|
+
'ThrowStatement|ReturnStatement'(path) {
|
|
120
|
+
push(path);
|
|
121
|
+
},
|
|
122
|
+
CallExpression(path) {
|
|
123
|
+
if (compare(path.parentPath.node, SEQUENCE))
|
|
133
124
|
return;
|
|
134
125
|
|
|
135
126
|
push(path);
|
|
136
127
|
},
|
|
137
|
-
|
|
138
|
-
if (path.
|
|
128
|
+
'CallExpression|NewExpression'(path) {
|
|
129
|
+
if (compare(path.parentPath.node, SEQUENCE))
|
|
139
130
|
return;
|
|
140
131
|
|
|
141
132
|
push(path);
|
|
142
133
|
},
|
|
143
|
-
|
|
144
|
-
if (
|
|
134
|
+
'AssignmentPattern|AssignmentExpression'(path) {
|
|
135
|
+
if (isExclude(path.get('right')))
|
|
145
136
|
return;
|
|
146
137
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
138
|
+
push(path);
|
|
139
|
+
},
|
|
140
|
+
ArrowFunctionExpression(path) {
|
|
141
|
+
if (path.get('body').isBlockStatement())
|
|
150
142
|
return;
|
|
151
143
|
|
|
152
144
|
push(path);
|
|
153
145
|
},
|
|
154
|
-
|
|
155
|
-
if (
|
|
146
|
+
'ContinueStatement|BreakStatement'(path) {
|
|
147
|
+
if (compare(path.getPrevSibling(), LINE))
|
|
156
148
|
return;
|
|
157
149
|
|
|
158
150
|
push(path);
|
|
159
151
|
},
|
|
152
|
+
LogicalExpression(path) {
|
|
153
|
+
const leftPath = path.get('left');
|
|
154
|
+
const rightPath = path.get('right');
|
|
155
|
+
|
|
156
|
+
if (!isExclude(leftPath))
|
|
157
|
+
push(leftPath);
|
|
158
|
+
|
|
159
|
+
if (!isExclude(rightPath))
|
|
160
|
+
push(rightPath);
|
|
161
|
+
},
|
|
160
162
|
BlockStatement(path) {
|
|
161
163
|
if (path.node.body.length)
|
|
162
164
|
return;
|
|
@@ -164,6 +166,10 @@ export const traverse = ({push}) => ({
|
|
|
164
166
|
push(path);
|
|
165
167
|
},
|
|
166
168
|
SequenceExpression(path) {
|
|
169
|
+
if (compare(path, `(${LINE}, __z)`)) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
167
173
|
const expressions = path.get('expressions');
|
|
168
174
|
|
|
169
175
|
for (const expPath of expressions) {
|
|
@@ -173,17 +179,17 @@ export const traverse = ({push}) => ({
|
|
|
173
179
|
push(expPath);
|
|
174
180
|
}
|
|
175
181
|
},
|
|
176
|
-
IfStatement(path) {
|
|
182
|
+
'IfStatement|ConditionalExpression'(path) {
|
|
177
183
|
const consequentPath = path.get('consequent');
|
|
178
184
|
const alternatePath = path.get('alternate');
|
|
179
185
|
|
|
180
|
-
if (!consequentPath.isBlockStatement() && !
|
|
186
|
+
if (!consequentPath.isBlockStatement() && !isExclude(consequentPath))
|
|
181
187
|
push(consequentPath);
|
|
182
188
|
|
|
183
189
|
if (!alternatePath.node)
|
|
184
190
|
return;
|
|
185
191
|
|
|
186
|
-
if (!alternatePath.isBlockStatement())
|
|
192
|
+
if (!alternatePath.isBlockStatement() && !isExclude(alternatePath))
|
|
187
193
|
push(alternatePath);
|
|
188
194
|
},
|
|
189
195
|
});
|
package/package.json
CHANGED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
types,
|
|
3
|
-
operator,
|
|
4
|
-
} from 'putout';
|
|
5
|
-
const {SequenceExpression} = types;
|
|
6
|
-
|
|
7
|
-
const {replaceWith} = operator;
|
|
8
|
-
|
|
9
|
-
export const addMarkToThrow = (path, lineNode) => {
|
|
10
|
-
const argumentPath = path.get('argument');
|
|
11
|
-
|
|
12
|
-
return replaceWith(argumentPath, SequenceExpression([
|
|
13
|
-
lineNode.expression,
|
|
14
|
-
argumentPath.node,
|
|
15
|
-
]));
|
|
16
|
-
};
|
|
17
|
-
|