@scriptc/compiler 0.1.3 → 0.1.4

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 (147) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +200 -51
  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 +10 -0
  6. package/dist/backend/c/c-emitter.js +14 -2
  7. package/dist/backend/c/c-emitter.js.map +1 -1
  8. package/dist/backend/c/exprs.js +293 -51
  9. package/dist/backend/c/exprs.js.map +1 -1
  10. package/dist/backend/c/types.js +2 -0
  11. package/dist/backend/c/types.js.map +1 -1
  12. package/dist/backend/link-plan.d.ts +2 -1
  13. package/dist/backend/link-plan.js +2 -1
  14. package/dist/backend/link-plan.js.map +1 -1
  15. package/dist/backend/llvm/emitter.js +20 -6
  16. package/dist/backend/llvm/emitter.js.map +1 -1
  17. package/dist/backend/llvm/expr-bytes.d.ts +1 -1
  18. package/dist/backend/llvm/expr-bytes.js +8 -8
  19. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  20. package/dist/backend/llvm/expr-callbacks.d.ts +9 -0
  21. package/dist/backend/llvm/expr-callbacks.js +125 -0
  22. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  23. package/dist/backend/llvm/expr-context.d.ts +14 -2
  24. package/dist/backend/llvm/expr-dispatch.js +1 -0
  25. package/dist/backend/llvm/expr-dispatch.js.map +1 -1
  26. package/dist/backend/llvm/expr-primitives.d.ts +1 -1
  27. package/dist/backend/llvm/expr-primitives.js +30 -9
  28. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  29. package/dist/backend/llvm/expr-primitives.test.d.ts +1 -0
  30. package/dist/backend/llvm/expr-primitives.test.js +38 -0
  31. package/dist/backend/llvm/expr-primitives.test.js.map +1 -0
  32. package/dist/backend/llvm/expr-stream-callbacks.d.ts +3 -0
  33. package/dist/backend/llvm/expr-stream-callbacks.js +69 -0
  34. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  35. package/dist/backend/llvm/lib-filesystem.js +68 -10
  36. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  37. package/dist/backend/llvm/lib-network.js +18 -2
  38. package/dist/backend/llvm/lib-network.js.map +1 -1
  39. package/dist/backend/llvm/lib-process.js +156 -6
  40. package/dist/backend/llvm/lib-process.js.map +1 -1
  41. package/dist/backend/llvm/lib-shared.js +36 -0
  42. package/dist/backend/llvm/lib-shared.js.map +1 -1
  43. package/dist/backend/llvm/lib-stream.js +23 -0
  44. package/dist/backend/llvm/lib-stream.js.map +1 -1
  45. package/dist/backend/native-toolchain.d.ts +3 -0
  46. package/dist/backend/native-toolchain.js +3 -1
  47. package/dist/backend/native-toolchain.js.map +1 -1
  48. package/dist/backend/runtime-pack.test.js +28 -10
  49. package/dist/backend/runtime-pack.test.js.map +1 -1
  50. package/dist/backend/targets.d.ts +4 -0
  51. package/dist/backend/targets.js +13 -0
  52. package/dist/backend/targets.js.map +1 -1
  53. package/dist/backend/targets.test.js +8 -1
  54. package/dist/backend/targets.test.js.map +1 -1
  55. package/dist/coverage/surface-manifest.js +8 -0
  56. package/dist/coverage/surface-manifest.js.map +1 -1
  57. package/dist/diagnostics/diagnostic.js +1 -1
  58. package/dist/diagnostics/diagnostic.js.map +1 -1
  59. package/dist/executable/executable-cache.d.ts +2 -0
  60. package/dist/executable/executable-cache.js +3 -0
  61. package/dist/executable/executable-cache.js.map +1 -1
  62. package/dist/frontend/fork-target.d.ts +17 -0
  63. package/dist/frontend/fork-target.js +256 -0
  64. package/dist/frontend/fork-target.js.map +1 -0
  65. package/dist/frontend/lowering/abstract-equality.d.ts +6 -0
  66. package/dist/frontend/lowering/abstract-equality.js +250 -0
  67. package/dist/frontend/lowering/abstract-equality.js.map +1 -0
  68. package/dist/frontend/lowering/lower-assert.js +71 -2
  69. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  70. package/dist/frontend/lowering/lower-builtins.d.ts +50 -23
  71. package/dist/frontend/lowering/lower-builtins.js +939 -106
  72. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  73. package/dist/frontend/lowering/lower-calls.d.ts +29 -21
  74. package/dist/frontend/lowering/lower-calls.js +573 -121
  75. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  76. package/dist/frontend/lowering/lower-classes.js +39 -8
  77. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  78. package/dist/frontend/lowering/lower-containers.js +150 -0
  79. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  80. package/dist/frontend/lowering/lower-event-emitter.js +212 -21
  81. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  82. package/dist/frontend/lowering/lower-exprs.js +135 -83
  83. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  84. package/dist/frontend/lowering/lower-inspect.d.ts +4 -0
  85. package/dist/frontend/lowering/lower-inspect.js +1 -1
  86. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  87. package/dist/frontend/lowering/lower-island.d.ts +6 -3
  88. package/dist/frontend/lowering/lower-island.js +165 -6
  89. package/dist/frontend/lowering/lower-island.js.map +1 -1
  90. package/dist/frontend/lowering/lower-modules.d.ts +6 -0
  91. package/dist/frontend/lowering/lower-modules.js +184 -38
  92. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  93. package/dist/frontend/lowering/lower-namespaces.js +7 -0
  94. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  95. package/dist/frontend/lowering/lower-server.d.ts +1 -1
  96. package/dist/frontend/lowering/lower-server.js +130 -27
  97. package/dist/frontend/lowering/lower-server.js.map +1 -1
  98. package/dist/frontend/lowering/lower-stmts.js +118 -15
  99. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  100. package/dist/frontend/lowering/lower-stream.d.ts +3 -0
  101. package/dist/frontend/lowering/lower-stream.js +7 -0
  102. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  103. package/dist/frontend/lowering/lowerer.d.ts +86 -9
  104. package/dist/frontend/lowering/lowerer.js +412 -72
  105. package/dist/frontend/lowering/lowerer.js.map +1 -1
  106. package/dist/frontend/lowering/surfaces.d.ts +26 -0
  107. package/dist/frontend/lowering/surfaces.js +140 -77
  108. package/dist/frontend/lowering/surfaces.js.map +1 -1
  109. package/dist/frontend/npm-static-declarations.d.ts +4 -0
  110. package/dist/frontend/npm-static-declarations.js +56 -0
  111. package/dist/frontend/npm-static-declarations.js.map +1 -1
  112. package/dist/frontend/npm-static-declarations.test.js +23 -2
  113. package/dist/frontend/npm-static-declarations.test.js.map +1 -1
  114. package/dist/frontend/npm-static.js +6 -5
  115. package/dist/frontend/npm-static.js.map +1 -1
  116. package/dist/frontend/npm.d.ts +15 -3
  117. package/dist/frontend/npm.js +80 -8
  118. package/dist/frontend/npm.js.map +1 -1
  119. package/dist/frontend/npm.test.js +76 -9
  120. package/dist/frontend/npm.test.js.map +1 -1
  121. package/dist/frontend/program.js +92 -10
  122. package/dist/frontend/program.js.map +1 -1
  123. package/dist/frontend/resolve.d.ts +6 -0
  124. package/dist/frontend/resolve.js +7 -4
  125. package/dist/frontend/resolve.js.map +1 -1
  126. package/dist/frontend/type-mapper.d.ts +5 -0
  127. package/dist/frontend/type-mapper.js +64 -24
  128. package/dist/frontend/type-mapper.js.map +1 -1
  129. package/dist/index.d.ts +5 -0
  130. package/dist/index.js +24 -3
  131. package/dist/index.js.map +1 -1
  132. package/dist/ir/ir.d.ts +93 -47
  133. package/dist/ir/ir.js +63 -4
  134. package/dist/ir/ir.js.map +1 -1
  135. package/dist/ir/ir.test.js +14 -1
  136. package/dist/ir/ir.test.js.map +1 -1
  137. package/dist/ir/serialize.d.ts +1 -1
  138. package/dist/ir/serialize.js +1 -1
  139. package/dist/ir/serialize.js.map +1 -1
  140. package/dist/ir/validate.js +165 -13
  141. package/dist/ir/validate.js.map +1 -1
  142. package/dist/library/int-infer.test.js +4 -4
  143. package/dist/library/int-infer.test.js.map +1 -1
  144. package/dist/library/library-cache.test.js +5 -5
  145. package/dist/library/library-cache.test.js.map +1 -1
  146. package/package.json +17 -17
  147. package/surface-manifest.json +132 -38
