as-test 0.4.4 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +196 -82
  3. package/as-test.config.schema.json +137 -0
  4. package/assembly/coverage.ts +19 -0
  5. package/assembly/index.ts +172 -85
  6. package/assembly/src/expectation.ts +263 -199
  7. package/assembly/src/log.ts +1 -9
  8. package/assembly/src/suite.ts +61 -25
  9. package/assembly/src/tests.ts +2 -0
  10. package/assembly/util/wipc.ts +286 -0
  11. package/bin/build.js +86 -41
  12. package/bin/index.js +337 -68
  13. package/bin/init.js +441 -183
  14. package/bin/reporter.js +1 -1
  15. package/bin/reporters/default.js +379 -0
  16. package/bin/reporters/types.js +1 -0
  17. package/bin/run.js +882 -194
  18. package/bin/types.js +14 -7
  19. package/bin/util.js +54 -3
  20. package/package.json +34 -16
  21. package/transform/lib/builder.js +169 -169
  22. package/transform/lib/builder.js.map +1 -1
  23. package/transform/lib/coverage.js +47 -1
  24. package/transform/lib/coverage.js.map +1 -1
  25. package/transform/lib/index.js +70 -0
  26. package/transform/lib/index.js.map +1 -1
  27. package/transform/lib/location.js +20 -0
  28. package/transform/lib/location.js.map +1 -0
  29. package/transform/lib/log.js +118 -0
  30. package/transform/lib/log.js.map +1 -0
  31. package/transform/lib/mock.js +2 -2
  32. package/transform/lib/mock.js.map +1 -1
  33. package/transform/lib/util.js +3 -3
  34. package/transform/lib/util.js.map +1 -1
  35. package/.github/workflows/as-test.yml +0 -26
  36. package/.prettierrc +0 -3
  37. package/as-test.config.json +0 -19
  38. package/assembly/__tests__/array.spec.ts +0 -25
  39. package/assembly/__tests__/math.spec.ts +0 -16
  40. package/assembly/__tests__/mock.spec.ts +0 -22
  41. package/assembly/__tests__/mock.ts +0 -7
  42. package/assembly/__tests__/sleep.spec.ts +0 -28
  43. package/assembly/tsconfig.json +0 -97
  44. package/assets/img/screenshot.png +0 -0
  45. package/cli/build.ts +0 -117
  46. package/cli/index.ts +0 -190
  47. package/cli/init.ts +0 -247
  48. package/cli/reporter.ts +0 -1
  49. package/cli/run.ts +0 -286
  50. package/cli/tsconfig.json +0 -9
  51. package/cli/types.ts +0 -29
  52. package/cli/util.ts +0 -65
  53. package/run/package.json +0 -27
  54. package/tests/array.run.js +0 -7
  55. package/tests/math.run.js +0 -7
  56. package/tests/mock.run.js +0 -14
  57. package/tests/sleep.run.js +0 -7
  58. package/transform/src/builder.ts +0 -1474
  59. package/transform/src/coverage.ts +0 -580
  60. package/transform/src/index.ts +0 -73
  61. package/transform/src/linker.ts +0 -41
  62. package/transform/src/mock.ts +0 -163
  63. package/transform/src/range.ts +0 -12
  64. package/transform/src/types.ts +0 -35
  65. package/transform/src/util.ts +0 -81
  66. package/transform/src/visitor.ts +0 -744
  67. package/transform/tsconfig.json +0 -10
package/bin/init.js CHANGED
@@ -2,213 +2,471 @@ import chalk from "chalk";
2
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
3
3
  import * as path from "path";
4
4
  import { createInterface } from "readline";
5
- import { loadConfig } from "./util.js";
5
+ import { getCliVersion, loadConfig } from "./util.js";
6
6
  const TARGETS = ["wasi", "bindings"];
