escover 1.0.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/README.md +38 -0
- package/bin/c4.js +69 -0
- package/c4.json +15 -0
- package/coverage.json +1 -0
- package/example/example.js +4 -0
- package/lib/c4.js +36 -0
- package/lib/exclude.js +8 -0
- package/lib/instrument/fixture/declare-fix.js +9 -0
- package/lib/instrument/fixture/declare.js +8 -0
- package/lib/instrument/index.js +21 -0
- package/lib/instrument/plugin-mark-line/arrow.js +14 -0
- package/lib/instrument/plugin-mark-line/fixture/arrow-fix.js +6 -0
- package/lib/instrument/plugin-mark-line/fixture/arrow.js +6 -0
- package/lib/instrument/plugin-mark-line/fixture/logical-fix.js +3 -0
- package/lib/instrument/plugin-mark-line/fixture/logical.js +2 -0
- package/lib/instrument/plugin-mark-line/fixture/mark-line-fix.js +30 -0
- package/lib/instrument/plugin-mark-line/fixture/mark-line.js +24 -0
- package/lib/instrument/plugin-mark-line/fixture/new-fix.js +1 -0
- package/lib/instrument/plugin-mark-line/fixture/new.js +1 -0
- package/lib/instrument/plugin-mark-line/fixture/no-loc-fix.js +8 -0
- package/lib/instrument/plugin-mark-line/fixture/no-loc.js +8 -0
- package/lib/instrument/plugin-mark-line/index.js +169 -0
- package/lib/instrument/plugin-mark-line/return.js +17 -0
- package/lib/report.js +17 -0
- package/lib/save.js +27 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# 🎩`ESCover` [![License][LicenseIMGURL]][LicenseURL] [![NPM version][NPMIMGURL]][NPMURL] [![Build Status][BuildStatusIMGURL]][BuildStatusURL] [![Coverage Status][CoverageIMGURL]][CoverageURL]
|
|
2
|
+
|
|
3
|
+
[NPMIMGURL]: https://img.shields.io/npm/v/escover.svg?style=flat
|
|
4
|
+
[BuildStatusURL]: https://github.com/coderaiser/escover/actions?query=workflow%3A%22Node+CI%22 "Build Status"
|
|
5
|
+
[BuildStatusIMGURL]: https://github.com/coderaiser/escover/workflows/Node%20CI/badge.svg
|
|
6
|
+
[LicenseIMGURL]: https://img.shields.io/badge/license-MIT-317BF9.svg?style=flat
|
|
7
|
+
[NPMURL]: https://npmjs.org/package/escover "npm"
|
|
8
|
+
[LicenseURL]: https://tldrlegal.com/license/mit-license "MIT License"
|
|
9
|
+
[CoverageURL]: https://coveralls.io/github/coderaiser/escover?branch=master
|
|
10
|
+
[CoverageIMGURL]: https://coveralls.io/repos/coderaiser/escover/badge.svg?branch=master&service=github
|
|
11
|
+
|
|
12
|
+
Explosive coverage tool
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
npm i escover -g
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Then run using:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
NODE_OPTIONS="'--loader escover'" escover npm test
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## How it looks like?
|
|
27
|
+
|
|
28
|
+
When everything is covered:
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
When some lines missing coverage:
|
|
33
|
+
|
|
34
|
+