@@ -198,7 +198,24 @@ export interface BuiltinModuleFn {
198
198
  result: IrType;
199
199
  variadicPack?: boolean;
200
200
  defaults?: string[];
201
+ /** The source-level function-value signature. Each admitted entry
202
+ * materializes as an interned zero-capture adapter over the fixed runtime
203
+ * libCall ABI. Optional parameters name the string default selected for
204
+ * omission or explicit undefined; rest parameters pack into one typed
205
+ * array slot. Entries with call-site-specific validation remain absent. */
206
+ valueParams?: BuiltinValueParam[];
201
207
  }
208
+ export type BuiltinValueParam = {
209
+ mode: "required";
210
+ type: IrType;
211
+ } | {
212
+ mode: "optional";
213
+ type: IrType;
214
+ defaultValue: string;
215
+ } | {
216
+ mode: "rest";
217
+ type: IrType;
218
+ };
202
219
  export declare const BUILTIN_MODULE_FNS: Record<string, Record<string, BuiltinModuleFn | undefined> | undefined>;
203
220
  /** Builtin-module CONSTANTS (value reads of named imports): each lowers to
204
221
  * a literal of its value's kind. The bare-module values are the TARGET
@@ -254,6 +271,14 @@ export declare function builtinConstLit(value: string | number | boolean, loc: {
254
271
  start: number;
255
272
  end: number;
256
273
  }): IrExpr;
274
+ /** node:module's builtinModules, BAKED — Node v24's exact list (verbatim
275
+ * order: the bare names, then the node:-prefix-only tails), pinned to
276
+ * the compat target rather than read from the COMPILING host's Node so
277
+ * emitted programs are host-independent (the cache-identity contract).
278
+ * Node ships one frozen singleton; each read here mints a fresh string
279
+ * array — a divergence only mutation could observe, and mutating Node's
280
+ * frozen array throws anyway. */
281
+ export declare const NODE_BUILTIN_MODULES_V24: readonly string[];
257
282
  /** The array-literal read of module.builtinModules — both value paths
258
283
  * (the named-import binding and the namespace member read) mint the
259
284
  * same fresh string[]. */
