as-test 0.5.1 → 0.5.3
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.md +101 -0
- package/README.md +268 -3
- package/as-test.config.schema.json +171 -2
- package/assembly/coverage.ts +20 -0
- package/assembly/index.ts +196 -12
- package/assembly/src/expectation.ts +15 -29
- package/assembly/src/log.ts +13 -1
- package/assembly/src/suite.ts +53 -9
- package/assembly/src/tests.ts +25 -5
- package/assembly/util/helpers.ts +0 -1
- package/assembly/util/json.ts +78 -0
- package/bin/build.js +118 -33
- package/bin/index.js +524 -35
- package/bin/init.js +35 -10
- package/bin/reporters/default.js +26 -9
- package/bin/reporters/tap.js +294 -0
- package/bin/run.js +368 -44
- package/bin/types.js +18 -0
- package/bin/util.js +229 -1
- package/package.json +40 -50
- package/transform/lib/coverage.js +135 -124
- package/transform/lib/index.js +57 -23
- package/transform/lib/log.js +2 -39
- package/transform/lib/mock.js +42 -22
- package/transform/lib/builder.js.map +0 -1
- package/transform/lib/coverage.js.map +0 -1
- package/transform/lib/index.js.map +0 -1
- package/transform/lib/linker.js.map +0 -1
- package/transform/lib/location.js.map +0 -1
- package/transform/lib/log.js.map +0 -1
- package/transform/lib/mock.js.map +0 -1
- package/transform/lib/range.js.map +0 -1
- package/transform/lib/types.js.map +0 -1
- package/transform/lib/util.js.map +0 -1
- package/transform/lib/visitor.js.map +0 -1
|
@@ -12,7 +12,36 @@ const COVERAGE_IGNORED_CALLS = new Set([
|
|
|
12
12
|
"beforeAll",
|
|
13
13
|
"afterAll",
|
|
14
14
|
"mockFn",
|
|
15
|
+
"unmockFn",
|
|
15
16
|
"mockImport",
|
|
17
|
+
"unmockImport",
|
|
18
|
+
"snapshotImport",
|
|
19
|
+
"restoreImport",
|
|
20
|
+
]);
|
|
21
|
+
const COVERAGE_IGNORED_BUILTINS = new Set([
|
|
22
|
+
"alignof",
|
|
23
|
+
"changetype",
|
|
24
|
+
"idof",
|
|
25
|
+
"isArray",
|
|
26
|
+
"isArrayLike",
|
|
27
|
+
"isBoolean",
|
|
28
|
+
"isConstant",
|
|
29
|
+
"isDefined",
|
|
30
|
+
"isFloat",
|
|
31
|
+
"isFunction",
|
|
32
|
+
"isInteger",
|
|
33
|
+
"isManaged",
|
|
34
|
+
"isNullable",
|
|
35
|
+
"isReference",
|
|
36
|
+
"isSigned",
|
|
37
|
+
"isString",
|
|
38
|
+
"isUnsigned",
|
|
39
|
+
"load",
|
|
40
|
+
"nameof",
|
|
41
|
+
"offsetof",
|
|
42
|
+
"sizeof",
|
|
43
|
+
"store",
|
|
44
|
+
"unchecked",
|
|
16
45
|
]);
|
|
17
46
|
class CoverPoint {
|
|
18
47
|
file = "";
|
|
@@ -40,6 +69,7 @@ export class CoverageTransform extends Visitor {
|
|
|
40
69
|
}
|
|
41
70
|
super.visitCallExpression(node);
|
|
42
71
|
}
|
|
72
|
+
visitDecoratorNode(_node, _ref) { }
|
|
43
73
|
visitBinaryExpression(node) {
|
|
44
74
|
super.visitBinaryExpression(node);
|
|
45
75
|
if (node.visited)
|
|
@@ -50,6 +80,8 @@ export class CoverageTransform extends Visitor {
|
|
|
50
80
|
case 98:
|
|
51
81
|
case 97: {
|
|
52
82
|
const right = node.right;
|
|
83
|
+
if (isBuiltinCallExpression(right))
|
|
84
|
+
break;
|
|
53
85
|
const rightLc = getLineCol(node);
|
|
54
86
|
const point = new CoverPoint();
|
|
55
87
|
point.line = rightLc?.line;
|
|
@@ -58,18 +90,10 @@ export class CoverageTransform extends Visitor {
|
|
|
58
90
|
point.type = CoverType.Expression;
|
|
59
91
|
point.hash = hash(point);
|
|
60
92
|
const replacer = new RangeTransform(node);
|
|
61
|
-
const registerStmt =
|
|
62
|
-
file: "${point.file}",
|
|
63
|
-
hash: "${point.hash}",
|
|
64
|
-
line: ${point.line},
|
|
65
|
-
column: ${point.column},
|
|
66
|
-
type: "Expression",
|
|
67
|
-
executed: false
|
|
68
|
-
});`);
|
|
93
|
+
const registerStmt = createRegisterStatement(point);
|
|
69
94
|
replacer.visit(registerStmt);
|
|
70
|
-
const coverExpression =
|
|
95
|
+
const coverExpression = createCoverExpression(point.hash, right, node);
|
|
71
96
|
replacer.visit(coverExpression);
|
|
72
|
-
coverExpression.expression.expressions[1] = right;
|
|
73
97
|
node.right = coverExpression;
|
|
74
98
|
this.globalStatements.push(registerStmt);
|
|
75
99
|
break;
|
|
@@ -94,16 +118,9 @@ export class CoverageTransform extends Visitor {
|
|
|
94
118
|
point.type = CoverType.Function;
|
|
95
119
|
point.hash = hash(point);
|
|
96
120
|
const replacer = new RangeTransform(node);
|
|
97
|
-
const registerStmt =
|
|
98
|
-
file: "${point.file}",
|
|
99
|
-
hash: "${point.hash}",
|
|
100
|
-
line: ${point.line},
|
|
101
|
-
column: ${point.column},
|
|
102
|
-
type: "Function",
|
|
103
|
-
executed: false
|
|
104
|
-
})`);
|
|
121
|
+
const registerStmt = createRegisterStatement(point);
|
|
105
122
|
replacer.visit(registerStmt);
|
|
106
|
-
const coverStmt =
|
|
123
|
+
const coverStmt = createCoverStatement(point.hash, node);
|
|
107
124
|
replacer.visit(coverStmt);
|
|
108
125
|
const bodyBlock = node.body;
|
|
109
126
|
bodyBlock.statements.unshift(coverStmt);
|
|
@@ -120,6 +137,8 @@ export class CoverageTransform extends Visitor {
|
|
|
120
137
|
return;
|
|
121
138
|
node.initializer.visited = true;
|
|
122
139
|
super.visitParameter(node);
|
|
140
|
+
if (isBuiltinCallExpression(node.initializer))
|
|
141
|
+
return;
|
|
123
142
|
const paramLc = getLineCol(node.initializer);
|
|
124
143
|
const point = new CoverPoint();
|
|
125
144
|
point.line = paramLc?.line;
|
|
@@ -128,19 +147,10 @@ export class CoverageTransform extends Visitor {
|
|
|
128
147
|
point.type = CoverType.Expression;
|
|
129
148
|
point.hash = hash(point);
|
|
130
149
|
const replacer = new RangeTransform(node);
|
|
131
|
-
const registerStmt =
|
|
132
|
-
file: "${point.file}",
|
|
133
|
-
hash: "${point.hash}",
|
|
134
|
-
line: ${point.line},
|
|
135
|
-
column: ${point.column},
|
|
136
|
-
type: "Expression",
|
|
137
|
-
executed: false
|
|
138
|
-
})`);
|
|
150
|
+
const registerStmt = createRegisterStatement(point);
|
|
139
151
|
replacer.visit(registerStmt);
|
|
140
|
-
const coverExpression =
|
|
152
|
+
const coverExpression = createCoverExpression(point.hash, node.initializer, node);
|
|
141
153
|
replacer.visit(coverExpression);
|
|
142
|
-
coverExpression.expression.expressions[1] =
|
|
143
|
-
node.initializer;
|
|
144
154
|
node.initializer = coverExpression;
|
|
145
155
|
this.globalStatements.push(registerStmt);
|
|
146
156
|
}
|
|
@@ -163,14 +173,7 @@ export class CoverageTransform extends Visitor {
|
|
|
163
173
|
point.type = CoverType.Function;
|
|
164
174
|
point.hash = hash(point);
|
|
165
175
|
const replacer = new RangeTransform(node);
|
|
166
|
-
const registerStmt =
|
|
167
|
-
file: "${point.file}",
|
|
168
|
-
hash: "${point.hash}",
|
|
169
|
-
line: ${point.line},
|
|
170
|
-
column: ${point.column},
|
|
171
|
-
type: "Function",
|
|
172
|
-
executed: false
|
|
173
|
-
})`);
|
|
176
|
+
const registerStmt = createRegisterStatement(point);
|
|
174
177
|
replacer.visit(registerStmt);
|
|
175
178
|
this.globalStatements.push(registerStmt);
|
|
176
179
|
if (node.body.kind === 35) {
|
|
@@ -186,7 +189,7 @@ export class CoverageTransform extends Visitor {
|
|
|
186
189
|
node.body = body;
|
|
187
190
|
}
|
|
188
191
|
else {
|
|
189
|
-
const coverStmt =
|
|
192
|
+
const coverStmt = createCoverStatement(point.hash, node);
|
|
190
193
|
replacer.visit(coverStmt);
|
|
191
194
|
if (node.body instanceof BlockStatement) {
|
|
192
195
|
node.body.statements.unshift(coverStmt);
|
|
@@ -209,7 +212,7 @@ export class CoverageTransform extends Visitor {
|
|
|
209
212
|
const ifTrue = node.ifTrue;
|
|
210
213
|
const ifFalse = node.ifFalse;
|
|
211
214
|
const path = node.range.source.normalizedPath;
|
|
212
|
-
if (ifTrue.kind !== 30) {
|
|
215
|
+
if (ifTrue.kind !== 30 && !isBuiltinStatement(ifTrue)) {
|
|
213
216
|
const trueLc = getLineCol(ifTrue);
|
|
214
217
|
const point = new CoverPoint();
|
|
215
218
|
point.line = trueLc?.line;
|
|
@@ -218,16 +221,9 @@ export class CoverageTransform extends Visitor {
|
|
|
218
221
|
point.type = CoverType.Expression;
|
|
219
222
|
point.hash = hash(point);
|
|
220
223
|
const replacer = new RangeTransform(ifTrue);
|
|
221
|
-
const registerStmt =
|
|
222
|
-
file: "${point.file}",
|
|
223
|
-
hash: "${point.hash}",
|
|
224
|
-
line: ${point.line},
|
|
225
|
-
column: ${point.column},
|
|
226
|
-
type: "Expression",
|
|
227
|
-
executed: false
|
|
228
|
-
})`);
|
|
224
|
+
const registerStmt = createRegisterStatement(point);
|
|
229
225
|
replacer.visit(registerStmt);
|
|
230
|
-
const coverStmt =
|
|
226
|
+
const coverStmt = Node.createBlockStatement([createCoverStatement(point.hash, ifTrue)], ifTrue.range);
|
|
231
227
|
replacer.visit(coverStmt);
|
|
232
228
|
coverStmt.statements.push(ifTrue);
|
|
233
229
|
node.ifTrue = coverStmt;
|
|
@@ -235,7 +231,9 @@ export class CoverageTransform extends Visitor {
|
|
|
235
231
|
visitIfTrue = true;
|
|
236
232
|
visitIfFalse = !!ifFalse;
|
|
237
233
|
}
|
|
238
|
-
if (ifFalse &&
|
|
234
|
+
if (ifFalse &&
|
|
235
|
+
ifFalse.kind !== 30 &&
|
|
236
|
+
!isBuiltinStatement(ifFalse)) {
|
|
239
237
|
const falseLc = getLineCol(ifFalse);
|
|
240
238
|
const point = new CoverPoint();
|
|
241
239
|
point.line = falseLc?.line;
|
|
@@ -243,17 +241,10 @@ export class CoverageTransform extends Visitor {
|
|
|
243
241
|
point.file = path;
|
|
244
242
|
point.type = CoverType.Expression;
|
|
245
243
|
point.hash = hash(point);
|
|
246
|
-
const replacer = new RangeTransform(
|
|
247
|
-
const registerStmt =
|
|
248
|
-
file: "${point.file}",
|
|
249
|
-
hash: "${point.hash}",
|
|
250
|
-
line: ${point.line},
|
|
251
|
-
column: ${point.column},
|
|
252
|
-
type: "Expression",
|
|
253
|
-
executed: false
|
|
254
|
-
})`);
|
|
244
|
+
const replacer = new RangeTransform(ifFalse);
|
|
245
|
+
const registerStmt = createRegisterStatement(point);
|
|
255
246
|
replacer.visit(registerStmt);
|
|
256
|
-
const coverStmt =
|
|
247
|
+
const coverStmt = Node.createBlockStatement([createCoverStatement(point.hash, ifFalse)], ifFalse.range);
|
|
257
248
|
replacer.visit(coverStmt);
|
|
258
249
|
coverStmt.statements.push(ifFalse);
|
|
259
250
|
node.ifFalse = coverStmt;
|
|
@@ -288,54 +279,40 @@ export class CoverageTransform extends Visitor {
|
|
|
288
279
|
const falseExpression = node.ifElse;
|
|
289
280
|
const path = node.range.source.normalizedPath;
|
|
290
281
|
{
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
replacer.visit(registerStmt);
|
|
308
|
-
const coverExpression = SimpleParser.parseExpression(`(__COVER("${point.hash}"), $$REPLACE_ME)`);
|
|
309
|
-
replacer.visit(coverExpression);
|
|
310
|
-
coverExpression.expression.expressions[1] =
|
|
311
|
-
trueExpression;
|
|
312
|
-
node.ifThen = coverExpression;
|
|
313
|
-
this.globalStatements.push(registerStmt);
|
|
282
|
+
if (!isBuiltinCallExpression(trueExpression)) {
|
|
283
|
+
const trueLc = getLineCol(trueExpression);
|
|
284
|
+
const point = new CoverPoint();
|
|
285
|
+
point.line = trueLc?.line;
|
|
286
|
+
point.column = trueLc?.column;
|
|
287
|
+
point.file = path;
|
|
288
|
+
point.type = CoverType.Expression;
|
|
289
|
+
point.hash = hash(point);
|
|
290
|
+
const replacer = new RangeTransform(trueExpression);
|
|
291
|
+
const registerStmt = createRegisterStatement(point);
|
|
292
|
+
replacer.visit(registerStmt);
|
|
293
|
+
const coverExpression = createCoverExpression(point.hash, trueExpression, trueExpression);
|
|
294
|
+
replacer.visit(coverExpression);
|
|
295
|
+
node.ifThen = coverExpression;
|
|
296
|
+
this.globalStatements.push(registerStmt);
|
|
297
|
+
}
|
|
314
298
|
}
|
|
315
299
|
{
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
replacer.visit(registerStmt);
|
|
333
|
-
const coverExpression = SimpleParser.parseExpression(`(__COVER("${point.hash}"), $$REPLACE_ME)`);
|
|
334
|
-
replacer.visit(coverExpression);
|
|
335
|
-
coverExpression.expression.expressions[1] =
|
|
336
|
-
falseExpression;
|
|
337
|
-
node.ifElse = coverExpression;
|
|
338
|
-
this.globalStatements.push(registerStmt);
|
|
300
|
+
if (!isBuiltinCallExpression(falseExpression)) {
|
|
301
|
+
const falseLc = getLineCol(falseExpression);
|
|
302
|
+
const point = new CoverPoint();
|
|
303
|
+
point.line = falseLc?.line;
|
|
304
|
+
point.column = falseLc?.column;
|
|
305
|
+
point.file = path;
|
|
306
|
+
point.type = CoverType.Expression;
|
|
307
|
+
point.hash = hash(point);
|
|
308
|
+
const replacer = new RangeTransform(falseExpression);
|
|
309
|
+
const registerStmt = createRegisterStatement(point);
|
|
310
|
+
replacer.visit(registerStmt);
|
|
311
|
+
const coverExpression = createCoverExpression(point.hash, falseExpression, falseExpression);
|
|
312
|
+
replacer.visit(coverExpression);
|
|
313
|
+
node.ifElse = coverExpression;
|
|
314
|
+
this.globalStatements.push(registerStmt);
|
|
315
|
+
}
|
|
339
316
|
}
|
|
340
317
|
}
|
|
341
318
|
visitSwitchCase(node) {
|
|
@@ -351,16 +328,9 @@ export class CoverageTransform extends Visitor {
|
|
|
351
328
|
point.type = CoverType.Block;
|
|
352
329
|
point.hash = hash(point);
|
|
353
330
|
const replacer = new RangeTransform(node);
|
|
354
|
-
const registerStmt =
|
|
355
|
-
file: "${point.file}",
|
|
356
|
-
hash: "${point.hash}",
|
|
357
|
-
line: ${point.line},
|
|
358
|
-
column: ${point.column},
|
|
359
|
-
type: "Block",
|
|
360
|
-
executed: false
|
|
361
|
-
})`);
|
|
331
|
+
const registerStmt = createRegisterStatement(point);
|
|
362
332
|
replacer.visit(registerStmt);
|
|
363
|
-
const coverStmt =
|
|
333
|
+
const coverStmt = createCoverStatement(point.hash, node);
|
|
364
334
|
replacer.visit(coverStmt);
|
|
365
335
|
this.globalStatements.push(registerStmt);
|
|
366
336
|
super.visitSwitchCase(node);
|
|
@@ -383,16 +353,9 @@ export class CoverageTransform extends Visitor {
|
|
|
383
353
|
point.type = CoverType.Block;
|
|
384
354
|
point.hash = hash(point);
|
|
385
355
|
const replacer = new RangeTransform(node);
|
|
386
|
-
const registerStmt =
|
|
387
|
-
file: "${point.file}",
|
|
388
|
-
hash: "${point.hash}",
|
|
389
|
-
line: ${point.line},
|
|
390
|
-
column: ${point.column},
|
|
391
|
-
type: "Block",
|
|
392
|
-
executed: false
|
|
393
|
-
})`);
|
|
356
|
+
const registerStmt = createRegisterStatement(point);
|
|
394
357
|
replacer.visit(registerStmt);
|
|
395
|
-
const coverStmt =
|
|
358
|
+
const coverStmt = createCoverStatement(point.hash, node);
|
|
396
359
|
replacer.visit(coverStmt);
|
|
397
360
|
this.globalStatements.push(registerStmt);
|
|
398
361
|
super.visitBlockStatement(node);
|
|
@@ -411,6 +374,29 @@ export class CoverageTransform extends Visitor {
|
|
|
411
374
|
function getCallName(node) {
|
|
412
375
|
return getExpressionName(node.expression);
|
|
413
376
|
}
|
|
377
|
+
function isBuiltinStatement(node) {
|
|
378
|
+
if (node.kind !== 38)
|
|
379
|
+
return false;
|
|
380
|
+
return isBuiltinCallExpression(node.expression);
|
|
381
|
+
}
|
|
382
|
+
function isBuiltinCallExpression(node) {
|
|
383
|
+
const unwrapped = unwrapParenthesized(node);
|
|
384
|
+
if (unwrapped.kind !== 9)
|
|
385
|
+
return false;
|
|
386
|
+
const call = unwrapped;
|
|
387
|
+
const expression = unwrapParenthesized(call.expression);
|
|
388
|
+
if (expression.kind !== 6)
|
|
389
|
+
return false;
|
|
390
|
+
const name = expression.text;
|
|
391
|
+
return COVERAGE_IGNORED_BUILTINS.has(name);
|
|
392
|
+
}
|
|
393
|
+
function unwrapParenthesized(node) {
|
|
394
|
+
let current = node;
|
|
395
|
+
while (current.kind === 20) {
|
|
396
|
+
current = current.expression;
|
|
397
|
+
}
|
|
398
|
+
return current;
|
|
399
|
+
}
|
|
414
400
|
function getExpressionName(node) {
|
|
415
401
|
switch (node.kind) {
|
|
416
402
|
case 6:
|
|
@@ -453,6 +439,31 @@ function getLineCol(node) {
|
|
|
453
439
|
column: node.range.source.columnAt(),
|
|
454
440
|
};
|
|
455
441
|
}
|
|
442
|
+
function createRegisterStatement(point) {
|
|
443
|
+
return SimpleParser.parseTopLevelStatement(`__REGISTER_RAW(${asStringLiteral(point.file)}, ${asStringLiteral(point.hash)}, ${point.line}, ${point.column}, ${asStringLiteral(coverTypeToString(point.type))})`);
|
|
444
|
+
}
|
|
445
|
+
function createCoverStatement(hashValue, ref) {
|
|
446
|
+
return Node.createExpressionStatement(createCoverCallExpression(hashValue, ref));
|
|
447
|
+
}
|
|
448
|
+
function createCoverExpression(hashValue, replacement, ref) {
|
|
449
|
+
return Node.createParenthesizedExpression(Node.createCommaExpression([createCoverCallExpression(hashValue, ref), replacement], ref.range), ref.range);
|
|
450
|
+
}
|
|
451
|
+
function createCoverCallExpression(hashValue, ref) {
|
|
452
|
+
return Node.createCallExpression(Node.createIdentifierExpression("__COVER", ref.range), null, [Node.createStringLiteralExpression(hashValue, ref.range)], ref.range);
|
|
453
|
+
}
|
|
454
|
+
function coverTypeToString(type) {
|
|
455
|
+
switch (type) {
|
|
456
|
+
case CoverType.Function:
|
|
457
|
+
return "Function";
|
|
458
|
+
case CoverType.Expression:
|
|
459
|
+
return "Expression";
|
|
460
|
+
default:
|
|
461
|
+
return "Block";
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
function asStringLiteral(value) {
|
|
465
|
+
return JSON.stringify(value);
|
|
466
|
+
}
|
|
456
467
|
function isConcreteSourceBlock(node) {
|
|
457
468
|
const source = node.range.source;
|
|
458
469
|
const start = node.range.start;
|
package/transform/lib/index.js
CHANGED
|
@@ -8,9 +8,9 @@ import { isStdlib } from "./util.js";
|
|
|
8
8
|
export default class Transformer extends Transform {
|
|
9
9
|
afterParse(parser) {
|
|
10
10
|
const mock = new MockTransform();
|
|
11
|
-
const coverage = new CoverageTransform();
|
|
12
11
|
const location = new LocationTransform();
|
|
13
12
|
const log = new LogTransform(parser);
|
|
13
|
+
const coverage = isCoverageEnabled() ? new CoverageTransform() : null;
|
|
14
14
|
const sources = parser.sources
|
|
15
15
|
.filter((source) => !isStdlib(source))
|
|
16
16
|
.sort((_a, _b) => {
|
|
@@ -27,19 +27,31 @@ export default class Transformer extends Transform {
|
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
29
|
const entryFile = sources.find((v) => v.sourceKind == 1).simplePath;
|
|
30
|
+
const mockedImportTargets = collectMockImportTargets(sources);
|
|
31
|
+
for (const target of mockedImportTargets) {
|
|
32
|
+
mock.importMocked.add(target);
|
|
33
|
+
}
|
|
30
34
|
for (const source of sources) {
|
|
35
|
+
const sourceInfo = analyzeSourceText(source.text);
|
|
31
36
|
const shouldInjectRunCall = source.sourceKind == 1 &&
|
|
32
|
-
|
|
37
|
+
sourceInfo.hasSuiteCalls &&
|
|
38
|
+
!sourceInfo.hasRunCall;
|
|
33
39
|
const node = Node.createVariableStatement(null, [
|
|
34
40
|
Node.createVariableDeclaration(Node.createIdentifierExpression("ENTRY_FILE", source.range), null, 8, null, Node.createStringLiteralExpression(entryFile + ".ts", source.range), source.range),
|
|
35
41
|
], source.range);
|
|
36
42
|
source.statements.unshift(node);
|
|
37
43
|
mock.visit(source);
|
|
38
|
-
coverage
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
if (coverage) {
|
|
45
|
+
coverage.visit(source);
|
|
46
|
+
}
|
|
47
|
+
if (sourceInfo.hasExpectCall) {
|
|
48
|
+
location.visit(source);
|
|
49
|
+
}
|
|
50
|
+
if (sourceInfo.hasLogCall) {
|
|
51
|
+
log.visit(source);
|
|
52
|
+
}
|
|
41
53
|
if (shouldInjectRunCall) {
|
|
42
|
-
const runImportPath =
|
|
54
|
+
const runImportPath = sourceInfo.runImportPath;
|
|
43
55
|
let runCall = "run();";
|
|
44
56
|
if (runImportPath) {
|
|
45
57
|
const autoImport = new Tokenizer(new Source(0, source.normalizedPath, `import { run as __as_test_auto_run } from "${runImportPath}";`));
|
|
@@ -52,31 +64,51 @@ export default class Transformer extends Transform {
|
|
|
52
64
|
source.statements.push(parser.parseTopLevelStatement(autoCall));
|
|
53
65
|
parser.currentSource = source;
|
|
54
66
|
}
|
|
55
|
-
if (coverage.globalStatements.length) {
|
|
67
|
+
if (coverage && coverage.globalStatements.length) {
|
|
56
68
|
source.statements.unshift(...coverage.globalStatements);
|
|
57
|
-
const tokenizer = new Tokenizer(new Source(0, source.normalizedPath, 'import {
|
|
69
|
+
const tokenizer = new Tokenizer(new Source(0, source.normalizedPath, 'import { __REGISTER_RAW, __COVER } from "as-test/assembly/coverage";'));
|
|
58
70
|
parser.currentSource = tokenizer.source;
|
|
59
71
|
source.statements.unshift(parser.parseTopLevelStatement(tokenizer));
|
|
60
72
|
parser.currentSource = source;
|
|
73
|
+
coverage.globalStatements = [];
|
|
61
74
|
}
|
|
62
75
|
}
|
|
63
|
-
coverage
|
|
76
|
+
if (coverage) {
|
|
77
|
+
coverage.globalStatements = [];
|
|
78
|
+
}
|
|
64
79
|
}
|
|
65
80
|
}
|
|
66
|
-
function
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
81
|
+
function collectMockImportTargets(sources) {
|
|
82
|
+
const out = new Set();
|
|
83
|
+
const pattern = /\bmockImport\s*\(\s*["']([^"']+)["']/g;
|
|
84
|
+
for (const source of sources) {
|
|
85
|
+
const text = stripComments(source.text);
|
|
86
|
+
for (const match of text.matchAll(pattern)) {
|
|
87
|
+
const target = (match[1] ?? "").trim();
|
|
88
|
+
if (!target.length)
|
|
89
|
+
continue;
|
|
90
|
+
out.add(target);
|
|
91
|
+
}
|
|
74
92
|
}
|
|
75
|
-
|
|
76
|
-
return !hasRunCall;
|
|
93
|
+
return out;
|
|
77
94
|
}
|
|
78
|
-
function
|
|
95
|
+
function analyzeSourceText(sourceText) {
|
|
79
96
|
const text = stripComments(sourceText);
|
|
97
|
+
const runImportPath = detectRunImportPath(text);
|
|
98
|
+
const runAlias = detectRunAlias(text);
|
|
99
|
+
const hasRunCall = runAlias
|
|
100
|
+
? new RegExp(`\\b${escapeRegex(runAlias)}\\s*\\(`).test(text)
|
|
101
|
+
: /\brun\s*\(/.test(text);
|
|
102
|
+
return {
|
|
103
|
+
hasSuiteCalls: /\b(?:describe|test|it)\s*\(/.test(text),
|
|
104
|
+
hasRunCall,
|
|
105
|
+
runImportPath,
|
|
106
|
+
hasMockCalls: /\b(?:mockFn|unmockFn|mockImport|unmockImport)\s*\(/.test(text),
|
|
107
|
+
hasLogCall: /\blog\s*\(/.test(text),
|
|
108
|
+
hasExpectCall: /\bexpect\s*\(/.test(text),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function detectRunImportPath(text) {
|
|
80
112
|
const imports = text.matchAll(/import\s*\{([^}]+)\}\s*from\s*["']([^"']+)["']/g);
|
|
81
113
|
for (const match of imports) {
|
|
82
114
|
const specifiers = match[1] ?? "";
|
|
@@ -88,8 +120,7 @@ function detectRunImportPath(sourceText) {
|
|
|
88
120
|
}
|
|
89
121
|
return null;
|
|
90
122
|
}
|
|
91
|
-
function detectRunAlias(
|
|
92
|
-
const text = stripComments(sourceText);
|
|
123
|
+
function detectRunAlias(text) {
|
|
93
124
|
const imports = text.matchAll(/import\s*\{([^}]+)\}\s*from\s*["']([^"']+)["']/g);
|
|
94
125
|
for (const match of imports) {
|
|
95
126
|
const specifiers = match[1] ?? "";
|
|
@@ -103,7 +134,7 @@ function detectRunAlias(sourceText) {
|
|
|
103
134
|
return null;
|
|
104
135
|
}
|
|
105
136
|
function looksLikeAsTestImport(specifiers) {
|
|
106
|
-
return /\b(?:describe|test|it|expect|beforeAll|afterAll|beforeEach|afterEach|mockFn|mockImport|log|run)\b/.test(specifiers);
|
|
137
|
+
return /\b(?:describe|test|it|expect|beforeAll|afterAll|beforeEach|afterEach|mockFn|unmockFn|mockImport|unmockImport|snapshotImport|restoreImport|log|run)\b/.test(specifiers);
|
|
107
138
|
}
|
|
108
139
|
function stripComments(sourceText) {
|
|
109
140
|
return sourceText.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
|
|
@@ -111,4 +142,7 @@ function stripComments(sourceText) {
|
|
|
111
142
|
function escapeRegex(value) {
|
|
112
143
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
113
144
|
}
|
|
145
|
+
function isCoverageEnabled() {
|
|
146
|
+
return process.env.AS_TEST_COVERAGE_ENABLED !== "0";
|
|
147
|
+
}
|
|
114
148
|
//# sourceMappingURL=index.js.map
|
package/transform/lib/log.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Node, Source, Tokenizer, } from "assemblyscript/dist/assemblyscript.js";
|
|
2
2
|
import { Visitor } from "./visitor.js";
|
|
3
3
|
import { toString } from "./util.js";
|
|
4
|
-
const LOG_VALUE_FN = "__as_test_log_value";
|
|
5
4
|
const LOG_CALL_FN = "__as_test_log_call";
|
|
6
5
|
const LOG_ENABLED_IMPORT = "__as_test_log_is_enabled_internal";
|
|
7
6
|
const LOG_SERIALIZED_IMPORT = "__as_test_log_serialized_internal";
|
|
@@ -11,7 +10,6 @@ export class LogTransform extends Visitor {
|
|
|
11
10
|
activeSource = null;
|
|
12
11
|
touchedSource = null;
|
|
13
12
|
hasLogCalls = false;
|
|
14
|
-
classNames = [];
|
|
15
13
|
constructor(parser) {
|
|
16
14
|
super();
|
|
17
15
|
this.parser = parser;
|
|
@@ -22,7 +20,6 @@ export class LogTransform extends Visitor {
|
|
|
22
20
|
this.activeSource = node;
|
|
23
21
|
this.touchedSource = node;
|
|
24
22
|
this.hasLogCalls = false;
|
|
25
|
-
this.classNames = [];
|
|
26
23
|
super.visitSource(node);
|
|
27
24
|
if (!this.hasLogCalls) {
|
|
28
25
|
this.activeSource = null;
|
|
@@ -34,18 +31,7 @@ export class LogTransform extends Visitor {
|
|
|
34
31
|
this.parser.currentSource = tokenizer.source;
|
|
35
32
|
node.statements.unshift(this.parser.parseTopLevelStatement(tokenizer));
|
|
36
33
|
this.parser.currentSource = node;
|
|
37
|
-
const
|
|
38
|
-
this.parser.currentSource = jsonTokenizer.source;
|
|
39
|
-
node.statements.unshift(this.parser.parseTopLevelStatement(jsonTokenizer));
|
|
40
|
-
this.parser.currentSource = node;
|
|
41
|
-
const classFallbackLines = this.classNames
|
|
42
|
-
.map((className) => `if (idof<nonnull<T>>() == idof<${className}>()) return JSON.stringify<${className}>(changetype<${className}>(value));`)
|
|
43
|
-
.join(" ");
|
|
44
|
-
const genericTokenizer = new Tokenizer(new Source(0, node.normalizedPath, `function ${LOG_VALUE_FN}<T>(value: T): string { const formatted = ${LOG_DEFAULT_IMPORT}<T>(value); if (formatted != "none") return formatted; if (isReference<T>()) { ${classFallbackLines} } return formatted; }`));
|
|
45
|
-
this.parser.currentSource = genericTokenizer.source;
|
|
46
|
-
node.statements.push(this.parser.parseTopLevelStatement(genericTokenizer));
|
|
47
|
-
this.parser.currentSource = node;
|
|
48
|
-
const callTokenizer = new Tokenizer(new Source(0, node.normalizedPath, `function ${LOG_CALL_FN}<T>(value: T): void { if (!${LOG_ENABLED_IMPORT}()) return; ${LOG_SERIALIZED_IMPORT}(${LOG_VALUE_FN}(value)); }`));
|
|
34
|
+
const callTokenizer = new Tokenizer(new Source(0, node.normalizedPath, `function ${LOG_CALL_FN}<T>(value: T): void { if (!${LOG_ENABLED_IMPORT}()) return; ${LOG_SERIALIZED_IMPORT}(${LOG_DEFAULT_IMPORT}<T>(value)); }`));
|
|
49
35
|
this.parser.currentSource = callTokenizer.source;
|
|
50
36
|
node.statements.push(this.parser.parseTopLevelStatement(callTokenizer));
|
|
51
37
|
this.parser.currentSource = node;
|
|
@@ -65,34 +51,11 @@ export class LogTransform extends Visitor {
|
|
|
65
51
|
node.args[0] = arg;
|
|
66
52
|
this.hasLogCalls = true;
|
|
67
53
|
}
|
|
68
|
-
visitClassDeclaration(node, isDefault = false) {
|
|
69
|
-
super.visitClassDeclaration(node, isDefault);
|
|
70
|
-
if (!this.activeSource || this.touchedSource !== this.activeSource)
|
|
71
|
-
return;
|
|
72
|
-
if (!node.name)
|
|
73
|
-
return;
|
|
74
|
-
if (node.flags & 32768)
|
|
75
|
-
return;
|
|
76
|
-
if (node.decorators?.some((decorator) => isDecoratorNamed(decorator, "json")))
|
|
77
|
-
return;
|
|
78
|
-
if (node.decorators?.some((decorator) => isDecoratorNamed(decorator, "unmanaged")))
|
|
79
|
-
return;
|
|
80
|
-
const className = node.name.text;
|
|
81
|
-
if (!this.classNames.includes(className)) {
|
|
82
|
-
this.classNames.push(className);
|
|
83
|
-
}
|
|
84
|
-
const decorators = node.decorators ? [...node.decorators] : [];
|
|
85
|
-
decorators.unshift(Node.createDecorator(Node.createIdentifierExpression("json", node.range), [], node.range));
|
|
86
|
-
node.decorators = decorators;
|
|
87
|
-
}
|
|
88
54
|
}
|
|
89
55
|
function isUserSource(source) {
|
|
90
56
|
return (source.sourceKind === 0 ||
|
|
91
57
|
source.sourceKind === 1);
|
|
92
58
|
}
|
|
93
|
-
function isDecoratorNamed(node, name) {
|
|
94
|
-
return toString(node.name) === name;
|
|
95
|
-
}
|
|
96
59
|
function detectAsTestImportPath(sourceText) {
|
|
97
60
|
const text = stripComments(sourceText);
|
|
98
61
|
const imports = text.matchAll(/import\s*\{([^}]+)\}\s*from\s*["']([^"']+)["']/g);
|
|
@@ -110,7 +73,7 @@ function detectAsTestImportPath(sourceText) {
|
|
|
110
73
|
function looksLikeAsTestImport(specifiers, modulePath) {
|
|
111
74
|
if (modulePath === "as-test" || modulePath.endsWith("/as-test"))
|
|
112
75
|
return true;
|
|
113
|
-
return /\b(?:describe|test|it|expect|beforeAll|afterAll|beforeEach|afterEach|mockFn|mockImport|log|run)\b/.test(specifiers);
|
|
76
|
+
return /\b(?:describe|test|it|expect|beforeAll|afterAll|beforeEach|afterEach|mockFn|unmockFn|mockImport|unmockImport|snapshotImport|restoreImport|log|run)\b/.test(specifiers);
|
|
114
77
|
}
|
|
115
78
|
function stripComments(sourceText) {
|
|
116
79
|
return sourceText.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
|