gofront 1.7.0 → 1.8.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.
Files changed (128) hide show
  1. package/README.md +13 -13
  2. package/package.json +8 -37
  3. package/src/backend/js/expressions.js +1341 -148
  4. package/src/backend/js/fmt-runtime.js +573 -0
  5. package/src/backend/js/index.js +375 -57
  6. package/src/backend/js/runtime.js +1460 -133
  7. package/src/backend/js/statements.js +900 -86
  8. package/src/backend/js/stdlib/bits.js +87 -14
  9. package/src/backend/js/stdlib/builder.js +41 -6
  10. package/src/backend/js/stdlib/bytes.js +253 -7
  11. package/src/backend/js/stdlib/errors.js +2 -1
  12. package/src/backend/js/stdlib/fmt.js +349 -10
  13. package/src/backend/js/stdlib/index.js +8 -3
  14. package/src/backend/js/stdlib/json.js +247 -52
  15. package/src/backend/js/stdlib/maps.js +0 -8
  16. package/src/backend/js/stdlib/math.js +17 -1
  17. package/src/backend/js/stdlib/simd.js +10 -0
  18. package/src/backend/js/stdlib/slices.js +36 -6
  19. package/src/backend/js/stdlib/strconv.js +10 -5
  20. package/src/backend/js/stdlib/strings.js +83 -4
  21. package/src/backend/js/stdlib/testing.js +7 -0
  22. package/src/backend/js/stdlib/time.js +79 -55
  23. package/src/backend/js/stdlib/unicode.js +1 -1
  24. package/src/backend/js/stdlib/utf8.js +1 -1
  25. package/src/backend/js/templ.js +38 -76
  26. package/src/backend/js/type-info.js +272 -0
  27. package/src/backend/shared/fmt-types.js +188 -0
  28. package/src/backend/wasm/boundary.js +436 -80
  29. package/src/backend/wasm/emit-builtins.js +303 -13
  30. package/src/backend/wasm/emit-exprs.js +1397 -203
  31. package/src/backend/wasm/emit-maps.js +61 -13
  32. package/src/backend/wasm/emit-stmts.js +1359 -164
  33. package/src/backend/wasm/emit.js +512 -77
  34. package/src/backend/wasm/encode.js +43 -13
  35. package/src/backend/wasm/globals.js +452 -0
  36. package/src/backend/wasm/index.js +194 -2489
  37. package/src/backend/wasm/method-expr.js +381 -0
  38. package/src/backend/wasm/module-emitter.js +2240 -0
  39. package/src/backend/wasm/monomorph.js +62 -4
  40. package/src/backend/wasm/prescan.js +397 -0
  41. package/src/backend/wasm/stdlib/bytes.js +1804 -127
  42. package/src/backend/wasm/stdlib/core.js +1574 -199
  43. package/src/backend/wasm/stdlib/index.js +0 -5
  44. package/src/backend/wasm/stdlib/io.js +1567 -150
  45. package/src/backend/wasm/stdlib/packages.js +2 -0
  46. package/src/backend/wasm/stdlib/simd.js +293 -28
  47. package/src/backend/wasm/stdlib/time.js +1041 -12
  48. package/src/backend/wasm/types.js +200 -15
  49. package/src/backend/wasm/variadic.js +93 -0
  50. package/src/backend/wasm/wat.js +47 -20
  51. package/src/{cli-core.js → cli/cli-core.js} +236 -10
  52. package/src/{test-runner.js → cli/test-runner.js} +332 -39
  53. package/src/{vendor.js → cli/vendor.js} +3 -4
  54. package/src/compiler.js +107 -269
  55. package/src/index.js +15 -169
  56. package/src/{lexer.js → lexer/lexer.js} +102 -55
  57. package/src/{tokens.js → lexer/tokens.js} +1 -0
  58. package/src/link/sourcemap.js +97 -0
  59. package/src/link/stdlib.js +515 -0
  60. package/src/link/wasm.js +294 -0
  61. package/src/lower/bounds.js +394 -0
  62. package/src/lower/boxing.js +1 -1
  63. package/src/lower/captures.js +176 -32
  64. package/src/lower/index.js +26 -18
  65. package/src/lower/json-codecs.js +1398 -0
  66. package/src/lower/ownership.js +22 -1
  67. package/src/lower/range.js +86 -1
  68. package/src/lower/reachability.js +132 -0
  69. package/src/parser/declarations.js +58 -13
  70. package/src/parser/expressions.js +29 -7
  71. package/src/parser/index.js +2 -1
  72. package/src/parser/statements.js +37 -22
  73. package/src/{templ-parser.js → parser/templ.js} +138 -15
  74. package/src/parser/types.js +69 -9
  75. package/src/resolver.js +22 -1
  76. package/src/typechecker/assignability.js +176 -17
  77. package/src/typechecker/const-fold.js +356 -0
  78. package/src/typechecker/constants.js +256 -0
  79. package/src/typechecker/expressions.js +931 -122
  80. package/src/typechecker/index.js +459 -67
  81. package/src/typechecker/init-order.js +330 -0
  82. package/src/typechecker/resolve.js +451 -56
  83. package/src/typechecker/statements.js +90 -9
  84. package/src/typechecker/stdlib/core.js +333 -55
  85. package/src/typechecker/stdlib/excluded.js +898 -0
  86. package/src/typechecker/stdlib/extended.js +322 -26
  87. package/src/typechecker/{stdlib.js → stdlib/index.js} +5 -5
  88. package/src/typechecker/stdlib/simd.js +65 -15
  89. package/src/typechecker/termination.js +1 -1
  90. package/src/typechecker/types.js +149 -25
  91. package/stdlib/bytes/iter.go +192 -0
  92. package/stdlib/bytes/search.go +240 -0
  93. package/stdlib/bytes/split.go +218 -0
  94. package/stdlib/cmp/cmp.go +65 -0
  95. package/stdlib/encoding/json/errors.go +31 -0
  96. package/stdlib/encoding/json/indent.go +71 -0
  97. package/stdlib/encoding/json/number.go +12 -0
  98. package/stdlib/encoding/json/stream.go +173 -0
  99. package/stdlib/errors/overlay.go +12 -0
  100. package/stdlib/hash/hash.go +53 -0
  101. package/stdlib/internal/jsonrt/dec.go +738 -0
  102. package/stdlib/internal/jsonrt/enc.go +366 -0
  103. package/stdlib/internal/jsonrt/indent.go +135 -0
  104. package/stdlib/internal/jsonrt/number.go +27 -0
  105. package/stdlib/internal/jsonrt/reader.go +73 -0
  106. package/stdlib/internal/jsonrt/scanner.go +649 -0
  107. package/stdlib/io/io.go +346 -0
  108. package/stdlib/iter/iter.go +18 -0
  109. package/stdlib/maps/iter.go +65 -0
  110. package/stdlib/math/extra.go +270 -0
  111. package/stdlib/slices/extra.go +73 -0
  112. package/stdlib/slices/iter.go +113 -0
  113. package/stdlib/sort/sort.go +561 -0
  114. package/stdlib/strconv/quote.go +341 -0
  115. package/stdlib/strings/extra.go +35 -0
  116. package/stdlib/strings/iter.go +122 -0
  117. package/stdlib/sync/extra.go +105 -0
  118. package/stdlib/unicode/unicode.go +112 -0
  119. package/stdlib/unicode/utf8/bytes.go +239 -0
  120. package/src/backend/wasm/const-fold.js +0 -205
  121. package/src/backend/wasm/emit-stdlib.js +0 -13
  122. /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
  123. /package/src/{colors.js → cli/colors.js} +0 -0
  124. /package/src/{dev-server.js → cli/dev-server.js} +0 -0
  125. /package/src/{minifier.js → cli/minifier.js} +0 -0
  126. /package/src/{project-config.js → cli/project-config.js} +0 -0
  127. /package/src/{pwa.js → cli/pwa.js} +0 -0
  128. /package/src/{templ-lexer.js → lexer/templ-lexer.js} +0 -0