@@ -321,6 +346,7 @@ export declare function stdlibGlobalMember(lowerer: Lowerer, access: ts.Property
321
346
  * nothing. Only the globals with lowered member surfaces alias this
322
347
  * way; aliasing, say, `Math` would change nothing (its members lower
323
348
  * by receiver too). Returns true when recognized. */
349
+ export declare function stdlibGlobalAliasNameOf(lowerer: Lowerer, init: ts.Expression | undefined): string | null;
324
350
  export declare function stdlibGlobalAliasDecl(lowerer: Lowerer, nameNode: ts.Node, init: ts.Expression | undefined): boolean;
325
351
  /** True iff the symbol is declared ONLY by the adopted @types/node
326
352
  * surface (no es-lib or shipped-ambient declaration merges in) — chooses
@@ -485,6 +485,13 @@ export const STATIC_MATH_FNS = {
485
485
  export const STATIC_NUMBER_METHODS = {
486
486
  toFixed: { fns: ["num.toFixed0", "num.toFixed"], minArgs: 0, maxArgs: 1 },
487
487
  };
488
+ /** The common first-class shape for builtin functions whose supported
489
+ * source signature is already exactly the fixed native ABI. Keeping the
490
+ * opt-in on each table row is deliberate: dispatch sentinels and functions
491
+ * with call-site validation must provide a real adapter instead. */
492
+ function exactValueParams(...types) {
493
+ return types.map((type) => ({ mode: "required", type }));
494
+ }
488
495
  /** The lowerable surface of the supported node builtin modules, keyed by
489
496
  * CANONICAL module name (both "fs" and "node:fs" land on "fs" — see
490
497
  * canonicalBuiltinModule). Like STR_METHODS, membership is only half the
@@ -498,36 +505,40 @@ export const STATIC_NUMBER_METHODS = {
498
505
  * platform's rules on any host). toNamespacedPath is the posix identity
499
506
  * (Node: a non-op on posix systems). */
500
507
  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 },
