as-test 0.1.4 → 0.1.5
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/.github/workflows/{nodejs.yml → as-test.yml} +10 -9
- package/.prettierrc +3 -0
- package/CHANGELOG.md +3 -1
- package/README.md +18 -65
- package/as-test.config.json +22 -0
- package/asconfig.json +30 -33
- package/assembly/__tests__/example.spec.ts +70 -0
- package/assembly/coverage.ts +15 -15
- package/assembly/index.ts +195 -132
- package/assembly/reporters/tap.ts +30 -0
- package/assembly/src/expectation.ts +302 -277
- package/assembly/src/group.ts +33 -33
- package/assembly/src/node.ts +7 -7
- package/assembly/test.ts +43 -46
- package/assembly/tsconfig.json +96 -98
- package/assembly/util.ts +90 -87
- package/bin/build.js +119 -0
- package/bin/index.js +159 -0
- package/bin/init.js +40 -0
- package/bin/package.json +3 -0
- package/bin/run.js +53 -0
- package/bin/types.js +41 -0
- package/bin/util.js +23 -0
- package/cli/build.ts +154 -0
- package/cli/index.ts +201 -0
- package/cli/init.ts +47 -0
- package/cli/run.ts +68 -0
- package/cli/tsconfig.json +8 -0
- package/cli/types.ts +34 -0
- package/cli/util.ts +30 -0
- package/index.ts +1 -1
- package/jest.test.js +44 -5
- package/package.json +18 -15
- package/tests/test.tap +14 -0
- package/transform/lib/index.js +391 -397
- package/transform/package.json +4 -4
- package/transform/src/index.ts +474 -506
- package/transform/tsconfig.json +2 -2
- package/assembly/example.spec.ts +0 -5
- package/src/cli.ts +0 -0
package/transform/lib/index.js
CHANGED
|
@@ -1,52 +1,56 @@
|
|
|
1
1
|
import { Transform } from "assemblyscript/dist/transform.js";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Source,
|
|
4
|
+
BlockStatement,
|
|
5
|
+
ExpressionStatement,
|
|
6
|
+
Node,
|
|
7
|
+
Tokenizer,
|
|
8
|
+
} from "assemblyscript/dist/assemblyscript.js";
|
|
3
9
|
import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js";
|
|
4
10
|
import { isStdlib } from "visitor-as/dist/utils.js";
|
|
5
11
|
import { RangeTransform } from "visitor-as/dist/transformRange.js";
|
|
6
|
-
let ENABLED = false;
|
|
7
12
|
var CoverType;
|
|
8
13
|
(function (CoverType) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
CoverType[(CoverType["Function"] = 0)] = "Function";
|
|
15
|
+
CoverType[(CoverType["Expression"] = 1)] = "Expression";
|
|
16
|
+
CoverType[(CoverType["Block"] = 2)] = "Block";
|
|
12
17
|
})(CoverType || (CoverType = {}));
|
|
13
18
|
class CoverPoint {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
constructor() {
|
|
20
|
+
this.file = "";
|
|
21
|
+
this.hash = "";
|
|
22
|
+
this.line = 0;
|
|
23
|
+
this.column = 0;
|
|
24
|
+
this.executed = false;
|
|
25
|
+
}
|
|
21
26
|
}
|
|
22
27
|
class CoverageTransform extends BaseVisitor {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({
|
|
28
|
+
constructor() {
|
|
29
|
+
super(...arguments);
|
|
30
|
+
this.mustImport = false;
|
|
31
|
+
this.points = new Map();
|
|
32
|
+
this.globalStatements = [];
|
|
33
|
+
}
|
|
34
|
+
visitBinaryExpression(node) {
|
|
35
|
+
super.visitBinaryExpression(node);
|
|
36
|
+
// @ts-ignore
|
|
37
|
+
if (node.visited) return;
|
|
38
|
+
// @ts-ignore
|
|
39
|
+
node.visited = true;
|
|
40
|
+
const path = node.range.source.normalizedPath;
|
|
41
|
+
switch (node.operator) {
|
|
42
|
+
case 98 /* Token.Bar_Bar */:
|
|
43
|
+
case 97 /* Token.Ampersand_Ampersand */: {
|
|
44
|
+
const right = node.right;
|
|
45
|
+
const rightLc = getLineCol(node);
|
|
46
|
+
const point = new CoverPoint();
|
|
47
|
+
point.line = rightLc?.line;
|
|
48
|
+
point.column = rightLc?.column;
|
|
49
|
+
point.file = path;
|
|
50
|
+
point.type = CoverType.Expression;
|
|
51
|
+
point.hash = hash(point);
|
|
52
|
+
const replacer = new RangeTransform(node);
|
|
53
|
+
const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({
|
|
50
54
|
file: "${point.file}",
|
|
51
55
|
hash: "${point.hash}",
|
|
52
56
|
line: ${point.line},
|
|
@@ -54,39 +58,39 @@ class CoverageTransform extends BaseVisitor {
|
|
|
54
58
|
type: "Expression",
|
|
55
59
|
executed: false
|
|
56
60
|
});`);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
replacer.visit(registerStmt);
|
|
62
|
+
let coverExpression = SimpleParser.parseExpression(
|
|
63
|
+
`(__COVER("${point.hash}"), $$REPLACE_ME)`,
|
|
64
|
+
);
|
|
65
|
+
replacer.visit(coverExpression);
|
|
66
|
+
coverExpression.expression.expressions[1] = right;
|
|
67
|
+
node.right = coverExpression;
|
|
68
|
+
this.globalStatements.push(registerStmt);
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
66
71
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({
|
|
72
|
+
}
|
|
73
|
+
visitMethodDeclaration(node) {
|
|
74
|
+
super.visitMethodDeclaration(node);
|
|
75
|
+
// @ts-ignore
|
|
76
|
+
if (node.visited) return;
|
|
77
|
+
// @ts-ignore
|
|
78
|
+
node.visited = true;
|
|
79
|
+
if (node.body) {
|
|
80
|
+
// @ts-ignore
|
|
81
|
+
if (node.body.visited) return;
|
|
82
|
+
// @ts-ignore
|
|
83
|
+
node.body.visited = true;
|
|
84
|
+
const path = node.range.source.normalizedPath;
|
|
85
|
+
const funcLc = getLineCol(node);
|
|
86
|
+
const point = new CoverPoint();
|
|
87
|
+
point.line = funcLc?.line;
|
|
88
|
+
point.column = funcLc?.column;
|
|
89
|
+
point.file = path;
|
|
90
|
+
point.type = CoverType.Function;
|
|
91
|
+
point.hash = hash(point);
|
|
92
|
+
const replacer = new RangeTransform(node);
|
|
93
|
+
const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({
|
|
90
94
|
file: "${point.file}",
|
|
91
95
|
hash: "${point.hash}",
|
|
92
96
|
line: ${point.line},
|
|
@@ -94,37 +98,38 @@ class CoverageTransform extends BaseVisitor {
|
|
|
94
98
|
type: "Function",
|
|
95
99
|
executed: false
|
|
96
100
|
})`);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
replacer.visit(registerStmt);
|
|
102
|
+
const coverStmt = SimpleParser.parseStatement(
|
|
103
|
+
`__COVER("${point.hash}")`,
|
|
104
|
+
true,
|
|
105
|
+
);
|
|
106
|
+
replacer.visit(coverStmt);
|
|
107
|
+
const bodyBlock = node.body;
|
|
108
|
+
bodyBlock.statements.unshift(coverStmt);
|
|
109
|
+
this.globalStatements.push(registerStmt);
|
|
104
110
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({
|
|
111
|
+
}
|
|
112
|
+
visitParameter(node) {
|
|
113
|
+
// @ts-ignore
|
|
114
|
+
if (node.visited) return;
|
|
115
|
+
// @ts-ignore
|
|
116
|
+
node.visited = true;
|
|
117
|
+
const path = node.range.source.normalizedPath;
|
|
118
|
+
if (node.initializer) {
|
|
119
|
+
// @ts-ignore
|
|
120
|
+
if (node.initializer.visited) return;
|
|
121
|
+
// @ts-ignore
|
|
122
|
+
node.initializer.visited = true;
|
|
123
|
+
super.visitParameter(node);
|
|
124
|
+
const paramLc = getLineCol(node.initializer);
|
|
125
|
+
const point = new CoverPoint();
|
|
126
|
+
point.line = paramLc?.line;
|
|
127
|
+
point.column = paramLc?.column;
|
|
128
|
+
point.file = path;
|
|
129
|
+
point.type = CoverType.Expression;
|
|
130
|
+
point.hash = hash(point);
|
|
131
|
+
const replacer = new RangeTransform(node);
|
|
132
|
+
const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({
|
|
128
133
|
file: "${point.file}",
|
|
129
134
|
hash: "${point.hash}",
|
|
130
135
|
line: ${point.line},
|
|
@@ -132,37 +137,37 @@ class CoverageTransform extends BaseVisitor {
|
|
|
132
137
|
type: "Expression",
|
|
133
138
|
executed: false
|
|
134
139
|
})`);
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
140
|
+
replacer.visit(registerStmt);
|
|
141
|
+
const coverExpression = SimpleParser.parseExpression(
|
|
142
|
+
`(__COVER("${point.hash}"), $$REPLACE_ME)`,
|
|
143
|
+
);
|
|
144
|
+
replacer.visit(coverExpression);
|
|
145
|
+
coverExpression.expression.expressions[1] = node.initializer;
|
|
146
|
+
node.initializer = coverExpression;
|
|
147
|
+
this.globalStatements.push(registerStmt);
|
|
142
148
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({
|
|
149
|
+
}
|
|
150
|
+
visitFunctionDeclaration(node, isDefault) {
|
|
151
|
+
super.visitFunctionDeclaration(node, isDefault);
|
|
152
|
+
// @ts-ignore
|
|
153
|
+
if (node.visited) return;
|
|
154
|
+
// @ts-ignore
|
|
155
|
+
node.visited = true;
|
|
156
|
+
if (node.body) {
|
|
157
|
+
// @ts-ignore
|
|
158
|
+
if (node.body.visited) return;
|
|
159
|
+
// @ts-ignore
|
|
160
|
+
node.body.visited = true;
|
|
161
|
+
const path = node.range.source.normalizedPath;
|
|
162
|
+
const funcLc = getLineCol(node);
|
|
163
|
+
const point = new CoverPoint();
|
|
164
|
+
point.line = funcLc?.line;
|
|
165
|
+
point.column = funcLc?.column;
|
|
166
|
+
point.file = path;
|
|
167
|
+
point.type = CoverType.Function;
|
|
168
|
+
point.hash = hash(point);
|
|
169
|
+
const replacer = new RangeTransform(node);
|
|
170
|
+
const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({
|
|
166
171
|
file: "${point.file}",
|
|
167
172
|
hash: "${point.hash}",
|
|
168
173
|
line: ${point.line},
|
|
@@ -170,59 +175,60 @@ class CoverageTransform extends BaseVisitor {
|
|
|
170
175
|
type: "Function",
|
|
171
176
|
executed: false
|
|
172
177
|
})`);
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
178
|
+
replacer.visit(registerStmt);
|
|
179
|
+
this.globalStatements.push(registerStmt);
|
|
180
|
+
if (node.body.kind === 35 /* NodeKind.Export */) {
|
|
181
|
+
const coverStmt = SimpleParser.parseStatement(`{
|
|
177
182
|
__COVER("${point.hash}")
|
|
178
183
|
return $$REPLACE_ME
|
|
179
184
|
}`);
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
185
|
+
replacer.visit(coverStmt);
|
|
186
|
+
const bodyReturn = coverStmt.statements[1];
|
|
187
|
+
const body = node.body;
|
|
188
|
+
node.arrowKind = 2 /* ArrowKind.Single */;
|
|
189
|
+
bodyReturn.value = body.expression;
|
|
190
|
+
node.body = body;
|
|
191
|
+
} else {
|
|
192
|
+
const coverStmt = SimpleParser.parseStatement(
|
|
193
|
+
`__COVER("${point.hash}")`,
|
|
194
|
+
true,
|
|
195
|
+
);
|
|
196
|
+
replacer.visit(coverStmt);
|
|
197
|
+
if (node.body instanceof BlockStatement) {
|
|
198
|
+
node.body.statements.unshift(coverStmt);
|
|
199
|
+
console.log(node);
|
|
200
|
+
} else if (node.body instanceof ExpressionStatement) {
|
|
201
|
+
const expression = node.body.expression;
|
|
202
|
+
node.body = Node.createBlockStatement(
|
|
203
|
+
[Node.createReturnStatement(expression, expression.range)],
|
|
204
|
+
expression.range,
|
|
205
|
+
);
|
|
206
|
+
const bodyBlock = node.body;
|
|
207
|
+
bodyBlock.statements.unshift(coverStmt);
|
|
203
208
|
}
|
|
209
|
+
}
|
|
204
210
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
211
|
+
}
|
|
212
|
+
visitIfStatement(node) {
|
|
213
|
+
// @ts-ignore
|
|
214
|
+
if (node.visited) return;
|
|
215
|
+
// @ts-ignore
|
|
216
|
+
node.visited = true;
|
|
217
|
+
let visitIfTrue = false;
|
|
218
|
+
let visitIfFalse = false;
|
|
219
|
+
const ifTrue = node.ifTrue;
|
|
220
|
+
const ifFalse = node.ifFalse;
|
|
221
|
+
const path = node.range.source.normalizedPath;
|
|
222
|
+
if (ifTrue.kind !== 30 /* NodeKind.Block */) {
|
|
223
|
+
const trueLc = getLineCol(ifTrue);
|
|
224
|
+
const point = new CoverPoint();
|
|
225
|
+
point.line = trueLc?.line;
|
|
226
|
+
point.column = trueLc?.column;
|
|
227
|
+
point.file = path;
|
|
228
|
+
point.type = CoverType.Expression;
|
|
229
|
+
point.hash = hash(point);
|
|
230
|
+
const replacer = new RangeTransform(ifTrue);
|
|
231
|
+
const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({
|
|
226
232
|
file: "${point.file}",
|
|
227
233
|
hash: "${point.hash}",
|
|
228
234
|
line: ${point.line},
|
|
@@ -230,25 +236,28 @@ class CoverageTransform extends BaseVisitor {
|
|
|
230
236
|
type: "Expression",
|
|
231
237
|
executed: false
|
|
232
238
|
})`);
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
239
|
+
replacer.visit(registerStmt);
|
|
240
|
+
const coverStmt = SimpleParser.parseStatement(
|
|
241
|
+
`{__COVER("${point.hash}")};`,
|
|
242
|
+
true,
|
|
243
|
+
);
|
|
244
|
+
replacer.visit(coverStmt);
|
|
245
|
+
coverStmt.statements.push(ifTrue);
|
|
246
|
+
node.ifTrue = coverStmt;
|
|
247
|
+
this.globalStatements.push(registerStmt);
|
|
248
|
+
visitIfTrue = true;
|
|
249
|
+
visitIfFalse = !!ifFalse;
|
|
250
|
+
}
|
|
251
|
+
if (ifFalse && ifFalse.kind !== 30 /* NodeKind.Block */) {
|
|
252
|
+
const falseLc = getLineCol(ifFalse);
|
|
253
|
+
const point = new CoverPoint();
|
|
254
|
+
point.line = falseLc?.line;
|
|
255
|
+
point.column = falseLc?.column;
|
|
256
|
+
point.file = path;
|
|
257
|
+
point.type = CoverType.Expression;
|
|
258
|
+
point.hash = hash(point);
|
|
259
|
+
const replacer = new RangeTransform(ifTrue);
|
|
260
|
+
const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({
|
|
252
261
|
file: "${point.file}",
|
|
253
262
|
hash: "${point.hash}",
|
|
254
263
|
line: ${point.line},
|
|
@@ -256,57 +265,56 @@ class CoverageTransform extends BaseVisitor {
|
|
|
256
265
|
type: "Expression",
|
|
257
266
|
executed: false
|
|
258
267
|
})`);
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
// @ts-ignore
|
|
271
|
-
if (ifTrue.visited)
|
|
272
|
-
return;
|
|
273
|
-
// @ts-ignore
|
|
274
|
-
ifTrue.visited = true;
|
|
275
|
-
this._visit(ifTrue);
|
|
276
|
-
}
|
|
277
|
-
if (visitIfFalse) {
|
|
278
|
-
// @ts-ignore
|
|
279
|
-
if (ifFalse.visited)
|
|
280
|
-
return;
|
|
281
|
-
// @ts-ignore
|
|
282
|
-
ifFalse.visited = true;
|
|
283
|
-
this._visit(ifFalse);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
else {
|
|
287
|
-
super.visitIfStatement(node);
|
|
288
|
-
}
|
|
268
|
+
replacer.visit(registerStmt);
|
|
269
|
+
const coverStmt = SimpleParser.parseStatement(
|
|
270
|
+
`{__COVER("${point.hash}")};`,
|
|
271
|
+
true,
|
|
272
|
+
);
|
|
273
|
+
replacer.visit(coverStmt);
|
|
274
|
+
coverStmt.statements.push(ifFalse);
|
|
275
|
+
node.ifFalse = coverStmt;
|
|
276
|
+
this.globalStatements.push(registerStmt);
|
|
277
|
+
visitIfTrue = true;
|
|
278
|
+
visitIfFalse = true;
|
|
289
279
|
}
|
|
290
|
-
|
|
280
|
+
if (visitIfTrue || visitIfFalse) {
|
|
281
|
+
if (visitIfTrue) {
|
|
282
|
+
// @ts-ignore
|
|
283
|
+
if (ifTrue.visited) return;
|
|
291
284
|
// @ts-ignore
|
|
292
|
-
|
|
293
|
-
|
|
285
|
+
ifTrue.visited = true;
|
|
286
|
+
this._visit(ifTrue);
|
|
287
|
+
}
|
|
288
|
+
if (visitIfFalse) {
|
|
294
289
|
// @ts-ignore
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
290
|
+
if (ifFalse.visited) return;
|
|
291
|
+
// @ts-ignore
|
|
292
|
+
ifFalse.visited = true;
|
|
293
|
+
this._visit(ifFalse);
|
|
294
|
+
}
|
|
295
|
+
} else {
|
|
296
|
+
super.visitIfStatement(node);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
visitTernaryExpression(node) {
|
|
300
|
+
// @ts-ignore
|
|
301
|
+
if (node.visited) return;
|
|
302
|
+
// @ts-ignore
|
|
303
|
+
node.visited = true;
|
|
304
|
+
super.visitTernaryExpression(node);
|
|
305
|
+
const trueExpression = node.ifThen;
|
|
306
|
+
const falseExpression = node.ifElse;
|
|
307
|
+
const path = node.range.source.normalizedPath;
|
|
308
|
+
{
|
|
309
|
+
const trueLc = getLineCol(trueExpression);
|
|
310
|
+
const point = new CoverPoint();
|
|
311
|
+
point.line = trueLc?.line;
|
|
312
|
+
point.column = trueLc?.column;
|
|
313
|
+
point.file = path;
|
|
314
|
+
point.type = CoverType.Expression;
|
|
315
|
+
point.hash = hash(point);
|
|
316
|
+
const replacer = new RangeTransform(trueExpression);
|
|
317
|
+
const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({
|
|
310
318
|
file: "${point.file}",
|
|
311
319
|
hash: "${point.hash}",
|
|
312
320
|
line: ${point.line},
|
|
@@ -314,23 +322,25 @@ class CoverageTransform extends BaseVisitor {
|
|
|
314
322
|
type: "Expression",
|
|
315
323
|
executed: false
|
|
316
324
|
})`);
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
325
|
+
replacer.visit(registerStmt);
|
|
326
|
+
const coverExpression = SimpleParser.parseExpression(
|
|
327
|
+
`(__COVER("${point.hash}"), $$REPLACE_ME)`,
|
|
328
|
+
);
|
|
329
|
+
replacer.visit(coverExpression);
|
|
330
|
+
coverExpression.expression.expressions[1] = trueExpression;
|
|
331
|
+
node.ifThen = coverExpression;
|
|
332
|
+
this.globalStatements.push(registerStmt);
|
|
333
|
+
}
|
|
334
|
+
{
|
|
335
|
+
const falseLc = getLineCol(falseExpression);
|
|
336
|
+
const point = new CoverPoint();
|
|
337
|
+
point.line = falseLc?.line;
|
|
338
|
+
point.column = falseLc?.column;
|
|
339
|
+
point.file = path;
|
|
340
|
+
point.type = CoverType.Expression;
|
|
341
|
+
point.hash = hash(point);
|
|
342
|
+
const replacer = new RangeTransform(falseExpression);
|
|
343
|
+
const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({
|
|
334
344
|
file: "${point.file}",
|
|
335
345
|
hash: "${point.hash}",
|
|
336
346
|
line: ${point.line},
|
|
@@ -338,30 +348,31 @@ class CoverageTransform extends BaseVisitor {
|
|
|
338
348
|
type: "Expression",
|
|
339
349
|
executed: false
|
|
340
350
|
})`);
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
351
|
+
replacer.visit(registerStmt);
|
|
352
|
+
const coverExpression = SimpleParser.parseExpression(
|
|
353
|
+
`(__COVER("${point.hash}"), $$REPLACE_ME)`,
|
|
354
|
+
);
|
|
355
|
+
replacer.visit(coverExpression);
|
|
356
|
+
coverExpression.expression.expressions[1] = falseExpression;
|
|
357
|
+
node.ifElse = coverExpression;
|
|
358
|
+
this.globalStatements.push(registerStmt);
|
|
348
359
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
360
|
+
}
|
|
361
|
+
visitSwitchCase(node) {
|
|
362
|
+
// @ts-ignore
|
|
363
|
+
if (node.visited) return;
|
|
364
|
+
// @ts-ignore
|
|
365
|
+
node.visited = true;
|
|
366
|
+
const path = node.range.source.normalizedPath;
|
|
367
|
+
const caseLc = getLineCol(node);
|
|
368
|
+
const point = new CoverPoint();
|
|
369
|
+
point.line = caseLc?.line;
|
|
370
|
+
point.column = caseLc?.column;
|
|
371
|
+
point.file = path;
|
|
372
|
+
point.type = CoverType.Block;
|
|
373
|
+
point.hash = hash(point);
|
|
374
|
+
const replacer = new RangeTransform(node);
|
|
375
|
+
const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({
|
|
365
376
|
file: "${point.file}",
|
|
366
377
|
hash: "${point.hash}",
|
|
367
378
|
line: ${point.line},
|
|
@@ -369,29 +380,28 @@ class CoverageTransform extends BaseVisitor {
|
|
|
369
380
|
type: "Block",
|
|
370
381
|
executed: false
|
|
371
382
|
})`);
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({
|
|
383
|
+
replacer.visit(registerStmt);
|
|
384
|
+
const coverStmt = SimpleParser.parseStatement(`__COVER("${point.hash}")`);
|
|
385
|
+
replacer.visit(coverStmt);
|
|
386
|
+
this.globalStatements.push(registerStmt);
|
|
387
|
+
super.visitSwitchCase(node);
|
|
388
|
+
node.statements.unshift(coverStmt);
|
|
389
|
+
}
|
|
390
|
+
visitBlockStatement(node) {
|
|
391
|
+
// @ts-ignore
|
|
392
|
+
if (node.visited) return;
|
|
393
|
+
// @ts-ignore
|
|
394
|
+
node.visited = true;
|
|
395
|
+
const path = node.range.source.normalizedPath;
|
|
396
|
+
const blockLc = getLineCol(node);
|
|
397
|
+
const point = new CoverPoint();
|
|
398
|
+
point.line = blockLc?.line;
|
|
399
|
+
point.column = blockLc?.column;
|
|
400
|
+
point.file = path;
|
|
401
|
+
point.type = CoverType.Block;
|
|
402
|
+
point.hash = hash(point);
|
|
403
|
+
const replacer = new RangeTransform(node);
|
|
404
|
+
const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({
|
|
395
405
|
file: "${point.file}",
|
|
396
406
|
hash: "${point.hash}",
|
|
397
407
|
line: ${point.line},
|
|
@@ -399,79 +409,60 @@ class CoverageTransform extends BaseVisitor {
|
|
|
399
409
|
type: "Block",
|
|
400
410
|
executed: false
|
|
401
411
|
})`);
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
413
|
-
class CoverageFinder extends BaseVisitor {
|
|
414
|
-
visitObjectLiteralExpression(node) {
|
|
415
|
-
for (let i = 0; i < node.names.length; i++) {
|
|
416
|
-
const name = node.names[i];
|
|
417
|
-
if (name.text === "coverage") {
|
|
418
|
-
const v = node.values[i];
|
|
419
|
-
if (v.kind === 25 /* NodeKind.True */) {
|
|
420
|
-
ENABLED = true;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
412
|
+
replacer.visit(registerStmt);
|
|
413
|
+
const coverStmt = SimpleParser.parseStatement(`__COVER("${point.hash}")`);
|
|
414
|
+
replacer.visit(coverStmt);
|
|
415
|
+
this.globalStatements.push(registerStmt);
|
|
416
|
+
super.visitBlockStatement(node);
|
|
417
|
+
node.statements.unshift(coverStmt);
|
|
418
|
+
}
|
|
419
|
+
visitSource(node) {
|
|
420
|
+
super.visitSource(node);
|
|
421
|
+
}
|
|
425
422
|
}
|
|
426
423
|
export default class Transformer extends Transform {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
424
|
+
// Trigger the transform after parse.
|
|
425
|
+
afterParse(parser) {
|
|
426
|
+
// Create new transform
|
|
427
|
+
const transformer = new CoverageTransform();
|
|
428
|
+
// Sort the sources so that user scripts are visited last
|
|
429
|
+
const sources = parser.sources
|
|
430
|
+
.filter((source) => !isStdlib(source))
|
|
431
|
+
.sort((_a, _b) => {
|
|
432
|
+
const a = _a.internalPath;
|
|
433
|
+
const b = _b.internalPath;
|
|
434
|
+
if (a[0] === "~" && b[0] !== "~") {
|
|
435
|
+
return -1;
|
|
436
|
+
} else if (a[0] !== "~" && b[0] === "~") {
|
|
437
|
+
return 1;
|
|
438
|
+
} else {
|
|
439
|
+
return 0;
|
|
434
440
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
// Loop over every source
|
|
456
|
-
for (const source of sources) {
|
|
457
|
-
if (source.isLibrary)
|
|
458
|
-
continue;
|
|
459
|
-
if (source.simplePath === "coverage")
|
|
460
|
-
continue;
|
|
461
|
-
// Ignore all lib and std. Visit everything else.
|
|
462
|
-
if (!isStdlib(source)) {
|
|
463
|
-
transformer.visit(source);
|
|
464
|
-
if (transformer.globalStatements.length) {
|
|
465
|
-
source.statements.unshift(...transformer.globalStatements);
|
|
466
|
-
const tokenizer = new Tokenizer(new Source(0 /* SourceKind.User */, source.normalizedPath, "import { __REGISTER, __COVER } from \"as-test/assembly/coverage\";"));
|
|
467
|
-
parser.currentSource = tokenizer.source;
|
|
468
|
-
source.statements.unshift(parser.parseTopLevelStatement(tokenizer));
|
|
469
|
-
parser.currentSource = source;
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
transformer.globalStatements = [];
|
|
441
|
+
});
|
|
442
|
+
// Loop over every source
|
|
443
|
+
for (const source of sources) {
|
|
444
|
+
if (source.isLibrary) continue;
|
|
445
|
+
if (source.simplePath === "coverage") continue;
|
|
446
|
+
// Ignore all lib and std. Visit everything else.
|
|
447
|
+
if (!isStdlib(source)) {
|
|
448
|
+
transformer.visit(source);
|
|
449
|
+
if (transformer.globalStatements.length) {
|
|
450
|
+
source.statements.unshift(...transformer.globalStatements);
|
|
451
|
+
const tokenizer = new Tokenizer(
|
|
452
|
+
new Source(
|
|
453
|
+
0 /* SourceKind.User */,
|
|
454
|
+
source.normalizedPath,
|
|
455
|
+
'import { __REGISTER, __COVER } from "as-test/assembly/coverage";',
|
|
456
|
+
),
|
|
457
|
+
);
|
|
458
|
+
parser.currentSource = tokenizer.source;
|
|
459
|
+
source.statements.unshift(parser.parseTopLevelStatement(tokenizer));
|
|
460
|
+
parser.currentSource = source;
|
|
473
461
|
}
|
|
462
|
+
}
|
|
463
|
+
transformer.globalStatements = [];
|
|
474
464
|
}
|
|
465
|
+
}
|
|
475
466
|
}
|
|
476
467
|
/**
|
|
477
468
|
* A simple djb2hash that returns a hash of a given string. See http://www.cse.yorku.ca/~oz/hash.html
|
|
@@ -481,28 +472,31 @@ export default class Transformer extends Transform {
|
|
|
481
472
|
* @returns {number} The hash of the string
|
|
482
473
|
*/
|
|
483
474
|
function djb2Hash(str) {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
475
|
+
const points = Array.from(str);
|
|
476
|
+
let h = 5381;
|
|
477
|
+
for (let p = 0; p < points.length; p++)
|
|
478
|
+
// h = (h * 31 + c) | 0;
|
|
479
|
+
h = ((h << 5) - h + points[p].codePointAt(0)) | 0;
|
|
480
|
+
return h;
|
|
490
481
|
}
|
|
491
482
|
function hash(point) {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
483
|
+
const hsh = djb2Hash(
|
|
484
|
+
point.file +
|
|
485
|
+
point.line.toString() +
|
|
486
|
+
point.column.toString() +
|
|
487
|
+
point.type.toString(),
|
|
488
|
+
);
|
|
489
|
+
if (hsh < 0) {
|
|
490
|
+
const out = hsh.toString(16);
|
|
491
|
+
return "3" + out.slice(1);
|
|
492
|
+
} else {
|
|
493
|
+
return hsh.toString(16);
|
|
494
|
+
}
|
|
502
495
|
}
|
|
496
|
+
class LineColumn {}
|
|
503
497
|
function getLineCol(node) {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
498
|
+
return {
|
|
499
|
+
line: node.range.source.lineAt(node.range.start),
|
|
500
|
+
column: node.range.source.columnAt(),
|
|
501
|
+
};
|
|
508
502
|
}
|