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
@@ -15,10 +15,27 @@
15
15
  // TemplFor { kind, stmtTokens, body: TemplNode[] }
16
16
  // TemplSwitch { kind, exprTokens, cases: TemplCase[] }
17
17
  // TemplCase { kind, caseTokens: tokens | null (null = default), body: TemplNode[] }
18
+ //
19
+ // Go expressions embedded in templ (`{ expr }`, attribute values, `if`
20
+ // conditions, `switch` and `case` expressions, `@Comp(...)` calls) and `for`
21
+ // headers are also parsed here, so the code generator never runs the parser.
22
+ // The results sit on the node as non-enumerable properties (the generic AST
23
+ // walkers in rename/lowering visit enumerable keys only, and these ASTs have
24
+ // no type information):
25
+ // expr Expression AST, or null when there are no tokens to parse
26
+ // exprError The ParseError a malformed expression raised. The parser keeps
27
+ // it instead of throwing, so the error still surfaces when the
28
+ // code generator reads the node (after type-checking), as before
29
+ // raw TemplComponent only: `@templ.Raw(arg)`; `expr` is then `arg`
30
+ // forStmt TemplFor only: the parsed ForStmt, or null when the header does
31
+ // not parse as a Go `for` clause
32
+ // forError TemplFor only: the ParseError the header raised (kept, like
33
+ // exprError, for the code generator to throw)
34
+ // attr.expr / attr.exprError on `expr` and `cond-bool` attributes
18
35
 
19
- import { Parser } from "./parser/index.js";
20
- import { TT } from "./templ-lexer.js";
21
- import { T } from "./tokens.js";
36
+ import { TT } from "../lexer/templ-lexer.js";
37
+ import { T, Token } from "../lexer/tokens.js";
38
+ import { Parser } from "./index.js";
22
39
 
