as-test 0.1.7 → 0.1.9

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.
@@ -0,0 +1,502 @@
1
+ import { Transform } from "assemblyscript/dist/transform.js";
2
+ import {
3
+ Source,
4
+ BlockStatement,
5
+ ExpressionStatement,
6
+ Node,
7
+ Tokenizer,
8
+ } from "assemblyscript/dist/assemblyscript.js";
9
+ import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js";
10
+ import { isStdlib } from "visitor-as/dist/utils.js";
11
+ import { RangeTransform } from "visitor-as/dist/transformRange.js";
12
+ var CoverType;
13
+ (function (CoverType) {
14
+ CoverType[(CoverType["Function"] = 0)] = "Function";
15
+ CoverType[(CoverType["Expression"] = 1)] = "Expression";
16
+ CoverType[(CoverType["Block"] = 2)] = "Block";
17
+ })(CoverType || (CoverType = {}));
18
+ class CoverPoint {
19
+ constructor() {
20
+ this.file = "";
21
+ this.hash = "";
22
+ this.line = 0;
23
+ this.column = 0;
24
+ this.executed = false;
25
+ }
26
+ }
27
+ class CoverageTransform extends BaseVisitor {
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({
54
+ file: "${point.file}",
55
+ hash: "${point.hash}",
56
+ line: ${point.line},
57
+ column: ${point.column},
58
+ type: "Expression",
59
+ executed: false
60
+ });`);
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
+ }
71
+ }
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({
94
+ file: "${point.file}",
95
+ hash: "${point.hash}",
96
+ line: ${point.line},
97
+ column: ${point.column},
98
+ type: "Function",
99
+ executed: false
100
+ })`);
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);
110
+ }
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({
133
+ file: "${point.file}",
134
+ hash: "${point.hash}",
135
+ line: ${point.line},
136
+ column: ${point.column},
137
+ type: "Expression",
138
+ executed: false
139
+ })`);
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);
148
+ }
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({
171
+ file: "${point.file}",
172
+ hash: "${point.hash}",
173
+ line: ${point.line},
174
+ column: ${point.column},
175
+ type: "Function",
176
+ executed: false
177
+ })`);
178
+ replacer.visit(registerStmt);
179
+ this.globalStatements.push(registerStmt);
180
+ if (node.body.kind === 35 /* NodeKind.Export */) {
181
+ const coverStmt = SimpleParser.parseStatement(`{
182
+ __COVER("${point.hash}")
183
+ return $$REPLACE_ME
184
+ }`);
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);
208
+ }
209
+ }
210
+ }
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({
232
+ file: "${point.file}",
233
+ hash: "${point.hash}",
234
+ line: ${point.line},
235
+ column: ${point.column},
236
+ type: "Expression",
237
+ executed: false
238
+ })`);
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({
261
+ file: "${point.file}",
262
+ hash: "${point.hash}",
263
+ line: ${point.line},
264
+ column: ${point.column},
265
+ type: "Expression",
266
+ executed: false
267
+ })`);
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;
279
+ }
280
+ if (visitIfTrue || visitIfFalse) {
281
+ if (visitIfTrue) {
282
+ // @ts-ignore
283
+ if (ifTrue.visited) return;
284
+ // @ts-ignore
285
+ ifTrue.visited = true;
286
+ this._visit(ifTrue);
287
+ }
288
+ if (visitIfFalse) {
289
+ // @ts-ignore
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({
318
+ file: "${point.file}",
319
+ hash: "${point.hash}",
320
+ line: ${point.line},
321
+ column: ${point.column},
322
+ type: "Expression",
323
+ executed: false
324
+ })`);
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({
344
+ file: "${point.file}",
345
+ hash: "${point.hash}",
346
+ line: ${point.line},
347
+ column: ${point.column},
348
+ type: "Expression",
349
+ executed: false
350
+ })`);
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);
359
+ }
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({
376
+ file: "${point.file}",
377
+ hash: "${point.hash}",
378
+ line: ${point.line},
379
+ column: ${point.column},
380
+ type: "Block",
381
+ executed: false
382
+ })`);
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({
405
+ file: "${point.file}",
406
+ hash: "${point.hash}",
407
+ line: ${point.line},
408
+ column: ${point.column},
409
+ type: "Block",
410
+ executed: false
411
+ })`);
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
+ }
422
+ }
423
+ export default class Transformer extends Transform {
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;
440
+ }
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;
461
+ }
462
+ }
463
+ transformer.globalStatements = [];
464
+ }
465
+ }
466
+ }
467
+ /**
468
+ * A simple djb2hash that returns a hash of a given string. See http://www.cse.yorku.ca/~oz/hash.html
469
+ * for implementation details.
470
+ *
471
+ * @param {string} str - The string to be hashed
472
+ * @returns {number} The hash of the string
473
+ */
474
+ function djb2Hash(str) {
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;
481
+ }
482
+ function hash(point) {
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
+ }
495
+ }
496
+ class LineColumn {}
497
+ function getLineCol(node) {
498
+ return {
499
+ line: node.range.source.lineAt(node.range.start),
500
+ column: node.range.source.columnAt(),
501
+ };
502
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@as-test/transform",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Testing framework for AssemblyScript. Compatible with WASI or Bindings ",
5
5
  "main": "./lib/index.js",
6
6
  "author": "Jairus Tanaka",