escover 1.11.0 → 1.15.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 +13 -12
- package/lib/coverage-file/lcov.js +36 -1
- package/lib/formatters/files.js +2 -0
- package/lib/formatters/lines.js +2 -6
- 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 +59 -41
- 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.26, v1.15.0
|
|
2
|
+
|
|
3
|
+
fix:
|
|
4
|
+
- escover: logical: find up
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
2022.01.21, v1.14.0
|
|
8
|
+
|
|
9
|
+
feature:
|
|
10
|
+
- escover: instrument: integrate with putout with crawling enabled
|
|
11
|
+
- escover: format: files: add align center
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
2022.01.20, v1.13.0
|
|
15
|
+
|
|
16
|
+
feature:
|
|
17
|
+
- escover: add ability to read lcov
|
|
18
|
+
- coverage-file: add ability to parse lcov
|
|
19
|
+
- escover: mark: add support of break
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
2022.01.19, v1.12.0
|
|
23
|
+
|
|
24
|
+
feature:
|
|
25
|
+
- escover: add lcov support
|
|
26
|
+
|
|
27
|
+
|
|
1
28
|
2022.01.19, v1.11.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.
|
|
@@ -3,18 +3,18 @@ import {
|
|
|
3
3
|
readFileSync,
|
|
4
4
|
} from 'fs';
|
|
5
5
|
import tryCatch from 'try-catch';
|
|
6
|
+
import {join} from 'path';
|
|
6
7
|
import {getFileEntries} from '../c4.js';
|
|
7
8
|
import {transform} from '../transform.js';
|
|
8
9
|
import {merge} from '../merge.js';
|
|
9
10
|
import {findCacheDir} from './find-cache-dir.js';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
} = JSON;
|
|
11
|
+
import {
|
|
12
|
+
generateLcov,
|
|
13
|
+
parseLcov,
|
|
14
|
+
} from './lcov.js';
|
|
15
15
|
|
|
16
16
|
const NAME = 'escover';
|
|
17
|
-
const
|
|
17
|
+
const LCOV = 'lcov.info';
|
|
18
18
|
|
|
19
19
|
export const writeCoverage = () => {
|
|
20
20
|
const files = getFileEntries();
|
|
@@ -23,26 +23,27 @@ export const writeCoverage = () => {
|
|
|
23
23
|
return;
|
|
24
24
|
|
|
25
25
|
const parsed = transform(files);
|
|
26
|
-
|
|
27
26
|
const merged = merge(parsed);
|
|
28
|
-
const
|
|
27
|
+
const lcov = generateLcov(merged);
|
|
28
|
+
|
|
29
|
+
const dir = findCacheDir({
|
|
29
30
|
name: NAME,
|
|
30
31
|
create: true,
|
|
31
32
|
});
|
|
32
33
|
|
|
33
|
-
writeFileSync(
|
|
34
|
+
writeFileSync(join(dir, LCOV), lcov);
|
|
34
35
|
};
|
|
35
36
|
|
|
36
37
|
export const readCoverage = () => {
|
|
37
|
-
const
|
|
38
|
+
const dir = findCacheDir({
|
|
38
39
|
name: NAME,
|
|
39
40
|
});
|
|
40
41
|
|
|
41
|
-
const [error, data] = tryCatch(readFileSync,
|
|
42
|
+
const [error, data] = tryCatch(readFileSync, join(dir, LCOV), 'utf8');
|
|
42
43
|
|
|
43
44
|
if (error)
|
|
44
45
|
return [];
|
|
45
46
|
|
|
46
|
-
return
|
|
47
|
+
return parseLcov(data);
|
|
47
48
|
};
|
|
48
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) {
|
|
@@ -15,3 +15,38 @@ export const createLcov = (files) => {
|
|
|
15
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
|
@@ -56,19 +56,15 @@ export default (coverageFile) => {
|
|
|
56
56
|
out(`1..${files.length}`);
|
|
57
57
|
out(`# files: ${files.length}`);
|
|
58
58
|
out(`# covered: ${coverage.coveredCount}`);
|
|
59
|
-
|
|
60
59
|
out('');
|
|
61
60
|
|
|
62
|
-
if (!coverage.uncoveredCount)
|
|
61
|
+
if (!coverage.uncoveredCount)
|
|
63
62
|
out('#️ 🌴 ok');
|
|
64
|
-
}
|
|
65
63
|
|
|
66
|
-
if (coverage.uncoveredCount)
|
|
64
|
+
if (coverage.uncoveredCount)
|
|
67
65
|
out(`# 🧨 fail: ${coverage.uncoveredCount}`);
|
|
68
|
-
}
|
|
69
66
|
|
|
70
67
|
out('');
|
|
71
68
|
|
|
72
69
|
return output.join('\n');
|
|
73
70
|
};
|
|
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,6 +63,12 @@ export const fix = (path, {options}) => {
|
|
|
65
63
|
return;
|
|
66
64
|
}
|
|
67
65
|
|
|
66
|
+
if (path.parentPath.isLogicalExpression())
|
|
67
|
+
return replaceWith(path, SequenceExpression([
|
|
68
|
+
lineNode.expression,
|
|
69
|
+
path.node,
|
|
70
|
+
]));
|
|
71
|
+
/*
|
|
68
72
|
if (path.isLogicalExpression()) {
|
|
69
73
|
replaceWith(path.get('left'), SequenceExpression([
|
|
70
74
|
lineNode.expression,
|
|
@@ -76,6 +80,7 @@ export const fix = (path, {options}) => {
|
|
|
76
80
|
]));
|
|
77
81
|
return;
|
|
78
82
|
}
|
|
83
|
+
*/
|
|
79
84
|
|
|
80
85
|
if (path.isAssignmentPattern() || path.isAssignmentExpression()) {
|
|
81
86
|
replaceWith(path.get('right'), SequenceExpression([
|
|
@@ -85,25 +90,18 @@ export const fix = (path, {options}) => {
|
|
|
85
90
|
return;
|
|
86
91
|
}
|
|
87
92
|
|
|
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
93
|
if (path.isArrowFunctionExpression())
|
|
100
94
|
return addMarkToArrowFunction(path, lineNode);
|
|
101
95
|
|
|
102
|
-
if (path.isThrowStatement())
|
|
103
|
-
return
|
|
96
|
+
if (path.isReturnStatement() || path.isThrowStatement())
|
|
97
|
+
return addMarkToArgument(path, lineNode);
|
|
104
98
|
|
|
105
|
-
if (path.isContinueStatement())
|
|
106
|
-
return
|
|
99
|
+
if (path.isContinueStatement() || path.isBreakStatement()) {
|
|
100
|
+
return replaceWithMultiple(path, [
|
|
101
|
+
lineNode,
|
|
102
|
+
path.node,
|
|
103
|
+
]);
|
|
104
|
+
}
|
|
107
105
|
|
|
108
106
|
replaceWith(path, BlockStatement([
|
|
109
107
|
node,
|
|
@@ -112,51 +110,68 @@ export const fix = (path, {options}) => {
|
|
|
112
110
|
|
|
113
111
|
const EXCLUDE = [
|
|
114
112
|
LINE,
|
|
115
|
-
`(${LINE}, __z)`,
|
|
116
113
|
`return (${LINE}, __z)`,
|
|
117
114
|
`return ${LINE}`,
|
|
118
115
|
`throw (${LINE}, __z)`,
|
|
119
116
|
];
|
|
120
117
|
|
|
121
|
-
|
|
118
|
+
const SEQUENCE = `(${LINE}, __z)`;
|
|
119
|
+
const isExclude = (node) => {
|
|
120
|
+
const templates = [
|
|
121
|
+
...EXCLUDE,
|
|
122
|
+
SEQUENCE,
|
|
123
|
+
];
|
|
124
|
+
return compareAny(node, templates, {
|
|
125
|
+
findUp: false,
|
|
126
|
+
});
|
|
127
|
+
};
|
|
122
128
|
|
|
123
|
-
export const
|
|
124
|
-
'CallExpression',
|
|
125
|
-
'NewExpression',
|
|
126
|
-
'ReturnStatement',
|
|
127
|
-
'ThrowStatement',
|
|
128
|
-
];
|
|
129
|
+
export const exclude = () => EXCLUDE;
|
|
129
130
|
|
|
130
131
|
export const traverse = ({push}) => ({
|
|
131
|
-
'
|
|
132
|
-
|
|
132
|
+
'ThrowStatement|ReturnStatement'(path) {
|
|
133
|
+
push(path);
|
|
134
|
+
},
|
|
135
|
+
CallExpression(path) {
|
|
136
|
+
if (compare(path.parentPath.node, SEQUENCE))
|
|
133
137
|
return;
|
|
134
138
|
|
|
135
139
|
push(path);
|
|
136
140
|
},
|
|
137
|
-
|
|
138
|
-
if (path.
|
|
141
|
+
'CallExpression|NewExpression'(path) {
|
|
142
|
+
if (compare(path.parentPath.node, SEQUENCE))
|
|
139
143
|
return;
|
|
140
144
|
|
|
141
145
|
push(path);
|
|
142
146
|
},
|
|
143
|
-
|
|
144
|
-
if (
|
|
147
|
+
'AssignmentPattern|AssignmentExpression'(path) {
|
|
148
|
+
if (isExclude(path.get('right')))
|
|
145
149
|
return;
|
|
146
150
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
151
|
+
push(path);
|
|
152
|
+
},
|
|
153
|
+
ArrowFunctionExpression(path) {
|
|
154
|
+
if (path.get('body').isBlockStatement())
|
|
150
155
|
return;
|
|
151
156
|
|
|
152
157
|
push(path);
|
|
153
158
|
},
|
|
154
|
-
|
|
155
|
-
if (
|
|
159
|
+
'ContinueStatement|BreakStatement'(path) {
|
|
160
|
+
if (compare(path.getPrevSibling(), LINE))
|
|
156
161
|
return;
|
|
157
162
|
|
|
158
163
|
push(path);
|
|
159
164
|
},
|
|
165
|
+
LogicalExpression(path) {
|
|
166
|
+
const leftPath = path.get('left');
|
|
167
|
+
const rightPath = path.get('right');
|
|
168
|
+
|
|
169
|
+
if (!isExclude(leftPath))
|
|
170
|
+
push(leftPath);
|
|
171
|
+
|
|
172
|
+
if (!isExclude(rightPath))
|
|
173
|
+
push(rightPath);
|
|
174
|
+
},
|
|
160
175
|
BlockStatement(path) {
|
|
161
176
|
if (path.node.body.length)
|
|
162
177
|
return;
|
|
@@ -164,6 +179,9 @@ export const traverse = ({push}) => ({
|
|
|
164
179
|
push(path);
|
|
165
180
|
},
|
|
166
181
|
SequenceExpression(path) {
|
|
182
|
+
if (compare(path, `(${LINE}, __z)`))
|
|
183
|
+
return;
|
|
184
|
+
|
|
167
185
|
const expressions = path.get('expressions');
|
|
168
186
|
|
|
169
187
|
for (const expPath of expressions) {
|
|
@@ -177,7 +195,7 @@ export const traverse = ({push}) => ({
|
|
|
177
195
|
const consequentPath = path.get('consequent');
|
|
178
196
|
const alternatePath = path.get('alternate');
|
|
179
197
|
|
|
180
|
-
if (!consequentPath.isBlockStatement() && !
|
|
198
|
+
if (!consequentPath.isBlockStatement() && !isExclude(consequentPath))
|
|
181
199
|
push(consequentPath);
|
|
182
200
|
|
|
183
201
|
if (!alternatePath.node)
|
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
|
-
|