@scriptc/compiler 0.1.3 → 0.1.5

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 (217) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +275 -62
  2. package/dist/backend/c/async.d.ts +25 -0
  3. package/dist/backend/c/async.js +167 -0
  4. package/dist/backend/c/async.js.map +1 -1
  5. package/dist/backend/c/c-emitter.d.ts +15 -1
  6. package/dist/backend/c/c-emitter.js +36 -11
  7. package/dist/backend/c/c-emitter.js.map +1 -1
  8. package/dist/backend/c/exprs.d.ts +2 -2
  9. package/dist/backend/c/exprs.js +556 -71
  10. package/dist/backend/c/exprs.js.map +1 -1
  11. package/dist/backend/c/stmts.js +5 -3
  12. package/dist/backend/c/stmts.js.map +1 -1
  13. package/dist/backend/c/types.d.ts +2 -3
  14. package/dist/backend/c/types.js +10 -1
  15. package/dist/backend/c/types.js.map +1 -1
  16. package/dist/backend/c/walkers.js +1 -1
  17. package/dist/backend/c/walkers.js.map +1 -1
  18. package/dist/backend/link-plan.d.ts +3 -1
  19. package/dist/backend/link-plan.js +3 -1
  20. package/dist/backend/link-plan.js.map +1 -1
  21. package/dist/backend/llvm/dyn.js +1 -1
  22. package/dist/backend/llvm/dyn.js.map +1 -1
  23. package/dist/backend/llvm/emitter.js +42 -12
  24. package/dist/backend/llvm/emitter.js.map +1 -1
  25. package/dist/backend/llvm/expr-bytes.d.ts +1 -2
  26. package/dist/backend/llvm/expr-bytes.js +28 -23
  27. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  28. package/dist/backend/llvm/expr-callbacks.d.ts +9 -0
  29. package/dist/backend/llvm/expr-callbacks.js +125 -0
  30. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  31. package/dist/backend/llvm/expr-containers.d.ts +1 -0
  32. package/dist/backend/llvm/expr-containers.js +32 -4
  33. package/dist/backend/llvm/expr-containers.js.map +1 -1
  34. package/dist/backend/llvm/expr-context.d.ts +19 -3
  35. package/dist/backend/llvm/expr-dispatch.js +1 -0
  36. package/dist/backend/llvm/expr-dispatch.js.map +1 -1
  37. package/dist/backend/llvm/expr-primitives.d.ts +1 -1
  38. package/dist/backend/llvm/expr-primitives.js +49 -13
  39. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  40. package/dist/backend/llvm/expr-primitives.test.d.ts +1 -0
  41. package/dist/backend/llvm/expr-primitives.test.js +38 -0
  42. package/dist/backend/llvm/expr-primitives.test.js.map +1 -0
  43. package/dist/backend/llvm/expr-stream-callbacks.d.ts +3 -0
  44. package/dist/backend/llvm/expr-stream-callbacks.js +69 -0
  45. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  46. package/dist/backend/llvm/lib-filesystem.js +80 -10
  47. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  48. package/dist/backend/llvm/lib-network.js +69 -10
  49. package/dist/backend/llvm/lib-network.js.map +1 -1
  50. package/dist/backend/llvm/lib-process.js +156 -6
  51. package/dist/backend/llvm/lib-process.js.map +1 -1
  52. package/dist/backend/llvm/lib-shared.js +100 -0
  53. package/dist/backend/llvm/lib-shared.js.map +1 -1
  54. package/dist/backend/llvm/lib-stream.js +23 -0
  55. package/dist/backend/llvm/lib-stream.js.map +1 -1
  56. package/dist/backend/native-toolchain.d.ts +5 -0
  57. package/dist/backend/native-toolchain.js +4 -1
  58. package/dist/backend/native-toolchain.js.map +1 -1
  59. package/dist/backend/runtime-pack.test.js +28 -10
  60. package/dist/backend/runtime-pack.test.js.map +1 -1
  61. package/dist/backend/targets.d.ts +7 -0
  62. package/dist/backend/targets.js +26 -0
  63. package/dist/backend/targets.js.map +1 -1
  64. package/dist/backend/targets.test.js +8 -1
  65. package/dist/backend/targets.test.js.map +1 -1
  66. package/dist/coverage/surface-manifest.js +14 -4
  67. package/dist/coverage/surface-manifest.js.map +1 -1
  68. package/dist/diagnostics/diagnostic.js +1 -1
  69. package/dist/diagnostics/diagnostic.js.map +1 -1
  70. package/dist/executable/executable-cache.d.ts +4 -0
  71. package/dist/executable/executable-cache.js +6 -1
  72. package/dist/executable/executable-cache.js.map +1 -1
  73. package/dist/executable/executable-cache.test.js +3 -3
  74. package/dist/executable/executable-cache.test.js.map +1 -1
  75. package/dist/frontend/fork-target.d.ts +17 -0
  76. package/dist/frontend/fork-target.js +256 -0
  77. package/dist/frontend/fork-target.js.map +1 -0
  78. package/dist/frontend/lowering/abstract-equality.d.ts +6 -0
  79. package/dist/frontend/lowering/abstract-equality.js +250 -0
  80. package/dist/frontend/lowering/abstract-equality.js.map +1 -0
  81. package/dist/frontend/lowering/containers/bytes.d.ts +1 -1
  82. package/dist/frontend/lowering/containers/bytes.js +6 -5
  83. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  84. package/dist/frontend/lowering/containers/string-and-regexp.d.ts +7 -6
  85. package/dist/frontend/lowering/containers/string-and-regexp.js +237 -28
  86. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  87. package/dist/frontend/lowering/expressions/object-literals.js +8 -0
  88. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  89. package/dist/frontend/lowering/lower-assert.js +71 -2
  90. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  91. package/dist/frontend/lowering/lower-builtins.d.ts +54 -28
  92. package/dist/frontend/lowering/lower-builtins.js +957 -116
  93. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  94. package/dist/frontend/lowering/lower-calls.d.ts +32 -23
  95. package/dist/frontend/lowering/lower-calls.js +835 -206
  96. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  97. package/dist/frontend/lowering/lower-classes.js +41 -10
  98. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  99. package/dist/frontend/lowering/lower-containers.d.ts +7 -9
  100. package/dist/frontend/lowering/lower-containers.js +293 -51
  101. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  102. package/dist/frontend/lowering/lower-event-emitter.js +212 -21
  103. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  104. package/dist/frontend/lowering/lower-exprs.d.ts +12 -0
  105. package/dist/frontend/lowering/lower-exprs.js +263 -93
  106. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  107. package/dist/frontend/lowering/lower-inspect.d.ts +4 -0
  108. package/dist/frontend/lowering/lower-inspect.js +1 -1
  109. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  110. package/dist/frontend/lowering/lower-island.d.ts +6 -3
  111. package/dist/frontend/lowering/lower-island.js +182 -12
  112. package/dist/frontend/lowering/lower-island.js.map +1 -1
  113. package/dist/frontend/lowering/lower-modules.d.ts +6 -0
  114. package/dist/frontend/lowering/lower-modules.js +184 -38
  115. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  116. package/dist/frontend/lowering/lower-namespaces.js +7 -0
  117. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  118. package/dist/frontend/lowering/lower-server.d.ts +3 -5
  119. package/dist/frontend/lowering/lower-server.js +413 -54
  120. package/dist/frontend/lowering/lower-server.js.map +1 -1
  121. package/dist/frontend/lowering/lower-stmts.js +122 -19
  122. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  123. package/dist/frontend/lowering/lower-stream.d.ts +3 -0
  124. package/dist/frontend/lowering/lower-stream.js +7 -0
  125. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  126. package/dist/frontend/lowering/lowerer.d.ts +86 -9
  127. package/dist/frontend/lowering/lowerer.js +449 -74
  128. package/dist/frontend/lowering/lowerer.js.map +1 -1
  129. package/dist/frontend/lowering/optional-arguments.d.ts +9 -1
  130. package/dist/frontend/lowering/optional-arguments.js +67 -1
  131. package/dist/frontend/lowering/optional-arguments.js.map +1 -1
  132. package/dist/frontend/lowering/pairs-snapshot.d.ts +3 -1
  133. package/dist/frontend/lowering/pairs-snapshot.js +12 -4
  134. package/dist/frontend/lowering/pairs-snapshot.js.map +1 -1
  135. package/dist/frontend/lowering/surfaces.d.ts +34 -14
  136. package/dist/frontend/lowering/surfaces.js +177 -104
  137. package/dist/frontend/lowering/surfaces.js.map +1 -1
  138. package/dist/frontend/npm-static-declarations.d.ts +4 -0
  139. package/dist/frontend/npm-static-declarations.js +56 -0
  140. package/dist/frontend/npm-static-declarations.js.map +1 -1
  141. package/dist/frontend/npm-static-declarations.test.js +23 -2
  142. package/dist/frontend/npm-static-declarations.test.js.map +1 -1
  143. package/dist/frontend/npm-static-prune.d.ts +6 -0
  144. package/dist/frontend/npm-static-prune.js +203 -0
  145. package/dist/frontend/npm-static-prune.js.map +1 -0
  146. package/dist/frontend/npm-static-prune.test.d.ts +1 -0
  147. package/dist/frontend/npm-static-prune.test.js +48 -0
  148. package/dist/frontend/npm-static-prune.test.js.map +1 -0
  149. package/dist/frontend/npm-static.js +6 -5
  150. package/dist/frontend/npm-static.js.map +1 -1
  151. package/dist/frontend/npm.d.ts +15 -3
  152. package/dist/frontend/npm.js +87 -14
  153. package/dist/frontend/npm.js.map +1 -1
  154. package/dist/frontend/npm.test.js +76 -9
  155. package/dist/frontend/npm.test.js.map +1 -1
  156. package/dist/frontend/program.js +107 -14
  157. package/dist/frontend/program.js.map +1 -1
  158. package/dist/frontend/provenance.js +8 -3
  159. package/dist/frontend/provenance.js.map +1 -1
  160. package/dist/frontend/resolve.d.ts +6 -0
  161. package/dist/frontend/resolve.js +7 -4
  162. package/dist/frontend/resolve.js.map +1 -1
  163. package/dist/frontend/type-mapper.d.ts +5 -0
  164. package/dist/frontend/type-mapper.js +80 -29
  165. package/dist/frontend/type-mapper.js.map +1 -1
  166. package/dist/index.d.ts +8 -3
  167. package/dist/index.js +34 -41
  168. package/dist/index.js.map +1 -1
  169. package/dist/ir/analysis.d.ts +5 -3
  170. package/dist/ir/analysis.js +25 -11
  171. package/dist/ir/analysis.js.map +1 -1
  172. package/dist/ir/analysis.test.js +50 -2
  173. package/dist/ir/analysis.test.js.map +1 -1
  174. package/dist/ir/constant-tables.d.ts +17 -0
  175. package/dist/ir/constant-tables.js +99 -0
  176. package/dist/ir/constant-tables.js.map +1 -0
  177. package/dist/ir/constant-tables.test.d.ts +1 -0
  178. package/dist/ir/constant-tables.test.js +78 -0
  179. package/dist/ir/constant-tables.test.js.map +1 -0
  180. package/dist/ir/integer-ranges.d.ts +13 -0
  181. package/dist/ir/integer-ranges.js +122 -0
  182. package/dist/ir/integer-ranges.js.map +1 -0
  183. package/dist/ir/integer-ranges.test.d.ts +1 -0
  184. package/dist/ir/integer-ranges.test.js +63 -0
  185. package/dist/ir/integer-ranges.test.js.map +1 -0
  186. package/dist/ir/ir.d.ts +130 -76
  187. package/dist/ir/ir.js +69 -4
  188. package/dist/ir/ir.js.map +1 -1
  189. package/dist/ir/ir.test.js +20 -1
  190. package/dist/ir/ir.test.js.map +1 -1
  191. package/dist/ir/scalar-records.d.ts +8 -0
  192. package/dist/ir/scalar-records.js +216 -0
  193. package/dist/ir/scalar-records.js.map +1 -0
  194. package/dist/ir/scalar-records.test.d.ts +1 -0
  195. package/dist/ir/scalar-records.test.js +142 -0
  196. package/dist/ir/scalar-records.test.js.map +1 -0
  197. package/dist/ir/serialize.d.ts +1 -1
  198. package/dist/ir/serialize.js +1 -1
  199. package/dist/ir/serialize.js.map +1 -1
  200. package/dist/ir/validate.js +256 -20
  201. package/dist/ir/validate.js.map +1 -1
  202. package/dist/ir/validate.test.d.ts +1 -0
  203. package/dist/ir/validate.test.js +31 -0
  204. package/dist/ir/validate.test.js.map +1 -0
  205. package/dist/library/cache-primitives.d.ts +1 -1
  206. package/dist/library/cache-primitives.js +3 -3
  207. package/dist/library/cache-primitives.js.map +1 -1
  208. package/dist/library/fence-eval.js +11 -4
  209. package/dist/library/fence-eval.js.map +1 -1
  210. package/dist/library/int-infer.test.js +4 -4
  211. package/dist/library/int-infer.test.js.map +1 -1
  212. package/dist/library/library-cache.js +0 -1
  213. package/dist/library/library-cache.js.map +1 -1
  214. package/dist/library/library-cache.test.js +8 -8
  215. package/dist/library/library-cache.test.js.map +1 -1
  216. package/package.json +17 -17
  217. package/surface-manifest.json +186 -79
