escover 1.0.0 → 1.0.4

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.
Files changed (34) hide show
  1. package/ChangeLog +27 -0
  2. package/example/example.js +1 -1
  3. package/lib/c4.js +12 -31
  4. package/lib/escover.js +37 -0
  5. package/lib/exit.js +9 -0
  6. package/lib/instrument/index.js +3 -3
  7. package/lib/instrument/{plugin-mark-line → plugin-mark}/arrow.js +0 -0
  8. package/lib/instrument/{plugin-mark-line → plugin-mark}/fixture/arrow-fix.js +2 -2
  9. package/lib/instrument/{plugin-mark-line → plugin-mark}/fixture/arrow.js +0 -0
  10. package/lib/instrument/plugin-mark/fixture/assignment-fix.js +2 -0
  11. package/lib/instrument/plugin-mark/fixture/assignment.js +2 -0
  12. package/lib/instrument/plugin-mark/fixture/if-fix.js +6 -0
  13. package/lib/instrument/plugin-mark/fixture/if.js +6 -0
  14. package/lib/instrument/plugin-mark/fixture/logical-fix.js +3 -0
  15. package/lib/instrument/{plugin-mark-line → plugin-mark}/fixture/logical.js +0 -0
  16. package/lib/instrument/plugin-mark/fixture/mark-line-fix.js +30 -0
  17. package/lib/instrument/{plugin-mark-line → plugin-mark}/fixture/mark-line.js +0 -0
  18. package/lib/instrument/plugin-mark/fixture/new-fix.js +1 -0
  19. package/lib/instrument/{plugin-mark-line → plugin-mark}/fixture/new.js +0 -0
  20. package/lib/instrument/plugin-mark/fixture/no-loc-fix.js +8 -0
  21. package/lib/instrument/{plugin-mark-line → plugin-mark}/fixture/no-loc.js +0 -0
  22. package/lib/instrument/{plugin-mark-line → plugin-mark}/index.js +19 -9
  23. package/lib/instrument/{plugin-mark-line → plugin-mark}/return.js +0 -0
  24. package/lib/instrument/plugin-mark/throw.js +17 -0
  25. package/lib/merge.js +44 -0
  26. package/lib/parse.js +20 -0
  27. package/lib/report.js +66 -13
  28. package/lib/save.js +8 -21
  29. package/package.json +1 -4
  30. package/bin/c4.js +0 -69
  31. package/lib/instrument/plugin-mark-line/fixture/logical-fix.js +0 -3
  32. package/lib/instrument/plugin-mark-line/fixture/mark-line-fix.js +0 -30
  33. package/lib/instrument/plugin-mark-line/fixture/new-fix.js +0 -1
  34. package/lib/instrument/plugin-mark-line/fixture/no-loc-fix.js +0 -8
package/ChangeLog ADDED
@@ -0,0 +1,27 @@
1
+ 2022.01.08, v1.0.4
2
+
3
+ feature:
4
+ - escover: add support of AssignmentExpression
5
+
6
+
7
+ 2022.01.08, v1.0.3
8
+
9
+ feature:
10
+ - escover: plugin-mark: add support ot ThrowStatement
11
+ - escover: add merger
12
+
13
+
14
+ 2022.01.08, v1.0.2
15
+
16
+ fix:
17
+ - escover: impove support of AssignmentPattern
18
+
19
+ feature:
20
+ - escover: plugin-mark-line -> plugin-mark
21
+
22
+
23
+ 2022.01.08, v1.0.1
24
+
25
+ fix:
26
+ - c4 -> escover
27
+
@@ -1,4 +1,4 @@
1
1
  export const sum = (a, b) => a + b;
2
2
 
3
- export const mul = (a, b) => a * b;
3
+ // export const mul = (a, b) => a * b;
4
4
 