package/src/compiler.js CHANGED
@@ -19,26 +19,40 @@
19
19
 
20
20
  import { readdirSync, readFileSync, statSync } from "node:fs";
21
21
  import { basename, dirname, join, relative, resolve, sep } from "node:path";
22
- import {
23
- buildSourceMap,
24
- buildWasmSourceMap,
25
- CodeGen,
26
- } from "./backend/js/index.js";
22
+ import { CodeGen } from "./backend/js/index.js";
27
23
  import { compileWasmModule, optimizeWasm } from "./backend/wasm/index.js";
28
- import { log } from "./colors.js";
24
+ import { log } from "./cli/colors.js";
29
25
  import { parseDts } from "./dts-parser.js";
30
- import { Lexer } from "./lexer.js";
26
+ import { Lexer } from "./lexer/lexer.js";
27
+ import { TemplLexer } from "./lexer/templ-lexer.js";
28
+ import {
29
+ attachSourceMap,
30
+ buildWasmMap,
31
+ mergeCompilationChunks,
32
+ WASM_MAP_URL,
33
+ } from "./link/sourcemap.js";
34
+ import {
35
+ checkJsonCodecs,
36
+ finishStdlibJs,
37
+ importStdlibPackages,
38
+ } from "./link/stdlib.js";
39
+ import {
40
+ linkIntoBundle,
41
+ registerPackageUnit,
42
+ registerWasmUnit,
43
+ wasmMarker,
44
+ } from "./link/wasm.js";
31
45
  import { lower } from "./lower/index.js";