23
40
  const VOID_ELEMENTS = new Set([
24
41
  "area",
@@ -37,6 +54,90 @@ const VOID_ELEMENTS = new Set([
37
54
  "wbr",
38
55
  ]);
39
56
 
57
+ function attach(node, props) {
58
+ for (const [name, value] of Object.entries(props)) {
59
+ Object.defineProperty(node, name, {
60
+ value,
61
+ enumerable: false,
62
+ writable: true,
63
+ configurable: true,
64
+ });
65
+ }
66
+ return node;
67
+ }
68
+
69
+ // Parses `tokens` as one Go expression, ending at a synthetic EOF token.
70
+ function parseExprTokens(tokens, allowEmpty = true) {
71
+ if (allowEmpty && (!tokens || tokens.length === 0)) return { expr: null };
72
+ try {
73
+ const eofTok = new Token(T.EOF, "", 1, 1);
74
+ return { expr: new Parser([...tokens, eofTok]).parseExpr() };
75
+ } catch (exprError) {
76
+ return { expr: null, exprError };
77
+ }
78
+ }
79
+
80
+ // Parses an `if` condition; the lexer may leave the `if` keyword in front.
81
+ function parseCondTokens(tokens) {
82
+ if (!tokens || tokens.length === 0) return { expr: null };
83
+ return parseExprTokens(
84
+ tokens[0]?.type === T.IF ? tokens.slice(1) : tokens,
85
+ false,
86
+ );
87
+ }
88
+
89
+ function isTemplRaw(toks) {
90
+ return (
91
+ toks.length >= 4 &&
92
+ toks[0]?.value === "templ" &&
93
+ toks[1]?.type === T.DOT &&
94
+ toks[2]?.value === "Raw" &&
95
+ toks[3]?.type === T.LPAREN
96
+ );
97
+ }
98
+
99
+ // Strips the trailing semicolons the Go lexer inserts at a newline.
100
+ function trimSemicolons(tokens) {
101
+ let end = tokens.length;
102
+ while (end > 0 && tokens[end - 1].type === T.SEMICOLON) end--;
103
+ return tokens.slice(0, end);
104
+ }
105
+
106
+ // Parses a `for` header (the `for` keyword plus the clause, no body) as a
107
+ // ForStmt, with a fake empty body `{ }` so the parser can complete it. A header
108
+ // that is not a valid Go `for` clause gives `forStmt: null` plus its error.
109
+ function parseForHeader(tokens) {
110
+ const eofTok = new Token(T.EOF, "", 1, 1);
111
+ const lbrace = new Token(T.LBRACE, "{", 1, 1);
112
+ const rbrace = new Token(T.RBRACE, "}", 1, 1);
113
+ const semi = new Token(T.SEMICOLON, ";", 1, 1);
114
+ const withFor =
115
+ tokens[0]?.type === T.FOR
116
+ ? [...tokens, lbrace, rbrace, semi, eofTok]
117
+ : [
118
+ new Token(T.FOR, "for", 1, 1),
119
+ ...tokens,
120
+ lbrace,
121
+ rbrace,
122
+ semi,
123
+ eofTok,
124
+ ];
125
+ try {
126
+ return { forStmt: new Parser(withFor).parseFor() };
127
+ } catch (forError) {
128
+ return { forStmt: null, forError };
129
+ }
130
+ }
131
+
132
+ // Parses the `expr` and `cond-bool` attribute expressions of an element.
133
+ function parseAttrExprs(attrs) {
134
+ for (const attr of attrs) {
135
+ if (attr.kind === "expr" || attr.kind === "cond-bool")
136
+ attach(attr, parseExprTokens(attr.tokens));
137
+ }
138
+ return attrs;
139
+ }
140
+
40
141
  export class TemplParser extends Parser {
41
142
  // ── Top-level declaration override ───────────────────────────
42
143
 
@@ -101,7 +202,7 @@ export class TemplParser extends Parser {
101
202
  return {
102
203
  kind: "TemplElement",
103
204
  tag: t.value.tag,
104
- attrs: t.value.attrs,
205
+ attrs: parseAttrExprs(t.value.attrs),
105
206
  children: [],
106
207
  };
107
208
  }
@@ -110,10 +211,13 @@ export class TemplParser extends Parser {
110
211
  return { kind: "TemplText", value: t.value };
111
212
  case TT.TEMPL_EXPR:
112
213
  this.advance();
113
- return { kind: "TemplExpr", tokens: t.value };
214
+ return attach(
215
+ { kind: "TemplExpr", tokens: t.value },
216
+ parseExprTokens(t.value),
217
+ );
114
218
  case TT.TEMPL_COMP:
115
219
  this.advance();
116
- return { kind: "TemplComponent", tokens: t.value };
220
+ return this.templComponent(t.value);
117
221
  case TT.TEMPL_CHILDREN:
118
222
  this.advance();
119
223
  return { kind: "TemplChildren" };
@@ -136,10 +240,18 @@ export class TemplParser extends Parser {
136
240
  }
137
241
  }
138
242
 
243
+ // `@templ.Raw(arg)` parses `arg`; any other component parses the whole call.
244
+ templComponent(tokens) {
245
+ const raw = isTemplRaw(tokens);
246
+ const parsed = parseExprTokens(raw ? tokens.slice(4, -1) : tokens);
247
+ return attach({ kind: "TemplComponent", tokens }, { raw, ...parsed });
248
+ }
249
+
139
250
  // Parse children of an element until the matching close tag.
140
251
  parseHtmlElement() {
141
252
  const openTok = this.advance(); // HTML_OPEN
142
- const { tag, attrs } = openTok.value;
253
+ const { tag } = openTok.value;
254
+ const attrs = parseAttrExprs(openTok.value.attrs);
143
255
 
144
256
  // Void elements have no children and no close tag even without />
145
257
  if (VOID_ELEMENTS.has(tag)) {
@@ -186,14 +298,20 @@ export class TemplParser extends Parser {
186
298
  else_ = this.parseHtmlChildren(); // else body until RBRACE
187
299
  }
188
300
  }
189
- return { kind: "TemplIf", condTokens, then, else_ };
301
+ return attach(
302
+ { kind: "TemplIf", condTokens, then, else_ },
303
+ parseCondTokens(condTokens),
304
+ );
190
305
  }
191
306
 
192
307
  // Parse a TemplFor node. `tok` is the TEMPL_FOR token (already advanced).
193
308
  parseTemplFor(tok) {
194
309
  const stmtTokens = tok.value;
195
310
  const body = this.parseHtmlChildren();
196
- return { kind: "TemplFor", stmtTokens, body };
311
+ return attach(
312
+ { kind: "TemplFor", stmtTokens, body },
313
+ parseForHeader(trimSemicolons(stmtTokens)),
314
+ );
197
315
  }
198
316
 
199
317
  // Parse a TemplSwitch node. `tok` is the TEMPL_SWITCH token (already advanced).
@@ -209,17 +327,22 @@ export class TemplParser extends Parser {
209
327
  const isDefault = this.check(TT.TEMPL_DEFAULT);
210
328
  const caseTok = this.advance();
211
329
  const body = this.parseTemplCaseBody();
212
- cases.push({
213
- kind: "TemplCase",
214
- caseTokens: isDefault ? null : caseTok.value,
215
- body,
216
- });
330
+ const caseTokens = isDefault ? null : caseTok.value;
331
+ cases.push(
332
+ attach(
333
+ { kind: "TemplCase", caseTokens, body },
334
+ isDefault ? { expr: null } : parseExprTokens(caseTokens),
335
+ ),
336
+ );
217
337
  } else {
218
338
  this.advance(); // skip unexpected
219
339
  }
220
340
  }
221
341
  if (this.check(TT.TEMPL_END)) this.advance(); // consume closing }
222
- return { kind: "TemplSwitch", exprTokens, cases };
342
+ return attach(
343
+ { kind: "TemplSwitch", exprTokens, cases },
344
+ parseExprTokens(exprTokens),
345
+ );
223
346
  }
224
347
 
225
348
  // Parse HTML nodes for a switch case body — stops at CASE/DEFAULT/END/RBRACE.
@@ -1,6 +1,6 @@
1
1
  // Parser type-expression methods — installed as a mixin on Parser.prototype.
2
2
 
3
- import { T } from "../tokens.js";
3
+ import { T } from "../lexer/tokens.js";
4
4
 
5
5
  // Token types that directly map to parseTypeName().
6
6
  const TYPE_NAME_TOKENS = new Set([
@@ -76,8 +76,10 @@ export const typeParserMethods = {
76
76
  i++;
77
77
  continue;
78
78
  }
79
- // Reject literals — it's an index/array expression
80
- if (tt === T.INT || tt === T.FLOAT || tt === T.STRING) return false;
79
+ // Reject literals — it's an index/array expression. A literal nested
80
+ // deeper is an array length inside a type argument: Stack[[2]int].
81
+ if (depth === 1 && (tt === T.INT || tt === T.FLOAT || tt === T.STRING))
82
+ return false;
81
83
  i++;
82
84
  }
83
85
  return depth === 0;
@@ -86,11 +88,17 @@ export const typeParserMethods = {
86
88
  parseTypeParamList() {
87
89
  this.expect(T.LBRACKET);
88
90
  const params = [];
89
- do {
90
- const name = this.expect(T.IDENT).value;
91
+ while (!this.check(T.RBRACKET) && !this.check(T.EOF)) {
92
+ const names = [this.expect(T.IDENT).value];
93
+ while (this.match(T.COMMA)) {
94
+ names.push(this.expect(T.IDENT).value);
95
+ }
91
96
  const constraint = this.parseConstraint();
92
- params.push({ kind: "TypeParam", name, constraint });
93
- } while (this.match(T.COMMA));
97
+ for (const name of names) {
98
+ params.push({ kind: "TypeParam", name, constraint });
99
+ }
100
+ if (!this.match(T.COMMA)) break;
101
+ }
94
102
  this.expect(T.RBRACKET);
95
103
  return params;
96
104
  },
@@ -185,7 +193,7 @@ export const typeParserMethods = {
185
193
  }
186
194
  const type = {
187
195
  kind: "PointerType",
188
- base: { kind: "TypeName", name: typeName },
196
+ base: this._embeddedTypeName(typeName, true),
189
197
  };
190
198
  let tag = null;
191
199
  if (this.check(T.STRING)) {
@@ -195,6 +203,7 @@ export const typeParserMethods = {
195
203
  names: [],
196
204
  type,
197
205
  embedded: true,
206
+ embeddedName: type.base.name,
198
207
  tag,
199
208
  });
200
209
  this.semi();
@@ -206,14 +215,38 @@ export const typeParserMethods = {
206
215
  if (names.length === 1 && this.check(T.DOT)) {
207
216
  this.advance();
208
217
  const typeName = `${names[0]}.${this.expect(T.IDENT).value}`;
218
+ const embeddedType = this._embeddedTypeName(typeName, true);
209
219
  let tag = null;
210
220
  if (this.check(T.STRING)) {
211
221
  tag = this.advance().value;
212
222
  }
213
223
  fields.push({
214
224
  names: [],
215
- type: { kind: "TypeName", name: typeName },
225
+ type: embeddedType,
216
226
  embedded: true,
227
+ embeddedName: typeName,
228
+ tag,
229
+ });
230
+ this.semi();
231
+ continue;
232
+ }
233
+
234
+ // Embedded generic instance: Inner[T] (not an array field `a [N]T`)
235
+ if (
236
+ names.length === 1 &&
237
+ this.check(T.LBRACKET) &&
238
+ this._bracketEndsEmbeddedField()
239
+ ) {
240
+ const embeddedType = this._embeddedTypeName(names[0], true);
241
+ let tag = null;
242
+ if (this.check(T.STRING)) {
243
+ tag = this.advance().value;
244
+ }
245
+ fields.push({
246
+ names: [],
247
+ type: embeddedType,
248
+ embedded: true,
249
+ embeddedName: names[0],
217
250
  tag,
218
251
  });
219
252
  this.semi();
@@ -255,6 +288,33 @@ export const typeParserMethods = {
255
288
  return { kind: "StructType", fields };
256
289
  },
257
290
 
291
+ // True when the `[...]` at the cursor is followed by the end of a field
292
+ // (`Inner[T]` embedded), rather than an element type (`a [N]T`).
293
+ _bracketEndsEmbeddedField() {
294
+ let depth = 0;
295
+ for (let i = this.pos; i < this.tokens.length; i++) {
296
+ const tt = this.tokens[i].type;
297
+ if (tt === T.LBRACKET) depth++;
298
+ else if (tt === T.RBRACKET && --depth === 0) {
299
+ const next = this.tokens[i + 1]?.type;
300
+ return next === T.SEMICOLON || next === T.RBRACE || next === T.STRING;
301
+ }
302
+ }
303
+ return false;
304
+ },
305
+
306
+ // Embedded field type: `name`, or `name[Args]` when type arguments follow.
307
+ _embeddedTypeName(name, allowArgs) {
308
+ if (allowArgs && this.check(T.LBRACKET)) {
309
+ this.expect(T.LBRACKET);
310
+ const typeArgs = [this.parseType()];
311
+ while (this.match(T.COMMA)) typeArgs.push(this.parseType());
312
+ this.expect(T.RBRACKET);
313
+ return { kind: "GenericTypeName", name, typeArgs };
314
+ }
315
+ return { kind: "TypeName", name };
316
+ },
317
+
258
318
  parseInterfaceType() {
259
319
  this.expect(T.INTERFACE);
260
320
  this.expect(T.LBRACE);
package/src/resolver.js CHANGED
@@ -12,6 +12,7 @@
12
12
 
13
13
  import { existsSync, readdirSync, readFileSync } from "node:fs";
14
14
  import { dirname, join, resolve } from "node:path";
15
+ import { fileURLToPath } from "node:url";
15
16
 
16
17
  // Walk up from startDir looking for a node_modules directory
17
18
  function findNodeModules(startDir) {
@@ -25,6 +26,7 @@ function findNodeModules(startDir) {
25
26
  }
26
27
  }
27
28
 
29
+ import { EXCLUDED_STDLIB_PACKAGES } from "./typechecker/stdlib/excluded.js";
28
30
  import { STDLIB_PACKAGES } from "./typechecker/types.js";
29
31
 
30
32
  // Returns true for local relative paths (start with ./ or ../)
@@ -36,6 +38,23 @@ export function isBuiltinPackage(importPath) {
36
38
  return STDLIB_PACKAGES.has(importPath);
37
39
  }
38
40
 
41
+ // Go-source stdlib: `stdlib/<import path>/*.go`, written in GoFront Go
42
+ // and compiled into the caller's target. A directory for a path that is also
43
+ // in STDLIB_PACKAGES is an overlay: its declarations extend that namespace.
44
+ const STDLIB_SOURCE_ROOT = fileURLToPath(
45
+ new URL("../stdlib/", import.meta.url),
46
+ );
47
+ const STDLIB_PATH_RE = /^[a-z0-9]+(\/[a-z0-9]+)*$/;
48
+
49
+ // Returns the source directory for a Go-source stdlib import path, or null.
50
+ // `root` replaces stdlib/ (tests use a temporary tree).
51
+ export function resolveStdlibSource(importPath, root = null) {
52
+ if (!STDLIB_PATH_RE.test(importPath)) return null;
53
+ const dir = join(root ?? STDLIB_SOURCE_ROOT, importPath);
54
+ if (!existsSync(dir)) return null;
55
+ return readdirSync(dir).some((f) => f.endsWith(".go")) ? dir : null;
56
+ }
57
+
39
58
  // Resolve a local relative import path to an absolute directory of .go files.
40
59
  // Returns the absolute dir path, or null if it doesn't contain any .go files.
41
60
  export function resolveGwDir(importPath, fromFile) {
@@ -86,14 +105,16 @@ function resolveImport(importPath, fromFile) {
86
105
 
87
106
  // Given an AST's import list, resolve all imports.
88
107
  // Returns Map<importPath, { dtsPath, importPath, types, values }>
89
- export function resolveAll(imports, fromFile, parseDts) {
108
+ export function resolveAll(imports, fromFile, parseDts, stdlibRoot = null) {
90
109
  const resolved = new Map();
91
110
 
92
111
  for (const imp of imports) {
93
112
  for (const { path } of imp.imports) {
94
113
  if (path.startsWith("js:")) continue; // handled separately
95
114
  if (isLocalPath(path)) continue; // local .go packages — handled by compiler
115
+ if (EXCLUDED_STDLIB_PACKAGES.has(path)) continue; // the checker reports it
96
116
  if (isBuiltinPackage(path)) continue; // built-in stdlib namespaces — always available
117
+ if (resolveStdlibSource(path, stdlibRoot)) continue; // Go-source stdlib — handled by compiler
97
118
 
98
119
  if (resolved.has(path)) continue;
99
120