7
- export async function init(args) {
8
- const rl = createInterface({
9
- input: process.stdin,
10
- output: process.stdout,
7
+ const EXAMPLE_MODES = ["minimal", "full", "none"];
8
+ export async function init(rawArgs) {
9
+ const options = parseInitArgs(rawArgs);
10
+ const root = path.resolve(process.cwd(), options.dir);
11
+ const rl = options.yes
12
+ ? null
13
+ : createInterface({
14
+ input: process.stdin,
15
+ output: process.stdout,
16
+ });
17
+ try {
18
+ console.log(chalk.bold(`as-test init v${getCliVersion()}`) + "\n");
19
+ const target = options.target ??
20
+ (await askChoice("Select target", TARGETS, rl, "wasi"));
21
+ const example = options.example ??
22
+ (await askChoice("Select example mode", EXAMPLE_MODES, rl, "minimal"));
23
+ printPlan(root, target, example);
24
+ if (!options.yes) {
25
+ const cont = (await ask("Continue? [Y/n] ", rl)).toLowerCase().trim();
26
+ if (["n", "no"].includes(cont)) {
27
+ console.log("Exiting.");
28
+ return;
29
+ }
30
+ }
31
+ const summary = applyInit(root, target, example, options.force);
32
+ printSummary(summary);
33
+ }
34
+ finally {
35
+ rl?.close();
36
+ }
37
+ }
38
+ function parseInitArgs(rawArgs) {
39
+ const options = {
40
+ yes: false,
41
+ force: false,
42
+ dir: ".",
43
+ };
44
+ const positional = [];
45
+ for (let i = 0; i < rawArgs.length; i++) {
46
+ const arg = rawArgs[i];
47
+ if (arg == "--yes" || arg == "-y") {
48
+ options.yes = true;
49
+ continue;
50
+ }
51
+ if (arg == "--force") {
52
+ options.force = true;
53
+ continue;
54
+ }
55
+ if (arg == "--target") {
56
+ const next = rawArgs[i + 1];
57
+ if (next && !next.startsWith("-")) {
58
+ options.target = parseTarget(next);
59
+ i++;
60
+ continue;
61
+ }
62
+ throw new Error("--target requires a value: wasi|bindings");
63
+ }
64
+ if (arg.startsWith("--target=")) {
65
+ options.target = parseTarget(arg.slice("--target=".length));
66
+ continue;
67
+ }
68
+ if (arg == "--example") {
69
+ const next = rawArgs[i + 1];
70
+ if (next && !next.startsWith("-")) {
71
+ options.example = parseExampleMode(next);
72
+ i++;
73
+ continue;
74
+ }
75
+ throw new Error("--example requires a value: minimal|full|none");
76
+ }
77
+ if (arg.startsWith("--example=")) {
78
+ options.example = parseExampleMode(arg.slice("--example=".length));
79
+ continue;
80
+ }
81
+ if (arg == "--dir") {
82
+ const next = rawArgs[i + 1];
83
+ if (next && !next.startsWith("-")) {
84
+ options.dir = next;
85
+ i++;
86
+ continue;
87
+ }
88
+ throw new Error("--dir requires a path value");
89
+ }
90
+ if (arg.startsWith("--dir=")) {
91
+ options.dir = arg.slice("--dir=".length);
92
+ continue;
93
+ }
94
+ if (arg.startsWith("-")) {
95
+ throw new Error(`Unknown init flag: ${arg}`);
96
+ }
97
+ positional.push(arg);
98
+ }
99
+ // First positional argument is always the target directory.
100
+ if (positional.length > 0) {
101
+ options.dir = positional.shift();
102
+ }
103
+ if (!options.target && positional.length > 0 && isTarget(positional[0])) {
104
+ options.target = positional.shift();
105
+ }
106
+ if (!options.example && positional.length > 0 && isExampleMode(positional[0])) {
107
+ options.example = positional.shift();
108
+ }
109
+ if (positional.length > 0) {
110
+ throw new Error(`Unknown init argument(s): ${positional.join(", ")}. Usage: init [dir] [--target wasi|bindings] [--example minimal|full|none] [--yes] [--force] [--dir <path>]`);
111
+ }
112
+ return options;
113
+ }
114
+ function parseTarget(value) {
115
+ if (!isTarget(value)) {
116
+ throw new Error(`Invalid target "${value}". Expected wasi|bindings`);
117
+ }
118
+ return value;
119
+ }
120
+ function parseExampleMode(value) {
121
+ if (!isExampleMode(value)) {
122
+ throw new Error(`Invalid example mode "${value}". Expected minimal|full|none`);
123
+ }
124
+ return value;
125
+ }
126
+ function isTarget(value) {
127
+ return TARGETS.includes(value);
128
+ }
129
+ function isExampleMode(value) {
130
+ return EXAMPLE_MODES.includes(value);
131
+ }
132
+ function printPlan(root, target, example) {
133
+ console.log(chalk.dim("Planned changes:\n"));
134
+ console.log(chalk.dim(` target: ${target}`));
135
+ console.log(chalk.dim(` example: ${example}`));
136
+ console.log(chalk.dim(` root: ${root}\n`));
137
+ console.log(chalk.dim(" directories:"));
138
+ console.log(chalk.dim(" .as-test/build"));
139
+ console.log(chalk.dim(" .as-test/logs"));
140
+ console.log(chalk.dim(" .as-test/coverage"));
141
+ console.log(chalk.dim(" .as-test/snapshots"));
142
+ console.log(chalk.dim(" assembly/__tests__"));
143
+ if (target == "wasi" || target == "bindings") {
144
+ console.log(chalk.dim(" .as-test/runners"));
145
+ }
146
+ console.log(chalk.dim("\n files:"));
147
+ console.log(chalk.dim(" as-test.config.json"));
148
+ if (example != "none") {
149
+ console.log(chalk.dim(" assembly/__tests__/example.spec.ts"));
150
+ }
151
+ if (target == "wasi") {
152
+ console.log(chalk.dim(" .as-test/runners/default.wasi.js"));
153
+ }
154
+ if (target == "bindings") {
155
+ console.log(chalk.dim(" .as-test/runners/default.run.js"));
156
+ }
157
+ console.log(chalk.dim(" package.json"));
158
+ console.log("");
159
+ }
160
+ function applyInit(root, target, example, force) {
161
+ const summary = {
162
+ created: [],
163
+ updated: [],
164
+ skipped: [],
165
+ };
166
+ ensureDir(root, ".as-test/build", summary);
167
+ ensureDir(root, ".as-test/logs", summary);
168
+ ensureDir(root, ".as-test/coverage", summary);
169
+ ensureDir(root, ".as-test/snapshots", summary);
170
+ ensureDir(root, "assembly/__tests__", summary);
171
+ if (target == "wasi" || target == "bindings") {
172
+ ensureDir(root, ".as-test/runners", summary);
173
+ }
174
+ const configPath = path.join(root, "as-test.config.json");
175
+ const config = loadConfig(configPath, false);
176
+ config.$schema = "./node_modules/as-test/as-test.config.schema.json";
177
+ config.buildOptions.target = target;
178
+ if (target == "wasi") {
179
+ config.runOptions.runtime.cmd = "node ./.as-test/runners/default.wasi.js <file>";
180
+ }
181
+ else {
182
+ config.runOptions.runtime.cmd = "node ./.as-test/runners/default.run.js <file>";
183
+ }
184
+ writeJson(configPath, config, summary, "as-test.config.json");
185
+ if (example != "none") {
186
+ const examplePath = path.join(root, "assembly/__tests__/example.spec.ts");
187
+ const content = example == "minimal" ? buildMinimalExampleSpec() : buildFullExampleSpec();
188
+ writeManagedFile(examplePath, content, force, summary, "assembly/__tests__/example.spec.ts");
189
+ }
190
+ if (target == "wasi") {
191
+ const runnerPath = path.join(root, ".as-test/runners/default.wasi.js");
192
+ writeManagedFile(runnerPath, buildWasiRunner(), force, summary, ".as-test/runners/default.wasi.js");
193
+ }
194
+ if (target == "bindings") {
195
+ const runnerPath = path.join(root, ".as-test/runners/default.run.js");
196
+ writeManagedFile(runnerPath, buildBindingsRunner(), force, summary, ".as-test/runners/default.run.js");
197
+ }
198
+ const pkgPath = path.join(root, "package.json");
199
+ const pkg = existsSync(pkgPath)
200
+ ? JSON.parse(readFileSync(pkgPath, "utf8"))
201
+ : {};
202
+ if (!pkg.scripts || typeof pkg.scripts != "object") {
203
+ pkg.scripts = {};
204
+ }
205
+ const scripts = pkg.scripts;
206
+ if (!scripts.test) {
207
+ scripts.test = "as-test test";
208
+ }
209
+ if (!pkg.type) {
210
+ pkg.type = "module";
211
+ }
212
+ if (!pkg.devDependencies || typeof pkg.devDependencies != "object") {
213
+ pkg.devDependencies = {};
214
+ }
215
+ const devDependencies = pkg.devDependencies;
216
+ if (!devDependencies["as-test"]) {
217
+ devDependencies["as-test"] = "^" + getCliVersion();
218
+ }
219
+ if (target == "wasi" && !devDependencies["@assemblyscript/wasi-shim"]) {
220
+ devDependencies["@assemblyscript/wasi-shim"] = "^0.1.0";
221
+ }
222
+ if (target == "bindings" && !pkg.type) {
223
+ pkg.type = "module";
224
+ }
225
+ writeJson(pkgPath, pkg, summary, "package.json");
226
+ return summary;
227
+ }
228
+ function ensureDir(root, rel, summary) {
229
+ const full = path.join(root, rel);
230
+ if (existsSync(full))
231
+ return;
232
+ mkdirSync(full, { recursive: true });
233
+ summary.created.push(rel + "/");
234
+ }
235
+ function writeJson(fullPath, value, summary, displayPath) {
236
+ const rel = displayPath ??
237
+ path.relative(process.cwd(), fullPath) ??
238
+ path.basename(fullPath);
239
+ const existed = existsSync(fullPath);
240
+ const data = JSON.stringify(value, null, 2) + "\n";
241
+ writeFileSync(fullPath, data);
242
+ if (existed)
243
+ summary.updated.push(rel);
244
+ else
245
+ summary.created.push(rel);
246
+ }
247
+ function writeManagedFile(fullPath, data, force, summary, displayPath) {
248
+ const rel = displayPath ??
249
+ path.relative(process.cwd(), fullPath) ??
250
+ path.basename(fullPath);
251
+ const existed = existsSync(fullPath);
252
+ if (existed && !force) {
253
+ summary.skipped.push(rel);
254
+ return;
255
+ }
256
+ if (!existsSync(path.dirname(fullPath))) {
257
+ mkdirSync(path.dirname(fullPath), { recursive: true });
258
+ }
259
+ writeFileSync(fullPath, data);
260
+ if (existed)
261
+ summary.updated.push(rel);
262
+ else
263
+ summary.created.push(rel);
264
+ }
265
+ function printSummary(summary) {
266
+ console.log("");
267
+ if (summary.created.length) {
268
+ console.log(chalk.bold("Created:"));
269
+ for (const item of summary.created) {
270
+ console.log(` + ${item}`);
271
+ }
272
+ }
273
+ if (summary.updated.length) {
274
+ console.log(chalk.bold("Updated:"));
275
+ for (const item of summary.updated) {
276
+ console.log(` ~ ${item}`);
277
+ }
278
+ }
279
+ if (summary.skipped.length) {
280
+ console.log(chalk.bold("Skipped (exists, use --force to overwrite):"));
281
+ for (const item of summary.skipped) {
282
+ console.log(` = ${item}`);
283
+ }
284
+ }
285
+ console.log("\nNow, install dependencies and run " + chalk.bold("as-test test") + "\n");
286
+ }
287
+ function ask(question, face) {
288
+ if (!face) {
289
+ throw new Error("interactive input is unavailable; pass --yes with options");
290
+ }
291
+ return new Promise((res) => {
292
+ face.question(question, (answer) => {
293
+ res(answer);
294
+ });
11
295
  });
12
- console.log(chalk.bold("as-test init v0.3.5") + "\n");
13
- console.log(chalk.dim("[1/3]") + " select a target [wasi/bindings]");
14
- const target = await ask(chalk.dim(" -> "), rl);
15
- if (!TARGETS.includes(target)) {
16
- console.log("Invalid target " + target + ". Exiting.");
17
- process.exit(0);
18
- }
19
- process.stdout.write(`\u001B[1A`);
20
- process.stdout.write("\x1B[2K");
21
- process.stdout.write("\x1B[0G");
22
- console.log("\n" +
23
- chalk.dim("[2/3]") +
24
- " attempting to create the following files. Continue? [y/n]\n");
25
- console.log(chalk.dim(` ├── 📂 assembly/
26
- │ └── 📂 __tests__/
27
- │ └── 🧪 example.spec.ts
28
- ├── 📂 build/
29
- ├── 📂 logs/
30
- ├── 📂 tests/
31
- │ └── 📃 as-test.run.js
32
- ├── ⚙️ as-test.config.json
33
- └── ⚙️ package.json\n`));
34
- const cont = (await ask(chalk.dim(" -> "), rl)).toLowerCase().trim();
35
- if (cont == "n" || cont == "no") {
36
- console.log("Exiting.");
37
- process.exit(0);
38
- }
39
- let config = loadConfig(path.join(process.cwd(), "./as-test.config.json"));
40
- if (target == "wasi" && config.buildOptions.target != "wasi") {
41
- config.buildOptions.target = "wasi";
42
- config.runOptions.runtime.name = "wasmtime";
43
- config.runOptions.runtime.run = "wasmtime <file>";
44
- }
45
- else if (target == "bindings" && config.buildOptions.target != "bindings") {
46
- config.buildOptions.target = "bindings";
47
- config.runOptions.runtime.name = "node";
48
- config.runOptions.runtime.run = "node ./tests/<name>.run.js";
49
- }
50
- writeFile("./as-test.config.json", JSON.stringify(config, null, 2));
51
- writeFile("./assembly/__tests__/example.spec.ts", `import {
52
- describe,
53
- expect,
54
- test,
55
- beforeAll,
56
- afterAll,
57
- mockFn,
58
- log,
59
- run,
60
- it
61
- } from "as-test";
296
+ }
297
+ async function askChoice(label, choices, face, fallback) {
298
+ if (!face) {
299
+ return fallback;
300
+ }
301
+ const answer = (await ask(`${label} [${choices.join("/")}] (${fallback}) -> `, face))
302
+ .trim()
303
+ .toLowerCase();
304
+ if (!answer.length)
305
+ return fallback;
306
+ if (choices.includes(answer))
307
+ return answer;
308
+ throw new Error(`Invalid choice "${answer}" for ${label}`);
309
+ }
310
+ function buildMinimalExampleSpec() {
311
+ return `import { describe, expect, test, run } from "as-test";
62
312
 
63
- beforeAll(() => {
64
- log("Setting up test environment...");
313
+ describe("example", () => {
314
+ test("adds numbers", () => {
315
+ expect(1 + 2).toBe(3);
316
+ });
65
317
  });
66
318
 
67
- afterAll(() => {
68
- log("Tearing down test environment...");
69
- });
319
+ run();
320
+ `;
321
+ }
322
+ function buildFullExampleSpec() {
323
+ return `import { afterAll, beforeAll, describe, expect, it, log, run, test } from "as-test";
70
324
 
71
- // Mock/override the function console.log
72
- mockFn<void>("console.log", (data: string): void => {
73
- console.log("[MOCKED]: " + data + "\\n");
325
+ beforeAll(() => {
326
+ log("setup");
74
327
  });
75
328
 
76
- describe("Should sleep", () => {
77
- test("1ms", () => {
78
- const start = Date.now();
79
- sleep(1);
80
- expect(Date.now() - start).toBeGreaterOrEqualTo(1);
81
- });
82
- test("10ms", () => {
83
- const start = Date.now();
84
- sleep(10);
85
- expect(Date.now() - start).toBeGreaterOrEqualTo(10);
86
- });
87
- test("1s", () => {
88
- const start = Date.now();
89
- sleep(1000);
90
- expect(Date.now() - start).toBeGreaterOrEqualTo(1000);
91
- });
92
- test("5s", () => {
93
- const start = Date.now();
94
- log("Sleeping...");
95
- sleep(5000);
96
- log("Done!");
97
- expect(Date.now() - start).toBeGreaterOrEqualTo(5000);
98
- });
329
+ afterAll(() => {
330
+ log("teardown");
99
331
  });
100
332
 
101
- describe("Math operations", () => {
102
- test("Addition", () => {
103
- expect(1 + 2).toBe(3);
104
- });
105
-
106
- test("Subtraction", () => {
107
- expect(1 - 2).toBe(-1);
108
- });
333
+ describe("math", () => {
334
+ test("addition", () => {
335
+ expect(2 + 2).toBe(4);
336
+ });
109
337
 
110
- test("Comparison", () => {
111
- expect(5).toBeGreaterThan(3);
112
- expect(2).toBeLessThan(4);
113
- });
114
-
115
- test("Type checking", () => {
116
- expect("hello").toBeString();
117
- expect(true).toBeBoolean();
118
- expect(10.5).toBeNumber();
119
- });
338
+ test("comparisons", () => {
339
+ expect(10).toBeGreaterThan(2);
340
+ expect(2).toBeLessThan(10);
341
+ });
120
342
  });
121
343
 
122
- let myArray: i32[] = [1, 2, 3];
344
+ describe("strings", () => {
345
+ it("contains", () => {
346
+ expect("assemblyscript").toContain("script");
347
+ });
123
348
 
124
- describe("Array manipulation", () => {
125
- test("Array length", () => {
126
- expect(myArray).toHaveLength(3);
127
- });
349
+ test("prefix", () => {
350
+ expect("as-test").toStartWith("as");
351
+ });
352
+ });
128
353
 
129
- test("Array inclusion", () => {
130
- expect(myArray).toContain(2);
131
- });
354
+ run();
355
+ `;
356
+ }
357
+ function buildWasiRunner() {
358
+ return `import { readFileSync } from "fs";
359
+ import { WASI } from "wasi";
132
360
 
133
- it("should be empty", () => { });
361
+ const originalEmitWarning = process.emitWarning.bind(process);
362
+ process.emitWarning = ((warning, ...args) => {
363
+ const type = typeof args[0] == "string" ? args[0] : "";
364
+ const name = typeof warning?.name == "string" ? warning.name : type;
365
+ const message =
366
+ typeof warning == "string" ? warning : String(warning?.message ?? "");
367
+ if (
368
+ name == "ExperimentalWarning" &&
369
+ message.includes("WASI is an experimental feature")
370
+ ) {
371
+ return;
372
+ }
373
+ return originalEmitWarning(warning, ...args);
134
374
  });
135
375
 
136
- run();
376
+ const wasmPath = process.argv[2];
377
+ if (!wasmPath) {
378
+ process.stderr.write("usage: node ./.as-test/runners/default.wasi.js <file.wasm>\\n");
379
+ process.exit(1);
380
+ }
137
381
 
138
- function sleep(ms: i64): void {
139
- const target = Date.now() + ms;
140
- while (target > Date.now()) { }
141
- }`);
142
- writeDir("./build/");
143
- writeDir("./logs/");
144
- if (target == "bindings") {
145
- writeFile("./tests/example.run.js", `import { readFileSync } from "fs";
146
- import { instantiate } from "../build/example.spec.js";
382
+ try {
383
+ const wasi = new WASI({
384
+ version: "preview1",
385
+ args: [wasmPath],
386
+ env: process.env,
387
+ preopens: {},
388
+ });
147
389
 
148
- const binary = readFileSync("./build/example.spec.wasm");
149
- const module = new WebAssembly.Module(binary);
390
+ const binary = readFileSync(wasmPath);
391
+ const module = new WebAssembly.Module(binary);
392
+ const instance = new WebAssembly.Instance(module, {
393
+ wasi_snapshot_preview1: wasi.wasiImport,
394
+ });
395
+ wasi.start(instance);
396
+ } catch (error) {
397
+ process.stderr.write("failed to run WASI module: " + String(error) + "\\n");
398
+ process.exit(1);
399
+ }
400
+ `;
401
+ }
402
+ function buildBindingsRunner() {
403
+ return `import fs from "fs";
404
+ import path from "path";
405
+ import { pathToFileURL } from "url";
150
406
 
151
- const exports = instantiate(module, {});`);
152
- }
153
- const PKG_PATH = path.join(process.cwd(), "./package.json");
154
- if (!hasDep(PKG_PATH, "assemblyscript")) {
155
- console.log(chalk.dim("AssemblyScript is not included in dependencies.\nInstall it with " +
156
- (process.env.npm_config_user_agent == "yarn"
157
- ? process.env.npm_config_user_agent + " add assemblyscript"
158
- : process.env.npm_config_user_agent + " install assemblyscript")));
159
- }
160
- const pkg = JSON.parse(existsSync(PKG_PATH) ? readFileSync(PKG_PATH).toString() : "{}");
161
- if (!pkg["scripts"])
162
- pkg["scripts"] = {};
163
- if (!pkg.scripts["pretest"]) {
164
- pkg.scripts["pretest"] = "as-test build";
165
- pkg.scripts["test"] = "as-test run";
166
- }
167
- else {
168
- pkg.scripts["test"] = "as-test test";
169
- }
170
- if (!pkg["devDependencies"])
171
- pkg["devDependencies"] = {};
172
- if (!pkg["devDependencies"]["as-test"])
173
- pkg["devDependencies"]["as-test"] = "^0.3.5";
174
- if (target == "bindings") {
175
- pkg["type"] = "module";
407
+ let patched = false;
408
+
409
+ function readExact(length) {
410
+ const out = Buffer.alloc(length);
411
+ let offset = 0;
412
+ while (offset < length) {
413
+ let read = 0;
414
+ try {
415
+ read = fs.readSync(0, out, offset, length - offset, null);
416
+ } catch (error) {
417
+ if (error && error.code === "EAGAIN") {
418
+ continue;
419
+ }
420
+ throw error;
176
421
  }
177
- writeFileSync(PKG_PATH, JSON.stringify(pkg, null, 2));
178
- process.exit(0);
422
+ if (!read) break;
423
+ offset += read;
424
+ }
425
+ const view = out.subarray(0, offset);
426
+ return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength);
179
427
  }
180
- function ask(question, face) {
181
- return new Promise((res, _) => {
182
- face.question(question, (answer) => {
183
- res(answer);
184
- });
185
- });
428
+
429
+ function writeRaw(data) {
430
+ const view = Buffer.from(data);
431
+ fs.writeSync(1, view);
186
432
  }
187
- function writeFile(pth, data) {
188
- const fmtPath = path.join(process.cwd(), pth);
189
- if (existsSync(fmtPath))
190
- return;
191
- if (!existsSync(path.dirname(fmtPath)))
192
- mkdirSync(path.dirname(fmtPath), { recursive: true });
193
- writeFileSync(fmtPath, data);
433
+
434
+ function withNodeIo(imports = {}) {
435
+ if (!patched) {
436
+ patched = true;
437
+ const originalWrite = process.stdout.write.bind(process.stdout);
438
+ process.stdout.write = (chunk, ...args) => {
439
+ if (chunk instanceof ArrayBuffer) {
440
+ writeRaw(chunk);
441
+ return true;
442
+ }
443
+ return originalWrite(chunk, ...args);
444
+ };
445
+ process.stdin.read = (size) => readExact(Number(size ?? 0));
446
+ }
447
+ return imports;
194
448
  }
195
- function writeDir(pth) {
196
- const fmtPath = path.join(process.cwd(), pth);
197
- if (existsSync(fmtPath))
198
- return;
199
- mkdirSync(fmtPath);
449
+
450
+ const wasmPathArg = process.argv[2];
451
+ if (!wasmPathArg) {
452
+ process.stderr.write("usage: node ./.as-test/runners/default.run.js <file.wasm>\\n");
453
+ process.exit(1);
200
454
  }
201
- function hasDep(PKG_PATH, dep) {
202
- const pkg = JSON.parse(existsSync(PKG_PATH) ? readFileSync(PKG_PATH).toString() : "{}");
203
- if (existsSync(path.join(process.cwd(), "./node_modules/", dep)))
204
- return true;
205
- if (pkg.dependencies &&
206
- !Object.keys(pkg.dependencies).includes(dep) &&
207
- pkg.devDependencies &&
208
- !Object.keys(pkg.devDependencies).includes(dep) &&
209
- pkg.peerDependencies &&
210
- !Object.keys(pkg.peerDependencies).includes(dep)) {
211
- return false;
212
- }
213
- return true;
455
+
456
+ const wasmPath = path.resolve(process.cwd(), wasmPathArg);
457
+ const jsPath = wasmPath.replace(/\\.wasm$/, ".js");
458
+
459
+ try {
460
+ const binary = fs.readFileSync(wasmPath);
461
+ const module = new WebAssembly.Module(binary);
462
+ const mod = await import(pathToFileURL(jsPath).href);
463
+ if (typeof mod.instantiate !== "function") {
464
+ throw new Error("bindings helper missing instantiate export");
465
+ }
466
+ mod.instantiate(module, withNodeIo({}));
467
+ } catch (error) {
468
+ process.stderr.write("failed to run bindings module: " + String(error) + "\\n");
469
+ process.exit(1);
470
+ }
471
+ `;
214
472
  }
package/bin/reporter.js CHANGED
@@ -1 +1 @@
1
- export function report() { }
1
+ export { createReporter } from "./reporters/default.js";