32
46
  import { Parser } from "./parser/index.js";
47
+ import { TemplParser } from "./parser/templ.js";
33
48
  import {
34
49
  isBuiltinPackage,
35
50
  isLocalPath,
36
51
  resolveAll,
37
52
  resolveGwDir,
53
+ resolveStdlibSource,
38
54
  } from "./resolver.js";
39
- import { TemplLexer } from "./templ-lexer.js";
40
- import { TemplParser } from "./templ-parser.js";
41
- import { TypeCheckError, TypeChecker } from "./typechecker/index.js";
55
+ import { EXCLUDED_STDLIB_PACKAGES, TypeChecker } from "./typechecker/index.js";
42
56
  import { WASM_SUPPORTED_STDLIB } from "./typechecker/types.js";
43
57
 
44
58
  // ── Parse cache ──────────────────────────────────────────────
@@ -89,98 +103,6 @@ export function gwFilesIn(dir, { includeTests = false } = {}) {
89
103
  .map((f) => join(dir, f));
90
104
  }
91
105
 
92
- function normalizeChunk(c) {
93
- if (typeof c === "string") {
94
- return { js: c, sourceFiles: [], sourcesContent: [], mappings: [] };
95
- }
96
- return c;
97
- }
98
-
99
- function appendChunkMappings(dest, mappings, localToUnifiedIdx, lineOffset) {
100
- if (!mappings) return;
101
- for (const m of mappings) {
102
- dest.push({
103
- genLine: m.genLine + lineOffset,
104
- srcLine: m.srcLine,
105
- srcFileIdx: localToUnifiedIdx[m.srcFileIdx ?? 0] ?? 0,
106
- });
107
- }
108
- }
109
-
110
- function mergeCompilationChunks(chunks) {
111
- const activeChunks = chunks
112
- .filter(Boolean)
113
- .map(normalizeChunk)
114
- .filter((c) => c.js.length > 0);
115
-
116
- if (activeChunks.length === 0) {
117
- return { js: "", sourceFiles: [], sourcesContent: [], mappings: [] };
118
- }
119
-
120
- const unifiedSources = [];
121
- const unifiedSourcesContent = [];
122
- const fileIdxMap = new Map();
123
-
124
- function getOrAddFile(filePath, content) {
125
- const key = resolve(filePath);
126
- let idx = fileIdxMap.get(key);
127
- if (idx === undefined) {
128
- idx = unifiedSources.length;
129
- fileIdxMap.set(key, idx);
130
- unifiedSources.push(key);
131
- unifiedSourcesContent.push(content);
132
- }
133
- return idx;
134
- }
135
-
136
- const combinedJsParts = [];
137
- const mergedMappings = [];
138
- let currentLineOffset = 0;
139
-
140
- for (const chunk of activeChunks) {
141
- combinedJsParts.push(chunk.js);
142
- const localToUnifiedIdx = (chunk.sourceFiles ?? []).map((file, i) =>
143
- getOrAddFile(file, chunk.sourcesContent?.[i] ?? ""),
144
- );
145
- appendChunkMappings(
146
- mergedMappings,
147
- chunk.mappings,
148
- localToUnifiedIdx,
149
- currentLineOffset,
150
- );
151
- currentLineOffset += chunk.js.split("\n").length;
152
- }
153
-
154
- return {
155
- js: combinedJsParts.join("\n"),
156
- sourceFiles: unifiedSources,
157
- sourcesContent: unifiedSourcesContent,
158
- mappings: mergedMappings,
159
- };
160
- }
161
-
162
- function attachSourceMap(merged, outputDir) {
163
- const relativeSources = merged.sourceFiles.map((f) => relative(outputDir, f));
164
- const mapJson = buildSourceMap(
165
- relativeSources,
166
- merged.mappings,
167
- merged.sourcesContent,
168
- );
169
- const b64 = Buffer.from(mapJson).toString("base64");
170
- merged.js += `\n//# sourceMappingURL=data:application/json;base64,${b64}`;
171
- }
172
-
173
- const WASM_MAP_URL = "app.wasm.map";
174
-
175
- // Function-level `app.wasm.map` (sources relative to the output dir).
176
- function buildWasmMap(info, outputDir) {
177
- if (!info || info.mappings.length === 0) return null;
178
- return buildWasmSourceMap(
179
- info.sources.map((f) => relative(outputDir, f)),
180
- info.mappings,
181
- );
182
- }
183
-
184
106
  // Shared tail of compileFiles / compileSingleFile: link `app.wasm`, run
