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.
- package/CHANGELOG.md +46 -0
- package/README.md +196 -82
- package/as-test.config.schema.json +137 -0
- package/assembly/coverage.ts +19 -0
- package/assembly/index.ts +172 -85
- package/assembly/src/expectation.ts +263 -199
- package/assembly/src/log.ts +1 -9
- package/assembly/src/suite.ts +61 -25
- package/assembly/src/tests.ts +2 -0
- package/assembly/util/wipc.ts +286 -0
- package/bin/build.js +86 -41
- package/bin/index.js +337 -68
- package/bin/init.js +441 -183
- package/bin/reporter.js +1 -1
- package/bin/reporters/default.js +379 -0
- package/bin/reporters/types.js +1 -0
- package/bin/run.js +882 -194
- package/bin/types.js +14 -7
- package/bin/util.js +54 -3
- package/package.json +34 -16
- package/transform/lib/builder.js +169 -169
- package/transform/lib/builder.js.map +1 -1
- package/transform/lib/coverage.js +47 -1
- package/transform/lib/coverage.js.map +1 -1
- package/transform/lib/index.js +70 -0
- package/transform/lib/index.js.map +1 -1
- package/transform/lib/location.js +20 -0
- package/transform/lib/location.js.map +1 -0
- package/transform/lib/log.js +118 -0
- package/transform/lib/log.js.map +1 -0
- package/transform/lib/mock.js +2 -2
- package/transform/lib/mock.js.map +1 -1
- package/transform/lib/util.js +3 -3
- package/transform/lib/util.js.map +1 -1
- package/.github/workflows/as-test.yml +0 -26
- package/.prettierrc +0 -3
- package/as-test.config.json +0 -19
- package/assembly/__tests__/array.spec.ts +0 -25
- package/assembly/__tests__/math.spec.ts +0 -16
- package/assembly/__tests__/mock.spec.ts +0 -22
- package/assembly/__tests__/mock.ts +0 -7
- package/assembly/__tests__/sleep.spec.ts +0 -28
- package/assembly/tsconfig.json +0 -97
- package/assets/img/screenshot.png +0 -0
- package/cli/build.ts +0 -117
- package/cli/index.ts +0 -190
- package/cli/init.ts +0 -247
- package/cli/reporter.ts +0 -1
- package/cli/run.ts +0 -286
- package/cli/tsconfig.json +0 -9
- package/cli/types.ts +0 -29
- package/cli/util.ts +0 -65
- package/run/package.json +0 -27
- package/tests/array.run.js +0 -7
- package/tests/math.run.js +0 -7
- package/tests/mock.run.js +0 -14
- package/tests/sleep.run.js +0 -7
- package/transform/src/builder.ts +0 -1474
- package/transform/src/coverage.ts +0 -580
- package/transform/src/index.ts +0 -73
- package/transform/src/linker.ts +0 -41
- package/transform/src/mock.ts +0 -163
- package/transform/src/range.ts +0 -12
- package/transform/src/types.ts +0 -35
- package/transform/src/util.ts +0 -81
- package/transform/src/visitor.ts +0 -744
- package/transform/tsconfig.json +0 -10
package/assembly/src/suite.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { rainbow } from "as-rainbow";
|
|
2
1
|
import { Time } from "..";
|
|
3
2
|
import { Expectation } from "./expectation";
|
|
4
3
|
import { Tests } from "./tests";
|
|
5
|
-
import { term } from "../util/term";
|
|
6
4
|
import { Log } from "./log";
|
|
5
|
+
import { after_each_callback, before_each_callback } from "..";
|
|
6
|
+
import { sendSuiteEnd, sendSuiteStart } from "../util/wipc";
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
@json
|
|
@@ -20,6 +20,10 @@ export class Suite {
|
|
|
20
20
|
public logs: Log[] = [];
|
|
21
21
|
public kind: string;
|
|
22
22
|
|
|
23
|
+
|
|
24
|
+
@omit
|
|
25
|
+
public parent: Suite | null = null;
|
|
26
|
+
|
|
23
27
|
public verdict: string = "none";
|
|
24
28
|
|
|
25
29
|
public callback: () => void;
|
|
@@ -38,6 +42,7 @@ export class Suite {
|
|
|
38
42
|
this.suites.push(suite);
|
|
39
43
|
suite.depth = this.depth + 1;
|
|
40
44
|
suite.file = this.file;
|
|
45
|
+
suite.parent = this;
|
|
41
46
|
}
|
|
42
47
|
addLog(log: Log): void {
|
|
43
48
|
log.order = this.order++;
|
|
@@ -52,50 +57,81 @@ export class Suite {
|
|
|
52
57
|
// @ts-ignore
|
|
53
58
|
depth++;
|
|
54
59
|
this.time.start = performance.now();
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
sendSuiteStart(this.file, this.depth, this.kind, this.description);
|
|
61
|
+
const isSkippedCase =
|
|
62
|
+
this.kind == "xdescribe" ||
|
|
63
|
+
this.kind == "xtest" ||
|
|
64
|
+
this.kind == "xit";
|
|
65
|
+
const isTestCase =
|
|
66
|
+
this.kind == "test" ||
|
|
67
|
+
this.kind == "it" ||
|
|
68
|
+
this.kind == "xtest" ||
|
|
69
|
+
this.kind == "xit";
|
|
70
|
+
|
|
71
|
+
if (isSkippedCase) {
|
|
72
|
+
this.time.end = performance.now();
|
|
73
|
+
this.verdict = "skip";
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
depth--;
|
|
76
|
+
sendSuiteEnd(
|
|
77
|
+
this.file,
|
|
78
|
+
this.depth,
|
|
79
|
+
this.kind,
|
|
80
|
+
this.description,
|
|
81
|
+
this.verdict,
|
|
82
|
+
);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// @ts-ignore
|
|
87
|
+
if (isTestCase && before_each_callback) before_each_callback();
|
|
60
88
|
this.callback();
|
|
89
|
+
// @ts-ignore
|
|
90
|
+
if (isTestCase && after_each_callback) after_each_callback();
|
|
61
91
|
this.time.end = performance.now();
|
|
62
92
|
// @ts-ignore
|
|
63
93
|
depth--;
|
|
64
94
|
|
|
65
|
-
let
|
|
95
|
+
let hasFail = false;
|
|
96
|
+
let hasOk = false;
|
|
97
|
+
let hasSkip = false;
|
|
66
98
|
for (let i = 0; i < this.suites.length; i++) {
|
|
67
99
|
const suite = unchecked(this.suites[i]);
|
|
68
100
|
suite.run();
|
|
69
101
|
if (suite.verdict == "fail") {
|
|
70
|
-
|
|
71
|
-
suiteNone = false;
|
|
102
|
+
hasFail = true;
|
|
72
103
|
} else if (suite.verdict == "ok") {
|
|
73
|
-
|
|
104
|
+
hasOk = true;
|
|
105
|
+
} else if (suite.verdict == "skip") {
|
|
106
|
+
hasSkip = true;
|
|
74
107
|
}
|
|
75
108
|
}
|
|
76
109
|
for (let i = 0; i < this.tests.length; i++) {
|
|
77
110
|
const test = unchecked(this.tests[i]);
|
|
78
111
|
if (test.verdict == "fail") {
|
|
79
|
-
|
|
80
|
-
suiteNone = false;
|
|
112
|
+
hasFail = true;
|
|
81
113
|
} else if (test.verdict == "ok") {
|
|
82
|
-
|
|
114
|
+
hasOk = true;
|
|
115
|
+
} else if (test.verdict == "skip") {
|
|
116
|
+
hasSkip = true;
|
|
83
117
|
}
|
|
84
118
|
}
|
|
85
119
|
|
|
86
|
-
if (
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
);
|
|
90
|
-
} else if (!suiteNone || this.tests.length) {
|
|
120
|
+
if (hasFail) {
|
|
121
|
+
this.verdict = "fail";
|
|
122
|
+
} else if (hasOk) {
|
|
91
123
|
this.verdict = "ok";
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
);
|
|
124
|
+
} else if (hasSkip) {
|
|
125
|
+
this.verdict = "skip";
|
|
95
126
|
} else {
|
|
96
|
-
|
|
97
|
-
`${suiteDepth}${rainbow.bgBlackBright(" EMPTY ")} ${rainbow.dimMk(this.description)}\n`,
|
|
98
|
-
);
|
|
127
|
+
this.verdict = "none";
|
|
99
128
|
}
|
|
129
|
+
sendSuiteEnd(
|
|
130
|
+
this.file,
|
|
131
|
+
this.depth,
|
|
132
|
+
this.kind,
|
|
133
|
+
this.description,
|
|
134
|
+
this.verdict,
|
|
135
|
+
);
|
|
100
136
|
}
|
|
101
137
|
}
|
package/assembly/src/tests.ts
CHANGED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
@external("env", "process.stdout.write")
|
|
3
|
+
declare function process_stdout_write(data: ArrayBuffer): void;
|
|
4
|
+
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
@external("env", "process.stdin.read")
|
|
7
|
+
declare function process_stdin_read(max: i32): ArrayBuffer;
|
|
8
|
+
|
|
9
|
+
// @ts-ignore
|
|
10
|
+
@external("wasi_snapshot_preview1", "fd_write")
|
|
11
|
+
declare function wasi_fd_write(
|
|
12
|
+
fd: i32,
|
|
13
|
+
iovs: usize,
|
|
14
|
+
iovsLen: i32,
|
|
15
|
+
written: usize,
|
|
16
|
+
): i32;
|
|
17
|
+
|
|
18
|
+
// @ts-ignore
|
|
19
|
+
@external("wasi_snapshot_preview1", "fd_read")
|
|
20
|
+
declare function wasi_fd_read(
|
|
21
|
+
fd: i32,
|
|
22
|
+
iovs: usize,
|
|
23
|
+
iovsLen: i32,
|
|
24
|
+
read: usize,
|
|
25
|
+
): i32;
|
|
26
|
+
|
|
27
|
+
const MAGIC_W: u8 = 0x57; // W
|
|
28
|
+
const MAGIC_I: u8 = 0x49; // I
|
|
29
|
+
const MAGIC_P: u8 = 0x50; // P
|
|
30
|
+
const MAGIC_C: u8 = 0x43; // C
|
|
31
|
+
const HEADER_SIZE: i32 = 9;
|
|
32
|
+
const IOV_SIZE: usize = sizeof<usize>() * 2;
|
|
33
|
+
const U32_SIZE: usize = sizeof<u32>();
|
|
34
|
+
|
|
35
|
+
// @ts-ignore
|
|
36
|
+
const IS_BINDINGS: bool = isDefined(AS_TEST_BINDINGS);
|
|
37
|
+
|
|
38
|
+
enum MessageType {
|
|
39
|
+
OPEN = 0x00,
|
|
40
|
+
CLOSE = 0x01,
|
|
41
|
+
CALL = 0x02,
|
|
42
|
+
DATA = 0x03,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class SnapshotReply {
|
|
46
|
+
public ok: bool = false;
|
|
47
|
+
public expected: string = "";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function sendAssertionFailure(
|
|
51
|
+
key: string,
|
|
52
|
+
instr: string,
|
|
53
|
+
left: string,
|
|
54
|
+
right: string,
|
|
55
|
+
message: string,
|
|
56
|
+
): void {
|
|
57
|
+
sendJson(
|
|
58
|
+
MessageType.CALL,
|
|
59
|
+
`{"kind":"event:assert-fail","key":${q(key)},"instr":${q(instr)},"left":${q(left)},"right":${q(right)},"message":${q(message)}}`,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function sendFileStart(file: string): void {
|
|
64
|
+
sendJson(MessageType.CALL, `{"kind":"event:file-start","file":${q(file)}}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function sendFileEnd(file: string, verdict: string, time: string): void {
|
|
68
|
+
sendJson(
|
|
69
|
+
MessageType.CALL,
|
|
70
|
+
`{"kind":"event:file-end","file":${q(file)},"verdict":${q(verdict)},"time":${q(time)}}`,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function sendSuiteStart(
|
|
75
|
+
file: string,
|
|
76
|
+
depth: i32,
|
|
77
|
+
kind: string,
|
|
78
|
+
description: string,
|
|
79
|
+
): void {
|
|
80
|
+
sendJson(
|
|
81
|
+
MessageType.CALL,
|
|
82
|
+
`{"kind":"event:suite-start","file":${q(file)},"depth":${depth.toString()},"suiteKind":${q(kind)},"description":${q(description)}}`,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function sendSuiteEnd(
|
|
87
|
+
file: string,
|
|
88
|
+
depth: i32,
|
|
89
|
+
kind: string,
|
|
90
|
+
description: string,
|
|
91
|
+
verdict: string,
|
|
92
|
+
): void {
|
|
93
|
+
sendJson(
|
|
94
|
+
MessageType.CALL,
|
|
95
|
+
`{"kind":"event:suite-end","file":${q(file)},"depth":${depth.toString()},"suiteKind":${q(kind)},"description":${q(description)},"verdict":${q(verdict)}}`,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function snapshotAssert(key: string, actual: string): SnapshotReply {
|
|
100
|
+
sendJson(
|
|
101
|
+
MessageType.CALL,
|
|
102
|
+
`{"kind":"snapshot:assert","key":${q(key)},"actual":${q(actual)}}`,
|
|
103
|
+
);
|
|
104
|
+
const response = readFrame();
|
|
105
|
+
if (response == null || response.type != MessageType.CALL) {
|
|
106
|
+
return new SnapshotReply();
|
|
107
|
+
}
|
|
108
|
+
const body = String.UTF8.decode(response.payload);
|
|
109
|
+
if (!body.length) {
|
|
110
|
+
return new SnapshotReply();
|
|
111
|
+
}
|
|
112
|
+
const sep = body.indexOf("\n");
|
|
113
|
+
if (sep < 0) return new SnapshotReply();
|
|
114
|
+
const reply = new SnapshotReply();
|
|
115
|
+
reply.ok = body.slice(0, sep) == "1";
|
|
116
|
+
reply.expected = body.slice(sep + 1);
|
|
117
|
+
return reply;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function sendReport(report: string): void {
|
|
121
|
+
sendFrame(MessageType.DATA, String.UTF8.encode(report));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function sendWarning(message: string): void {
|
|
125
|
+
writeStdout(String.UTF8.encode("[WARN] " + message + "\n"));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function sendJson(type: MessageType, body: string): void {
|
|
129
|
+
sendFrame(type, String.UTF8.encode(body));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function sendFrame(type: MessageType, payload: ArrayBuffer): void {
|
|
133
|
+
const payloadLen = payload.byteLength;
|
|
134
|
+
const out = new ArrayBuffer(HEADER_SIZE + payloadLen);
|
|
135
|
+
const ptr = changetype<usize>(out);
|
|
136
|
+
|
|
137
|
+
store<u8>(ptr, MAGIC_W, 0);
|
|
138
|
+
store<u8>(ptr, MAGIC_I, 1);
|
|
139
|
+
store<u8>(ptr, MAGIC_P, 2);
|
|
140
|
+
store<u8>(ptr, MAGIC_C, 3);
|
|
141
|
+
store<u8>(ptr, <u8>type, 4);
|
|
142
|
+
store<u32>(ptr, <u32>payloadLen, 5);
|
|
143
|
+
|
|
144
|
+
if (payloadLen) {
|
|
145
|
+
memory.copy(ptr + HEADER_SIZE, changetype<usize>(payload), payloadLen);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
writeStdout(out);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
class Frame {
|
|
152
|
+
constructor(
|
|
153
|
+
public type: MessageType,
|
|
154
|
+
public payload: ArrayBuffer,
|
|
155
|
+
) {}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function readFrame(): Frame | null {
|
|
159
|
+
const header = readExact(HEADER_SIZE);
|
|
160
|
+
if (header.byteLength < HEADER_SIZE) return null;
|
|
161
|
+
const head = changetype<usize>(header);
|
|
162
|
+
if (
|
|
163
|
+
load<u8>(head, 0) != MAGIC_W ||
|
|
164
|
+
load<u8>(head, 1) != MAGIC_I ||
|
|
165
|
+
load<u8>(head, 2) != MAGIC_P ||
|
|
166
|
+
load<u8>(head, 3) != MAGIC_C
|
|
167
|
+
) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
const type = <MessageType>load<u8>(head, 4);
|
|
171
|
+
const length = load<u32>(head, 5);
|
|
172
|
+
const payload = readExact(<i32>length);
|
|
173
|
+
if (payload.byteLength < <i32>length) return null;
|
|
174
|
+
return new Frame(type, payload);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function readExact(length: i32): ArrayBuffer {
|
|
178
|
+
const out = new ArrayBuffer(length);
|
|
179
|
+
let offset = 0;
|
|
180
|
+
while (offset < length) {
|
|
181
|
+
const chunk = readStdin(length - offset);
|
|
182
|
+
const size = chunk.byteLength;
|
|
183
|
+
if (!size) break;
|
|
184
|
+
memory.copy(
|
|
185
|
+
changetype<usize>(out) + offset,
|
|
186
|
+
changetype<usize>(chunk),
|
|
187
|
+
size,
|
|
188
|
+
);
|
|
189
|
+
offset += size;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (offset == length) return out;
|
|
193
|
+
|
|
194
|
+
const partial = new ArrayBuffer(offset);
|
|
195
|
+
if (offset) {
|
|
196
|
+
memory.copy(changetype<usize>(partial), changetype<usize>(out), offset);
|
|
197
|
+
}
|
|
198
|
+
return partial;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function writeStdout(data: ArrayBuffer): void {
|
|
202
|
+
if (IS_BINDINGS) {
|
|
203
|
+
process_stdout_write(data);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
wasiWriteAll(data);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function readStdin(max: i32): ArrayBuffer {
|
|
210
|
+
if (max <= 0) return new ArrayBuffer(0);
|
|
211
|
+
if (IS_BINDINGS) {
|
|
212
|
+
return process_stdin_read(max);
|
|
213
|
+
}
|
|
214
|
+
return wasiRead(max);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function wasiWriteAll(data: ArrayBuffer): void {
|
|
218
|
+
const total = data.byteLength;
|
|
219
|
+
if (!total) return;
|
|
220
|
+
|
|
221
|
+
const iovec = new ArrayBuffer(<i32>IOV_SIZE);
|
|
222
|
+
const writtenBuf = new ArrayBuffer(<i32>U32_SIZE);
|
|
223
|
+
let offset: i32 = 0;
|
|
224
|
+
while (offset < total) {
|
|
225
|
+
const left = total - offset;
|
|
226
|
+
const ptr = changetype<usize>(data) + <usize>offset;
|
|
227
|
+
const iovPtr = changetype<usize>(iovec);
|
|
228
|
+
const writtenPtr = changetype<usize>(writtenBuf);
|
|
229
|
+
store<usize>(iovPtr, ptr, 0);
|
|
230
|
+
store<usize>(iovPtr, <usize>left, sizeof<usize>());
|
|
231
|
+
store<u32>(writtenPtr, 0, 0);
|
|
232
|
+
const errno = wasi_fd_write(1, iovPtr, 1, writtenPtr);
|
|
233
|
+
if (errno != 0) return;
|
|
234
|
+
const written = <i32>load<u32>(writtenPtr, 0);
|
|
235
|
+
if (written <= 0) return;
|
|
236
|
+
offset += written;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function wasiRead(max: i32): ArrayBuffer {
|
|
241
|
+
const out = new ArrayBuffer(max);
|
|
242
|
+
const iovec = new ArrayBuffer(<i32>IOV_SIZE);
|
|
243
|
+
const readBuf = new ArrayBuffer(<i32>U32_SIZE);
|
|
244
|
+
const iovPtr = changetype<usize>(iovec);
|
|
245
|
+
const readPtr = changetype<usize>(readBuf);
|
|
246
|
+
|
|
247
|
+
store<usize>(iovPtr, changetype<usize>(out), 0);
|
|
248
|
+
store<usize>(iovPtr, <usize>max, sizeof<usize>());
|
|
249
|
+
store<u32>(readPtr, 0, 0);
|
|
250
|
+
|
|
251
|
+
const errno = wasi_fd_read(0, iovPtr, 1, readPtr);
|
|
252
|
+
if (errno != 0) return new ArrayBuffer(0);
|
|
253
|
+
|
|
254
|
+
const size = <i32>load<u32>(readPtr, 0);
|
|
255
|
+
if (size <= 0) return new ArrayBuffer(0);
|
|
256
|
+
if (size == max) return out;
|
|
257
|
+
|
|
258
|
+
const partial = new ArrayBuffer(size);
|
|
259
|
+
memory.copy(changetype<usize>(partial), changetype<usize>(out), size);
|
|
260
|
+
return partial;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function q(value: string): string {
|
|
264
|
+
return '"' + escape(value) + '"';
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function escape(value: string): string {
|
|
268
|
+
let out = "";
|
|
269
|
+
for (let i = 0; i < value.length; i++) {
|
|
270
|
+
const ch = value.charCodeAt(i);
|
|
271
|
+
if (ch == 34) {
|
|
272
|
+
out += '\\"';
|
|
273
|
+
} else if (ch == 92) {
|
|
274
|
+
out += "\\\\";
|
|
275
|
+
} else if (ch == 10) {
|
|
276
|
+
out += "\\n";
|
|
277
|
+
} else if (ch == 13) {
|
|
278
|
+
out += "\\r";
|
|
279
|
+
} else if (ch == 9) {
|
|
280
|
+
out += "\\t";
|
|
281
|
+
} else {
|
|
282
|
+
out += String.fromCharCode(ch);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return out;
|
|
286
|
+
}
|
package/bin/build.js
CHANGED
|
@@ -1,82 +1,118 @@
|
|
|
1
|
-
import { existsSync
|
|
1
|
+
import { existsSync } from "fs";
|
|
2
2
|
import { glob } from "glob";
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import { execSync } from "child_process";
|
|
5
5
|
import * as path from "path";
|
|
6
|
-
import { loadConfig } from "./util.js";
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
let config = loadConfig(CONFIG_PATH, true);
|
|
11
|
-
const ASCONFIG_PATH = path.join(process.cwd(), config.config);
|
|
12
|
-
if (config.config && config.config !== "none" && !existsSync(ASCONFIG_PATH)) {
|
|
13
|
-
console.log(`${chalk.bgMagentaBright(" WARN ")}${chalk.dim(":")} Could not locate asconfig.json file! If you do not want to provide a config, set "config": "none"`);
|
|
14
|
-
}
|
|
6
|
+
import { getPkgRunner, loadConfig } from "./util.js";
|
|
7
|
+
const DEFAULT_CONFIG_PATH = path.join(process.cwd(), "./as-test.config.json");
|
|
8
|
+
export async function build(configPath = DEFAULT_CONFIG_PATH, selectors = []) {
|
|
9
|
+
const config = loadConfig(configPath, false);
|
|
15
10
|
ensureDeps(config);
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
11
|
+
const pkgRunner = getPkgRunner();
|
|
12
|
+
const inputPatterns = resolveInputPatterns(config.input, selectors);
|
|
13
|
+
const inputFiles = await glob(inputPatterns);
|
|
14
|
+
const buildArgs = getBuildArgs(config);
|
|
19
15
|
for (const file of inputFiles) {
|
|
20
16
|
let cmd = `${pkgRunner} asc ${file}${buildArgs}`;
|
|
21
17
|
const outFile = `${config.outDir}/${file.slice(file.lastIndexOf("/") + 1).replace(".ts", ".wasm")}`;
|
|
22
18
|
if (config.outDir) {
|
|
23
19
|
cmd += " -o " + outFile;
|
|
24
20
|
}
|
|
25
|
-
|
|
21
|
+
try {
|
|
22
|
+
buildFile(cmd);
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
throw new Error(`Failed to build ${path.basename(file)} with ${getBuildStderr(error)}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function resolveInputPatterns(configured, selectors) {
|
|
30
|
+
const configuredInputs = Array.isArray(configured) ? configured : [configured];
|
|
31
|
+
if (!selectors.length)
|
|
32
|
+
return configuredInputs;
|
|
33
|
+
const patterns = new Set();
|
|
34
|
+
for (const selector of selectors) {
|
|
35
|
+
if (!selector)
|
|
36
|
+
continue;
|
|
37
|
+
if (isBareSuiteSelector(selector)) {
|
|
38
|
+
const base = stripSuiteSuffix(selector);
|
|
39
|
+
for (const configuredInput of configuredInputs) {
|
|
40
|
+
patterns.add(path.join(path.dirname(configuredInput), `${base}.spec.ts`));
|
|
41
|
+
}
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
patterns.add(selector);
|
|
26
45
|
}
|
|
46
|
+
return [...patterns];
|
|
47
|
+
}
|
|
48
|
+
function isBareSuiteSelector(selector) {
|
|
49
|
+
return (!selector.includes("/") &&
|
|
50
|
+
!selector.includes("\\") &&
|
|
51
|
+
!/[*?[\]{}]/.test(selector));
|
|
52
|
+
}
|
|
53
|
+
function stripSuiteSuffix(selector) {
|
|
54
|
+
return selector.replace(/\.spec\.ts$/, "").replace(/\.ts$/, "");
|
|
27
55
|
}
|
|
28
56
|
function ensureDeps(config) {
|
|
29
|
-
const pkg = JSON.parse(readFileSync(PKG_PATH).toString());
|
|
30
57
|
if (config.buildOptions.target == "wasi") {
|
|
31
58
|
if (!existsSync("./node_modules/@assemblyscript/wasi-shim/asconfig.json")) {
|
|
32
59
|
console.log(`${chalk.bgRed(" ERROR ")}${chalk.dim(":")} could not find @assemblyscript/wasi-shim! Add it to your dependencies to run with WASI!`);
|
|
33
60
|
process.exit(1);
|
|
34
61
|
}
|
|
35
|
-
if (pkg.dependencies &&
|
|
36
|
-
!Object.keys(pkg.dependencies).includes("@assemblyscript/wasi-shim") &&
|
|
37
|
-
pkg.devDependencies &&
|
|
38
|
-
!Object.keys(pkg.devDependencies).includes("@assemblyscript/wasi-shim") &&
|
|
39
|
-
pkg.peerDependencies &&
|
|
40
|
-
!Object.keys(pkg.peerDependencies).includes("@assemblyscript/wasi-shim") &&
|
|
41
|
-
existsSync("./node_modules/@assemblyscript/wasi-shim/asconfig.json")) {
|
|
42
|
-
console.log(`${chalk.bold.bgMagentaBright(" WARN ")}${chalk.dim(":")} @assemblyscript/wasi-shim is not included in project dependencies!"`);
|
|
43
|
-
}
|
|
44
62
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
case "pnpm": {
|
|
49
|
-
return "pnpx";
|
|
50
|
-
}
|
|
51
|
-
case "yarn": {
|
|
52
|
-
return "yarn";
|
|
53
|
-
}
|
|
54
|
-
case "bun": {
|
|
55
|
-
return "bunx";
|
|
56
|
-
}
|
|
63
|
+
if (!hasJsonAsTransform()) {
|
|
64
|
+
console.log(`${chalk.bgRed(" ERROR ")}${chalk.dim(":")} could not find json-as. Install it to compile as-test suites.`);
|
|
65
|
+
process.exit(1);
|
|
57
66
|
}
|
|
58
|
-
return "npx";
|
|
59
67
|
}
|
|
60
68
|
function buildFile(command) {
|
|
61
|
-
execSync(command, {
|
|
69
|
+
execSync(command, {
|
|
70
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
71
|
+
encoding: "utf8",
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function getBuildStderr(error) {
|
|
75
|
+
const err = error;
|
|
76
|
+
const stderr = err?.stderr;
|
|
77
|
+
if (typeof stderr == "string") {
|
|
78
|
+
const trimmed = stderr.trim();
|
|
79
|
+
if (trimmed.length)
|
|
80
|
+
return trimmed;
|
|
81
|
+
}
|
|
82
|
+
else if (stderr instanceof Buffer) {
|
|
83
|
+
const trimmed = stderr.toString("utf8").trim();
|
|
84
|
+
if (trimmed.length)
|
|
85
|
+
return trimmed;
|
|
86
|
+
}
|
|
87
|
+
const message = typeof err?.message == "string" ? err.message.trim() : "";
|
|
88
|
+
return message || "unknown error";
|
|
62
89
|
}
|
|
63
90
|
function getBuildArgs(config) {
|
|
64
91
|
let buildArgs = "";
|
|
65
|
-
buildArgs += " --transform as-test/transform
|
|
92
|
+
buildArgs += " --transform as-test/transform";
|
|
93
|
+
buildArgs += " --transform json-as/transform";
|
|
94
|
+
if (hasTryAsRuntime()) {
|
|
95
|
+
buildArgs += " --transform try-as/transform";
|
|
96
|
+
}
|
|
66
97
|
if (config.config && config.config !== "none") {
|
|
67
98
|
buildArgs += " --config " + config.config;
|
|
68
99
|
}
|
|
100
|
+
if (hasTryAsRuntime()) {
|
|
101
|
+
buildArgs += " --use AS_TEST_TRY_AS=1";
|
|
102
|
+
}
|
|
69
103
|
// Should also strip any bindings-enabling from asconfig
|
|
70
104
|
if (config.buildOptions.target == "bindings") {
|
|
105
|
+
buildArgs += " --use AS_TEST_BINDINGS=1";
|
|
71
106
|
buildArgs += " --bindings raw --exportRuntime --exportStart _start";
|
|
72
107
|
}
|
|
73
108
|
else if (config.buildOptions.target == "wasi") {
|
|
109
|
+
buildArgs += " --use AS_TEST_WASI=1";
|
|
74
110
|
buildArgs +=
|
|
75
111
|
" --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json";
|
|
76
112
|
}
|
|
77
113
|
else {
|
|
78
|
-
console.log(`${chalk.bgRed(" ERROR ")}${chalk.dim(":")} could determine target in config! Set target to 'bindings' or 'wasi'`);
|
|
79
|
-
process.exit(
|
|
114
|
+
console.log(`${chalk.bgRed(" ERROR ")}${chalk.dim(":")} could not determine target in config! Set target to 'bindings' or 'wasi'`);
|
|
115
|
+
process.exit(1);
|
|
80
116
|
}
|
|
81
117
|
if (config.buildOptions.args.length &&
|
|
82
118
|
config.buildOptions.args.find((v) => v.length > 0)) {
|
|
@@ -84,3 +120,12 @@ function getBuildArgs(config) {
|
|
|
84
120
|
}
|
|
85
121
|
return buildArgs;
|
|
86
122
|
}
|
|
123
|
+
function hasTryAsRuntime() {
|
|
124
|
+
return (existsSync(path.join(process.cwd(), "node_modules/try-as")) ||
|
|
125
|
+
existsSync(path.join(process.cwd(), "node_modules/try-as/package.json")));
|
|
126
|
+
}
|
|
127
|
+
function hasJsonAsTransform() {
|
|
128
|
+
return (existsSync(path.join(process.cwd(), "node_modules/json-as/transform.js")) ||
|
|
129
|
+
existsSync(path.join(process.cwd(), "node_modules/json-as/transform.ts")) ||
|
|
130
|
+
existsSync(path.join(process.cwd(), "node_modules/json-as/transform")));
|
|
131
|
+
}
|