gofront 1.7.0 → 1.9.0
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/README.md +14 -14
- package/package.json +10 -38
- package/src/backend/js/expressions.js +2060 -389
- package/src/backend/js/index.js +586 -174
- package/src/backend/js/natives.js +383 -0
- package/src/backend/js/runtime.js +936 -1644
- package/src/backend/js/statements.js +1349 -132
- package/src/backend/js/stdlib/index.js +51 -94
- package/src/backend/js/templ.js +67 -118
- package/src/backend/js/type-info.js +436 -0
- package/src/backend/shared/fixed-float.js +20 -0
- package/src/backend/shared/fmt-types.js +80 -0
- package/src/backend/shared/host-unicode.js +36 -0
- package/src/backend/wasm/boundary.js +753 -872
- package/src/backend/wasm/emit-builtins.js +914 -237
- package/src/backend/wasm/emit-exprs.js +1456 -195
- package/src/backend/wasm/emit-maps.js +78 -380
- package/src/backend/wasm/emit-stmts.js +1659 -214
- package/src/backend/wasm/emit.js +614 -88
- package/src/backend/wasm/encode.js +43 -13
- package/src/backend/wasm/globals.js +491 -0
- package/src/backend/wasm/glue.js +2 -4
- package/src/backend/wasm/index.js +406 -3195
- package/src/backend/wasm/method-expr.js +392 -0
- package/src/backend/wasm/module-emitter.js +1615 -0
- package/src/backend/wasm/monomorph.js +164 -9
- package/src/backend/wasm/natives.js +596 -0
- package/src/backend/wasm/prescan.js +249 -0
- package/src/backend/wasm/prune-funcs.js +89 -0
- package/src/backend/wasm/stdlib/index.js +2 -37
- package/src/backend/wasm/stdlib/simd.js +293 -28
- package/src/backend/wasm/types.js +260 -27
- package/src/backend/wasm/variadic.js +93 -0
- package/src/backend/wasm/wat.js +47 -20
- package/src/{cli-core.js → cli/cli-core.js} +241 -11
- package/src/{test-runner.js → cli/test-runner.js} +188 -122
- package/src/{vendor.js → cli/vendor.js} +3 -4
- package/src/compiler.js +202 -386
- package/src/index.js +15 -169
- package/src/{lexer.js → lexer/lexer.js} +203 -62
- package/src/{templ-lexer.js → lexer/templ-lexer.js} +61 -18
- package/src/{tokens.js → lexer/tokens.js} +2 -0
- package/src/link/sourcemap.js +97 -0
- package/src/link/stdlib.js +737 -0
- package/src/link/type-names.js +148 -0
- package/src/link/wasm.js +318 -0
- package/src/lower/bounds.js +547 -0
- package/src/lower/boxing.js +1 -1
- package/src/lower/captures.js +267 -64
- package/src/lower/embedding.js +32 -3
- package/src/lower/errors-as.js +196 -0
- package/src/lower/fmt-formatters.js +905 -0
- package/src/lower/functions.js +2 -0
- package/src/lower/gen-types.js +274 -0
- package/src/lower/index.js +33 -19
- package/src/lower/json-codecs.js +1379 -0
- package/src/lower/ownership.js +47 -8
- package/src/lower/range.js +86 -1
- package/src/lower/reachability.js +150 -0
- package/src/lower/walk.js +12 -0
- package/src/parser/declarations.js +83 -15
- package/src/parser/expressions.js +110 -18
- package/src/parser/index.js +2 -1
- package/src/parser/statements.js +38 -22
- package/src/{templ-parser.js → parser/templ.js} +179 -17
- package/src/parser/types.js +70 -9
- package/src/resolver.js +21 -1
- package/src/typechecker/assignability.js +291 -19
- package/src/typechecker/const-fold.js +399 -0
- package/src/typechecker/constants.js +282 -0
- package/src/typechecker/expressions.js +1220 -183
- package/src/typechecker/index.js +659 -92
- package/src/typechecker/init-order.js +426 -0
- package/src/typechecker/operand-text.js +40 -0
- package/src/typechecker/resolve.js +613 -62
- package/src/typechecker/statements.js +212 -20
- package/src/typechecker/stdlib/excluded.js +902 -0
- package/src/typechecker/stdlib/index.js +38 -0
- package/src/typechecker/stdlib/simd.js +65 -15
- package/src/typechecker/termination.js +11 -2
- package/src/typechecker/types.js +268 -514
- package/stdlib/bytes/buffer.go +479 -0
- package/stdlib/bytes/bytes.go +1010 -0
- package/stdlib/bytes/reader.go +161 -0
- package/stdlib/cmp/cmp.go +65 -0
- package/stdlib/context/context.go +115 -0
- package/stdlib/crypto/rand/rand.go +34 -0
- package/stdlib/crypto/sha256/sha256.go +249 -0
- package/stdlib/encoding/base64/base64.go +331 -0
- package/stdlib/encoding/binary/binary.go +332 -0
- package/stdlib/encoding/hex/hex.go +140 -0
- package/stdlib/encoding/json/errors.go +31 -0
- package/stdlib/encoding/json/indent.go +71 -0
- package/stdlib/encoding/json/json.go +62 -0
- package/stdlib/encoding/json/number.go +12 -0
- package/stdlib/encoding/json/stream.go +173 -0
- package/stdlib/errors/errors.go +174 -0
- package/stdlib/fmt/errors.go +110 -0
- package/stdlib/fmt/format.go +732 -0
- package/stdlib/fmt/print.go +1232 -0
- package/stdlib/gom/gom.go +293 -0
- package/stdlib/hash/hash.go +53 -0
- package/stdlib/html/html.go +251 -0
- package/stdlib/internal/fmtrt/fmtrt.go +163 -0
- package/stdlib/internal/jsonrt/dec.go +871 -0
- package/stdlib/internal/jsonrt/enc.go +516 -0
- package/stdlib/internal/jsonrt/indent.go +135 -0
- package/stdlib/internal/jsonrt/number.go +27 -0
- package/stdlib/internal/jsonrt/reader.go +73 -0
- package/stdlib/internal/jsonrt/scanner.go +658 -0
- package/stdlib/io/io.go +502 -0
- package/stdlib/iter/iter.go +18 -0
- package/stdlib/maps/maps.go +131 -0
- package/stdlib/math/bits/bits.go +507 -0
- package/stdlib/math/extra.go +272 -0
- package/stdlib/math/math.go +439 -0
- package/stdlib/math/rand/rand.go +297 -0
- package/stdlib/os/os.go +93 -0
- package/stdlib/path/filepath/filepath.go +47 -0
- package/stdlib/path/path.go +394 -0
- package/stdlib/regexp/regexp.go +231 -0
- package/stdlib/slices/slices.go +526 -0
- package/stdlib/slices/sort.go +209 -0
- package/stdlib/slices/zsort_cmp.go +480 -0
- package/stdlib/slices/zsort_ordered.go +482 -0
- package/stdlib/sort/sort.go +500 -0
- package/stdlib/sort/zsort_func.go +480 -0
- package/stdlib/sort/zsort_iface.go +480 -0
- package/stdlib/strconv/float.go +1699 -0
- package/stdlib/strconv/isprint.go +752 -0
- package/stdlib/strconv/quote.go +526 -0
- package/stdlib/strconv/strconv.go +616 -0
- package/stdlib/strings/builder.go +95 -0
- package/stdlib/strings/reader.go +163 -0
- package/stdlib/strings/replacer.go +102 -0
- package/stdlib/strings/strings.go +807 -0
- package/stdlib/sync/sync.go +268 -0
- package/stdlib/testing/async_js.go +61 -0
- package/stdlib/testing/benchmark.go +297 -0
- package/stdlib/testing/testing.go +523 -0
- package/stdlib/time/duration.go +233 -0
- package/stdlib/time/format.go +745 -0
- package/stdlib/time/parse.go +790 -0
- package/stdlib/time/sleep_js.go +63 -0
- package/stdlib/time/time.go +834 -0
- package/stdlib/unicode/unicode.go +250 -0
- package/stdlib/unicode/utf8/utf8.go +464 -0
- package/src/backend/js/stdlib/base64.js +0 -12
- package/src/backend/js/stdlib/binary.js +0 -102
- package/src/backend/js/stdlib/bits.js +0 -46
- package/src/backend/js/stdlib/builder.js +0 -63
- package/src/backend/js/stdlib/bytes.js +0 -122
- package/src/backend/js/stdlib/errors.js +0 -44
- package/src/backend/js/stdlib/fmt.js +0 -178
- package/src/backend/js/stdlib/gom.js +0 -155
- package/src/backend/js/stdlib/hex.js +0 -17
- package/src/backend/js/stdlib/html.js +0 -20
- package/src/backend/js/stdlib/io.js +0 -137
- package/src/backend/js/stdlib/json.js +0 -972
- package/src/backend/js/stdlib/maps.js +0 -45
- package/src/backend/js/stdlib/math.js +0 -69
- package/src/backend/js/stdlib/os.js +0 -13
- package/src/backend/js/stdlib/path.js +0 -48
- package/src/backend/js/stdlib/rand.js +0 -32
- package/src/backend/js/stdlib/regexp.js +0 -54
- package/src/backend/js/stdlib/sha256.js +0 -12
- package/src/backend/js/stdlib/shared.js +0 -17
- package/src/backend/js/stdlib/simd.js +0 -24
- package/src/backend/js/stdlib/slices.js +0 -77
- package/src/backend/js/stdlib/sort.js +0 -30
- package/src/backend/js/stdlib/strconv.js +0 -74
- package/src/backend/js/stdlib/strings.js +0 -222
- package/src/backend/js/stdlib/sync.js +0 -13
- package/src/backend/js/stdlib/testing.js +0 -34
- package/src/backend/js/stdlib/time.js +0 -128
- package/src/backend/js/stdlib/unicode.js +0 -25
- package/src/backend/js/stdlib/utf8.js +0 -26
- package/src/backend/wasm/const-fold.js +0 -205
- package/src/backend/wasm/emit-stdlib.js +0 -13
- package/src/backend/wasm/stdlib/bytes.js +0 -5039
- package/src/backend/wasm/stdlib/core.js +0 -8903
- package/src/backend/wasm/stdlib/io.js +0 -2161
- package/src/backend/wasm/stdlib/packages.js +0 -2400
- package/src/backend/wasm/stdlib/pure.js +0 -720
- package/src/backend/wasm/stdlib/time.js +0 -1200
- package/src/typechecker/stdlib/core.js +0 -801
- package/src/typechecker/stdlib/extended.js +0 -914
- package/src/typechecker/stdlib.js +0 -22
- /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
- /package/src/{colors.js → cli/colors.js} +0 -0
- /package/src/{dev-server.js → cli/dev-server.js} +0 -0
- /package/src/{minifier.js → cli/minifier.js} +0 -0
- /package/src/{project-config.js → cli/project-config.js} +0 -0
- /package/src/{pwa.js → cli/pwa.js} +0 -0
|
@@ -6,13 +6,12 @@ import { statSync } from "node:fs";
|
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
import { basename, dirname, join, resolve } from "node:path";
|
|
8
8
|
import { pathToFileURL } from "node:url";
|
|
9
|
-
import { HELPER_SPRINTF, HELPER_TESTING } from "./backend/js/runtime.js";
|
|
10
|
-
import { colorEnabled, createColors, formatDiagnostic } from "./colors.js";
|
|
11
9
|
import {
|
|
12
10
|
compilePackageTests,
|
|
13
11
|
compilePackageTestsWasm,
|
|
14
12
|
gwFilesIn,
|
|
15
|
-
} from "
|
|
13
|
+
} from "../compiler.js";
|
|
14
|
+
import { colorEnabled, createColors, formatDiagnostic } from "./colors.js";
|
|
16
15
|
|
|
17
16
|
// WasmGC + exception handling (what the wasm backend emits) ship enabled by
|
|
18
17
|
// default from Node 22 (V8 11.9+). Older runtimes fail at instantiate time
|
|
@@ -30,11 +29,55 @@ export function checkWasmRuntime(version = process.version) {
|
|
|
30
29
|
export function isTestFunc(decl) {
|
|
31
30
|
if (decl.kind !== "FuncDecl") return false;
|
|
32
31
|
if (!decl.name.startsWith("Test")) return false;
|
|
32
|
+
if (decl.name === "TestMain") return false;
|
|
33
|
+
if (decl.params?.length !== 1) return false;
|
|
34
|
+
const pType = decl.params[0].type;
|
|
35
|
+
if (
|
|
36
|
+
pType?.kind === "PointerType" &&
|
|
37
|
+
(pType.base?.name === "testing.T" || pType.base?.name === "T")
|
|
38
|
+
)
|
|
39
|
+
return true;
|
|
40
|
+
if (
|
|
41
|
+
pType?.kind === "TypeName" &&
|
|
42
|
+
(pType.name === "testing.T" || pType.name === "T")
|
|
43
|
+
)
|
|
44
|
+
return true;
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function isBenchmarkFunc(decl) {
|
|
49
|
+
if (decl.kind !== "FuncDecl") return false;
|
|
50
|
+
if (!decl.name.startsWith("Benchmark")) return false;
|
|
51
|
+
if (decl.params?.length !== 1) return false;
|
|
52
|
+
const pType = decl.params[0].type;
|
|
53
|
+
if (
|
|
54
|
+
pType?.kind === "PointerType" &&
|
|
55
|
+
(pType.base?.name === "testing.B" || pType.base?.name === "B")
|
|
56
|
+
)
|
|
57
|
+
return true;
|
|
58
|
+
if (
|
|
59
|
+
pType?.kind === "TypeName" &&
|
|
60
|
+
(pType.name === "testing.B" || pType.name === "B")
|
|
61
|
+
)
|
|
62
|
+
return true;
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function isTestMainFunc(decl) {
|
|
67
|
+
if (decl.kind !== "FuncDecl") return false;
|
|
68
|
+
if (decl.name !== "TestMain") return false;
|
|
33
69
|
if (decl.params?.length !== 1) return false;
|
|
34
70
|
const pType = decl.params[0].type;
|
|
35
|
-
if (
|
|
71
|
+
if (
|
|
72
|
+
pType?.kind === "PointerType" &&
|
|
73
|
+
(pType.base?.name === "testing.M" || pType.base?.name === "M")
|
|
74
|
+
)
|
|
75
|
+
return true;
|
|
76
|
+
if (
|
|
77
|
+
pType?.kind === "TypeName" &&
|
|
78
|
+
(pType.name === "testing.M" || pType.name === "M")
|
|
79
|
+
)
|
|
36
80
|
return true;
|
|
37
|
-
if (pType?.kind === "TypeName" && pType.name === "testing.T") return true;
|
|
38
81
|
return false;
|
|
39
82
|
}
|
|
40
83
|
|
|
@@ -53,8 +96,89 @@ export function discoverTests(programs) {
|
|
|
53
96
|
return testNames;
|
|
54
97
|
}
|
|
55
98
|
|
|
56
|
-
|
|
57
|
-
|
|
99
|
+
// The `async func Test…` names (js packages only).
|
|
100
|
+
export function discoverAsyncTests(programs) {
|
|
101
|
+
const names = [];
|
|
102
|
+
for (const p of programs) {
|
|
103
|
+
if (p._filename && !p._filename.endsWith("_test.go")) continue;
|
|
104
|
+
for (const d of p.decls) {
|
|
105
|
+
if (isTestFunc(d) && (d.async || d.isAsync) && !names.includes(d.name))
|
|
106
|
+
names.push(d.name);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return names;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function discoverBenchmarks(programs) {
|
|
113
|
+
const benchNames = [];
|
|
114
|
+
for (const p of programs) {
|
|
115
|
+
if (p._filename && !p._filename.endsWith("_test.go")) continue;
|
|
116
|
+
for (const d of p.decls) {
|
|
117
|
+
if (isBenchmarkFunc(d) && !benchNames.includes(d.name)) {
|
|
118
|
+
benchNames.push(d.name);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return benchNames;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function discoverTestMain(programs) {
|
|
126
|
+
for (const p of programs) {
|
|
127
|
+
if (p._filename && !p._filename.endsWith("_test.go")) continue;
|
|
128
|
+
for (const d of p.decls) {
|
|
129
|
+
if (isTestMainFunc(d)) return d.name;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// The Go source of the driver the runner compiles with a package's tests (see
|
|
136
|
+
// `testDriver` in compileFiles; it is never written to disk). `target` is the
|
|
137
|
+
// package's target: a `js` package is driven asynchronously so that async
|
|
138
|
+
// tests and subtests can be awaited; a TestMain gets the M and runs it
|
|
139
|
+
// itself.
|
|
140
|
+
export function generateTestDriver(
|
|
141
|
+
pkgName,
|
|
142
|
+
target,
|
|
143
|
+
{ testNames, benchNames, testMain, asyncTests = [] },
|
|
144
|
+
) {
|
|
145
|
+
if (testMain && asyncTests.length > 0) {
|
|
146
|
+
throw new Error(
|
|
147
|
+
`async test functions cannot be combined with TestMain (${asyncTests.join(", ")}): remove TestMain or make the tests synchronous`,
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
const entries = (names, _type) =>
|
|
151
|
+
names.map((n) => `\t\t{Name: ${JSON.stringify(n)}, F: ${n}},`).join("\n");
|
|
152
|
+
const table = (type, names) =>
|
|
153
|
+
names.length === 0
|
|
154
|
+
? `[]testing.${type}{}`
|
|
155
|
+
: `[]testing.${type}{\n${entries(names)}\n\t}`;
|
|
156
|
+
const make = `\tm := testing.GofrontMain(${JSON.stringify(pkgName)}, run, bench, verbose, ${table("GofrontTest", testNames)}, ${table("GofrontBenchmark", benchNames)})`;
|
|
157
|
+
let body;
|
|
158
|
+
let head = "func";
|
|
159
|
+
if (testMain) {
|
|
160
|
+
body = `\tTestMain(m)\n\treturn m.ExitCode()`;
|
|
161
|
+
} else if (target === "js") {
|
|
162
|
+
head = "async func";
|
|
163
|
+
body = "\treturn await m.RunAsync()";
|
|
164
|
+
} else {
|
|
165
|
+
body = "\treturn m.Run()";
|
|
166
|
+
}
|
|
167
|
+
return `package ${pkgName}
|
|
168
|
+
|
|
169
|
+
import "testing"
|
|
170
|
+
|
|
171
|
+
${head} GofrontRunTests(run, bench string, verbose bool) int {
|
|
172
|
+
${make}
|
|
173
|
+
${body}
|
|
174
|
+
}
|
|
175
|
+
`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// The module the test child process runs: the compiled package (with its
|
|
179
|
+
// driver), then one call to GofrontRunTests. Everything else (running,
|
|
180
|
+
// filtering, reporting) happens inside the package.
|
|
181
|
+
export function generateTestHarness(bundleJs, options = {}) {
|
|
58
182
|
const verbose = Boolean(options.verbose);
|
|
59
183
|
const dom = Boolean(options.dom);
|
|
60
184
|
const color = Boolean(options.color);
|
|
@@ -64,6 +188,12 @@ export function generateTestHarness(bundleJs, testNames, options = {}) {
|
|
|
64
188
|
const jsdomSpec = options.jsdomPath
|
|
65
189
|
? pathToFileURL(options.jsdomPath).href
|
|
66
190
|
: "jsdom";
|
|
191
|
+
const run = options.run ?? "";
|
|
192
|
+
const bench = options.bench
|
|
193
|
+
? options.bench === true
|
|
194
|
+
? "."
|
|
195
|
+
: options.bench
|
|
196
|
+
: "";
|
|
67
197
|
|
|
68
198
|
return `
|
|
69
199
|
${
|
|
@@ -95,14 +225,12 @@ globalThis.customElements = __dom.window.customElements;
|
|
|
95
225
|
globalThis.document = globalThis.document ?? null;
|
|
96
226
|
`
|
|
97
227
|
}
|
|
98
|
-
|
|
228
|
+
// The package line and colours the testing package prints come from here.
|
|
229
|
+
process.env.GOFRONT_TEST_LABEL = ${JSON.stringify(pkgName)};
|
|
230
|
+
process.env.GOFRONT_TEST_COLOR = ${color ? '"1"' : '"0"'};
|
|
99
231
|
${
|
|
100
232
|
options.wasmBytes
|
|
101
|
-
? `
|
|
102
|
-
// ── WASM module (tests run inside app.wasm; *testing.T stays in JS) ──
|
|
103
|
-
${HELPER_SPRINTF}
|
|
104
|
-
${HELPER_TESTING}
|
|
105
|
-
globalThis.__GOFRONT_WASM_BYTES = Uint8Array.from(atob(${JSON.stringify(Buffer.from(options.wasmBytes).toString("base64"))}), (c) => c.charCodeAt(0));
|
|
233
|
+
? `globalThis.__GOFRONT_WASM_BYTES = Uint8Array.from(atob(${JSON.stringify(Buffer.from(options.wasmBytes).toString("base64"))}), (c) => c.charCodeAt(0));
|
|
106
234
|
`
|
|
107
235
|
: ""
|
|
108
236
|
}
|
|
@@ -110,106 +238,13 @@ globalThis.__GOFRONT_WASM_BYTES = Uint8Array.from(atob(${JSON.stringify(Buffer.f
|
|
|
110
238
|
${bundleJs}
|
|
111
239
|
// ─────────────────────────────
|
|
112
240
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const paint = ${color}
|
|
119
|
-
? (code) => (s) => "\\x1b[" + code + "m" + s + "\\x1b[0m"
|
|
120
|
-
: () => (s) => s;
|
|
121
|
-
const red = paint(31), green = paint(32), yellow = paint(33), dim = paint(2), bold = paint(1);
|
|
122
|
-
const PASS = green("PASS"), FAIL = bold(red("FAIL")), SKIP = yellow("SKIP");
|
|
123
|
-
const okLine = (name, t) => console.log(green("ok ") + "\\t" + name + "\\t" + dim(t + "s"));
|
|
124
|
-
|
|
125
|
-
const testsToRun = runFilter
|
|
126
|
-
? allTests.filter((name) => runFilter.test(name))
|
|
127
|
-
: allTests;
|
|
128
|
-
|
|
129
|
-
if (testsToRun.length === 0) {
|
|
130
|
-
if (allTests.length > 0 && runFilter) {
|
|
131
|
-
console.log(yellow("testing: warning: no tests to run matching " + ${JSON.stringify(runRegex)}));
|
|
132
|
-
}
|
|
133
|
-
console.log(PASS);
|
|
134
|
-
okLine(pkgName, "0.000");
|
|
135
|
-
process.exit(0);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
let totalFailures = 0;
|
|
139
|
-
let totalSkipped = 0;
|
|
140
|
-
const now = () => (typeof performance !== "undefined" ? performance.now() : Date.now());
|
|
141
|
-
const suiteStart = now();
|
|
142
|
-
|
|
143
|
-
// Go-style streaming report. In non-verbose mode only failures and skips are
|
|
144
|
-
// shown, so the "=== RUN" header is emitted late for failures.
|
|
145
|
-
const report = (t) => {
|
|
146
|
-
const elapsed = dim("(" + ((now() - t._start) / 1000).toFixed(2) + "s)");
|
|
147
|
-
if (t.skipped) {
|
|
148
|
-
console.log("--- " + SKIP + ": " + t._name + " " + elapsed);
|
|
149
|
-
for (const log of t._logs) console.log(" " + log);
|
|
150
|
-
} else if (t.failed) {
|
|
151
|
-
if (!verbose) console.log(dim("=== RUN ") + t._name);
|
|
152
|
-
for (const log of t._logs) console.log(" " + red(log));
|
|
153
|
-
console.log("--- " + FAIL + ": " + t._name + " " + elapsed);
|
|
154
|
-
} else if (verbose) {
|
|
155
|
-
for (const log of t._logs) console.log(" " + log);
|
|
156
|
-
console.log("--- " + PASS + ": " + t._name + " " + elapsed);
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
// FailNow/SkipNow are control flow; anything else is a panic → failure.
|
|
161
|
-
const recordTestError = (t, e) => {
|
|
162
|
-
if (e instanceof __GoFront_FailNow || e instanceof __GoFront_SkipNow) return;
|
|
163
|
-
t.Fail();
|
|
164
|
-
t.Log("panic: " + (e?.message ?? String(e)));
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
globalThis.__onSubtestStart = (name) => {
|
|
168
|
-
if (verbose) console.log(dim("=== RUN ") + name);
|
|
169
|
-
};
|
|
170
|
-
globalThis.__onSubtestEnd = report;
|
|
171
|
-
|
|
172
|
-
const __testRegistry = {
|
|
173
|
-
${testNames.map((n) => ` ${JSON.stringify(n)}: typeof ${n} !== "undefined" ? ${n} : null`).join(",\n")}
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
for (const name of testsToRun) {
|
|
177
|
-
const fn = __testRegistry[name] ?? (typeof globalThis[name] === "function" ? globalThis[name] : null);
|
|
178
|
-
if (typeof fn !== "function") {
|
|
179
|
-
console.error(red("testing: cannot find test function " + name));
|
|
180
|
-
totalFailures++;
|
|
181
|
-
continue;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const t = new __GoFront_T(name);
|
|
185
|
-
if (verbose) console.log(dim("=== RUN ") + name);
|
|
186
|
-
|
|
187
|
-
try {
|
|
188
|
-
const res = fn(t);
|
|
189
|
-
if (res && typeof res.then === "function") await res;
|
|
190
|
-
} catch (e) {
|
|
191
|
-
recordTestError(t, e);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (t.skipped) totalSkipped++;
|
|
195
|
-
else if (t.failed) totalFailures++;
|
|
196
|
-
report(t);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const suiteElapsed = ((now() - suiteStart) / 1000).toFixed(3);
|
|
200
|
-
|
|
201
|
-
if (totalFailures > 0) {
|
|
202
|
-
console.log(FAIL);
|
|
203
|
-
console.log(FAIL + "\\t" + pkgName + "\\t" + dim(suiteElapsed + "s"));
|
|
204
|
-
process.exit(1);
|
|
205
|
-
} else {
|
|
206
|
-
console.log(PASS);
|
|
207
|
-
okLine(pkgName, suiteElapsed);
|
|
208
|
-
process.exit(0);
|
|
209
|
-
}
|
|
241
|
+
let __exitCode = 1;
|
|
242
|
+
try {
|
|
243
|
+
__exitCode = Number(await GofrontRunTests(${JSON.stringify(run)}, ${JSON.stringify(bench)}, ${verbose}));
|
|
244
|
+
} catch (e) {
|
|
245
|
+
console.error("panic: " + (e?.message ?? String(e)));
|
|
210
246
|
}
|
|
211
|
-
|
|
212
|
-
__runGoFrontSuite();
|
|
247
|
+
process.exit(__exitCode);
|
|
213
248
|
`;
|
|
214
249
|
}
|
|
215
250
|
|
|
@@ -324,10 +359,16 @@ function reportBuildFailure(err, resolvedDir, options) {
|
|
|
324
359
|
|
|
325
360
|
// `both` packages run twice (JS and wasm) so the two backends are kept in
|
|
326
361
|
// agreement; output of both runs is concatenated.
|
|
327
|
-
async function runDualTarget(
|
|
362
|
+
async function runDualTarget(
|
|
363
|
+
compiled,
|
|
364
|
+
resolvedDir,
|
|
365
|
+
runHarness,
|
|
366
|
+
compileOptions,
|
|
367
|
+
options,
|
|
368
|
+
) {
|
|
328
369
|
let wasmCompiled;
|
|
329
370
|
try {
|
|
330
|
-
wasmCompiled = compilePackageTestsWasm(resolvedDir,
|
|
371
|
+
wasmCompiled = compilePackageTestsWasm(resolvedDir, compileOptions);
|
|
331
372
|
} catch (err) {
|
|
332
373
|
return reportBuildFailure(err, resolvedDir, options);
|
|
333
374
|
}
|
|
@@ -365,31 +406,50 @@ export async function runTests(targetDir, options = {}) {
|
|
|
365
406
|
return reportEmptyTests(basename(resolvedDir), "no test files", options);
|
|
366
407
|
}
|
|
367
408
|
|
|
409
|
+
// The driver is generated while the package compiles, once its files are
|
|
410
|
+
// parsed and its target is known.
|
|
411
|
+
let testNames = [];
|
|
412
|
+
let benchNames = [];
|
|
413
|
+
let testMain = null;
|
|
414
|
+
const compileOptions = {
|
|
415
|
+
...options,
|
|
416
|
+
testDriver: (programs, target) => {
|
|
417
|
+
testNames = discoverTests(programs);
|
|
418
|
+
benchNames = discoverBenchmarks(programs);
|
|
419
|
+
testMain = discoverTestMain(programs);
|
|
420
|
+
if (testNames.length === 0 && benchNames.length === 0 && !testMain)
|
|
421
|
+
return null;
|
|
422
|
+
return generateTestDriver(programs[0].pkg.name, target, {
|
|
423
|
+
testNames,
|
|
424
|
+
benchNames,
|
|
425
|
+
testMain,
|
|
426
|
+
asyncTests: discoverAsyncTests(programs),
|
|
427
|
+
});
|
|
428
|
+
},
|
|
429
|
+
};
|
|
368
430
|
let compiled;
|
|
369
431
|
try {
|
|
370
|
-
compiled = compilePackageTests(resolvedDir,
|
|
432
|
+
compiled = compilePackageTests(resolvedDir, compileOptions);
|
|
371
433
|
} catch (err) {
|
|
372
434
|
return reportBuildFailure(err, resolvedDir, options);
|
|
373
435
|
}
|
|
374
436
|
|
|
375
|
-
const { pkgName, js
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
if (testNames.length === 0) {
|
|
437
|
+
const { pkgName, js } = compiled;
|
|
438
|
+
if (testNames.length === 0 && benchNames.length === 0 && !testMain) {
|
|
379
439
|
return reportEmptyTests(pkgName, "no tests to run", options);
|
|
380
440
|
}
|
|
381
441
|
|
|
382
442
|
const runHarness = (bundleJs, label, wasmBytes) =>
|
|
383
443
|
spawnTestRunner(
|
|
384
444
|
resolvedDir,
|
|
385
|
-
generateTestHarness(bundleJs,
|
|
445
|
+
generateTestHarness(bundleJs, {
|
|
386
446
|
...options,
|
|
387
447
|
pkgName: label,
|
|
388
448
|
jsdomPath,
|
|
389
449
|
wasmBytes,
|
|
390
450
|
color: colorsFor(options, options.stdout ?? process.stdout).enabled,
|
|
391
451
|
}),
|
|
392
|
-
testNames.length,
|
|
452
|
+
testNames.length + benchNames.length,
|
|
393
453
|
options,
|
|
394
454
|
);
|
|
395
455
|
|
|
@@ -403,7 +463,13 @@ export async function runTests(targetDir, options = {}) {
|
|
|
403
463
|
}
|
|
404
464
|
}
|
|
405
465
|
if (compiled.target === "both") {
|
|
406
|
-
return runDualTarget(
|
|
466
|
+
return runDualTarget(
|
|
467
|
+
compiled,
|
|
468
|
+
resolvedDir,
|
|
469
|
+
runHarness,
|
|
470
|
+
compileOptions,
|
|
471
|
+
options,
|
|
472
|
+
);
|
|
407
473
|
}
|
|
408
474
|
return runHarness(js, pkgName, compiled.wasm ?? null);
|
|
409
475
|
}
|
|
@@ -442,10 +442,9 @@ export async function bundleVendor(projectDir = ".", options = {}) {
|
|
|
442
442
|
}
|
|
443
443
|
|
|
444
444
|
const entryCode = generateVendorEntry(packages, globals, namedExports);
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
);
|
|
445
|
+
// A fixed name: the bundler records the entry path in vendor.js, so a
|
|
446
|
+
// per-run name would make every prep produce different bytes.
|
|
447
|
+
const entryFile = join(projectRoot, ".gofront-vendor-entry.mjs");
|
|
449
448
|
writeFileSync(entryFile, entryCode);
|
|
450
449
|
|
|
451
450
|
try {
|