package/lib/c4.js CHANGED
@@ -1,36 +1,17 @@
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';
1
+ const files = new Map();
7
2
 
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
- `;
3
+ export const createFileEntry = (url) => {
4
+ const lines = files.get(url) || new Map();
5
+ files.set(url, lines);
28
6
 
29
7
  return {
30
- format,
31
- source: `${source}\n console.log('🧨', '${url}')`,
8
+ '🧨': (line, column) => {
9
+ lines.set(`${line}:${column}`, true);
10
+ },
11
+ 'init': (line, column) => {
12
+ lines.set(`${line}:${column}`, false);
13
+ },
32
14
  };
33
- }
34
-
35
- process.once('exit', save);
15
+ };
36
16
 
17
+ export const getFiles = () => files;
package/lib/escover.js ADDED
@@ -0,0 +1,37 @@
1
+ import montag from 'montag';
2
+ import process from 'process';
3
+
4
+ import {instrument} from './instrument/index.js';
5
+ import {exclude} from './exclude.js';
6
+ import {exit} from './exit.js';
7
+ import {createFileEntry} from './c4.js';
8
+
9
+ global.__createC4 = createFileEntry;
10
+
11
+ export async function load(url, context, defaultLoad) {
12
+ const {format, source: rawSource} = await defaultLoad(url, context, defaultLoad);
13
+
14
+ if (/commonjs|builtin/.test(format))
15
+ return {
16
+ format,
17
+ };
18
+
19
+ if (exclude(url, ['.spec.js', 'node_modules']))
20
+ return {
21
+ format,
22
+ source: rawSource,
23
+ };
24
+
25
+ const source = montag`
26
+ const __c4 = global.__createC4('${url}');
27
+ ${instrument(url, rawSource)}
28
+ `;
29
+
30
+ return {
31
+ format,
32
+ source,
33
+ };
34
+ }
35
+
36
+ process.once('exit', exit);
37
+
package/lib/exit.js ADDED
@@ -0,0 +1,9 @@
1
+ import once from 'once';
2
+
3
+ import {save} from './save.js';
4
+ import {report} from './report.js';
5
+
6
+ export const exit = once(() => {
7
+ save();
8
+ report();
9
+ });
@@ -1,17 +1,17 @@
1
1
  import putout, {} from 'putout';
2
2
 
3
- import * as markLine from './plugin-mark-line/index.js';
3
+ import * as mark from './plugin-mark/index.js';
4
4
 
5
5
  export const instrument = (url, source) => {
6
6
  const __c4 = global.__createC4(url);
7
7
  const options = {
8
8
  rules: {
9
- 'mark-line': ['on', {
9
+ mark: ['on', {
10
10
  __c4,
11
11
  }],
12
12
  },
13
13
  plugins: [
14
- ['mark-line', markLine],
14
+ ['mark', mark],
15
15
  ],
16
16
  };
17
17
 
@@ -1,6 +1,6 @@
1
1
  export const nothing = (a, b) => {
2
- return __c4.mark(2, 4);
2
+ return __c4['🧨'](2, 4);
3
3
  };
4
4
  export const sum = (a, b) => {
5
- return __c4.mark(5, 4), a + b;
5
+ return __c4['🧨'](5, 4), a + b;
6
6
  };
@@ -0,0 +1,2 @@
1
+ const [error, {packageJson} = (__c4['🧨'](1, 14), {})] = (__c4['🧨'](1, 36), tryCatch(readPackageUpSync));
2
+ data += (__c4['🧨'](2, 0), 'fix:' + '\n');
@@ -0,0 +1,2 @@
1
+ const [error, {packageJson} = {}] = tryCatch(readPackageUpSync);
2
+ data += 'fix:' + '\n';
@@ -0,0 +1,6 @@
1
+ if (error) {
2
+ throw (__c4['🧨'](2, 4), `error reading package.json: ${error.message}`);
3
+ }
4
+
5
+ if (error)
6
+ throw (__c4['🧨'](6, 4), (__c4.mark(11, 8), `error reading package.json: ${error.message}`));
@@ -0,0 +1,6 @@
1
+ if (error) {
2
+ throw `error reading package.json: ${error.message}`;
3
+ }
4
+
5
+ if (error)
6
+ throw (__c4.mark(11, 8), `error reading package.json: ${error.message}`);
@@ -0,0 +1,3 @@
1
+ if ((__c4['🧨'](1, 4), a) || (__c4['🧨'](1, 9), b)) {
2
+ __c4['🧨'](1, 12);
3
+ }
@@ -0,0 +1,30 @@
1
+ const a = () => {
2
+ a = (__c4['🧨'](2, 4), 5);
3
+ __c4['🧨'](3, 4), console.log(5);
4
+ };
5
+
6
+
7
+ function x() {
8
+
9
+ if (a > 2) {
10
+ __c4['🧨'](9, 14), a();
11
+ } else {
12
+ __c4['🧨'](10, 9), b();
13
+ }
14
+ }
15
+
16
+ for (const x of y) {
17
+ __c4['🧨'](13, 19);
18
+ }
19
+
20
+ const ax = ((__c4['🧨'](16, 12), a()), (__c4['🧨'](16, 17), b()));
21
+ const bx = (c, (__c4['🧨'](17, 15), d()));
22
+
23
+ if ((__c4['🧨'](19, 4), a) || (__c4['🧨'](19, 9), b)) {
24
+ __c4['🧨'](19, 12);
25
+ }
26
+
27
+
28
+ function x1(a, b = (__c4['🧨'](23, 15), 5)) {
29
+ __c4['🧨'](23, 22);
30
+ }
@@ -0,0 +1 @@
1
+ const files = (__c4['🧨'](1, 14), new Map());
@@ -0,0 +1,8 @@
1
+ __c4['🧨'](1, 0), cli({
2
+ stdout,
3
+ stderr,
4
+ exit,
5
+ cwd: (__c4['🧨'](5, 9), process.cwd()),
6
+ argv: (__c4['🧨'](6, 10), process.argv.slice(2))
7
+ });
8
+
@@ -5,6 +5,7 @@ import {
5
5
  } from 'putout';
6
6
  import {addMarkToReturn} from './return.js';
7
7
  import {addMarkToArrowFunction} from './arrow.js';
8
+ import {addMarkToThrow} from './throw.js';
8
9
 
9
10
  const {
10
11
  NumericLiteral,
@@ -13,12 +14,11 @@ const {
13
14
  } = types;
14
15
 
15
16
  const {
16
- replaceWithMultiple,
17
17
  replaceWith,
18
18
  compareAny,
19
19
  } = operator;
20
20
 
21
- const LINE = '__c4.mark(__l, __c)';
21
+ const LINE = `__c4['🧨'](__l, __c)`;
22
22
  const buildLineNode = template(LINE, {
23
23
  placeholderPattern: /^__[a-z]$/,
24
24
  });
@@ -80,11 +80,11 @@ export const fix = (path, {options}) => {
80
80
  return;
81
81
  }
82
82
 
83
- if (path.isAssignmentPattern()) {
84
- replaceWithMultiple(path.get('right'), [
85
- lineNode,
86
- node.left,
87
- ]);
83
+ if (path.isAssignmentPattern() || path.isAssignmentExpression()) {
84
+ replaceWith(path.get('right'), SequenceExpression([
85
+ lineNode.expression,
86
+ node.right,
87
+ ]));
88
88
  return;
89
89
  }
90
90
 
@@ -102,6 +102,9 @@ export const fix = (path, {options}) => {
102
102
  if (path.isArrowFunctionExpression())
103
103
  return addMarkToArrowFunction(path, lineNode);
104
104
 
105
+ if (path.isThrowStatement())
106
+ return addMarkToThrow(path, lineNode);
107
+
105
108
  replaceWith(path, BlockStatement([
106
109
  node,
107
110
  ]));
@@ -112,18 +115,25 @@ const EXCLUDE = [
112
115
  `(${LINE}, __z)`,
113
116
  `return (${LINE}, __z)`,
114
117
  `return ${LINE}`,
118
+ `throw (${LINE}, __z)`,
115
119
  ];
116
120
 
117
121
  export const exclude = () => EXCLUDE;
118
122
 
119
123
  export const include = () => [
120
- 'AssignmentPattern',
121
124
  'CallExpression',
122
125
  'NewExpression',
123
126
  'ReturnStatement',
127
+ 'ThrowStatement',
124
128
  ];
125
129
 
126
130
  export const traverse = ({push}) => ({
131
+ 'AssignmentPattern|AssignmentExpression'(path) {
132
+ if (compareAny(path.get('right'), EXCLUDE))
133
+ return;
134
+
135
+ push(path);
136
+ },
127
137
  ArrowFunctionExpression(path) {
128
138
  if (path.get('body').isBlockStatement())
129
139
  return;
@@ -156,7 +166,7 @@ export const traverse = ({push}) => ({
156
166
  const consequentPath = path.get('consequent');
157
167
  const alternatePath = path.get('alternate');
158
168
 
159
- if (!consequentPath.isBlockStatement())
169
+ if (!consequentPath.isBlockStatement() && !compareAny(consequentPath, EXCLUDE))
160
170
  push(consequentPath);
161
171
 
162
172
  if (!alternatePath.node)
@@ -0,0 +1,17 @@
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
+
package/lib/merge.js ADDED
@@ -0,0 +1,44 @@
1
+ const {entries} = Object;
2
+
3
+ export const merge = (files) => {
4
+ const deduplicator = {};
5
+
6
+ for (const {rawName, rawLines} of files) {
7
+ const name = cutQuery(rawName);
8
+ const lines = applyCoverage({
9
+ name,
10
+ rawLines,
11
+ deduplicator,
12
+ });
13
+
14
+ deduplicator[name] = lines;
15
+ }
16
+
17
+ const list = [];
18
+ for (const [name, lines] of entries(deduplicator)) {
19
+ list.push({
20
+ name,
21
+ lines,
22
+ });
23
+ }
24
+
25
+ return list;
26
+ };
27
+
28
+ function applyCoverage({rawLines, name, deduplicator}) {
29
+ if (!deduplicator[name])
30
+ return rawLines;
31
+
32
+ const newLines = {};
33
+
34
+ for (const [line, value] of entries(rawLines))
35
+ newLines[line] = deduplicator[name][line] || value;
36
+
37
+ return newLines;
38
+ }
39
+
40
+ function cutQuery(name) {
41
+ return name
42
+ .replace('file://', '')
43
+ .replace(/\?.*/, '');
44
+ }
package/lib/parse.js ADDED
@@ -0,0 +1,20 @@
1
+ export const parse = (files) => {
2
+ const result = [];
3
+
4
+ for (const [rawName, places] of files.entries()) {
5
+ const rawLines = {};
6
+
7
+ for (const [place, covered] of places.entries()) {
8
+ const [line] = place.split(':');
9
+
10
+ rawLines[line] = covered;
11
+ }
12
+
13
+ result.push({
14
+ rawName,
15
+ rawLines,
16
+ });
17
+ }
18
+
19
+ return result;
20
+ };
package/lib/report.js CHANGED
@@ -1,17 +1,70 @@
1
- const files = new Map();
1
+ import chalk from 'chalk';
2
+ import {readFileSync} from 'fs';
2
3
 
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
- },
4
+ const {parse} = JSON;
5
+ const {entries} = Object;
6
+
7
+ export const report = () => {
8
+ const coverageFile = parse(readFileSync('./coverage.json', 'utf8'));
9
+
10
+ const files = [];
11
+ const coverage = {
12
+ files,
13
+ coveredCount: 0,
14
+ uncoveredCount: 0,
14
15
  };
16
+
17
+ console.log('# CAP version 13');
18
+ console.log('');
19
+
20
+ for (const {name, lines} of coverageFile) {
21
+ const uncoveredLines = [];
22
+
23
+ for (const [line, covered] of 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
+ }
15
69
  };
16
70
 
17
- export const getFiles = () => files;
package/lib/save.js CHANGED
@@ -1,27 +1,14 @@
1
1
  import {writeFileSync} from 'fs';
2
- import once from 'once';
3
- import {getFiles} from './report.js';
2
+ import {getFiles} from './c4.js';
3
+ import {parse} from './parse.js';
4
+ import {merge} from './merge.js';
4
5
 
5
6
  const {stringify} = JSON;
6
7
 
7
- export const save = once(() => {
8
+ export const save = () => {
8
9
  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
- }
10
+ const parsed = parse(files);
11
+ const merged = merge(parsed);
24
12
 
25
- writeFileSync('./coverage.json', stringify(report, null, 4));
26
- });
27
-
13
+ writeFileSync('./coverage.json', stringify(merged, null, 4));
14
+ };
package/package.json CHANGED
@@ -1,13 +1,10 @@
1
1
  {
2
2
  "name": "escover",
3
- "version": "1.0.0",
3
+ "version": "1.0.4",
4
4
  "author": "coderaiser <mnemonic.enemy@gmail.com> (https://github.com/coderaiser)",
5
5
  "description": "Coverage for EcmaScript Modules",
6
6
  "main": "lib/escover.js",
7
7
  "type": "module",
8
- "bin": {
9
- "escover": "bin/escover.js"
10
- },
11
8
  "repository": {
12
9
  "type": "git",
13
10
  "url": "git://github.com/coderaiser/escover.git"
package/bin/c4.js DELETED
@@ -1,69 +0,0 @@
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
-
@@ -1,3 +0,0 @@
1
- if ((__c4.mark(1, 4), a) || (__c4.mark(1, 9), b)) {
2
- __c4.mark(1, 12);
3
- }
@@ -1,30 +0,0 @@
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
- }
@@ -1 +0,0 @@
1
- const files = (__c4.mark(1, 14), new Map());
@@ -1,8 +0,0 @@
1
- __c4.mark(1, 0), cli({
2
- stdout,
3
- stderr,
4
- exit,
5
- cwd: (__c4.mark(5, 9), process.cwd()),
6
- argv: (__c4.mark(6, 10), process.argv.slice(2))
7
- });
8
-