@@ -276,6 +276,7 @@ export const ARRAY_METHODS = new Set([
276
276
  "reduce",
277
277
  "reduceRight",
278
278
  "indexOf",
279
+ "lastIndexOf",
279
280
  "includes",
280
281
  "join",
281
282
  "slice",
@@ -330,19 +331,19 @@ export const COMPOUND_ASSIGN_OPS = {
330
331
  * parameters) that typecheck but have no lowering — those forms are fenced
331
332
  * per site instead of silently dropping arguments. */
332
333
  export const STR_METHODS = {
333
- charCodeAt: { method: "charCodeAt", result: F64, minArgs: 1, maxArgs: 1 },
334
- charAt: { method: "charAt", result: STRING, minArgs: 1, maxArgs: 1 },
335
- indexOf: { method: "indexOf", result: F64, minArgs: 1, maxArgs: 2 },
334
+ charCodeAt: { method: "charCodeAt", result: F64, minArgs: 0, maxArgs: 1 },
335
+ charAt: { method: "charAt", result: STRING, minArgs: 0, maxArgs: 1 },
336
+ indexOf: { method: "indexOf", result: F64, minArgs: 0, maxArgs: 2 },
336
337
  // includes with a position argument is indexOf's clamp exactly (the
337
338
  // spec routes both through StringIndexOf) — the emitter composes
338
339
  // scr_str_index_of(...) != -1 for the two-argument form.
339
- includes: { method: "includes", result: BOOL, minArgs: 1, maxArgs: 2 },
340
- startsWith: { method: "startsWith", result: BOOL, minArgs: 1, maxArgs: 1 },
341
- endsWith: { method: "endsWith", result: BOOL, minArgs: 1, maxArgs: 1 },
340
+ includes: { method: "includes", result: BOOL, minArgs: 0, maxArgs: 2 },
341
+ startsWith: { method: "startsWith", result: BOOL, minArgs: 0, maxArgs: 2 },
342
+ endsWith: { method: "endsWith", result: BOOL, minArgs: 0, maxArgs: 2 },
342
343
  slice: { method: "slice", result: STRING, minArgs: 0, maxArgs: 2 },
343
344
  // substring: slice's clamp-and-swap sibling (negatives clamp to 0
344
345
  // instead of counting from the end; start > end swaps).
345
- substring: { method: "substring", result: STRING, minArgs: 1, maxArgs: 2 },
346
+ substring: { method: "substring", result: STRING, minArgs: 0, maxArgs: 2 },
346
347
  repeat: { method: "repeat", result: STRING, minArgs: 1, maxArgs: 1 },
347
348
  trim: { method: "trim", result: STRING, minArgs: 0, maxArgs: 0 },
348
349
  trimStart: { method: "trimStart", result: STRING, minArgs: 0, maxArgs: 0 },
@@ -358,10 +359,9 @@ export const STR_METHODS = {
358
359
  // astral halves become U+FFFD (SEMANTICS.md divergence 2, the same
359
360
  // substitution the island's boundary marshal applied).
360
361
  split: { method: "split", result: arrayOf(STRING), minArgs: 1, maxArgs: 2 },
361
- // padStart/padEnd with the fill omitted: Node pads with " " — the
362
- // lowering completes the default (lowerStringMethodCall).
363
- padStart: { method: "padStart", result: STRING, minArgs: 1, maxArgs: 2 },
364
- padEnd: { method: "padEnd", result: STRING, minArgs: 1, maxArgs: 2 },
362
+ // Padding completes omitted lengths and fill strings in its lowering.
363
+ padStart: { method: "padStart", result: STRING, minArgs: 0, maxArgs: 2 },
364
+ padEnd: { method: "padEnd", result: STRING, minArgs: 0, maxArgs: 2 },
365
365
  // The lre-backed pair (ECMA Default Case Conversion, final sigma
366
366
  // included — scr_regex.c): static now, no island needed; their presence
367
367
  // flips the regex LINK switch (moduleUsesRegex).
@@ -383,8 +383,8 @@ export const boundaryOutOfIslandMsg = (typeName) => `using an 'any' value where
383
383
  `(an 'any' value can only exit to numbers, strings, booleans, JSON-safe records/arrays/unions, ` +
384
384
  `and 'T | undefined' over those)`;
385
385
  /** The island-backed surface — standard-library APIs with no static
386
- * runtime implementation (Math methods/properties beyond the compile-time
387
- * constants, number/string methods beyond the
386
+ * runtime implementation (Math methods outside STATIC_MATH_FNS,
387
+ * number/string methods beyond the
388
388
  * intrinsic set, parseFloat, ...). ONE table drives both sides of the
389
389
  * gate: under --dynamic each entry lowers to marshal → engine execution →
390
390
  * validated exit to the declared return type; without the flag each use
@@ -401,11 +401,10 @@ export const ISLAND_SURFACE = {
401
401
  /** `Math.<fn>(...)` lowers to callMethod(globalGet("Math"), fn, args);
402
402
  * Math.PI and Math.E are compile-time numeric literals in STATIC_MATH_PROPS;
403
403
  * remaining Math properties retain island/fence behavior.
404
- * min/max/atan2/hypot/pow are declared with exactly two parameters
405
- * (rest/optional parameters aren't representable). */
404
+ * The entries here handle untabled scalar call shapes where --dynamic is
405
+ * available; STATIC_MATH_FNS handles the ordinary typed calls first. */
406
406
  math: {
407
- // floor, min/max (two-arg), and random are STATIC now
408
- // (STATIC_MATH_FNS below).
407
+ // The static table below handles these methods at its admitted arities.
409
408
  fns: {
410
409
  abs: ISL_N1, acos: ISL_N1, asin: ISL_N1, atan: ISL_N1, atan2: ISL_N2,
411
410
  cbrt: ISL_N1, ceil: ISL_N1, cos: ISL_N1, exp: ISL_N1,
@@ -456,16 +455,10 @@ export const STATIC_MATH_PROPS = {
456
455
  PI: 3.141592653589793,
457
456
  E: 2.718281828459045,
458
457
  };
459
- /** Math members with a STATIC lowering — each is one C call that IS the
460
- * JS operation, at the tabled arity (floor: libm's floor; min/max: the
461
- * NaN-poisoning ±0-ordered scalar folds; random: arc4random-backed
462
- * uniform [0,1) — SEMANTICS.md 62). Checked BEFORE the island table
463
- * (lowerIslandMethodCall), so the tabled arities compile statically and
464
- * other arities keep the island/fence story — except min/max, whose
465
- * variadic spelling lowers at ANY plain arity (the n-ary left fold of
466
- * the scalar compare; zero arguments answer the fold's ∓Infinity seed);
467
- * unioned with the island table for the methods-as-values fence
468
- * (lowerMathProperty). */
458
+ /** Math members with a STATIC lowering. Most use the tabled arity; min/max
459
+ * accept any plain arity, and hypot accepts any arity including number[]
460
+ * spreads. Checked before the island table by lowerIslandMethodCall and
461
+ * included in the methods-as-values fence by lowerMathProperty. */
469
462
  export const STATIC_MATH_FNS = {
470
463
  floor: { fn: "math.floor", arity: 1 },
471
464
  abs: { fn: "math.abs", arity: 1 },
@@ -478,6 +471,22 @@ export const STATIC_MATH_FNS = {
478
471
  min: { fn: "math.min", arity: 2 },
479
472
  max: { fn: "math.max", arity: 2 },
480
473
  random: { fn: "math.random", arity: 0 },
474
+ sin: { fn: "math.sin", arity: 1 },
475
+ cos: { fn: "math.cos", arity: 1 },
476
+ tan: { fn: "math.tan", arity: 1 },
477
+ asin: { fn: "math.asin", arity: 1 },
478
+ acos: { fn: "math.acos", arity: 1 },
479
+ atan: { fn: "math.atan", arity: 1 },
480
+ cbrt: { fn: "math.cbrt", arity: 1 },
481
+ sign: { fn: "math.sign", arity: 1 },
482
+ exp: { fn: "math.exp", arity: 1 },
483
+ sqrt: { fn: "math.sqrt", arity: 1 },
484
+ log: { fn: "math.log", arity: 1 },
485
+ log2: { fn: "math.log2", arity: 1 },
486
+ log10: { fn: "math.log10", arity: 1 },
487
+ atan2: { fn: "math.atan2", arity: 2 },
488
+ pow: { fn: "math.pow", arity: 2 },
489
+ hypot: { fn: "math.hypotArr", arity: 2 },
481
490
  };
482
491
  /** Number prototype methods with dedicated STATIC lowering paths. The
483
492
  * libCall spellings are also the compiled-graph witnesses used by library
@@ -485,6 +494,13 @@ export const STATIC_MATH_FNS = {
485
494
  export const STATIC_NUMBER_METHODS = {
486
495
  toFixed: { fns: ["num.toFixed0", "num.toFixed"], minArgs: 0, maxArgs: 1 },
487
496
  };
497
+ /** The common first-class shape for builtin functions whose supported
498
+ * source signature is already exactly the fixed native ABI. Keeping the
499
+ * opt-in on each table row is deliberate: dispatch sentinels and functions
500
+ * with call-site validation must provide a real adapter instead. */
501
+ function exactValueParams(...types) {
502
+ return types.map((type) => ({ mode: "required", type }));
503
+ }
488
504
  /** The lowerable surface of the supported node builtin modules, keyed by
489
505
  * CANONICAL module name (both "fs" and "node:fs" land on "fs" — see
490
506
  * canonicalBuiltinModule). Like STR_METHODS, membership is only half the
@@ -498,36 +514,40 @@ export const STATIC_NUMBER_METHODS = {
498
514
  * platform's rules on any host). toNamespacedPath is the posix identity
499
515
  * (Node: a non-op on posix systems). */
500
516
  const PATH_MODULE_FNS = {
501
- join: { fn: "path.join", params: [STRING], result: STRING, variadicPack: true },
502
- resolve: { fn: "path.resolve", params: [STRING], result: STRING, variadicPack: true },
503
- normalize: { fn: "path.normalize", params: [STRING], result: STRING },
504
- dirname: { fn: "path.dirname", params: [STRING], result: STRING },
505
- basename: { fn: "path.basename", params: [STRING, STRING], result: STRING, defaults: [""] },
506
- extname: { fn: "path.extname", params: [STRING], result: STRING },
507
- isAbsolute: { fn: "path.isAbsolute", params: [STRING], result: BOOL },
508
- relative: { fn: "path.relative", params: [STRING, STRING], result: STRING },
509
- toNamespacedPath: { fn: "path.toNamespacedPath", params: [STRING], result: STRING },
517
+ join: { fn: "path.join", params: [STRING], result: STRING, variadicPack: true, valueParams: [{ mode: "rest", type: STRING }] },
518
+ resolve: { fn: "path.resolve", params: [STRING], result: STRING, variadicPack: true, valueParams: [{ mode: "rest", type: STRING }] },
519
+ normalize: { fn: "path.normalize", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
520
+ dirname: { fn: "path.dirname", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
521
+ basename: { fn: "path.basename", params: [STRING, STRING], result: STRING, defaults: [""], valueParams: [{ mode: "required", type: STRING }, { mode: "optional", type: STRING, defaultValue: "" }] },
522
+ extname: { fn: "path.extname", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
523
+ isAbsolute: { fn: "path.isAbsolute", params: [STRING], result: BOOL, valueParams: [{ mode: "required", type: STRING }] },
524
+ relative: { fn: "path.relative", params: [STRING, STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }, { mode: "required", type: STRING }] },
525
+ toNamespacedPath: { fn: "path.toNamespacedPath", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
510
526
  };
511
527
  /** The win32 twins (scr_path.c's Node-v24 path.win32 port, byte-for-byte):
512
528
  * "path/win32" everywhere, and the bare-module table when the build
513
529
  * TARGETS win32 — Node on Windows is path.win32. */
514
530
  const PATH_WIN32_MODULE_FNS = {
515
- join: { fn: "path.win32Join", params: [STRING], result: STRING, variadicPack: true },
516
- resolve: { fn: "path.win32Resolve", params: [STRING], result: STRING, variadicPack: true },
517
- normalize: { fn: "path.win32Normalize", params: [STRING], result: STRING },
518
- dirname: { fn: "path.win32Dirname", params: [STRING], result: STRING },
519
- basename: { fn: "path.win32Basename", params: [STRING, STRING], result: STRING, defaults: [""] },
520
- extname: { fn: "path.win32Extname", params: [STRING], result: STRING },
521
- isAbsolute: { fn: "path.win32IsAbsolute", params: [STRING], result: BOOL },
522
- relative: { fn: "path.win32Relative", params: [STRING, STRING], result: STRING },
523
- toNamespacedPath: { fn: "path.win32ToNamespacedPath", params: [STRING], result: STRING },
531
+ join: { fn: "path.win32Join", params: [STRING], result: STRING, variadicPack: true, valueParams: [{ mode: "rest", type: STRING }] },
532
+ resolve: { fn: "path.win32Resolve", params: [STRING], result: STRING, variadicPack: true, valueParams: [{ mode: "rest", type: STRING }] },
533
+ normalize: { fn: "path.win32Normalize", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
534
+ dirname: { fn: "path.win32Dirname", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
535
+ basename: { fn: "path.win32Basename", params: [STRING, STRING], result: STRING, defaults: [""], valueParams: [{ mode: "required", type: STRING }, { mode: "optional", type: STRING, defaultValue: "" }] },
536
+ extname: { fn: "path.win32Extname", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
537
+ isAbsolute: { fn: "path.win32IsAbsolute", params: [STRING], result: BOOL, valueParams: [{ mode: "required", type: STRING }] },
538
+ relative: { fn: "path.win32Relative", params: [STRING, STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }, { mode: "required", type: STRING }] },
539
+ toNamespacedPath: { fn: "path.win32ToNamespacedPath", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
524
540
  };
525
541
  export const BUILTIN_MODULE_FNS = {
526
542
  fs: {
527
543
  readFileSync: { fn: "fs.readFileSync", params: [STRING, STRING], result: STRING },
544
+ // The exact-API subset is first-class. A fixed native ABI is not enough:
545
+ // rows whose Node function has behavior-bearing trailing options remain
546
+ // call-only, or function-width adaptation could silently discard those
547
+ // options before entering the fixed runtime call.
528
548
  writeFileSync: { fn: "fs.writeFileSync", params: [STRING, STRING], result: VOID },
529
549
  appendFileSync: { fn: "fs.appendFileSync", params: [STRING, STRING], result: VOID },
530
- existsSync: { fn: "fs.existsSync", params: [STRING], result: BOOL },
550
+ existsSync: { fn: "fs.existsSync", params: [STRING], result: BOOL, valueParams: exactValueParams(STRING) },
531
551
  mkdirSync: { fn: "fs.mkdirSync", params: [STRING], result: VOID },
532
552
  rmSync: { fn: "fs.rmSync", params: [STRING], result: VOID },
533
553
  rmdirSync: { fn: "fs.rmdirSync", params: [STRING], result: VOID },
@@ -537,9 +557,9 @@ export const BUILTIN_MODULE_FNS = {
537
557
  // accessSync's omitted mode completes to 0 (F_OK) in the special case
538
558
  // in lowerBuiltinModuleCall — string `defaults` can't spell a number.
539
559
  accessSync: { fn: "fs.accessSync", params: [STRING, F64], result: VOID },
540
- unlinkSync: { fn: "fs.unlinkSync", params: [STRING], result: VOID },
541
- chmodSync: { fn: "fs.chmodSync", params: [STRING, F64], result: VOID },
542
- chownSync: { fn: "fs.chownSync", params: [STRING, F64, F64], result: VOID },
560
+ unlinkSync: { fn: "fs.unlinkSync", params: [STRING], result: VOID, valueParams: exactValueParams(STRING) },
561
+ chmodSync: { fn: "fs.chmodSync", params: [STRING, F64], result: VOID, valueParams: exactValueParams(STRING, F64) },
562
+ chownSync: { fn: "fs.chownSync", params: [STRING, F64, F64], result: VOID, valueParams: exactValueParams(STRING, F64, F64) },
543
563
  // The 2-argument form only: Node's mode flags (COPYFILE_EXCL, ...)
544
564
  // land on the arity fence.
545
565
  copyFileSync: { fn: "fs.copyFileSync", params: [STRING, STRING], result: VOID },
@@ -548,18 +568,22 @@ export const BUILTIN_MODULE_FNS = {
548
568
  // adapter. The row still projects the static surface and routes the
549
569
  // dispatch.
550
570
  rename: { fn: "fs.renameCb", params: [], result: VOID },
551
- renameSync: { fn: "fs.renameSync", params: [STRING, STRING], result: VOID },
571
+ renameSync: { fn: "fs.renameSync", params: [STRING, STRING], result: VOID, valueParams: exactValueParams(STRING, STRING) },
552
572
  // statSync's no-follow sibling; stats.isSymbolicLink answers what the
553
573
  // follow-free snapshot saw.
554
574
  lstatSync: { fn: "fs.lstatSync", params: [STRING], result: STATS_T },
575
+ fstatSync: { fn: "fs.fstatSync", params: [F64], result: STATS_T, valueParams: exactValueParams(F64) },
576
+ fchmodSync: { fn: "fs.fchmodSync", params: [F64, F64], result: VOID, valueParams: exactValueParams(F64, F64) },
577
+ fsyncSync: { fn: "fs.fsyncSync", params: [F64], result: VOID, valueParams: exactValueParams(F64) },
578
+ linkSync: { fn: "fs.linkSync", params: [STRING, STRING], result: VOID, valueParams: exactValueParams(STRING, STRING) },
555
579
  // realpath(3) — Node's realpathSync (failures spell syscall "lstat",
556
580
  // Node's own message shape).
557
581
  realpathSync: { fn: "fs.realpathSync", params: [STRING], result: STRING },
558
582
  // The fd pair behind spawn's fd-stdio form (the daemon-log idiom:
559
583
  // openSync(logPath, "a") → spawn stdio ["ignore", fd, fd] →
560
- // closeSync). openSync takes Node's string flags ("r", "w", "a", the
561
- // +/x variants — unknown flags throw Node's TypeError text); the
562
- // numeric-mode third argument fences by arity.
584
+ // closeSync). String flags use the established two-argument path;
585
+ // inline numeric O_* expressions route through openNumericSync, with
586
+ // an optional creation mode as the third argument.
563
587
  openSync: { fn: "fs.openSync", params: [STRING, STRING], result: F64 },
564
588
  // The buffer forms (fd, buffer, offset, length[, position]). The
565
589
  // lowering completes an omitted or literal-null position to -1 (the
@@ -570,7 +594,7 @@ export const BUILTIN_MODULE_FNS = {
570
594
  // overloads lower to separate fixed-width runtime ABIs. As with
571
595
  // readSync, -1 is the current-offset sentinel.
572
596
  writeSync: { fn: "fs.writeSync", params: [F64, BYTES_U8, F64, F64, F64], result: F64 },
573
- closeSync: { fn: "fs.closeSync", params: [F64], result: VOID },
597
+ closeSync: { fn: "fs.closeSync", params: [F64], result: VOID, valueParams: exactValueParams(F64) },
574
598
  // Entirely special-cased (lowerFsWatchCall — the callback needs an
575
599
  // adapter per listener shape); this entry only routes the dispatch.
576
600
  watch: { fn: "fs.watch", params: [], result: VOID },
@@ -585,9 +609,11 @@ export const BUILTIN_MODULE_FNS = {
585
609
  readdir: { fn: "fsp.readdir", params: [STRING], result: { kind: "promise", inner: arrayOf(STRING) } },
586
610
  rm: { fn: "fsp.rm", params: [STRING], result: { kind: "promise", inner: VOID } },
587
611
  stat: { fn: "fsp.stat", params: [STRING], result: { kind: "promise", inner: STATS_T } },
588
- unlink: { fn: "fsp.unlink", params: [STRING], result: { kind: "promise", inner: VOID } },
589
- chmod: { fn: "fsp.chmod", params: [STRING, F64], result: { kind: "promise", inner: VOID } },
590
- rename: { fn: "fsp.rename", params: [STRING, STRING], result: { kind: "promise", inner: VOID } },
612
+ realpath: { fn: "fsp.realpath", params: [STRING], result: { kind: "promise", inner: STRING } },
613
+ lstat: { fn: "fsp.lstat", params: [STRING], result: { kind: "promise", inner: STATS_T } },
614
+ unlink: { fn: "fsp.unlink", params: [STRING], result: { kind: "promise", inner: VOID }, valueParams: exactValueParams(STRING) },
615
+ chmod: { fn: "fsp.chmod", params: [STRING, F64], result: { kind: "promise", inner: VOID }, valueParams: exactValueParams(STRING, F64) },
616
+ rename: { fn: "fsp.rename", params: [STRING, STRING], result: { kind: "promise", inner: VOID }, valueParams: exactValueParams(STRING, STRING) },
591
617
  // open's optional flags/mode completion is special-cased in
592
618
  // lowerBuiltinModuleCall; this row routes all import spellings and
593
619
  // gives coverage the static member.
@@ -605,18 +631,18 @@ export const BUILTIN_MODULE_FNS = {
605
631
  "path/win32": PATH_WIN32_MODULE_FNS,
606
632
  os: {
607
633
  // One platform implementation: os.platform() === process.platform.
608
- platform: { fn: "process.platform", params: [], result: STRING },
609
- homedir: { fn: "os.homedir", params: [], result: STRING },
610
- tmpdir: { fn: "os.tmpdir", params: [], result: STRING },
634
+ platform: { fn: "process.platform", params: [], result: STRING, valueParams: [] },
635
+ homedir: { fn: "os.homedir", params: [], result: STRING, valueParams: [] },
636
+ tmpdir: { fn: "os.tmpdir", params: [], result: STRING, valueParams: [] },
611
637
  // uname(2)'s release field — Node's own implementation.
612
- release: { fn: "os.release", params: [], result: STRING },
638
+ release: { fn: "os.release", params: [], result: STRING, valueParams: [] },
613
639
  // uname(2)'s sysname field ("Darwin", "Linux", "Windows_NT") — the
614
640
  // libFn/runtime pair predates this entry (the portless surface used
615
641
  // them); this row makes the MODULE call reach them (test/common's
616
642
  // isAIX/isIBMi getters are the canonical callers).
617
- type: { fn: "os.type", params: [], result: STRING },
643
+ type: { fn: "os.type", params: [], result: STRING, valueParams: [] },
618
644
  // Total physical memory in bytes — same predating-pair story.
619
- totalmem: { fn: "os.totalmem", params: [], result: F64 },
645
+ totalmem: { fn: "os.totalmem", params: [], result: F64, valueParams: [] },
620
646
  // Entirely special-cased (lowerOsNetworkInterfacesCall): the result is
621
647
  // the call site's mapped Dict<NetworkInterfaceInfo[]> shape, verified
622
648
  // structurally there — this entry only routes the dispatch.
@@ -645,11 +671,25 @@ export const BUILTIN_MODULE_FNS = {
645
671
  pbkdf2: { fn: "crypto.pbkdf2Cb", params: [], result: VOID },
646
672
  },
647
673
  zlib: {
648
- // Buffer in, Buffer out, Node's default options; string inputs fence
649
- // per site (see the zlib special case in lowerBuiltinModuleCall).
674
+ // The default-options convenience family is special-cased in
675
+ // lowerBuiltinModuleCall: string inputs UTF-8 encode, callback forms
676
+ // carry program-shaped closures, and explicit options fence per site.
650
677
  // native-toolchain.ts links libz only when these appear on the IR.
678
+ deflate: { fn: "zlib.deflateCb", params: [], result: VOID },
651
679
  deflateSync: { fn: "zlib.deflateSync", params: [BYTES_U8], result: BYTES_U8 },
680
+ inflate: { fn: "zlib.inflateCb", params: [], result: VOID },
652
681
  inflateSync: { fn: "zlib.inflateSync", params: [BYTES_U8], result: BYTES_U8 },
682
+ deflateRaw: { fn: "zlib.deflateRawCb", params: [], result: VOID },
683
+ deflateRawSync: { fn: "zlib.deflateRawSync", params: [BYTES_U8], result: BYTES_U8 },
684
+ inflateRaw: { fn: "zlib.inflateRawCb", params: [], result: VOID },
685
+ inflateRawSync: { fn: "zlib.inflateRawSync", params: [BYTES_U8], result: BYTES_U8 },
686
+ gzip: { fn: "zlib.gzipCb", params: [], result: VOID },
687
+ gzipSync: { fn: "zlib.gzipSync", params: [BYTES_U8], result: BYTES_U8 },
688
+ gunzip: { fn: "zlib.gunzipCb", params: [], result: VOID },
689
+ gunzipSync: { fn: "zlib.gunzipSync", params: [BYTES_U8], result: BYTES_U8 },
690
+ unzip: { fn: "zlib.unzipCb", params: [], result: VOID },
691
+ unzipSync: { fn: "zlib.unzipSync", params: [BYTES_U8], result: BYTES_U8 },
692
+ crc32: { fn: "zlib.crc32", params: [], result: F64 },
653
693
  },
654
694
  url: {
655
695
  // fileURLToPath accepts a URL value OR a string — the call lowering
@@ -661,11 +701,13 @@ export const BUILTIN_MODULE_FNS = {
661
701
  child_process: {
662
702
  // spawnSync's and spawn's call completions are entirely special-cased
663
703
  // (an omitted args list completes to an empty string[]; spawnSync
664
- // accepts exactly { encoding: "utf8" } as options, spawn requires
665
- // exactly { stdio: "ignore" } — see lowerBuiltinModuleCall); the
704
+ // accepts its documented literal options, while spawn supports the
705
+ // stdio/detached/env/cwd/windowsHide/shell subset — see
706
+ // lowerBuiltinModuleCall); the
666
707
  // entries carry the canonical shapes.
667
708
  spawnSync: { fn: "cp.spawnSync", params: [STRING, arrayOf(STRING)], result: SPAWNRES_T },
668
709
  spawn: { fn: "cp.spawn", params: [STRING, arrayOf(STRING)], result: CHILD_T },
710
+ fork: { fn: "cp.fork", params: [STRING, arrayOf(STRING)], result: CHILD_T },
669
711
  // execFileSync(file, args?, options?) and execSync(command, options?)
670
712
  // share the cp.execSync runtime entry (execSync sets the shell flag);
671
713
  // both call completions are special-cased in lowerBuiltinModuleCall.
@@ -704,8 +746,8 @@ export const BUILTIN_MODULE_FNS = {
704
746
  decode: { fn: "qs.parse", params: [STRING], result: VOID },
705
747
  stringify: { fn: "qs.stringify", params: [DYN], result: STRING },
706
748
  encode: { fn: "qs.stringify", params: [DYN], result: STRING },
707
- escape: { fn: "qs.escape", params: [STRING], result: STRING },
708
- unescape: { fn: "qs.unescape", params: [STRING], result: STRING },
749
+ escape: { fn: "qs.escape", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
750
+ unescape: { fn: "qs.unescape", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
709
751
  },
710
752
  // node:readline: createInterface's options are entirely special-cased
711
753
  // (exactly { input: process.stdin, output?: process.stdout } — see
@@ -795,6 +837,7 @@ export const BUILTIN_MODULE_FNS = {
795
837
  * thread machinery) and never runs as a cluster worker (cluster forks the
796
838
  * node binary itself) — Node's own answers for a directly-run script. */
797
839
  export const BUILTIN_MODULE_CONSTS = {
840
+ http: { maxHeaderSize: 16384 },
798
841
  path: { sep: "/", delimiter: ":" },
799
842
  "path/posix": { sep: "/", delimiter: ":" },
800
843
  "path/win32": { sep: "\\", delimiter: ";" },
@@ -812,6 +855,8 @@ export const BUILTIN_MODULE_CONSTS = {
812
855
  * (library/fence-eval.ts) and the attestation-parity test. */
813
856
  export const BUILTIN_MODULE_FN_ALIASES = {
814
857
  fs: {
858
+ // Inline numeric O_* flags use a target-neutral runtime entry point.
859
+ openSync: ["fs.openNumericSync"],
815
860
  // The Buffer form (no encoding), the fd forms (readFileSync(fd[,
816
861
  // "utf8"])), and the checked-dynamic encoding form.
817
862
  readFileSync: ["fs.readFileSyncBuf", "fs.readFileSyncBytes", "fs.readFileSyncDyn", "fs.readFdSync", "fs.readFdSyncBytes"],
@@ -841,6 +886,8 @@ export const BUILTIN_MODULE_FN_ALIASES = {
841
886
  readFile: ["fsp.readFileBytes"],
842
887
  // The string-data { mode } options form.
843
888
  writeFile: ["fsp.writeFileMode"],
889
+ // The { withFileTypes: true } Dirent form.
890
+ readdir: ["fsp.readdirTypes"],
844
891
  },
845
892
  crypto: {
846
893
  // The composed randomBytes(n).toString(enc) chain keeps its one-libCall
@@ -866,6 +913,13 @@ export const AMBIENT_SURFACE_FNS = [
866
913
  fns: ["date.now"],
867
914
  note: "the live clock",
868
915
  },
916
+ {
917
+ id: "stdlib.date.parse",
918
+ kind: "stdlib",
919
+ name: "Date.parse",
920
+ fns: ["date.parse"],
921
+ note: "one date string, using the bounded parser shared with new Date(dateString).getTime()",
922
+ },
869
923
  {
870
924
  id: "stdlib.date.constructor",
871
925
  kind: "stdlib",
@@ -1006,6 +1060,13 @@ export const AMBIENT_SURFACE_FNS = [
1006
1060
  fns: ["process.exit", "process.exiting"],
1007
1061
  note: "process.exit and the process._exiting flag read are one surface",
1008
1062
  },
1063
+ {
1064
+ id: "node-builtin.process.exitCode",
1065
+ kind: "node-builtin",
1066
+ name: "process.exitCode",
1067
+ fns: ["process.setExitCode"],
1068
+ note: "numeric writes in statement position set the implicit exit status; process.exit() reads it",
1069
+ },
1009
1070
  // ── the tls CA store (lowerTlsCaCall / lowerTlsRootCertificates): the
1010
1071
  // host's trust anchors, read and replaced. Dedicated paths, and
1011
1072
  // rootCertificates is a VALUE read with no call form at all, so none of
@@ -1113,7 +1174,7 @@ export function builtinConstLit(value, loc) {
1113
1174
  * Node ships one frozen singleton; each read here mints a fresh string
1114
1175
  * array — a divergence only mutation could observe, and mutating Node's
1115
1176
  * frozen array throws anyway. */
1116
- const NODE_BUILTIN_MODULES_V24 = [
1177
+ export const NODE_BUILTIN_MODULES_V24 = [
1117
1178
  "_http_agent", "_http_client", "_http_common", "_http_incoming",
1118
1179
  "_http_outgoing", "_http_server", "_stream_duplex", "_stream_passthrough",
1119
1180
  "_stream_readable", "_stream_transform", "_stream_wrap", "_stream_writable",
@@ -1141,19 +1202,16 @@ export function builtinModulesArrayLit(loc) {
1141
1202
  };
1142
1203
  }
1143
1204
  /** Member-specific hints for RECOGNIZED builtin modules whose member has
1144
- * no lowering. deflateSync/inflateSync lower now (Buffers are real);
1145
- * the rest of the zlib surface points at the lowered pair. */
1146
- const ZLIB_HINT = "deflateSync and inflateSync are the lowered zlib surface";
1147
- /** The loose-equality quartet's shared hint: == coercion has no lowering
1148
- * anywhere in this compiler, and Node itself points at the strict forms. */
1149
- const ASSERT_LOOSE_HINT = "loose == equality has no lowering — the strict forms compare with " +
1150
- "Object.is/structural equality like Node's assert/strict module, where " +
1151
- "equal IS strictEqual";
1205
+ * no lowering. The default-options one-shot zlib/deflate-raw/gzip codecs
1206
+ * lower for strings and Buffers; the remaining surface points at them. */
1207
+ const ZLIB_HINT = "the default-options deflate/inflate, raw, gzip/gunzip, and unzip sync/callback forms plus crc32 are the lowered zlib surface";
1208
+ /** The legacy deep pair remains fenced. The shallow equal/notEqual pair
1209
+ * lowers through the static Abstract Equality kernel in lower-assert. */
1210
+ const ASSERT_LOOSE_DEEP_HINT = "legacy deep equality has no lowering yet — deepStrictEqual and " +
1211
+ "notDeepStrictEqual compare structures with Node's modern semantics";
1152
1212
  const ASSERT_MODULE_HINTS = {
1153
- equal: ASSERT_LOOSE_HINT,
1154
- notEqual: ASSERT_LOOSE_HINT,
1155
- deepEqual: ASSERT_LOOSE_HINT,
1156
- notDeepEqual: ASSERT_LOOSE_HINT,
1213
+ deepEqual: ASSERT_LOOSE_DEEP_HINT,
1214
+ notDeepEqual: ASSERT_LOOSE_DEEP_HINT,
1157
1215
  ifError: "test explicitly instead: assert.strictEqual(err, null) / " +
1158
1216
  "assert.strictEqual(err, undefined)",
1159
1217
  rejects: "await the promise inside assert.throws's callback story instead: " +
@@ -1176,10 +1234,7 @@ export const BUILTIN_MODULE_FENCE_HINTS = {
1176
1234
  AssertionError: ASSERT_MODULE_HINTS["AssertionError"],
1177
1235
  },
1178
1236
  util: {
1179
- promisify: "the one lowered shape is a const binding over child_process.execFile: " +
1180
- "const execFileAsync = promisify(execFile), then call execFileAsync directly",
1181
- // child_process.execFile itself exists to be promisified — the same
1182
- // story from the other end.
1237
+ promisify: "the lowered shapes are const bindings over child_process.execFile and fs.readFile; call the bound function directly",
1183
1238
  },
1184
1239
  "stream/consumers": {
1185
1240
  arrayBuffer: "no free-standing ArrayBuffer value exists here (typed arrays own their storage) — " +
@@ -1189,17 +1244,15 @@ export const BUILTIN_MODULE_FENCE_HINTS = {
1189
1244
  },
1190
1245
  module: {
1191
1246
  createRequire: "the lowered shape is a const binding over createRequire(import.meta.url) (or __filename) " +
1192
- "whose require calls take STATIC string literals — builtins, relative .json documents, " +
1193
- "and installed npm packages (under --dynamic) resolve at build time; " +
1247
+ "whose require calls take STATIC string literals — builtins, project modules (including #imports), " +
1248
+ "relative .json documents, --npm-static packages, and installed npm packages under --dynamic resolve at build time; " +
1194
1249
  "dynamic specifiers cannot exist in a compiled binary's fixed module graph",
1195
- isBuiltin: "builtinModules.includes(name) answers the same question over the baked list " +
1196
- "(strip a node: prefix first; the prefix-only builtins appear with it, as node:test)",
1197
- syncBuiltinESMExports: "a compiled program has no live builtin ESM namespace bindings to synchronize — " +
1198
- "nothing a compiled surface can mutate makes the call observable; remove it",
1250
+ isBuiltin: "the lowered call checks a string against the baked Node v24 list, including bare/node: aliases and prefix-only builtins",
1251
+ syncBuiltinESMExports: "the direct zero-argument call is a no-op because compiled builtin exports are immutable and cannot become stale",
1199
1252
  },
1200
1253
  child_process: {
1201
- execFile: "the callback form has no lowering — promisify it: " +
1202
- "const execFileAsync = promisify(execFile) (from node:util), or use execFileSync",
1254
+ execFile: "the callback forms execFile(file, callback), execFile(file, args, callback), and execFile(file, args, { encoding: 'utf8', maxBuffer: N }, callback) lower; " +
1255
+ "maxBuffer is not enforced by the growing native capture; other options and reached no-callback calls remain fenced, while util.promisify(execFile) retains its wider options slice",
1203
1256
  },
1204
1257
  crypto: {
1205
1258
  ...Object.fromEntries([
@@ -1231,9 +1284,6 @@ export const BUILTIN_MODULE_FENCE_HINTS = {
1231
1284
  "randomBytes, and the createHash chain",
1232
1285
  },
1233
1286
  zlib: {
1234
- gzipSync: ZLIB_HINT,
1235
- gunzipSync: ZLIB_HINT,
1236
- unzipSync: ZLIB_HINT,
1237
1287
  brotliCompressSync: ZLIB_HINT,
1238
1288
  brotliDecompressSync: ZLIB_HINT,
1239
1289
  },
@@ -1546,27 +1596,50 @@ export function stdlibGlobalMember(lowerer, access, name) {
1546
1596
  * nothing. Only the globals with lowered member surfaces alias this
1547
1597
  * way; aliasing, say, `Math` would change nothing (its members lower
1548
1598
  * by receiver too). Returns true when recognized. */
1549
- export function stdlibGlobalAliasDecl(lowerer, nameNode, init) {
1550
- if (!init || !ts.isIdentifier(nameNode))
1551
- return false;
1599
+ export function stdlibGlobalAliasNameOf(lowerer, init) {
1600
+ if (!init)
1601
+ return null;
1602
+ // CommonJS packages commonly guard Node's always-present globals for
1603
+ // browser bundlers (`let p = process || {}`). In the Node execution
1604
+ // model the left object is unconditionally truthy, so the fallback is
1605
+ // never evaluated and the binding is the same global snapshot as the
1606
+ // direct spelling. Keep this deliberately to `||` with a surfaced
1607
+ // stdlib-global left operand; arbitrary capability probes retain their
1608
+ // runtime value semantics.
1609
+ let aliasExpr = init;
1610
+ while (ts.isParenthesizedExpression(aliasExpr))
1611
+ aliasExpr = aliasExpr.expression;
1612
+ if (ts.isBinaryExpression(aliasExpr) &&
1613
+ aliasExpr.operatorToken.kind === ts.SyntaxKind.BarBarToken &&
1614
+ stdlibGlobalNameOf(lowerer, aliasExpr.left) !== null) {
1615
+ aliasExpr = aliasExpr.left;
1616
+ }
1552
1617
  // `const process = require('node:process')`: Node's process MODULE is
1553
1618
  // the global process object (module.exports === globalThis.process),
1554
1619
  // so the binding aliases the global exactly like `const process =
1555
1620
  // globalThis.process`. Preflight admits exactly this shape
1556
1621
  // (processModuleAliasRequire7); commander's lib/command.js opens with
1557
1622
  // it.
1558
- const requireSpec = requireSpecOf(init);
1623
+ const requireSpec = requireSpecOf(aliasExpr);
1559
1624
  const name = requireSpec === "process" || requireSpec === "node:process"
1560
1625
  ? "process"
1561
- : stdlibGlobalNameOf(lowerer, init);
1626
+ : stdlibGlobalNameOf(lowerer, aliasExpr);
1562
1627
  if (name === null)
1563
- return false;
1628
+ return null;
1564
1629
  // Only alias OBJECT-shaped globals whose members lower by receiver
1565
1630
  // identity (process, console, globalThis itself, and perf_hooks'
1566
1631
  // performance — the mockable-clock idiom snapshots it). Function-valued
1567
1632
  // globals (setTimeout) taken as values are a different story — the
1568
1633
  // ordinary value paths (and their fences) apply.
1569
- if (name !== "process" && name !== "console" && name !== "globalThis" && name !== "performance")
1634
+ return name === "process" || name === "console" || name === "globalThis" || name === "performance"
1635
+ ? name
1636
+ : null;
1637
+ }
1638
+ export function stdlibGlobalAliasDecl(lowerer, nameNode, init) {
1639
+ if (!ts.isIdentifier(nameNode))
1640
+ return false;
1641
+ const name = stdlibGlobalAliasNameOf(lowerer, init);
1642
+ if (name === null)
1570
1643
  return false;
1571
1644
  const symbol = lowerer.checker.getSymbolAtLocation(nameNode);
1572
1645
  if (!symbol)