as-test 0.1.0 → 0.1.2

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