508
+ join: { fn: "path.join", params: [STRING], result: STRING, variadicPack: true, valueParams: [{ mode: "rest", type: STRING }] },
509
+ resolve: { fn: "path.resolve", params: [STRING], result: STRING, variadicPack: true, valueParams: [{ mode: "rest", type: STRING }] },
510
+ normalize: { fn: "path.normalize", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
511
+ dirname: { fn: "path.dirname", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
512
+ basename: { fn: "path.basename", params: [STRING, STRING], result: STRING, defaults: [""], valueParams: [{ mode: "required", type: STRING }, { mode: "optional", type: STRING, defaultValue: "" }] },
513
+ extname: { fn: "path.extname", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
514
+ isAbsolute: { fn: "path.isAbsolute", params: [STRING], result: BOOL, valueParams: [{ mode: "required", type: STRING }] },
515
+ relative: { fn: "path.relative", params: [STRING, STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }, { mode: "required", type: STRING }] },
516
+ toNamespacedPath: { fn: "path.toNamespacedPath", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
510
517
  };
511
518
  /** The win32 twins (scr_path.c's Node-v24 path.win32 port, byte-for-byte):
512
519
  * "path/win32" everywhere, and the bare-module table when the build
513
520
  * TARGETS win32 — Node on Windows is path.win32. */
514
521
  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 },
522
+ join: { fn: "path.win32Join", params: [STRING], result: STRING, variadicPack: true, valueParams: [{ mode: "rest", type: STRING }] },
523
+ resolve: { fn: "path.win32Resolve", params: [STRING], result: STRING, variadicPack: true, valueParams: [{ mode: "rest", type: STRING }] },
524
+ normalize: { fn: "path.win32Normalize", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
525
+ dirname: { fn: "path.win32Dirname", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
526
+ basename: { fn: "path.win32Basename", params: [STRING, STRING], result: STRING, defaults: [""], valueParams: [{ mode: "required", type: STRING }, { mode: "optional", type: STRING, defaultValue: "" }] },
527
+ extname: { fn: "path.win32Extname", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
528
+ isAbsolute: { fn: "path.win32IsAbsolute", params: [STRING], result: BOOL, valueParams: [{ mode: "required", type: STRING }] },
529
+ relative: { fn: "path.win32Relative", params: [STRING, STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }, { mode: "required", type: STRING }] },
530
+ toNamespacedPath: { fn: "path.win32ToNamespacedPath", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
524
531
  };
525
532
  export const BUILTIN_MODULE_FNS = {
526
533
  fs: {
527
534
  readFileSync: { fn: "fs.readFileSync", params: [STRING, STRING], result: STRING },
535
+ // The exact-API subset is first-class. A fixed native ABI is not enough:
536
+ // rows whose Node function has behavior-bearing trailing options remain
537
+ // call-only, or function-width adaptation could silently discard those
538
+ // options before entering the fixed runtime call.
528
539
  writeFileSync: { fn: "fs.writeFileSync", params: [STRING, STRING], result: VOID },
529
540
  appendFileSync: { fn: "fs.appendFileSync", params: [STRING, STRING], result: VOID },
530
- existsSync: { fn: "fs.existsSync", params: [STRING], result: BOOL },
541
+ existsSync: { fn: "fs.existsSync", params: [STRING], result: BOOL, valueParams: exactValueParams(STRING) },
531
542
  mkdirSync: { fn: "fs.mkdirSync", params: [STRING], result: VOID },
532
543
  rmSync: { fn: "fs.rmSync", params: [STRING], result: VOID },
533
544
  rmdirSync: { fn: "fs.rmdirSync", params: [STRING], result: VOID },
@@ -537,9 +548,9 @@ export const BUILTIN_MODULE_FNS = {
537
548
  // accessSync's omitted mode completes to 0 (F_OK) in the special case
538
549
  // in lowerBuiltinModuleCall — string `defaults` can't spell a number.
539
550
  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 },
551
+ unlinkSync: { fn: "fs.unlinkSync", params: [STRING], result: VOID, valueParams: exactValueParams(STRING) },
552
+ chmodSync: { fn: "fs.chmodSync", params: [STRING, F64], result: VOID, valueParams: exactValueParams(STRING, F64) },
553
+ chownSync: { fn: "fs.chownSync", params: [STRING, F64, F64], result: VOID, valueParams: exactValueParams(STRING, F64, F64) },
543
554
  // The 2-argument form only: Node's mode flags (COPYFILE_EXCL, ...)
544
555
  // land on the arity fence.
545
556
  copyFileSync: { fn: "fs.copyFileSync", params: [STRING, STRING], result: VOID },
@@ -548,18 +559,22 @@ export const BUILTIN_MODULE_FNS = {
548
559
  // adapter. The row still projects the static surface and routes the
549
560
  // dispatch.
550
561
  rename: { fn: "fs.renameCb", params: [], result: VOID },
551
- renameSync: { fn: "fs.renameSync", params: [STRING, STRING], result: VOID },
562
+ renameSync: { fn: "fs.renameSync", params: [STRING, STRING], result: VOID, valueParams: exactValueParams(STRING, STRING) },
552
563
  // statSync's no-follow sibling; stats.isSymbolicLink answers what the
553
564
  // follow-free snapshot saw.
554
565
  lstatSync: { fn: "fs.lstatSync", params: [STRING], result: STATS_T },
566
+ fstatSync: { fn: "fs.fstatSync", params: [F64], result: STATS_T, valueParams: exactValueParams(F64) },
567
+ fchmodSync: { fn: "fs.fchmodSync", params: [F64, F64], result: VOID, valueParams: exactValueParams(F64, F64) },
568
+ fsyncSync: { fn: "fs.fsyncSync", params: [F64], result: VOID, valueParams: exactValueParams(F64) },
569
+ linkSync: { fn: "fs.linkSync", params: [STRING, STRING], result: VOID, valueParams: exactValueParams(STRING, STRING) },
555
570
  // realpath(3) — Node's realpathSync (failures spell syscall "lstat",
556
571
  // Node's own message shape).
557
572
  realpathSync: { fn: "fs.realpathSync", params: [STRING], result: STRING },
558
573
  // The fd pair behind spawn's fd-stdio form (the daemon-log idiom:
559
574
  // 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.
575
+ // closeSync). String flags use the established two-argument path;
576
+ // inline numeric O_* expressions route through openNumericSync, with
577
+ // an optional creation mode as the third argument.
563
578
  openSync: { fn: "fs.openSync", params: [STRING, STRING], result: F64 },
564
579
  // The buffer forms (fd, buffer, offset, length[, position]). The
565
580
  // lowering completes an omitted or literal-null position to -1 (the
@@ -570,7 +585,7 @@ export const BUILTIN_MODULE_FNS = {
570
585
  // overloads lower to separate fixed-width runtime ABIs. As with
571
586
  // readSync, -1 is the current-offset sentinel.
572
587
  writeSync: { fn: "fs.writeSync", params: [F64, BYTES_U8, F64, F64, F64], result: F64 },
573
- closeSync: { fn: "fs.closeSync", params: [F64], result: VOID },
588
+ closeSync: { fn: "fs.closeSync", params: [F64], result: VOID, valueParams: exactValueParams(F64) },
574
589
  // Entirely special-cased (lowerFsWatchCall — the callback needs an
575
590
  // adapter per listener shape); this entry only routes the dispatch.
576
591
  watch: { fn: "fs.watch", params: [], result: VOID },
@@ -585,9 +600,11 @@ export const BUILTIN_MODULE_FNS = {
585
600
  readdir: { fn: "fsp.readdir", params: [STRING], result: { kind: "promise", inner: arrayOf(STRING) } },
586
601
  rm: { fn: "fsp.rm", params: [STRING], result: { kind: "promise", inner: VOID } },
587
602
  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 } },
603
+ realpath: { fn: "fsp.realpath", params: [STRING], result: { kind: "promise", inner: STRING } },
604
+ lstat: { fn: "fsp.lstat", params: [STRING], result: { kind: "promise", inner: STATS_T } },
605
+ unlink: { fn: "fsp.unlink", params: [STRING], result: { kind: "promise", inner: VOID }, valueParams: exactValueParams(STRING) },
606
+ chmod: { fn: "fsp.chmod", params: [STRING, F64], result: { kind: "promise", inner: VOID }, valueParams: exactValueParams(STRING, F64) },
607
+ rename: { fn: "fsp.rename", params: [STRING, STRING], result: { kind: "promise", inner: VOID }, valueParams: exactValueParams(STRING, STRING) },
591
608
  // open's optional flags/mode completion is special-cased in
592
609
  // lowerBuiltinModuleCall; this row routes all import spellings and
593
610
  // gives coverage the static member.
@@ -605,18 +622,18 @@ export const BUILTIN_MODULE_FNS = {
605
622
  "path/win32": PATH_WIN32_MODULE_FNS,
606
623
  os: {
607
624
  // 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 },
625
+ platform: { fn: "process.platform", params: [], result: STRING, valueParams: [] },
626
+ homedir: { fn: "os.homedir", params: [], result: STRING, valueParams: [] },
627
+ tmpdir: { fn: "os.tmpdir", params: [], result: STRING, valueParams: [] },
611
628
  // uname(2)'s release field — Node's own implementation.
612
- release: { fn: "os.release", params: [], result: STRING },
629
+ release: { fn: "os.release", params: [], result: STRING, valueParams: [] },
613
630
  // uname(2)'s sysname field ("Darwin", "Linux", "Windows_NT") — the
614
631
  // libFn/runtime pair predates this entry (the portless surface used
615
632
  // them); this row makes the MODULE call reach them (test/common's
616
633
  // isAIX/isIBMi getters are the canonical callers).
617
- type: { fn: "os.type", params: [], result: STRING },
634
+ type: { fn: "os.type", params: [], result: STRING, valueParams: [] },
618
635
  // Total physical memory in bytes — same predating-pair story.
619
- totalmem: { fn: "os.totalmem", params: [], result: F64 },
636
+ totalmem: { fn: "os.totalmem", params: [], result: F64, valueParams: [] },
620
637
  // Entirely special-cased (lowerOsNetworkInterfacesCall): the result is
621
638
  // the call site's mapped Dict<NetworkInterfaceInfo[]> shape, verified
622
639
  // structurally there — this entry only routes the dispatch.
@@ -645,11 +662,25 @@ export const BUILTIN_MODULE_FNS = {
645
662
  pbkdf2: { fn: "crypto.pbkdf2Cb", params: [], result: VOID },
646
663
  },
647
664
  zlib: {
648
- // Buffer in, Buffer out, Node's default options; string inputs fence
649
- // per site (see the zlib special case in lowerBuiltinModuleCall).
665
+ // The default-options convenience family is special-cased in
666
+ // lowerBuiltinModuleCall: string inputs UTF-8 encode, callback forms
667
+ // carry program-shaped closures, and explicit options fence per site.
650
668
  // native-toolchain.ts links libz only when these appear on the IR.
669
+ deflate: { fn: "zlib.deflateCb", params: [], result: VOID },
651
670
  deflateSync: { fn: "zlib.deflateSync", params: [BYTES_U8], result: BYTES_U8 },
671
+ inflate: { fn: "zlib.inflateCb", params: [], result: VOID },
652
672
  inflateSync: { fn: "zlib.inflateSync", params: [BYTES_U8], result: BYTES_U8 },
673
+ deflateRaw: { fn: "zlib.deflateRawCb", params: [], result: VOID },
674
+ deflateRawSync: { fn: "zlib.deflateRawSync", params: [BYTES_U8], result: BYTES_U8 },
675
+ inflateRaw: { fn: "zlib.inflateRawCb", params: [], result: VOID },
676
+ inflateRawSync: { fn: "zlib.inflateRawSync", params: [BYTES_U8], result: BYTES_U8 },
677
+ gzip: { fn: "zlib.gzipCb", params: [], result: VOID },
678
+ gzipSync: { fn: "zlib.gzipSync", params: [BYTES_U8], result: BYTES_U8 },
679
+ gunzip: { fn: "zlib.gunzipCb", params: [], result: VOID },
680
+ gunzipSync: { fn: "zlib.gunzipSync", params: [BYTES_U8], result: BYTES_U8 },
681
+ unzip: { fn: "zlib.unzipCb", params: [], result: VOID },
682
+ unzipSync: { fn: "zlib.unzipSync", params: [BYTES_U8], result: BYTES_U8 },
683
+ crc32: { fn: "zlib.crc32", params: [], result: F64 },
653
684
  },
654
685
  url: {
655
686
  // fileURLToPath accepts a URL value OR a string — the call lowering
@@ -661,11 +692,13 @@ export const BUILTIN_MODULE_FNS = {
661
692
  child_process: {
662
693
  // spawnSync's and spawn's call completions are entirely special-cased
663
694
  // (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
695
+ // accepts its documented literal options, while spawn supports the
696
+ // stdio/detached/env/cwd/windowsHide/shell subset — see
697
+ // lowerBuiltinModuleCall); the
666
698
  // entries carry the canonical shapes.
667
699
  spawnSync: { fn: "cp.spawnSync", params: [STRING, arrayOf(STRING)], result: SPAWNRES_T },
668
700
  spawn: { fn: "cp.spawn", params: [STRING, arrayOf(STRING)], result: CHILD_T },
701
+ fork: { fn: "cp.fork", params: [STRING, arrayOf(STRING)], result: CHILD_T },
669
702
  // execFileSync(file, args?, options?) and execSync(command, options?)
670
703
  // share the cp.execSync runtime entry (execSync sets the shell flag);
671
704
  // both call completions are special-cased in lowerBuiltinModuleCall.
@@ -704,8 +737,8 @@ export const BUILTIN_MODULE_FNS = {
704
737
  decode: { fn: "qs.parse", params: [STRING], result: VOID },
705
738
  stringify: { fn: "qs.stringify", params: [DYN], result: STRING },
706
739
  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 },
740
+ escape: { fn: "qs.escape", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
741
+ unescape: { fn: "qs.unescape", params: [STRING], result: STRING, valueParams: [{ mode: "required", type: STRING }] },
709
742
  },
710
743
  // node:readline: createInterface's options are entirely special-cased
711
744
  // (exactly { input: process.stdin, output?: process.stdout } — see
@@ -812,6 +845,8 @@ export const BUILTIN_MODULE_CONSTS = {
812
845
  * (library/fence-eval.ts) and the attestation-parity test. */
813
846
  export const BUILTIN_MODULE_FN_ALIASES = {
814
847
  fs: {
848
+ // Inline numeric O_* flags use a target-neutral runtime entry point.
849
+ openSync: ["fs.openNumericSync"],
815
850
  // The Buffer form (no encoding), the fd forms (readFileSync(fd[,
816
851
  // "utf8"])), and the checked-dynamic encoding form.
817
852
  readFileSync: ["fs.readFileSyncBuf", "fs.readFileSyncBytes", "fs.readFileSyncDyn", "fs.readFdSync", "fs.readFdSyncBytes"],
@@ -841,6 +876,8 @@ export const BUILTIN_MODULE_FN_ALIASES = {
841
876
  readFile: ["fsp.readFileBytes"],
842
877
  // The string-data { mode } options form.
843
878
  writeFile: ["fsp.writeFileMode"],
879
+ // The { withFileTypes: true } Dirent form.
880
+ readdir: ["fsp.readdirTypes"],
844
881
  },
845
882
  crypto: {
846
883
  // The composed randomBytes(n).toString(enc) chain keeps its one-libCall
@@ -866,6 +903,13 @@ export const AMBIENT_SURFACE_FNS = [
866
903
  fns: ["date.now"],
867
904
  note: "the live clock",
868
905
  },
906
+ {
907
+ id: "stdlib.date.parse",
908
+ kind: "stdlib",
909
+ name: "Date.parse",
910
+ fns: ["date.parse"],
911
+ note: "one date string, using the bounded parser shared with new Date(dateString).getTime()",
912
+ },
869
913
  {
870
914
  id: "stdlib.date.constructor",
871
915
  kind: "stdlib",
@@ -1006,6 +1050,13 @@ export const AMBIENT_SURFACE_FNS = [
1006
1050
  fns: ["process.exit", "process.exiting"],
1007
1051
  note: "process.exit and the process._exiting flag read are one surface",
1008
1052
  },
1053
+ {
1054
+ id: "node-builtin.process.exitCode",
1055
+ kind: "node-builtin",
1056
+ name: "process.exitCode",
1057
+ fns: ["process.setExitCode"],
1058
+ note: "numeric writes in statement position set the implicit exit status; process.exit() reads it",
1059
+ },
1009
1060
  // ── the tls CA store (lowerTlsCaCall / lowerTlsRootCertificates): the
1010
1061
  // host's trust anchors, read and replaced. Dedicated paths, and
1011
1062
  // rootCertificates is a VALUE read with no call form at all, so none of
@@ -1113,7 +1164,7 @@ export function builtinConstLit(value, loc) {
1113
1164
  * Node ships one frozen singleton; each read here mints a fresh string
1114
1165
  * array — a divergence only mutation could observe, and mutating Node's
1115
1166
  * frozen array throws anyway. */
1116
- const NODE_BUILTIN_MODULES_V24 = [
1167
+ export const NODE_BUILTIN_MODULES_V24 = [
1117
1168
  "_http_agent", "_http_client", "_http_common", "_http_incoming",
1118
1169
  "_http_outgoing", "_http_server", "_stream_duplex", "_stream_passthrough",
1119
1170
  "_stream_readable", "_stream_transform", "_stream_wrap", "_stream_writable",
@@ -1141,19 +1192,16 @@ export function builtinModulesArrayLit(loc) {
1141
1192
  };
1142
1193
  }
1143
1194
  /** 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";
1195
+ * no lowering. The default-options one-shot zlib/deflate-raw/gzip codecs
1196
+ * lower for strings and Buffers; the remaining surface points at them. */
1197
+ const ZLIB_HINT = "the default-options deflate/inflate, raw, gzip/gunzip, and unzip sync/callback forms plus crc32 are the lowered zlib surface";
1198
+ /** The legacy deep pair remains fenced. The shallow equal/notEqual pair
1199
+ * lowers through the static Abstract Equality kernel in lower-assert. */
1200
+ const ASSERT_LOOSE_DEEP_HINT = "legacy deep equality has no lowering yet — deepStrictEqual and " +
1201
+ "notDeepStrictEqual compare structures with Node's modern semantics";
1152
1202
  const ASSERT_MODULE_HINTS = {
1153
- equal: ASSERT_LOOSE_HINT,
1154
- notEqual: ASSERT_LOOSE_HINT,
1155
- deepEqual: ASSERT_LOOSE_HINT,
1156
- notDeepEqual: ASSERT_LOOSE_HINT,
1203
+ deepEqual: ASSERT_LOOSE_DEEP_HINT,
1204
+ notDeepEqual: ASSERT_LOOSE_DEEP_HINT,
1157
1205
  ifError: "test explicitly instead: assert.strictEqual(err, null) / " +
1158
1206
  "assert.strictEqual(err, undefined)",
1159
1207
  rejects: "await the promise inside assert.throws's callback story instead: " +
@@ -1176,10 +1224,7 @@ export const BUILTIN_MODULE_FENCE_HINTS = {
1176
1224
  AssertionError: ASSERT_MODULE_HINTS["AssertionError"],
1177
1225
  },
1178
1226
  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.
1227
+ promisify: "the lowered shapes are const bindings over child_process.execFile and fs.readFile; call the bound function directly",
1183
1228
  },
1184
1229
  "stream/consumers": {
1185
1230
  arrayBuffer: "no free-standing ArrayBuffer value exists here (typed arrays own their storage) — " +
@@ -1189,17 +1234,15 @@ export const BUILTIN_MODULE_FENCE_HINTS = {
1189
1234
  },
1190
1235
  module: {
1191
1236
  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; " +
1237
+ "whose require calls take STATIC string literals — builtins, project modules (including #imports), " +
1238
+ "relative .json documents, --npm-static packages, and installed npm packages under --dynamic resolve at build time; " +
1194
1239
  "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",
1240
+ isBuiltin: "the lowered call checks a string against the baked Node v24 list, including bare/node: aliases and prefix-only builtins",
1241
+ syncBuiltinESMExports: "the direct zero-argument call is a no-op because compiled builtin exports are immutable and cannot become stale",
1199
1242
  },
1200
1243
  child_process: {
1201
- execFile: "the callback form has no lowering — promisify it: " +
1202
- "const execFileAsync = promisify(execFile) (from node:util), or use execFileSync",
1244
+ execFile: "the callback forms execFile(file, callback), execFile(file, args, callback), and execFile(file, args, { encoding: 'utf8', maxBuffer: N }, callback) lower; " +
1245
+ "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
1246
  },
1204
1247
  crypto: {
1205
1248
  ...Object.fromEntries([
@@ -1231,9 +1274,6 @@ export const BUILTIN_MODULE_FENCE_HINTS = {
1231
1274
  "randomBytes, and the createHash chain",
1232
1275
  },
1233
1276
  zlib: {
1234
- gzipSync: ZLIB_HINT,
1235
- gunzipSync: ZLIB_HINT,
1236
- unzipSync: ZLIB_HINT,
1237
1277
  brotliCompressSync: ZLIB_HINT,
1238
1278
  brotliDecompressSync: ZLIB_HINT,
1239
1279
  },
@@ -1546,27 +1586,50 @@ export function stdlibGlobalMember(lowerer, access, name) {
1546
1586
  * nothing. Only the globals with lowered member surfaces alias this
1547
1587
  * way; aliasing, say, `Math` would change nothing (its members lower
1548
1588
  * by receiver too). Returns true when recognized. */
1549
- export function stdlibGlobalAliasDecl(lowerer, nameNode, init) {
1550
- if (!init || !ts.isIdentifier(nameNode))
1551
- return false;
1589
+ export function stdlibGlobalAliasNameOf(lowerer, init) {
1590
+ if (!init)
1591
+ return null;
1592
+ // CommonJS packages commonly guard Node's always-present globals for
1593
+ // browser bundlers (`let p = process || {}`). In the Node execution
1594
+ // model the left object is unconditionally truthy, so the fallback is
1595
+ // never evaluated and the binding is the same global snapshot as the
1596
+ // direct spelling. Keep this deliberately to `||` with a surfaced
1597
+ // stdlib-global left operand; arbitrary capability probes retain their
1598
+ // runtime value semantics.
1599
+ let aliasExpr = init;
1600
+ while (ts.isParenthesizedExpression(aliasExpr))
1601
+ aliasExpr = aliasExpr.expression;
1602
+ if (ts.isBinaryExpression(aliasExpr) &&
1603
+ aliasExpr.operatorToken.kind === ts.SyntaxKind.BarBarToken &&
1604
+ stdlibGlobalNameOf(lowerer, aliasExpr.left) !== null) {
1605
+ aliasExpr = aliasExpr.left;
1606
+ }
1552
1607
  // `const process = require('node:process')`: Node's process MODULE is
1553
1608
  // the global process object (module.exports === globalThis.process),
1554
1609
  // so the binding aliases the global exactly like `const process =
1555
1610
  // globalThis.process`. Preflight admits exactly this shape
1556
1611
  // (processModuleAliasRequire7); commander's lib/command.js opens with
1557
1612
  // it.
1558
- const requireSpec = requireSpecOf(init);
1613
+ const requireSpec = requireSpecOf(aliasExpr);
1559
1614
  const name = requireSpec === "process" || requireSpec === "node:process"
1560
1615
  ? "process"
1561
- : stdlibGlobalNameOf(lowerer, init);
1616
+ : stdlibGlobalNameOf(lowerer, aliasExpr);
1562
1617
  if (name === null)
1563
- return false;
1618
+ return null;
1564
1619
  // Only alias OBJECT-shaped globals whose members lower by receiver
1565
1620
  // identity (process, console, globalThis itself, and perf_hooks'
1566
1621
  // performance — the mockable-clock idiom snapshots it). Function-valued
1567
1622
  // globals (setTimeout) taken as values are a different story — the
1568
1623
  // ordinary value paths (and their fences) apply.
1569
- if (name !== "process" && name !== "console" && name !== "globalThis" && name !== "performance")
1624
+ return name === "process" || name === "console" || name === "globalThis" || name === "performance"
1625
+ ? name
1626
+ : null;
1627
+ }
1628
+ export function stdlibGlobalAliasDecl(lowerer, nameNode, init) {
1629
+ if (!ts.isIdentifier(nameNode))
1630
+ return false;
1631
+ const name = stdlibGlobalAliasNameOf(lowerer, init);
1632
+ if (name === null)
1570
1633
  return false;
1571
1634
  const symbol = lowerer.checker.getSymbolAtLocation(nameNode);
1572
1635
  if (!symbol)