|
|
35
|
+
|
|
36
|
+
## License
|
|
37
|
+
|
|
38
|
+
MIT
|
package/bin/c4.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
|
|
5
|
+
import {readFileSync} from 'fs';
|
|
6
|
+
|
|
7
|
+
const {parse} = JSON;
|
|
8
|
+
const coverageFile = parse(readFileSync('./coverage.json', 'utf8'));
|
|
9
|
+
|
|
10
|
+
const files = [];
|
|
11
|
+
const coverage = {
|
|
12
|
+
files,
|
|
13
|
+
coveredCount: 0,
|
|
14
|
+
uncoveredCount: 0,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
console.log('# TAP version 13');
|
|
18
|
+
console.log('');
|
|
19
|
+
|
|
20
|
+
for (const {name, lines} of coverageFile) {
|
|
21
|
+
const uncoveredLines = [];
|
|
22
|
+
|
|
23
|
+
for (const [line, covered] of Object.entries(lines)) {
|
|
24
|
+
if (covered)
|
|
25
|
+
continue;
|
|
26
|
+
|
|
27
|
+
uncoveredLines.push(line);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const file = {
|
|
31
|
+
name,
|
|
32
|
+
covered: !uncoveredLines.length,
|
|
33
|
+
uncoveredLines,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
if (file.covered)
|
|
37
|
+
++coverage.coveredCount;
|
|
38
|
+
|
|
39
|
+
if (!file.covered)
|
|
40
|
+
++coverage.uncoveredCount;
|
|
41
|
+
|
|
42
|
+
files.push(file);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
for (const {name, covered, uncoveredLines} of files) {
|
|
46
|
+
if (!covered) {
|
|
47
|
+
console.log(`# ${name}`);
|
|
48
|
+
console.log('❌ should be covered');
|
|
49
|
+
console.log('---');
|
|
50
|
+
console.log(`lines: ${chalk.red(uncoveredLines.join(','))}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (coverage.uncoveredCount)
|
|
55
|
+
console.log('');
|
|
56
|
+
|
|
57
|
+
console.log(`1..${files.length}`);
|
|
58
|
+
console.log(`# files: ${files.length}`);
|
|
59
|
+
console.log(`# covered: ${coverage.coveredCount}`);
|
|
60
|
+
|
|
61
|
+
if (!coverage.uncoveredCount) {
|
|
62
|
+
console.log('');
|
|
63
|
+
console.log('# ☘️ ok');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (coverage.uncoveredCount) {
|
|
67
|
+
console.log(`# 🧨 fail: ${coverage.uncoveredCount}`);
|
|
68
|
+
}
|
|
69
|
+
|
package/c4.json
ADDED
package/coverage.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[]
|
package/lib/c4.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import montag from 'montag';
|
|
2
|
+
import process from 'process';
|
|
3
|
+
import {instrument} from './instrument/index.js';
|
|
4
|
+
import {exclude} from './exclude.js';
|
|
5
|
+
import {save} from './save.js';
|
|
6
|
+
import {createFileEntry} from './report.js';
|
|
7
|
+
|
|
8
|
+
global.__createC4 = createFileEntry;
|
|
9
|
+
|
|
10
|
+
export async function load(url, context, defaultLoad) {
|
|
11
|
+
const {format, source: rawSource} = await defaultLoad(url, context, defaultLoad);
|
|
12
|
+
|
|
13
|
+
if (/commonjs|builtin/.test(format))
|
|
14
|
+
return {
|
|
15
|
+
format,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
if (exclude(url, ['.spec.js', 'node_modules']))
|
|
19
|
+
return {
|
|
20
|
+
format,
|
|
21
|
+
source: rawSource,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const source = montag`
|
|
25
|
+
const __c4 = global.__createC4('${url}');
|
|
26
|
+
${instrument(url, rawSource)}
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
format,
|
|
31
|
+
source: `${source}\n console.log('🧨', '${url}')`,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
process.once('exit', save);
|
|
36
|
+
|
package/lib/exclude.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import putout, {} from 'putout';
|
|
2
|
+
|
|
3
|
+
import * as markLine from './plugin-mark-line/index.js';
|
|
4
|
+
|
|
5
|
+
export const instrument = (url, source) => {
|
|
6
|
+
const __c4 = global.__createC4(url);
|
|
7
|
+
const options = {
|
|
8
|
+
rules: {
|
|
9
|
+
'mark-line': ['on', {
|
|
10
|
+
__c4,
|
|
11
|
+
}],
|
|
12
|
+
},
|
|
13
|
+
plugins: [
|
|
14
|
+
['mark-line', markLine],
|
|
15
|
+
],
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const {code} = putout(source, options);
|
|
19
|
+
return code;
|
|
20
|
+
};
|
|
21
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {types} from 'putout';
|
|
2
|
+
|
|
3
|
+
const {SequenceExpression} = types;
|
|
4
|
+
|
|
5
|
+
export const addMarkToArrowFunction = (path, lineNode) => {
|
|
6
|
+
const {node} = path;
|
|
7
|
+
const {expression} = lineNode;
|
|
8
|
+
|
|
9
|
+
node.body = SequenceExpression([
|
|
10
|
+
expression,
|
|
11
|
+
node.body,
|
|
12
|
+
]);
|
|
13
|
+
};
|
|
14
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const a = () => {
|
|
2
|
+
a = 5;
|
|
3
|
+
__c4.mark(3, 4), console.log(5);
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
function x() {
|
|
8
|
+
|
|
9
|
+
if (a > 2) {
|
|
10
|
+
__c4.mark(9, 14), a();
|
|
11
|
+
} else {
|
|
12
|
+
__c4.mark(10, 9), b();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
for (const x of y) {
|
|
17
|
+
__c4.mark(13, 19);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const ax = ((__c4.mark(16, 12), a()), (__c4.mark(16, 17), b()));
|
|
21
|
+
const bx = (c, (__c4.mark(17, 15), d()));
|
|
22
|
+
|
|
23
|
+
if ((__c4.mark(19, 4), a) || (__c4.mark(19, 9), b)) {
|
|
24
|
+
__c4.mark(19, 12);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
function x1(a, b = (__c4.mark(23, 15), b)) {
|
|
29
|
+
__c4.mark(23, 22);
|
|
30
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const a = () => {
|
|
2
|
+
a = 5;
|
|
3
|
+
console.log(5);
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
function x() {
|
|
8
|
+
|
|
9
|
+
if (a > 2)a()
|
|
10
|
+
else b();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
for (const x of y) {
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const ax = (a(), b());
|
|
17
|
+
const bx = (c, d());
|
|
18
|
+
|
|
19
|
+
if (a || b) {
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
function x1(a, b = 5) {
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const files = (__c4.mark(1, 14), new Map());
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const files = new Map();
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import {
|
|
2
|
+
template,
|
|
3
|
+
types,
|
|
4
|
+
operator,
|
|
5
|
+
} from 'putout';
|
|
6
|
+
import {addMarkToReturn} from './return.js';
|
|
7
|
+
import {addMarkToArrowFunction} from './arrow.js';
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
NumericLiteral,
|
|
11
|
+
SequenceExpression,
|
|
12
|
+
BlockStatement,
|
|
13
|
+
} = types;
|
|
14
|
+
|
|
15
|
+
const {
|
|
16
|
+
replaceWithMultiple,
|
|
17
|
+
replaceWith,
|
|
18
|
+
compareAny,
|
|
19
|
+
} = operator;
|
|
20
|
+
|
|
21
|
+
const LINE = '__c4.mark(__l, __c)';
|
|
22
|
+
const buildLineNode = template(LINE, {
|
|
23
|
+
placeholderPattern: /^__[a-z]$/,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
function getLineNode(__c4, {line, column}) {
|
|
27
|
+
__c4.init(line, column);
|
|
28
|
+
|
|
29
|
+
return buildLineNode({
|
|
30
|
+
__l: NumericLiteral(line),
|
|
31
|
+
__c: NumericLiteral(column),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const report = () => 'Mark line';
|
|
36
|
+
|
|
37
|
+
export const fix = (path, {options}) => {
|
|
38
|
+
const {
|
|
39
|
+
parentPath,
|
|
40
|
+
node,
|
|
41
|
+
} = path;
|
|
42
|
+
|
|
43
|
+
const {start} = path.node.loc || parentPath.node.loc || {};
|
|
44
|
+
|
|
45
|
+
if (!start)
|
|
46
|
+
return;
|
|
47
|
+
|
|
48
|
+
const {
|
|
49
|
+
__c4 = {
|
|
50
|
+
mark: () => {},
|
|
51
|
+
init: () => {},
|
|
52
|
+
},
|
|
53
|
+
} = options;
|
|
54
|
+
|
|
55
|
+
const lineNode = getLineNode(__c4, start);
|
|
56
|
+
|
|
57
|
+
if (path.isBlockStatement()) {
|
|
58
|
+
path.node.body.unshift(lineNode);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (path.isCallExpression()) {
|
|
63
|
+
const {node} = path;
|
|
64
|
+
replaceWith(path, SequenceExpression([
|
|
65
|
+
lineNode.expression,
|
|
66
|
+
node,
|
|
67
|
+
]));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (path.isLogicalExpression()) {
|
|
72
|
+
replaceWith(path.get('left'), SequenceExpression([
|
|
73
|
+
lineNode.expression,
|
|
74
|
+
path.node.left,
|
|
75
|
+
]));
|
|
76
|
+
replaceWith(path.get('right'), SequenceExpression([
|
|
77
|
+
getLineNode(__c4, path.node.right.loc.start).expression,
|
|
78
|
+
path.node.right,
|
|
79
|
+
]));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (path.isAssignmentPattern()) {
|
|
84
|
+
replaceWithMultiple(path.get('right'), [
|
|
85
|
+
lineNode,
|
|
86
|
+
node.left,
|
|
87
|
+
]);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (path.isNewExpression()) {
|
|
92
|
+
replaceWith(path, SequenceExpression([
|
|
93
|
+
lineNode.expression,
|
|
94
|
+
node,
|
|
95
|
+
]));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (path.isReturnStatement())
|
|
100
|
+
return addMarkToReturn(path, lineNode);
|
|
101
|
+
|
|
102
|
+
if (path.isArrowFunctionExpression())
|
|
103
|
+
return addMarkToArrowFunction(path, lineNode);
|
|
104
|
+
|
|
105
|
+
replaceWith(path, BlockStatement([
|
|
106
|
+
node,
|
|
107
|
+
]));
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const EXCLUDE = [
|
|
111
|
+
LINE,
|
|
112
|
+
`(${LINE}, __z)`,
|
|
113
|
+
`return (${LINE}, __z)`,
|
|
114
|
+
`return ${LINE}`,
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
export const exclude = () => EXCLUDE;
|
|
118
|
+
|
|
119
|
+
export const include = () => [
|
|
120
|
+
'AssignmentPattern',
|
|
121
|
+
'CallExpression',
|
|
122
|
+
'NewExpression',
|
|
123
|
+
'ReturnStatement',
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
export const traverse = ({push}) => ({
|
|
127
|
+
ArrowFunctionExpression(path) {
|
|
128
|
+
if (path.get('body').isBlockStatement())
|
|
129
|
+
return;
|
|
130
|
+
|
|
131
|
+
push(path);
|
|
132
|
+
},
|
|
133
|
+
LogicalExpression(path) {
|
|
134
|
+
if (compareAny(path.get('left'), EXCLUDE))
|
|
135
|
+
return;
|
|
136
|
+
|
|
137
|
+
push(path);
|
|
138
|
+
},
|
|
139
|
+
BlockStatement(path) {
|
|
140
|
+
if (path.node.body.length)
|
|
141
|
+
return;
|
|
142
|
+
|
|
143
|
+
push(path);
|
|
144
|
+
},
|
|
145
|
+
SequenceExpression(path) {
|
|
146
|
+
const expressions = path.get('expressions');
|
|
147
|
+
|
|
148
|
+
for (const expPath of expressions) {
|
|
149
|
+
if (!expPath.isCallExpression())
|
|
150
|
+
continue;
|
|
151
|
+
|
|
152
|
+
push(expPath);
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
IfStatement(path) {
|
|
156
|
+
const consequentPath = path.get('consequent');
|
|
157
|
+
const alternatePath = path.get('alternate');
|
|
158
|
+
|
|
159
|
+
if (!consequentPath.isBlockStatement())
|
|
160
|
+
push(consequentPath);
|
|
161
|
+
|
|
162
|
+
if (!alternatePath.node)
|
|
163
|
+
return;
|
|
164
|
+
|
|
165
|
+
if (!alternatePath.isBlockStatement())
|
|
166
|
+
push(alternatePath);
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {types} from 'putout';
|
|
2
|
+
const {SequenceExpression} = types;
|
|
3
|
+
|
|
4
|
+
export const addMarkToReturn = (path, lineNode) => {
|
|
5
|
+
const {node} = path;
|
|
6
|
+
const {expression} = lineNode;
|
|
7
|
+
|
|
8
|
+
if (!node.argument) {
|
|
9
|
+
node.argument = expression;
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
node.argument = SequenceExpression([
|
|
14
|
+
expression,
|
|
15
|
+
node.argument,
|
|
16
|
+
]);
|
|
17
|
+
};
|
package/lib/report.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const files = new Map();
|
|
2
|
+
|
|
3
|
+
export const createFileEntry = (url) => {
|
|
4
|
+
const lines = files.get(url) || new Map();
|
|
5
|
+
files.set(url, lines);
|
|
6
|
+
|
|
7
|
+
return {
|
|
8
|
+
mark: (line, column) => {
|
|
9
|
+
lines.set(`${line}:${column}`, true);
|
|
10
|
+
},
|
|
11
|
+
init: (line, column) => {
|
|
12
|
+
lines.set(`${line}:${column}`, false);
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const getFiles = () => files;
|
package/lib/save.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {writeFileSync} from 'fs';
|
|
2
|
+
import once from 'once';
|
|
3
|
+
import {getFiles} from './report.js';
|
|
4
|
+
|
|
5
|
+
const {stringify} = JSON;
|
|
6
|
+
|
|
7
|
+
export const save = once(() => {
|
|
8
|
+
const files = getFiles();
|
|
9
|
+
const report = [];
|
|
10
|
+
for (const [name, places] of files.entries()) {
|
|
11
|
+
const lines = {};
|
|
12
|
+
const current = {
|
|
13
|
+
name,
|
|
14
|
+
lines,
|
|
15
|
+
};
|
|
16
|
+
for (const [place, covered] of places.entries()) {
|
|
17
|
+
const [line] = place.split(':');
|
|
18
|
+
|
|
19
|
+
lines[line] = covered;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
report.push(current);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
writeFileSync('./coverage.json', stringify(report, null, 4));
|
|
26
|
+
});
|
|
27
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "escover",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"author": "coderaiser <mnemonic.enemy@gmail.com> (https://github.com/coderaiser)",
|
|
5
|
+
"description": "Coverage for EcmaScript Modules",
|
|
6
|
+
"main": "lib/escover.js",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"escover": "bin/escover.js"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git://github.com/coderaiser/escover.git"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"coverage",
|
|
17
|
+
"putout",
|
|
18
|
+
"loader"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"test": "madrun test",
|
|
22
|
+
"coverage": "madrun coverage",
|
|
23
|
+
"lint": "madrun lint",
|
|
24
|
+
"fresh:lint": "madrun fresh:lint",
|
|
25
|
+
"lint:fresh": "madrun lint:fresh",
|
|
26
|
+
"fix:lint": "madrun fix:lint",
|
|
27
|
+
"report": "madrun report",
|
|
28
|
+
"watcher": "madrun watcher",
|
|
29
|
+
"watch:test": "madrun watch:test",
|
|
30
|
+
"watch:lint": "madrun watch:lint",
|
|
31
|
+
"watch:tape": "madrun watch:tape",
|
|
32
|
+
"watch:coverage": "madrun watch:coverage"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"chalk": "^5.0.0",
|
|
36
|
+
"montag": "^1.2.1",
|
|
37
|
+
"once": "^1.4.0",
|
|
38
|
+
"putout": "^23.5.0"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=14"
|
|
42
|
+
},
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@putout/test": "^4.1.0",
|
|
46
|
+
"c8": "^7.8.0",
|
|
47
|
+
"eslint": "^8.3.0",
|
|
48
|
+
"eslint-plugin-node": "^11.1.0",
|
|
49
|
+
"eslint-plugin-putout": "^12.2.0",
|
|
50
|
+
"madrun": "^8.8.1",
|
|
51
|
+
"mock-import": "^2.0.0",
|
|
52
|
+
"supertape": "^6.0.5",
|
|
53
|
+
"zenload": "^1.0.0"
|
|
54
|
+
}
|
|
55
|
+
}
|