185
107
  // wasm-opt when requested and produce the wasm source map.
186
108
  function finishWasm(options, merged, pkgTarget, outputDir) {
@@ -213,171 +135,16 @@ function finishWasm(options, merged, pkgTarget, outputDir) {
213
135
  return { wasm, wat, wasmOptInfo, wasmSourceMap };
214
136
  }
215
137
 
216
- // ── WASM linking ──────────────────────────────────────────────
217
- //
218
- // Every `wasm`/`both` package reached during a build registers a unit in the
219
- // shared `options.wasmUnits` array. The root compile links all units into a
220
- // single `app.wasm` and splices the generated JS facade into the bundle where
221
- // the first wasm package's JS would have been.
222
-
223
- const WASM_MARKER_RE = /^\/\*__GOFRONT_WASM_UNIT:[^*]*\*\/$/m;
224
-
225
- function wasmMarker(pkgName) {
226
- return `/*__GOFRONT_WASM_UNIT:${pkgName}*/`;
227
- }
228
-
229
- function registerWasmUnit(options, unit) {
230
- const units = options.wasmUnits;
231
- if (!units) return;
232
- if (units.some((u) => u.key === unit.key)) return;
233
- units.push(unit);
234
- }
235
-
236
- // Registers a `wasm`/`both` package as a link unit and returns the target the
237
- // package's own code is emitted for. `options.wasmTests` runs a `both`
238
- // package's tests through the wasm backend (the package is then treated as
239
- // `wasm` for linking so its test functions are exposed by the facade).
240
- function registerPackageUnit(options, unit) {
241
- const { pkgTarget, programs } = unit;
242
- if (pkgTarget !== "wasm" && pkgTarget !== "both") return pkgTarget;
243
- const emitTarget =
244
- options.wasmTests && options.isTest && pkgTarget === "both"
245
- ? "wasm"
246
- : pkgTarget;
247
- registerWasmUnit(options, {
248
- ...unit,
249
- target: emitTarget,
250
- programs:
251
- emitTarget === pkgTarget
252
- ? programs
253
- : programs.map((p) => ({ ...p, target: emitTarget })),
254
- });
255
- return emitTarget;
256
- }
257
-
258
- function linkWasmUnits(
259
- units,
260
- { emitWat = false, rootTarget = "js", sourceMappingURL = null } = {},
261
- ) {
262
- if (!units.some((u) => u.target === "wasm")) return null;
263
- checkLinkCollisions(units);
264
-
265
- const types = new Map();
266
- const bundledPackages = new Set();
267
- const programs = [];
268
- for (const u of units) {
269
- for (const [k, v] of u.types) types.set(k, v);
270
- for (const b of u.bundledPackages) bundledPackages.add(b);
271
- programs.push(...u.programs);
272
- }
273
- const checker = {
274
- types,
275
- errors: [],
276
- err(msg, node) {
277
- const e = new TypeCheckError(
278
- msg,
279
- node,
280
- this._currentFile,
281
- this._currentSource,
282
- );
283
- this.errors.push(e);
284
- return e;
285
- },
286
- };
287
- const lowerRes = lower(programs, checker);
288
- return compileWasmModule(programs, checker, lowerRes, {
289
- boundary: true,
290
- bundledPackages,
291
- emitWat,
292
- callMain: rootTarget === "wasm",
293
- sourceMappingURL,
294
- });
295
- }
296
-
297
- // The linked module is one flat namespace (like the JS bundle), so a top-level
298
- // name declared by two different packages would silently resolve to whichever
299
- // was emitted last. Reject it up front.
300
- function topLevelDeclNames(decl) {
301
- switch (decl.kind) {
302
- case "FuncDecl":
303
- return [decl.name];
304
- case "MethodDecl":
305
- return [`${decl.recvType?.name ?? "?"}.${decl.name}`];
306
- case "TypeDecl":
307
- return [decl.name];
308
- case "VarDecl":
309
- case "ConstDecl":
310
- return (decl.decls ?? []).flatMap((spec) => spec.names ?? []);
311
- default:
312
- return [];
313
- }
314
- }
315
-
316
- function checkLinkCollisions(units) {
317
- const owner = new Map(); // name -> pkgName
318
- const errors = [];
319
- for (const u of units) {
320
- for (const p of u.programs) {
321
- for (const d of p.decls ?? []) {
322
- for (const name of topLevelDeclNames(d)) {
323
- if (name === "_") continue;
324
- const prev = owner.get(name);
325
- if (prev === undefined) owner.set(name, u.pkgName);
326
- else if (prev !== u.pkgName)
327
- errors.push(
328
- `cannot link wasm packages: '${name}' is declared in both '${prev}' and '${u.pkgName}' (linked wasm packages share one namespace)`,
329
- );
330
- }
331
- }
332
- }
333
- }
334
- if (errors.length > 0) throw new Error([...new Set(errors)].join("\n"));
335
- }
336
-
337
- // Replaces the first wasm marker with the facade (dropping the others) and
338
- // shifts source-map lines that follow it.
339
- function spliceFacade(merged, facade) {
340
- const lines = merged.js.split("\n");
341
- const first = lines.findIndex((l) => WASM_MARKER_RE.test(l));
342
- if (first < 0) {
343
- merged.js = `${facade}\n${merged.js}`;
344
- const shift = facade.split("\n").length;
345
- for (const m of merged.mappings) m.genLine += shift;
346
- return;
347
- }
348
- const facadeLines = facade.split("\n");
349
- const delta = facadeLines.length - 1;
350
- for (const m of merged.mappings) {
351
- if (m.genLine > first) m.genLine += delta;
352
- }
353
- const out = [...lines.slice(0, first), ...facadeLines];
354
- for (let i = first + 1; i < lines.length; i++) {
355
- if (!WASM_MARKER_RE.test(lines[i])) out.push(lines[i]);
356
- }
357
- merged.js = out.join("\n");
358
- }
359
-
360
- // Root compiles only: link every registered unit into app.wasm and splice the
361
- // facade into the merged bundle. Returns `{ wasm, wat, sourceMapInfo }`
362
- // (nulls when there is nothing to link).
363
- function linkIntoBundle(options, merged, pkgTarget, { sourceMappingURL } = {}) {
364
- const none = { wasm: null, wat: null, sourceMapInfo: null };
365
- if (options.isDependency) return none;
366
- const linked = linkWasmUnits(options.wasmUnits, {
367
- emitWat: options.emitWat,
368
- rootTarget: pkgTarget,
369
- sourceMappingURL,
370
- });
371
- if (!linked) return none;
372
- spliceFacade(merged, linked.facade);
373
- return {
374
- wasm: linked.wasm,
375
- wat: linked.wat ?? null,
376
- sourceMapInfo: linked.sourceMapInfo ?? null,
377
- };
138
+ // Prints non-fatal diagnostics (e.g. JS Number precision of a constant).
139
+ function logWarnings(warnings) {
140
+ for (const w of warnings) log.warn(w);
378
141
  }
379
142
 
380
143
  // ── Import resolution ─────────────────────────────────────────
144
+
145
+ // What link/stdlib.js needs from this module. Injected rather than imported
146
+ // so that link/stdlib.js does not depend on compiler.js.
147
+ const STDLIB_DEPS = { gwFilesIn, resolveImports, TypeChecker };
381
148
  //
382
149
  // Shared by compileFiles (multi-file) and the single-file path in index.js.
383
150
  // Mutates checker, jsImports, bundledPackages, and preambles in place.
@@ -428,7 +195,12 @@ function resolveImports(
428
195
  "'gofront/shared' requires a wasm-only package (//gofront:target wasm): a both package has no linear memory on the JS side",
429
196
  impNode,
430
197
  );
431
- } else if (!isLocalPath(path)) {
198
+ } else if (
199
+ !isLocalPath(path) &&
200
+ !EXCLUDED_STDLIB_PACKAGES.has(path) &&
201
+ (isBuiltinPackage(path) ||
202
+ !resolveStdlibSource(path, options.stdlibRoot))
203
+ ) {
432
204
  if (!isBuiltinPackage(path)) {
433
205
  checker.recordBlocker("js: import", path);
434
206
  checker.err(
@@ -469,13 +241,27 @@ function resolveImports(
469
241
  ...imp,
470
242
  imports: imp.imports.filter(({ alias }) => alias !== "_"),
471
243
  }));
472
- const resolved = resolveAll(allImportsNoSideEffect, fromFile, parseDts);
244
+ const resolved = resolveAll(
245
+ allImportsNoSideEffect,
246
+ fromFile,
247
+ parseDts,
248
+ options.stdlibRoot,
249
+ );
473
250
  for (const [path, info] of resolved) {
474
251
  if (!info) continue;
475
252
  checker.addDefinitions(info.types, info.values);
476
253
  jsImports.set(path, [...info.values.keys()]);
477
254
  }
478
255
 
256
+ importStdlibPackages(
257
+ programs,
258
+ checker,
259
+ preambles,
260
+ bundledDirs,
261
+ options,
262
+ STDLIB_DEPS,
263
+ );
264
+
479
265
  // local GoFront packages (./subdir)
480
266
  const seenLocalPaths = new Set();
481
267
  for (const p of programs) {
@@ -541,7 +327,10 @@ function resolveImports(
541
327
 
542
328
  if (alias === "_") continue;
543
329
  if (alias === ".") {
544
- checker.addDefinitions(dep.exportedTypes, dep.exportedSymbols);
330
+ checker.addDefinitions(dep.exportedTypes, dep.exportedSymbols, {
331
+ external: false,
332
+ consts: dep.exportedConsts,
333
+ });
545
334
  continue;
546
335
  }
547
336
  const nameUsed = alias ?? dep.pkgName;
@@ -551,6 +340,7 @@ function resolveImports(
551
340
  dep.exportedSymbols,
552
341
  dep.exportedTypes,
553
342
  dep.target,
343
+ dep.exportedConsts,
554
344
  );
555
345
  checker.trackImport(nameUsed, { _line }, p._filename, p._source);
556
346
  }
@@ -590,7 +380,13 @@ export function compileSingleFile(inputPath, options = {}) {
590
380
  dumpTokens = false,
591
381
  dumpAst = false,
592
382
  } = options;
593
- options = { ...options, wasmUnits: options.wasmUnits ?? [] };
383
+ options = {
384
+ ...options,
385
+ wasmUnits: options.wasmUnits ?? [],
386
+ stdlibCache: options.stdlibCache ?? new Map(),
387
+ jsRootPrograms: options.jsRootPrograms ?? [],
388
+ bundledDirs: options.bundledDirs ?? new Set(),
389
+ };
594
390
 
595
391
  let source;
596
392
  try {
@@ -661,6 +457,7 @@ export function compileSingleFile(inputPath, options = {}) {
661
457
  });
662
458
  const mainJs =
663
459
  pkgTarget === "wasm" ? wasmMarker(checker.pkgName) : cg.generate(ast);
460
+ logWarnings(cg.warnings);
664
461
 
665
462
  const mainChunk = {
666
463
  js: mainJs,
@@ -670,6 +467,7 @@ export function compileSingleFile(inputPath, options = {}) {
670
467
  };
671
468
 
672
469
  const merged = mergeCompilationChunks([...preambles, mainChunk]);
470
+ finishStdlibJs(merged, options, [ast], pkgTarget);
673
471
  const { wasm, wat, wasmOptInfo, wasmSourceMap } = finishWasm(
674
472
  { ...options, sourceMap },
675
473
  merged,
@@ -716,7 +514,10 @@ export function compileFiles(files, options = {}) {
716
514
  options = {
717
515
  ...options,
718
516
  wasmUnits: options.wasmUnits ?? [],
517
+ stdlibCache: options.stdlibCache ?? new Map(),
518
+ jsRootPrograms: options.jsRootPrograms ?? [],
719
519
  rootDir: options.rootDir ?? fromDir,
520
+ bundledDirs: options.bundledDirs ?? new Set(),
720
521
  };
721
522
  const outputDir =
722
523
  options.outputDir ??
@@ -792,6 +593,13 @@ export function compileFiles(files, options = {}) {
792
593
 
793
594
  // ── 3. Type-check ─────────────────────────────────────────────
794
595
  const errors = checker.checkAll(programs);
596
+ const codecs = checkJsonCodecs(
597
+ programs,
598
+ checker,
599
+ preambles,
600
+ options,
601
+ STDLIB_DEPS,
602
+ );
795
603
  checker.reportUnusedImports();
796
604
  if (errors.length > 0) {
797
605
  const msgs = errors.map((e) => e.message).join("\n");
@@ -804,7 +612,7 @@ export function compileFiles(files, options = {}) {
804
612
  key: resolve(fromDir),
805
613
  pkgName,
806
614
  pkgTarget,
807
- programs,
615
+ programs: [...programs, ...codecs],
808
616
  types: checker.types,
809
617
  bundledPackages,
810
618
  });
@@ -820,6 +628,7 @@ export function compileFiles(files, options = {}) {
820
628
  : codegen.generateAll(programs, {
821
629
  isTest: options.isTest ?? false,
822
630
  });
631
+ logWarnings(codegen.warnings);
823
632
 
824
633
  const mainChunk = {
825
634
  js: mainJs,
@@ -829,6 +638,7 @@ export function compileFiles(files, options = {}) {
829
638
  };
830
639
 
831
640
  const merged = mergeCompilationChunks([...preambles, mainChunk]);
641
+ finishStdlibJs(merged, options, programs, emitTarget);
832
642
  const { wasm, wat, wasmOptInfo, wasmSourceMap } = finishWasm(
833
643
  options,
834
644
  merged,
@@ -857,8 +667,36 @@ export function compileFiles(files, options = {}) {
857
667
  programs,
858
668
  exportedSymbols: checker.getExportedSymbols(),
859
669
  exportedTypes: checker.getExportedTypes(),
670
+ exportedConsts: checker.getExportedConsts(),
860
671
  sourceFiles: merged.sourceFiles,
861
672
  sourcesContent: merged.sourcesContent,
862
673
  mappings: merged.mappings,
863
674
  };
864
675
  }
676
+
677
+ export function compileWasm(source, options = {}) {
678
+ const filename = options.filename ?? "main.go";
679
+ const tokens = new Lexer(source, filename).tokenize();
680
+ const ast = new Parser(tokens, filename, source).parse();
681
+
682
+ const checker = new TypeChecker();
683
+ checker.target = "wasm";
684
+ checker.pkgName = ast.pkg?.name ?? "main";
685
+
686
+ const errors = checker.check(ast);
687
+ if (errors.length > 0) {
688
+ return { wasm: null, errors };
689
+ }
690
+
691
+ const lowerRes = lower([ast], checker);
692
+ const res = compileWasmModule([ast], checker, lowerRes, {
693
+ ...options,
694
+ exportAll: options.exportAll ?? true,
695
+ });
696
+
697
+ if (checker.errors?.length > 0) {
698
+ return { wasm: null, errors: checker.errors };
699
+ }
700
+
701
+ return { ...res, errors: [] };
702
+ }