@scriptc/compiler 0.2.0 → 0.2.2

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 (284) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +84 -19
  2. package/dist/backend/cycle-analysis.js +1 -0
  3. package/dist/backend/cycle-analysis.js.map +1 -1
  4. package/dist/backend/llvm/classes.js +21 -5
  5. package/dist/backend/llvm/classes.js.map +1 -1
  6. package/dist/backend/llvm/dyn.d.ts +8 -0
  7. package/dist/backend/llvm/dyn.js +247 -108
  8. package/dist/backend/llvm/dyn.js.map +1 -1
  9. package/dist/backend/llvm/emitter.d.ts +6 -3
  10. package/dist/backend/llvm/emitter.js +99 -25
  11. package/dist/backend/llvm/emitter.js.map +1 -1
  12. package/dist/backend/llvm/emitter.test.js +9 -1
  13. package/dist/backend/llvm/emitter.test.js.map +1 -1
  14. package/dist/backend/llvm/expr-bytes.d.ts +1 -1
  15. package/dist/backend/llvm/expr-bytes.js +28 -17
  16. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  17. package/dist/backend/llvm/expr-containers.js +5 -0
  18. package/dist/backend/llvm/expr-containers.js.map +1 -1
  19. package/dist/backend/llvm/expr-control.js +1 -1
  20. package/dist/backend/llvm/expr-control.js.map +1 -1
  21. package/dist/backend/llvm/expr-dynamic.js +47 -13
  22. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  23. package/dist/backend/llvm/expr-primitives.js +11 -1
  24. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  25. package/dist/backend/llvm/expr-records.js +11 -3
  26. package/dist/backend/llvm/expr-records.js.map +1 -1
  27. package/dist/backend/llvm/expr-stream-bridges.js +187 -18
  28. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  29. package/dist/backend/llvm/expr-stream-callbacks.d.ts +2 -2
  30. package/dist/backend/llvm/expr-stream-callbacks.js +7 -57
  31. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  32. package/dist/backend/llvm/lib-dispatch.js +41 -3
  33. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  34. package/dist/backend/llvm/lib-filesystem.js +12 -9
  35. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  36. package/dist/backend/llvm/lib-process.js +23 -3
  37. package/dist/backend/llvm/lib-process.js.map +1 -1
  38. package/dist/backend/llvm/lib-shared.js +80 -3
  39. package/dist/backend/llvm/lib-shared.js.map +1 -1
  40. package/dist/backend/llvm/shapes.js +8 -2
  41. package/dist/backend/llvm/shapes.js.map +1 -1
  42. package/dist/backend/may-throw.js +4 -0
  43. package/dist/backend/may-throw.js.map +1 -1
  44. package/dist/backend/native-codegen.d.ts +1 -1
  45. package/dist/backend/native-codegen.js +4 -3
  46. package/dist/backend/native-codegen.js.map +1 -1
  47. package/dist/backend/native-codegen.test.js +11 -0
  48. package/dist/backend/native-codegen.test.js.map +1 -1
  49. package/dist/backend/native-toolchain.d.ts +3 -6
  50. package/dist/backend/native-toolchain.js +53 -23
  51. package/dist/backend/native-toolchain.js.map +1 -1
  52. package/dist/backend/native-toolchain.test.js +72 -0
  53. package/dist/backend/native-toolchain.test.js.map +1 -1
  54. package/dist/backend/runtime-abi.d.ts +2 -2
  55. package/dist/backend/runtime-abi.js +2 -2
  56. package/dist/backend/runtime-pack-native.js +4 -1
  57. package/dist/backend/runtime-pack-native.js.map +1 -1
  58. package/dist/backend/runtime-pack-targets.test.js +1 -1
  59. package/dist/backend/runtime-pack.test.js +1 -1
  60. package/dist/backend/target-diagnostics.d.ts +5 -0
  61. package/dist/backend/target-diagnostics.js +72 -1
  62. package/dist/backend/target-diagnostics.js.map +1 -1
  63. package/dist/backend/target-diagnostics.test.d.ts +1 -0
  64. package/dist/backend/target-diagnostics.test.js +68 -0
  65. package/dist/backend/target-diagnostics.test.js.map +1 -0
  66. package/dist/backend/targets.js +10 -6
  67. package/dist/backend/targets.js.map +1 -1
  68. package/dist/backend/targets.test.js +7 -0
  69. package/dist/backend/targets.test.js.map +1 -1
  70. package/dist/compat/fetch-profile.js +34 -4
  71. package/dist/compat/fetch-profile.js.map +1 -1
  72. package/dist/coverage/surface-manifest.js +5 -3
  73. package/dist/coverage/surface-manifest.js.map +1 -1
  74. package/dist/diagnostics/diagnostic.js +2 -7
  75. package/dist/diagnostics/diagnostic.js.map +1 -1
  76. package/dist/executable/executable-cache.d.ts +7 -3
  77. package/dist/executable/executable-cache.js +47 -11
  78. package/dist/executable/executable-cache.js.map +1 -1
  79. package/dist/executable/executable-cache.test.js +109 -2
  80. package/dist/executable/executable-cache.test.js.map +1 -1
  81. package/dist/executable/prepare.js +2 -1
  82. package/dist/executable/prepare.js.map +1 -1
  83. package/dist/frontend/builtin-modules.d.ts +1 -1
  84. package/dist/frontend/builtin-modules.js +1 -1
  85. package/dist/frontend/builtin-modules.js.map +1 -1
  86. package/dist/frontend/function-completion.d.ts +6 -0
  87. package/dist/frontend/function-completion.js +50 -0
  88. package/dist/frontend/function-completion.js.map +1 -0
  89. package/dist/frontend/lowering/abstract-equality.js +5 -1
  90. package/dist/frontend/lowering/abstract-equality.js.map +1 -1
  91. package/dist/frontend/lowering/checked-iterable-spread.d.ts +4 -0
  92. package/dist/frontend/lowering/checked-iterable-spread.js +30 -0
  93. package/dist/frontend/lowering/checked-iterable-spread.js.map +1 -0
  94. package/dist/frontend/lowering/checked-promise-all.d.ts +5 -0
  95. package/dist/frontend/lowering/checked-promise-all.js +31 -0
  96. package/dist/frontend/lowering/checked-promise-all.js.map +1 -0
  97. package/dist/frontend/lowering/class-callbacks.d.ts +4 -4
  98. package/dist/frontend/lowering/class-callbacks.js +29 -17
  99. package/dist/frontend/lowering/class-callbacks.js.map +1 -1
  100. package/dist/frontend/lowering/class-construction.d.ts +14 -0
  101. package/dist/frontend/lowering/class-construction.js +185 -0
  102. package/dist/frontend/lowering/class-construction.js.map +1 -0
  103. package/dist/frontend/lowering/class-descriptors.d.ts +2 -1
  104. package/dist/frontend/lowering/class-descriptors.js +58 -10
  105. package/dist/frontend/lowering/class-descriptors.js.map +1 -1
  106. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +36 -1
  107. package/dist/frontend/lowering/class-dynamic-dispatch.js +965 -91
  108. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  109. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +66 -3
  110. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  111. package/dist/frontend/lowering/class-instance-constructor.d.ts +1 -1
  112. package/dist/frontend/lowering/class-instance-constructor.js +15 -42
  113. package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
  114. package/dist/frontend/lowering/class-method-values.d.ts +20 -1
  115. package/dist/frontend/lowering/class-method-values.js +120 -24
  116. package/dist/frontend/lowering/class-method-values.js.map +1 -1
  117. package/dist/frontend/lowering/class-prototypes.d.ts +10 -3
  118. package/dist/frontend/lowering/class-prototypes.js +188 -21
  119. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  120. package/dist/frontend/lowering/class-runtime-statics.d.ts +8 -0
  121. package/dist/frontend/lowering/class-runtime-statics.js +84 -0
  122. package/dist/frontend/lowering/class-runtime-statics.js.map +1 -0
  123. package/dist/frontend/lowering/class-static-data.d.ts +1 -0
  124. package/dist/frontend/lowering/class-static-data.js +6 -4
  125. package/dist/frontend/lowering/class-static-data.js.map +1 -1
  126. package/dist/frontend/lowering/containers/bytes.js +66 -17
  127. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  128. package/dist/frontend/lowering/containers/string-and-regexp.js +24 -47
  129. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  130. package/dist/frontend/lowering/deferred-module-initializers.d.ts +13 -0
  131. package/dist/frontend/lowering/deferred-module-initializers.js +410 -0
  132. package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -0
  133. package/dist/frontend/lowering/deferred-module-initializers.test.d.ts +1 -0
  134. package/dist/frontend/lowering/deferred-module-initializers.test.js +92 -0
  135. package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -0
  136. package/dist/frontend/lowering/error-methods.d.ts +4 -1
  137. package/dist/frontend/lowering/error-methods.js +100 -1
  138. package/dist/frontend/lowering/error-methods.js.map +1 -1
  139. package/dist/frontend/lowering/expressions/native-proxy.js +3 -1
  140. package/dist/frontend/lowering/expressions/native-proxy.js.map +1 -1
  141. package/dist/frontend/lowering/expressions/nullish-assignment.js +19 -11
  142. package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
  143. package/dist/frontend/lowering/expressions/object-literals.js +68 -7
  144. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  145. package/dist/frontend/lowering/expressions/optional-chains.d.ts +3 -4
  146. package/dist/frontend/lowering/expressions/optional-chains.js +72 -20
  147. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  148. package/dist/frontend/lowering/function-context.d.ts +11 -3
  149. package/dist/frontend/lowering/function-context.js +11 -5
  150. package/dist/frontend/lowering/function-context.js.map +1 -1
  151. package/dist/frontend/lowering/generator-dynamic-dispatch.d.ts +1 -0
  152. package/dist/frontend/lowering/generator-dynamic-dispatch.js +39 -1
  153. package/dist/frontend/lowering/generator-dynamic-dispatch.js.map +1 -1
  154. package/dist/frontend/lowering/lib-boundary.d.ts +2 -0
  155. package/dist/frontend/lowering/lib-boundary.js +54 -1
  156. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  157. package/dist/frontend/lowering/lower-builtin-values.d.ts +7 -1
  158. package/dist/frontend/lowering/lower-builtin-values.js +113 -3
  159. package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
  160. package/dist/frontend/lowering/lower-builtins.d.ts +10 -14
  161. package/dist/frontend/lowering/lower-builtins.js +443 -88
  162. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  163. package/dist/frontend/lowering/lower-calls.d.ts +8 -5
  164. package/dist/frontend/lowering/lower-calls.js +717 -142
  165. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  166. package/dist/frontend/lowering/lower-classes.d.ts +18 -13
  167. package/dist/frontend/lowering/lower-classes.js +1076 -188
  168. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  169. package/dist/frontend/lowering/lower-containers.d.ts +9 -0
  170. package/dist/frontend/lowering/lower-containers.js +172 -51
  171. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  172. package/dist/frontend/lowering/lower-dgram.js +3 -2
  173. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  174. package/dist/frontend/lowering/lower-exprs.d.ts +12 -8
  175. package/dist/frontend/lowering/lower-exprs.js +802 -232
  176. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  177. package/dist/frontend/lowering/lower-generators.js +17 -2
  178. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  179. package/dist/frontend/lowering/lower-inspect.js +15 -1
  180. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  181. package/dist/frontend/lowering/lower-island.d.ts +2 -0
  182. package/dist/frontend/lowering/lower-island.js +36 -10
  183. package/dist/frontend/lowering/lower-island.js.map +1 -1
  184. package/dist/frontend/lowering/lower-island.test.d.ts +1 -0
  185. package/dist/frontend/lowering/lower-island.test.js +51 -0
  186. package/dist/frontend/lowering/lower-island.test.js.map +1 -0
  187. package/dist/frontend/lowering/lower-modules.d.ts +1 -3
  188. package/dist/frontend/lowering/lower-modules.js +380 -73
  189. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  190. package/dist/frontend/lowering/lower-modules.test.d.ts +1 -0
  191. package/dist/frontend/lowering/lower-modules.test.js +107 -0
  192. package/dist/frontend/lowering/lower-modules.test.js.map +1 -0
  193. package/dist/frontend/lowering/lower-stmts.d.ts +7 -3
  194. package/dist/frontend/lowering/lower-stmts.js +221 -47
  195. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  196. package/dist/frontend/lowering/lower-stmts.test.d.ts +1 -0
  197. package/dist/frontend/lowering/lower-stmts.test.js +77 -0
  198. package/dist/frontend/lowering/lower-stmts.test.js.map +1 -0
  199. package/dist/frontend/lowering/lower-stream.js +3 -1
  200. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  201. package/dist/frontend/lowering/lower-url.d.ts +2 -1
  202. package/dist/frontend/lowering/lower-url.js +32 -9
  203. package/dist/frontend/lowering/lower-url.js.map +1 -1
  204. package/dist/frontend/lowering/lowerer.d.ts +53 -10
  205. package/dist/frontend/lowering/lowerer.js +390 -77
  206. package/dist/frontend/lowering/lowerer.js.map +1 -1
  207. package/dist/frontend/lowering/lowerer.test.js +187 -3
  208. package/dist/frontend/lowering/lowerer.test.js.map +1 -1
  209. package/dist/frontend/lowering/module-namespace-elements.d.ts +7 -0
  210. package/dist/frontend/lowering/module-namespace-elements.js +54 -0
  211. package/dist/frontend/lowering/module-namespace-elements.js.map +1 -0
  212. package/dist/frontend/lowering/object-factory-new.d.ts +4 -3
  213. package/dist/frontend/lowering/object-factory-new.js +27 -14
  214. package/dist/frontend/lowering/object-factory-new.js.map +1 -1
  215. package/dist/frontend/lowering/surfaces.d.ts +3 -0
  216. package/dist/frontend/lowering/surfaces.js +48 -19
  217. package/dist/frontend/lowering/surfaces.js.map +1 -1
  218. package/dist/frontend/lowering/text-decoder-encoding.d.ts +2 -0
  219. package/dist/frontend/lowering/text-decoder-encoding.js +8 -0
  220. package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -1
  221. package/dist/frontend/lowering/text-decoder-encoding.test.js +2 -1
  222. package/dist/frontend/lowering/text-decoder-encoding.test.js.map +1 -1
  223. package/dist/frontend/lowering/unregistered-class-types.test.js +3 -3
  224. package/dist/frontend/lowering/unregistered-class-types.test.js.map +1 -1
  225. package/dist/frontend/npm-static-prune.js +116 -34
  226. package/dist/frontend/npm-static-prune.js.map +1 -1
  227. package/dist/frontend/npm-static-prune.test.js +8 -0
  228. package/dist/frontend/npm-static-prune.test.js.map +1 -1
  229. package/dist/frontend/program.d.ts +1 -1
  230. package/dist/frontend/program.js +57 -26
  231. package/dist/frontend/program.js.map +1 -1
  232. package/dist/frontend/program.test.js +18 -0
  233. package/dist/frontend/program.test.js.map +1 -1
  234. package/dist/frontend/ts7/ast.js +4 -3
  235. package/dist/frontend/ts7/ast.js.map +1 -1
  236. package/dist/frontend/ts7/semantic-json.js +5 -10
  237. package/dist/frontend/ts7/semantic-json.js.map +1 -1
  238. package/dist/frontend/type-mapper.d.ts +9 -1
  239. package/dist/frontend/type-mapper.js +169 -23
  240. package/dist/frontend/type-mapper.js.map +1 -1
  241. package/dist/frontend/type-mapper.test.js +23 -0
  242. package/dist/frontend/type-mapper.test.js.map +1 -1
  243. package/dist/frontend/union-discriminants.d.ts +1 -1
  244. package/dist/frontend/union-discriminants.js +24 -9
  245. package/dist/frontend/union-discriminants.js.map +1 -1
  246. package/dist/index.js +16 -10
  247. package/dist/index.js.map +1 -1
  248. package/dist/ir/analysis.js +2 -0
  249. package/dist/ir/analysis.js.map +1 -1
  250. package/dist/ir/ir.d.ts +74 -41
  251. package/dist/ir/ir.js +167 -43
  252. package/dist/ir/ir.js.map +1 -1
  253. package/dist/ir/ir.test.js +35 -0
  254. package/dist/ir/ir.test.js.map +1 -1
  255. package/dist/ir/serialize.js +35 -3
  256. package/dist/ir/serialize.js.map +1 -1
  257. package/dist/ir/serialize.test.js +26 -1
  258. package/dist/ir/serialize.test.js.map +1 -1
  259. package/dist/ir/traverse.d.ts +0 -3
  260. package/dist/ir/traverse.js +33 -20
  261. package/dist/ir/traverse.js.map +1 -1
  262. package/dist/ir/validate.js +136 -16
  263. package/dist/ir/validate.js.map +1 -1
  264. package/dist/ir/validate.test.js +77 -1
  265. package/dist/ir/validate.test.js.map +1 -1
  266. package/dist/library/compiler-self-identity.js +1 -1
  267. package/dist/library/compiler-self-identity.test.js +2 -2
  268. package/dist/library/compiler-self-identity.test.js.map +1 -1
  269. package/dist/library/int-infer.d.ts +2 -2
  270. package/dist/library/int-infer.js +10 -7
  271. package/dist/library/int-infer.js.map +1 -1
  272. package/dist/library/int-infer.test.js +44 -0
  273. package/dist/library/int-infer.test.js.map +1 -1
  274. package/dist/library/prepare.js +2 -1
  275. package/dist/library/prepare.js.map +1 -1
  276. package/dist/native/sanitizer.js +3 -1
  277. package/dist/native/sanitizer.js.map +1 -1
  278. package/dist/native/toolchain.d.ts +1 -1
  279. package/dist/native/toolchain.js +26 -6
  280. package/dist/native/toolchain.js.map +1 -1
  281. package/dist/native/toolchain.test.js +53 -1
  282. package/dist/native/toolchain.test.js.map +1 -1
  283. package/package.json +20 -20
  284. package/surface-manifest.json +170 -93
@@ -1,4 +1,5 @@
1
1
  import { staticTextDecoderEncoding } from "./text-decoder-encoding.js";
2
+ import { checkedPromiseAll } from "./checked-promise-all.js";
2
3
  import { InternalCompilerError } from "../../errors.js";
3
4
  /* Builtin-surface lowering: node builtin-module calls (fs, path, os, url,
4
5
  * crypto, child_process spawn/spawnSync and child/stats/spawn-result
@@ -7,6 +8,7 @@ import { InternalCompilerError } from "../../errors.js";
7
8
  import { builtinModules } from "node:module";
8
9
  import { dirname, isAbsolute, resolve } from "node:path";
9
10
  import * as ts from "../ts7/adapter.js";
11
+ import { lowerCheckedPredicateValue } from "./lower-builtin-values.js";
10
12
  import { PoisonError, dynUndefinedExpr, ladderFenceExpr, nodeThrowExpr, own } from "./lowerer.js";
11
13
  import { canonicalBuiltinModule, isCreateRequireBinding7, isJsSourceFile, isNodeEsmFile, locOf, npmStaticDepSf7, requireSpecOf, resolveImport } from "../program.js";
12
14
  import { isRelativeSpecifier } from "../workspace-registry.js";
@@ -480,7 +482,7 @@ export function createRequireProgramModuleOf(lowerer, expr) {
480
482
  const cr = createRequireSpecOf(lowerer, call);
481
483
  if (cr === null || cr.spec === null || canonicalBuiltinModule(cr.spec) !== null)
482
484
  return null;
483
- const dep = resolveImport(lowerer.program, cr.baseFile, cr.spec) ??
485
+ const dep = resolveImport(lowerer.program, cr.baseFile, cr.spec, "require") ??
484
486
  npmStaticDepSf7(lowerer.program, cr.baseFile, cr.spec, "require");
485
487
  if (dep === null || dep.fileName.endsWith(".json"))
486
488
  return null;
@@ -1161,6 +1163,9 @@ export function lowerFsToUnixTimestampCall(lowerer, expr, bi, loc) {
1161
1163
  * after every validation passes, exactly Node's order. Null when this
1162
1164
  * is not a claimed member/shape (the table or fence path stands). */
1163
1165
  export function lowerFsLadderCall(lowerer, expr, bi, loc) {
1166
+ if (bi.module === "fs" && bi.member !== "rename" && builtinModuleFnOf(lowerer, bi.module, bi.member)?.fn === "fs.callbackCall") {
1167
+ return lowerer.lowerBuiltinModuleCall(expr, bi, { fn: "fs.callbackCall", params: [], result: DYN }, loc);
1168
+ }
1164
1169
  if (bi.module !== "fs" && bi.module !== "fs/promises")
1165
1170
  return null;
1166
1171
  if (!isJsSourceFile(expr.getSourceFile()))
@@ -1410,6 +1415,36 @@ function lowerZlibModuleCall(lowerer, expr, bi, loc) {
1410
1415
  }
1411
1416
  export function lowerBuiltinModuleCall(lowerer, expr, bi, fn, loc) {
1412
1417
  const name = expr.expression.getText();
1418
+ if (bi.module === "process" && bi.member === "loadEnvFile")
1419
+ return lowerProcessLoadEnvFile(lowerer, expr);
1420
+ if (bi.module === "buffer" && ["isAscii", "isUtf8", "transcode"].includes(bi.member)) {
1421
+ if (expr.arguments.some(ts.isSpreadElement))
1422
+ lowerer.noLowering("buffer encoding call with spread arguments", expr);
1423
+ const arity = bi.member === "transcode" ? 3 : 1;
1424
+ const args = Array.from({ length: arity }, (_, index) => expr.arguments[index]
1425
+ ? lowerer.lowerExprExpecting(stripTypeCasts(expr.arguments[index]), DYN) : dynUndefinedExpr(loc));
1426
+ if (expr.arguments.length > arity)
1427
+ lowerer.noLowering("buffer encoding call with extra arguments", expr);
1428
+ return { kind: "libCall", fn: fn.fn, args, type: fn.result, loc };
1429
+ }
1430
+ if (fn.fn === "fs.callbackCall" && bi.member !== "rename") {
1431
+ if (expr.arguments.some(ts.isSpreadElement))
1432
+ lowerer.noLowering("filesystem callback call with spread arguments", expr);
1433
+ const args = { kind: "dynArrLit", elems: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
1434
+ return { kind: "libCall", fn: "fs.callbackCall", args: [{ kind: "strLit", value: bi.member, type: STRING, loc }, args], type: DYN, loc };
1435
+ }
1436
+ if (bi.module === "fs" && (bi.member === "readvSync" || bi.member === "writevSync" || bi.member === "ftruncateSync")) {
1437
+ const vector = bi.member !== "ftruncateSync";
1438
+ const required = vector ? 2 : 1;
1439
+ if (expr.arguments.length < required || expr.arguments.length > required + 1 || expr.arguments.some(ts.isSpreadElement))
1440
+ lowerer.noLowering(`${name} with this argument shape`, expr);
1441
+ const args = [lowerer.lowerExprExpecting(expr.arguments[0], F64)];
1442
+ if (vector)
1443
+ args.push(lowerer.lowerExprExpecting(expr.arguments[1], arrayOf(BYTES_U8)));
1444
+ const optional = expr.arguments[required];
1445
+ args.push(optional ? lowerBuiltinOptionalDefault(lowerer, optional, F64, numLit(vector ? -1 : 0, loc), vector) : numLit(vector ? -1 : 0, loc));
1446
+ return { kind: "libCall", fn: fn.fn, args, type: vector ? F64 : VOID, loc };
1447
+ }
1413
1448
  // Numeric open flags are interpreted symbolically at the call site. The
1414
1449
  // O_* bit values differ between Darwin and Linux, so emit a stable mask
1415
1450
  // and let the target runtime select its own native constants.
@@ -2318,17 +2353,35 @@ export function lowerBuiltinModuleCall(lowerer, expr, bi, fn, loc) {
2318
2353
  }
2319
2354
  return { kind: "libCall", fn: fn.fn, args, type: fn.result, loc };
2320
2355
  }
2321
- /** Reflect.apply(target, thisArg, argsList) where the TARGET is a builtin
2356
+ /** Reflect.ownKeys uses native computed-key reflection. Reflect.apply(target,
2357
+ * thisArg, argsList) where the TARGET is a builtin
2322
2358
  * rest-parameter table fn (path.join / path.resolve — test/common
2323
2359
  * fixtures.js's fixturesPath forwards its rest args exactly this way):
2324
2360
  * the packed libCall over a validated string[] extraction of argsList.
2325
2361
  * The builtins ignore the receiver, so thisArg must be an effect-free
2326
2362
  * spelling (`this`, an identifier, a unit literal) whose dropped
2327
2363
  * evaluation is unobservable; every other Reflect.apply keeps the
2328
- * fence. Null when this isn't a Reflect.apply call. */
2329
- export function lowerReflectApplyCall(lowerer, call, access) {
2364
+ * fence. Null when this isn't a supported Reflect call. */
2365
+ export function lowerReflectCall(lowerer, call, access) {
2366
+ if (!call.questionDotToken && !access.questionDotToken && lowerer.stdlibGlobalMember(access, "Reflect") === "ownKeys" &&
2367
+ call.arguments.length === 1 && !ts.isSpreadElement(call.arguments[0])) {
2368
+ return { kind: "libCall", fn: "dyn.ownKeys", args: [lowerer.lowerExprExpecting(call.arguments[0], DYN)], type: DYN, loc: locOf(call) };
2369
+ }
2330
2370
  if (call.questionDotToken)
2331
2371
  return null;
2372
+ const reflectMember = lowerer.stdlibGlobalMember(access, "Reflect");
2373
+ if (reflectMember === "get" || reflectMember === "set") {
2374
+ const required = reflectMember === "get" ? 2 : 3;
2375
+ if (call.arguments.length < required || call.arguments.length > required + 1 || call.arguments.some(ts.isSpreadElement)) {
2376
+ lowerer.noLowering(`Reflect.${reflectMember} with this argument shape`, call, `use Reflect.${reflectMember}(target, key${reflectMember === "set" ? ", value" : ""}, receiver?)`);
2377
+ }
2378
+ const loc = locOf(call);
2379
+ const args = call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN));
2380
+ const target = call.arguments.length === required ? lowerer.declareHiddenLocal("%reflectTarget", DYN) : null;
2381
+ const operation = { kind: "libCall", fn: reflectMember === "get" ? "dyn.reflectGet" : "dyn.reflectSet",
2382
+ args: target ? [varRef(target.id, DYN, loc), ...args.slice(1), varRef(target.id, DYN, loc)] : args, type: reflectMember === "get" ? DYN : BOOL, loc };
2383
+ return target ? { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: target.id, init: args[0], loc }], result: operation, type: operation.type, loc } : operation;
2384
+ }
2332
2385
  if (lowerer.stdlibGlobalMember(access, "Reflect") !== "apply")
2333
2386
  return null;
2334
2387
  const loc = locOf(call);
@@ -2340,7 +2393,10 @@ export function lowerReflectApplyCall(lowerer, call, access) {
2340
2393
  const bi = ts.isPropertyAccessExpression(targetNode) ? lowerer.builtinMemberOf(targetNode) : null;
2341
2394
  const fn = bi ? builtinModuleFnOf(lowerer, bi.module, bi.member) : null;
2342
2395
  if (!fn || fn.variadicPack !== true) {
2343
- lowerer.noLowering(`Reflect.apply of '${targetNode.getText()}'`, targetNode, fenceHint);
2396
+ const target = lowerer.lowerExprExpecting(targetNode, DYN);
2397
+ const receiver = lowerer.lowerExprExpecting(call.arguments[1], DYN);
2398
+ const argumentsList = lowerer.lowerExprExpecting(call.arguments[2], DYN);
2399
+ return { kind: "libCall", fn: "dyn.reflectApply", args: [target, receiver, argumentsList], type: DYN, loc };
2344
2400
  }
2345
2401
  const thisNode = call.arguments[1];
2346
2402
  const effectFree = thisNode.kind === ts.SyntaxKind.ThisKeyword ||
@@ -2524,8 +2580,8 @@ export function lowerSpawnSyncCall(lowerer, expr, loc) {
2524
2580
  };
2525
2581
  }
2526
2582
  /** `spawn(command, args?, options)` → one cp.spawn / cp.spawnOpts
2527
- * libCall. The options argument, when present, must be an object
2528
- * LITERAL. Stdio accepts "ignore", "inherit", or "pipe" as the scalar,
2583
+ * libCall. Computed options use native runtime normalization. Inline
2584
+ * stdio accepts "ignore", "inherit", or "pipe" as the scalar,
2529
2585
  * or the 3-tuple whose stdin pipe becomes child.stdin, stdout/stderr
2530
2586
  * pipes become child.stdout/child.stderr, and output slots may also be
2531
2587
  * number fds. Omitting stdio uses Node's default: all three piped. The
@@ -2559,7 +2615,11 @@ export function lowerSpawnCall(lowerer, expr, loc) {
2559
2615
  optsNode = second;
2560
2616
  }
2561
2617
  if (optsNode !== undefined && !ts.isObjectLiteralExpression(optsNode)) {
2562
- lowerer.noLowering("spawn with a non-literal options argument", optsNode, "pass stdio, detached, env, cwd, windowsHide, and shell in an inline object literal");
2618
+ return {
2619
+ kind: "libCall", fn: "cp.spawnDynamic",
2620
+ args: [cmd, lowerer.lowerChildArgsArg(argsNode, loc), lowerer.lowerExprExpecting(optsNode, DYN)],
2621
+ type: CHILD_T, loc,
2622
+ };
2563
2623
  }
2564
2624
  const emptyStr = { kind: "strLit", value: "", type: STRING, loc };
2565
2625
  // Per-slot stdio modes (scr_child.c: 0 ignore, 1 inherit, 2 fd) and
@@ -4166,13 +4226,8 @@ function isStringDecoderTyped(lowerer, node) {
4166
4226
  return lowerer.checker.declarationsOf(sym).some((d) => (ts.isClassDeclaration(d) || ts.isInterfaceDeclaration(d)) &&
4167
4227
  lowerer.isStdlibFile(d.getSourceFile()));
4168
4228
  }
4169
- /** Method calls on StringDecoder receivers: `d.write(chunk)` decodes the
4170
- * complete prefix of pending+chunk and re-buffers the trailing partial
4171
- * sequence; `d.end()` flushes the buffered partial as its replacement
4172
- * chars — Node's utf8 StringDecoder exactly (SEMANTICS.md), through the
4173
- * interned %strdec helpers over the packed-f64 pending field. end(buf)
4174
- * and the rest of @types/node's surface fence per member. Null for
4175
- * non-decoder receivers. */
4229
+ /** StringDecoder writes preserve pending bytes; end(input) performs the
4230
+ * final write and flushes the state. String input passes through unchanged. */
4176
4231
  export function lowerStringDecoderMethodCall(lowerer, call, access) {
4177
4232
  if (call.questionDotToken || access.questionDotToken)
4178
4233
  return null;
@@ -4182,29 +4237,37 @@ export function lowerStringDecoderMethodCall(lowerer, call, access) {
4182
4237
  return null;
4183
4238
  const name = access.name.text;
4184
4239
  const loc = locOf(call);
4185
- if (name === "write" && call.arguments.length === 1) {
4186
- const receiver = lowerer.lowerExpr(access.expression);
4187
- if (receiver.type.kind !== "record")
4188
- lowerer.badType(access.expression, lowerer.typeOf(access.expression));
4189
- let chunk = lowerBuiltinValuePreservingUndefined(lowerer, call.arguments[0]);
4190
- chunk = checkedOptionalBuiltinArm(lowerer, chunk, BYTES_U8) ?? chunk;
4191
- if (!(chunk.type.kind === "bytes" && chunk.type.elem === "u8")) {
4192
- lowerer.noLowering(`StringDecoder.write of '${lowerer.fmt(chunk.type)}' data`, call.arguments[0], "Buffer/Uint8Array chunks decode (narrow unions first)");
4193
- }
4194
- const helper = lowerer.strdecHelper("write", receiver.type.shapeId, loc);
4195
- return { kind: "call", callee: helper, args: [receiver, chunk], type: STRING, loc };
4240
+ if ((name !== "write" && name !== "end") || call.arguments.length > 1 ||
4241
+ (name === "write" && call.arguments.length !== 1) || call.arguments.some(ts.isSpreadElement)) {
4242
+ lowerer.noLowering(`StringDecoder.${name}`, call, "use write(input) or end(input?)", lowerer.checker.getSymbolAtLocation(access.name));
4196
4243
  }
4197
- if (name === "end") {
4198
- if (call.arguments.length !== 0) {
4199
- lowerer.noLowering("StringDecoder.end with a buffer argument", call, "write the buffer, then end(): d.write(buf) + d.end() is Node's own equivalence");
4200
- }
4201
- const receiver = lowerer.lowerExpr(access.expression);
4202
- if (receiver.type.kind !== "record")
4203
- lowerer.badType(access.expression, lowerer.typeOf(access.expression));
4204
- const helper = lowerer.strdecHelper("end", receiver.type.shapeId, loc);
4205
- return { kind: "call", callee: helper, args: [receiver], type: STRING, loc };
4244
+ const receiver = lowerer.lowerExpr(access.expression);
4245
+ if (receiver.type.kind !== "record")
4246
+ lowerer.badType(access.expression, lowerer.typeOf(access.expression));
4247
+ if (call.arguments.length === 0) {
4248
+ return { kind: "call", callee: lowerer.strdecHelper("end", receiver.type.shapeId, loc), args: [receiver], type: STRING, loc };
4249
+ }
4250
+ const node = call.arguments[0];
4251
+ const undefinedArg = name === "end" ? lowerStaticallyUndefinedArgument(lowerer, node) : null;
4252
+ if (undefinedArg) {
4253
+ const saved = lowerer.declareHiddenLocal("%strdecRecv", receiver.type);
4254
+ const result = { kind: "call", callee: lowerer.strdecHelper("end", receiver.type.shapeId, loc), args: [varRef(saved.id, receiver.type, loc)], type: STRING, loc };
4255
+ return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: saved.id, init: receiver, loc }], result: defaultAfterUndefined(undefinedArg, result), type: STRING, loc };
4206
4256
  }
4207
- lowerer.noLowering(`StringDecoder.${name}`, call, "write(buffer) and end() are the supported StringDecoder members", lowerer.checker.getSymbolAtLocation(access.name));
4257
+ let chunk = lowerBuiltinValuePreservingUndefined(lowerer, node);
4258
+ if (chunk.type.kind === "string") {
4259
+ const op = name === "end" ? "endString" : "writeString";
4260
+ return { kind: "call", callee: lowerer.strdecHelper(op, receiver.type.shapeId, loc), args: [receiver, chunk], type: STRING, loc };
4261
+ }
4262
+ chunk = checkedOptionalBuiltinArm(lowerer, chunk, BYTES_U8) ?? chunk;
4263
+ if (chunk.type.kind === "bytes" && chunk.type.elem !== "u8") {
4264
+ chunk = { kind: "libCall", fn: "bytes.bufferSource", args: [lowerer.coerceInto(node, chunk, DYN)], type: BYTES_U8, loc };
4265
+ }
4266
+ if (!(chunk.type.kind === "bytes" && chunk.type.elem === "u8")) {
4267
+ lowerer.noLowering(`StringDecoder.${name} of '${lowerer.fmt(chunk.type)}' data`, node, "pass a string or typed-array view (narrow unions first)");
4268
+ }
4269
+ const helper = lowerer.strdecHelper(name === "end" ? "endChunk" : "write", receiver.type.shapeId, loc);
4270
+ return { kind: "call", callee: helper, args: [receiver, chunk], type: STRING, loc };
4208
4271
  }
4209
4272
  /** The interned %strdec helpers: write(d, chunk) returns the decoded
4210
4273
  * complete prefix and re-buffers the trailing partial into the pending
@@ -4242,7 +4305,7 @@ export function strdecHelper(lowerer, op, shapeId, loc) {
4242
4305
  { id: "s.0", name: "s", type: STRING, mutable: false },
4243
4306
  ];
4244
4307
  let body;
4245
- if (op === "write") {
4308
+ if (op === "write" || op === "endChunk") {
4246
4309
  params.push({ localId: "chunk.0", name: "chunk", type: BYTES_U8 });
4247
4310
  locals.splice(1, 0, { id: "chunk.0", name: "chunk", type: BYTES_U8, mutable: false });
4248
4311
  body = [
@@ -4282,6 +4345,24 @@ export function strdecHelper(lowerer, op, shapeId, loc) {
4282
4345
  { kind: "return", value: varRef("s.0", STRING, loc), loc },
4283
4346
  ];
4284
4347
  }
4348
+ if (op === "endString" || op === "writeString") {
4349
+ const inputT = STRING;
4350
+ params.push({ localId: "chunk.0", name: "chunk", type: inputT });
4351
+ locals.push({ id: "chunk.0", name: "chunk", type: inputT, mutable: false });
4352
+ if (op === "writeString")
4353
+ body = [{ kind: "return", value: varRef("chunk.0", STRING, loc), loc }];
4354
+ if (op === "endString")
4355
+ body[body.length - 1] = { kind: "return", value: {
4356
+ kind: "strConcat", left: varRef("chunk.0", STRING, loc), right: varRef("s.0", STRING, loc), type: STRING, loc,
4357
+ }, loc };
4358
+ }
4359
+ if (op === "endChunk") {
4360
+ locals.push({ id: "tail.0", name: "tail", type: STRING, mutable: false });
4361
+ body.splice(body.length - 1, 0, { kind: "varDecl", localId: "tail.0", init: { kind: "libCall", fn: "strdec.end", args: [encRead(), pendingRead()], type: STRING, loc }, loc }, { kind: "recordSet", obj: varRef("d.0", recT, loc), shapeId, field: "%pending", value: { kind: "numLit", value: 0, type: F64, loc }, loc });
4362
+ body[body.length - 1] = { kind: "return", value: {
4363
+ kind: "strConcat", left: varRef("s.0", STRING, loc), right: varRef("tail.0", STRING, loc), type: STRING, loc,
4364
+ }, loc };
4365
+ }
4285
4366
  lowerer.liftedFns.push({ name, params, returnType: STRING, locals, body, loc });
4286
4367
  return name;
4287
4368
  }
@@ -4312,6 +4393,18 @@ export function lowerJsonMethodCall(lowerer, call, access) {
4312
4393
  return { kind: "libCall", fn: "json.parseReviver", args: [text, callback], type: DYN, loc };
4313
4394
  }
4314
4395
  if (member === "stringify") {
4396
+ const replacerNode = call.arguments[1];
4397
+ const spaceNode = call.arguments[2];
4398
+ const runtimeOptions = replacerNode && !jsonNullishArgument(lowerer, replacerNode) &&
4399
+ lowerer.mapTypeOf(lowerer.typeOf(replacerNode))?.kind === "dyn" ||
4400
+ spaceNode && !jsonNullishArgument(lowerer, spaceNode) &&
4401
+ !ts.isNumericLiteral(spaceNode) && !ts.isStringLiteral(spaceNode) && !ts.isNoSubstitutionTemplateLiteral(spaceNode) &&
4402
+ !(ts.isPrefixUnaryExpression(spaceNode) && ts.isNumericLiteral(spaceNode.operand));
4403
+ if (runtimeOptions && call.arguments[0]) {
4404
+ const args = [0, 1, 2].map((index) => call.arguments[index]
4405
+ ? lowerer.lowerExprExpecting(call.arguments[index], DYN) : dynUndefinedExpr(loc));
4406
+ return { kind: "libCall", fn: "json.stringifyValue", args, type: DYN, loc };
4407
+ }
4315
4408
  const indent = stringifySpaceIndent(lowerer, call);
4316
4409
  if (call.arguments.length === 0) {
4317
4410
  return lowerer.wrappedUndefined(lowerer.withUndefinedArm(STRING), loc);
@@ -4366,11 +4459,11 @@ export function lowerJsonMethodCall(lowerer, call, access) {
4366
4459
  const optionalString = lowerOptionalStringifyRoot(lowerer, value, indent, loc);
4367
4460
  if (optionalString)
4368
4461
  return optionalString;
4369
- if (value.type.kind === "dyn" || isJsonStringifyDynamicType(value.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
4462
+ if (value.type.kind === "url" || value.type.kind === "dyn" || isJsonStringifyDynamicType(value.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
4370
4463
  // Keep the original containers live while the runtime visits them:
4371
4464
  // a toJSON callback can mutate a later field, and shared/cyclic
4372
4465
  // references must retain their identities throughout traversal.
4373
- const boxed = value.type.kind === "dyn" ? value : { kind: "dynFrom", value, liveRef: true, type: DYN, loc };
4466
+ const boxed = value.type.kind === "dyn" ? value : { kind: "dynFrom", value, ...(value.type.kind === "url" ? {} : { liveRef: true }), type: DYN, loc };
4374
4467
  const raw = {
4375
4468
  kind: "libCall", fn: "json.stringifyReplacer",
4376
4469
  args: [boxed, dynUndefinedExpr(loc), { kind: "strLit", value: indent, type: STRING, loc }],
@@ -4516,6 +4609,12 @@ function jsonNullishArgument(lowerer, node) {
4516
4609
  * refuse signatures that request one until that protocol is implemented. */
4517
4610
  function lowerJsonCallback(lowerer, node, role) {
4518
4611
  const callback = lowerer.lowerExpr(node);
4612
+ if (callback.type.kind === "dyn")
4613
+ return callback;
4614
+ if (callback.type.kind === "union" && lowerer.dynConvertible(callback.type) &&
4615
+ lowerer.unions.get(callback.type.unionId)?.arms.every((arm) => isUnitType(arm) || arm.kind === "func" &&
4616
+ arm.params.length <= 2 && (role !== "reviver" || (!arm.rest && !arm.argumentsAll))))
4617
+ return lowerer.coerceToExpected(callback, DYN);
4519
4618
  if (callback.type.kind === "func" && callback.type.params.length <= 2 &&
4520
4619
  (role !== "reviver" || (!callback.type.rest && !callback.type.argumentsAll)) &&
4521
4620
  canBoxFuncIntoDyn(callback.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
@@ -4702,8 +4801,8 @@ function cryptoEncoding(lowerer, node, use) {
4702
4801
  }
4703
4802
  function cryptoAlgorithm(lowerer, node, use) {
4704
4803
  const type = lowerer.typeOf(node);
4705
- if (type.isStringLiteralType() && !["md5", "sha1", "sha256"].includes(type.value.toLowerCase())) {
4706
- lowerer.noLowering(`${use} with algorithm '${type.value}'`, node, "md5, sha1, and sha256 are the lowered digest algorithms");
4804
+ if (type.isStringLiteralType() && !["md5", "sha1", "sha224", "sha256", "sha384", "sha512"].includes(type.value.toLowerCase())) {
4805
+ lowerer.noLowering(`${use} with algorithm '${type.value}'`, node, "md5, sha1, sha224, sha256, sha384, and sha512 are the lowered digest algorithms");
4707
4806
  }
4708
4807
  return lowerer.lowerExprExpecting(node, STRING);
4709
4808
  }
@@ -4722,7 +4821,19 @@ function cryptoInputBytes(lowerer, node, loc) {
4722
4821
  }
4723
4822
  lowerer.noLowering(`crypto byte input of '${lowerer.fmt(value.type)}' values`, node, "string and Buffer/Uint8Array values are supported");
4724
4823
  }
4725
- function errorFirstBytesCallback(lowerer, node, api) {
4824
+ function cryptoKdfInput(lowerer, node) {
4825
+ const loc = locOf(node);
4826
+ const type = lowerer.mapTypeOf(lowerer.typeOf(node));
4827
+ if (type?.kind === "string" || (type?.kind === "bytes" && type.elem === "u8"))
4828
+ return cryptoInputBytes(lowerer, node, loc);
4829
+ const symbol = lowerer.typeOf(node).getSymbol();
4830
+ if (type?.kind === "bytes" || (symbol?.name === "ArrayBuffer" && lowerer.isStdlibSymbol(symbol))) {
4831
+ const value = lowerer.coerceInto(node, lowerer.lowerExpr(node), DYN);
4832
+ return { kind: "libCall", fn: "bytes.bufferSource", args: [value], type: BYTES_U8, loc };
4833
+ }
4834
+ lowerer.noLowering("crypto key derivation with this input", node, "strings, Buffers, numeric typed arrays, DataViews, and fixed-length ArrayBuffers are supported; KeyObjects are not yet lowered");
4835
+ }
4836
+ function errorFirstBytesCallback(lowerer, node, api, arrayBuffer = false) {
4726
4837
  let callback = lowerer.lowerExpr(node);
4727
4838
  if (callback.type.kind === "dyn") {
4728
4839
  callback = { kind: "dynCheck", value: callback, type: funcOf([DYN, DYN], VOID), loc: locOf(node) };
@@ -4744,8 +4855,8 @@ function errorFirstBytesCallback(lowerer, node, api) {
4744
4855
  lowerer.unsupported("SC1090", node, `${api} callback error parameters must be Error | null`);
4745
4856
  }
4746
4857
  const value = callback.type.params[1];
4747
- if (value !== undefined && value.kind !== "dyn" && !(value.kind === "bytes" && value.elem === "u8")) {
4748
- lowerer.unsupported("SC1090", node, `${api} callback result parameters must be Buffer/Uint8Array values`);
4858
+ if (value !== undefined && value.kind !== "dyn" && (arrayBuffer || !(value.kind === "bytes" && value.elem === "u8"))) {
4859
+ lowerer.unsupported("SC1090", node, `${api} callback result parameters must be ${arrayBuffer ? "ArrayBuffer" : "Buffer/Uint8Array"} values`);
4749
4860
  }
4750
4861
  return voidizedCallback(lowerer, callback, locOf(node));
4751
4862
  }
@@ -4793,6 +4904,31 @@ export function lowerCryptoModuleCall(lowerer, expr, bi, loc) {
4793
4904
  loc,
4794
4905
  };
4795
4906
  }
4907
+ if (bi.member === "hkdf" || bi.member === "hkdfSync") {
4908
+ const async = bi.member === "hkdf";
4909
+ if (args.length !== (async ? 6 : 5))
4910
+ lowerer.noLowering(`crypto.${bi.member} with ${args.length} arguments`, expr);
4911
+ const values = [
4912
+ cryptoAlgorithm(lowerer, args[0], `crypto.${bi.member}`),
4913
+ cryptoKdfInput(lowerer, args[1]), cryptoKdfInput(lowerer, args[2]), cryptoKdfInput(lowerer, args[3]),
4914
+ lowerer.lowerExprExpecting(args[4], F64),
4915
+ ];
4916
+ if (async)
4917
+ values.push(errorFirstBytesCallback(lowerer, args[5], "crypto.hkdf", true));
4918
+ return { kind: "libCall", fn: async ? "crypto.hkdfCb" : "crypto.hkdf", args: values, type: async ? VOID : DYN, loc };
4919
+ }
4920
+ if (bi.member === "scrypt" || bi.member === "scryptSync") {
4921
+ const async = bi.member === "scrypt";
4922
+ const minimum = async ? 4 : 3;
4923
+ if (args.length < minimum || args.length > minimum + 1)
4924
+ lowerer.noLowering(`crypto.${bi.member} with ${args.length} arguments`, expr);
4925
+ const values = [cryptoKdfInput(lowerer, args[0]), cryptoKdfInput(lowerer, args[1]), lowerer.lowerExprExpecting(args[2], F64)];
4926
+ const options = args.length > minimum ? args[3] : undefined;
4927
+ values.push(options ? lowerer.coerceInto(options, lowerer.lowerExpr(options), DYN) : dynUndefinedExpr(loc));
4928
+ if (async)
4929
+ values.push(errorFirstBytesCallback(lowerer, args[args.length - 1], "crypto.scrypt"));
4930
+ return { kind: "libCall", fn: async ? "crypto.scryptCb" : "crypto.scrypt", args: values, type: async ? VOID : BYTES_U8, loc };
4931
+ }
4796
4932
  if (bi.member === "createHash") {
4797
4933
  if (args.length !== 1) {
4798
4934
  lowerer.noLowering(`crypto.createHash with ${args.length} arguments`, expr, "createHash(algorithm) is supported; options are not yet lowered");
@@ -4900,7 +5036,7 @@ export function lowerCryptoModuleCall(lowerer, expr, bi, loc) {
4900
5036
  loc,
4901
5037
  };
4902
5038
  }
4903
- /** Method calls on URL-typed receivers: `u.toString()` is Node's href
5039
+ /** Method calls on URL-typed receivers: `u.toString()` and `u.toJSON()` are Node's href
4904
5040
  * serialization (the href getter's libCall). Everything else the lib
4905
5041
  * declares fences member-qualified. Null for non-URL receivers. */
4906
5042
  export function lowerUrlMethodCall(lowerer, call, access) {
@@ -4911,11 +5047,11 @@ export function lowerUrlMethodCall(lowerer, call, access) {
4911
5047
  if (!lowerer.isStdlibMember(access))
4912
5048
  return null;
4913
5049
  const name = access.name.text;
4914
- if (name === "toString" && call.arguments.length === 0) {
5050
+ if ((name === "toString" || name === "toJSON") && call.arguments.length === 0) {
4915
5051
  const receiver = lowerer.lowerExpr(access.expression);
4916
5052
  return { kind: "libCall", fn: "url.href", args: [receiver], type: STRING, loc: locOf(call) };
4917
5053
  }
4918
- lowerer.noLowering(`URL.${name}`, call, "protocol, origin, username, password, pathname, href, host, hostname, port, search, hash, searchParams, and toString() are the supported URL members", lowerer.checker.getSymbolAtLocation(access.name));
5054
+ lowerer.noLowering(`URL.${name}`, call, "protocol, origin, username, password, pathname, href, host, hostname, port, search, hash, searchParams, toString(), and toJSON() are the supported URL members", lowerer.checker.getSymbolAtLocation(access.name));
4919
5055
  }
4920
5056
  /** `new URLSearchParams(init?)` — the WHATWG constructor's lowered init
4921
5057
  * shapes: omitted / literal `undefined` (empty list), a string (parsed,
@@ -4959,6 +5095,9 @@ export function lowerSearchParamsNew(lowerer, expr, loc) {
4959
5095
  return acc;
4960
5096
  }
4961
5097
  const init = lowerer.lowerExpr(arg);
5098
+ if (init.type.kind === "dyn") {
5099
+ return { kind: "libCall", fn: "sp.newChecked", args: [init], type: SEARCH_PARAMS_T, loc };
5100
+ }
4962
5101
  if (init.type.kind === "string") {
4963
5102
  return { kind: "libCall", fn: "sp.parse", args: [init], type: SEARCH_PARAMS_T, loc };
4964
5103
  }
@@ -5286,18 +5425,21 @@ export function lowerFileHandleMethodCall(lowerer, call, access) {
5286
5425
  const loc = locOf(call);
5287
5426
  const receiver = () => lowerer.lowerExprExpecting(access.expression, FILEHANDLE_T);
5288
5427
  const promise = (inner) => ({ kind: "promise", inner });
5289
- const num = (node, dflt) => {
5428
+ const num = (node, dflt, lowered) => {
5290
5429
  const defaultValue = { kind: "numLit", value: dflt, type: F64, loc };
5291
- if (!node)
5430
+ if (!node && !lowered)
5292
5431
  return { value: defaultValue, defaulted: boolLit(true, loc) };
5293
- const undefinedArg = lowerStaticallyUndefinedArgument(lowerer, node);
5432
+ if (lowered && isUnitType(lowered.type)) {
5433
+ return { value: defaultAfterUndefined(lowered, defaultValue), defaulted: boolLit(true, loc) };
5434
+ }
5435
+ const undefinedArg = !lowered && node ? lowerStaticallyUndefinedArgument(lowerer, node) : null;
5294
5436
  if (undefinedArg) {
5295
5437
  return { value: defaultAfterUndefined(undefinedArg, defaultValue), defaulted: boolLit(true, loc) };
5296
5438
  }
5297
- if ((lowerer.typeOf(node).flags & ts.TypeFlags.Null) !== 0) {
5439
+ if (!lowered && node && (lowerer.typeOf(node).flags & ts.TypeFlags.Null) !== 0) {
5298
5440
  return { value: defaultAfterUndefined(lowerer.lowerExpr(node), defaultValue), defaulted: boolLit(true, loc) };
5299
5441
  }
5300
- const value = lowerer.lowerExpr(node);
5442
+ const value = lowered ?? lowerer.lowerExpr(node);
5301
5443
  if (value.type.kind === "union") {
5302
5444
  const def = lowerer.unions.get(value.type.unionId);
5303
5445
  const units = def?.arms.filter(isUnitType) ?? [];
@@ -5343,7 +5485,7 @@ export function lowerFileHandleMethodCall(lowerer, call, access) {
5343
5485
  };
5344
5486
  }
5345
5487
  }
5346
- return { value: lowerer.coerceInto(node, value, F64), defaulted: boolLit(false, loc) };
5488
+ return { value: lowerer.coerceInto(node ?? call, value, F64), defaulted: boolLit(false, loc) };
5347
5489
  };
5348
5490
  const utf8 = (node) => {
5349
5491
  const dflt = { kind: "strLit", value: "utf8", type: STRING, loc };
@@ -5358,6 +5500,30 @@ export function lowerFileHandleMethodCall(lowerer, call, access) {
5358
5500
  }
5359
5501
  return lowerBuiltinOptionalDefault(lowerer, node, STRING, dflt, true);
5360
5502
  };
5503
+ if (name === "sync" || name === "datasync") {
5504
+ if (call.arguments.length !== 0)
5505
+ lowerer.noLowering(`FileHandle.${name} with arguments`, call);
5506
+ return { kind: "libCall", fn: name === "sync" ? "fileHandle.sync" : "fileHandle.datasync", args: [receiver()], type: promise(VOID), loc };
5507
+ }
5508
+ if (name === "truncate" || name === "chmod") {
5509
+ if (call.arguments.length > 1 || (name === "chmod" && call.arguments.length !== 1))
5510
+ lowerer.noLowering(`FileHandle.${name} with ${call.arguments.length} arguments`, call);
5511
+ return {
5512
+ kind: "libCall", fn: name === "truncate" ? "fileHandle.truncate" : "fileHandle.chmod",
5513
+ args: [receiver(), num(call.arguments[0], 0).value], type: promise(VOID), loc,
5514
+ };
5515
+ }
5516
+ if (name === "readv" || name === "writev") {
5517
+ if (call.arguments.length < 1 || call.arguments.length > 2)
5518
+ lowerer.noLowering(`FileHandle.${name} with ${call.arguments.length} arguments`, call);
5519
+ const type = lowerer.mapTypeOf(lowerer.typeOf(call));
5520
+ if (type?.kind !== "promise" || type.inner.kind !== "record")
5521
+ lowerer.badType(call, lowerer.typeOf(call));
5522
+ return {
5523
+ kind: "libCall", fn: name === "readv" ? "fileHandle.readv" : "fileHandle.writev",
5524
+ args: [receiver(), lowerer.lowerExprExpecting(call.arguments[0], arrayOf(BYTES_U8)), num(call.arguments[1], -1).value], type, loc,
5525
+ };
5526
+ }
5361
5527
  if (name === "close" || name === "stat") {
5362
5528
  if (call.arguments.length !== 0)
5363
5529
  lowerer.noLowering(`FileHandle.${name} with arguments`, call);
@@ -5415,6 +5581,65 @@ export function lowerFileHandleMethodCall(lowerer, call, access) {
5415
5581
  }
5416
5582
  lowerer.noLowering(`FileHandle.${name} of '${dataT ? lowerer.fmt(dataT) : lowerer.checker.typeToString(lowerer.typeOf(dataNode))}' data`, dataNode, "string and Uint8Array data are supported");
5417
5583
  }
5584
+ if (name === "read" || name === "write") {
5585
+ const firstNode = call.arguments[0];
5586
+ const firstT = firstNode ? lowerer.mapTypeOf(lowerer.typeOf(firstNode)) : undefined;
5587
+ const secondT = call.arguments[1] ? lowerer.mapTypeOf(lowerer.typeOf(call.arguments[1])) : undefined;
5588
+ const readOptions = name === "read" && (!firstNode || firstT?.kind === "record" || (firstT && isUnitType(firstT)));
5589
+ const bufferOptions = firstT?.kind === "bytes" && firstT.elem === "u8" && secondT?.kind === "record";
5590
+ if (readOptions || bufferOptions) {
5591
+ if (call.arguments.length > (bufferOptions ? 2 : 1))
5592
+ lowerer.noLowering(`FileHandle.${name} options with extra arguments`, call);
5593
+ const type = lowerer.mapTypeOf(lowerer.typeOf(call));
5594
+ if (type?.kind !== "promise" || type.inner.kind !== "record")
5595
+ lowerer.badType(call, lowerer.typeOf(call));
5596
+ const stmts = [];
5597
+ const stage = (value, label) => {
5598
+ const local = lowerer.declareHiddenLocal(label, value.type);
5599
+ stmts.push({ kind: "varDecl", localId: local.id, init: value, loc: value.loc });
5600
+ return varRef(local.id, local.type, loc);
5601
+ };
5602
+ const handle = stage(receiver(), "%fhWindowReceiver");
5603
+ let buffer = bufferOptions ? stage(lowerer.lowerExprExpecting(firstNode, BYTES_U8), "%fhWindowBuffer") : undefined;
5604
+ const optionsNode = bufferOptions ? call.arguments[1] : firstNode;
5605
+ const options = optionsNode ? stage(lowerer.lowerExpr(optionsNode), "%fhWindowOptions") : undefined;
5606
+ const field = (key) => {
5607
+ if (options?.type.kind !== "record")
5608
+ return undefined;
5609
+ const fields = lowerer.shapes.get(options.type.shapeId)?.fields;
5610
+ const getter = fields?.find((f) => f.name === `%get:${key}`);
5611
+ if (getter?.type.kind === "func") {
5612
+ const callee = { kind: "recordGet", obj: options, shapeId: options.type.shapeId, field: getter.name, type: getter.type, loc };
5613
+ return { kind: "callValue", callee, args: [], type: getter.type.ret, loc };
5614
+ }
5615
+ const member = fields?.find((f) => f.name === key);
5616
+ return member ? { kind: "recordGet", obj: options, shapeId: options.type.shapeId, field: key, type: member.type, loc } : undefined;
5617
+ };
5618
+ if (!buffer) {
5619
+ const supplied = field("buffer");
5620
+ const fresh = { kind: "bytesNew", source: numLit(16384, loc), type: BYTES_U8, loc };
5621
+ if (!supplied || isUnitType(supplied.type))
5622
+ buffer = supplied ? defaultAfterUndefined(supplied, fresh) : fresh;
5623
+ else if (supplied.type.kind === "union") {
5624
+ const arms = lowerer.unions.get(supplied.type.unionId)?.arms;
5625
+ if (!arms?.every((arm) => typeEquals(arm, BYTES_U8) || isUnitType(arm)))
5626
+ lowerer.noLowering("FileHandle.read with this buffer type", call);
5627
+ buffer = { kind: "nullish", left: supplied, right: fresh, type: BYTES_U8, loc };
5628
+ }
5629
+ else
5630
+ buffer = lowerer.coerceInto(call, supplied, BYTES_U8);
5631
+ buffer = stage(buffer, "%fhWindowBuffer");
5632
+ }
5633
+ const offset = num(undefined, 0, field("offset"));
5634
+ const length = num(undefined, -1, field("length"));
5635
+ const position = num(undefined, -1, field("position"));
5636
+ const result = {
5637
+ kind: "libCall", fn: name === "read" ? "fileHandle.read" : "fileHandle.writeBytes",
5638
+ args: [handle, buffer, offset.value, length.value, position.value, length.defaulted], type, loc,
5639
+ };
5640
+ return { kind: "seqExpr", stmts, result, type, loc };
5641
+ }
5642
+ }
5418
5643
  if (name === "read") {
5419
5644
  if (call.arguments.length < 1 || call.arguments.length > 4) {
5420
5645
  lowerer.noLowering(`FileHandle.read with ${call.arguments.length} arguments`, call, "use read(buffer[, offset[, length[, position]]])");
@@ -5473,7 +5698,7 @@ export function lowerFileHandleMethodCall(lowerer, call, access) {
5473
5698
  }
5474
5699
  lowerer.noLowering(`FileHandle.write of '${dataT ? lowerer.fmt(dataT) : lowerer.checker.typeToString(lowerer.typeOf(dataNode))}' data`, dataNode, "string and Uint8Array data are supported");
5475
5700
  }
5476
- lowerer.noLowering(`FileHandle.${name}`, call, "fd, close(), read(), write(), readFile(), writeFile(), appendFile(), and stat() are the supported FileHandle members", lowerer.checker.getSymbolAtLocation(access.name));
5701
+ lowerer.noLowering(`FileHandle.${name}`, call, "fd, close(), read(), write(), readv(), writev(), readFile(), writeFile(), appendFile(), stat(), sync(), datasync(), truncate(), and chmod() are the supported FileHandle members", lowerer.checker.getSymbolAtLocation(access.name));
5477
5702
  }
5478
5703
  /** Method calls on Stats-typed receivers: isFile()/isDirectory()/
5479
5704
  * isSymbolicLink() are pure reads on the stat snapshot (a followed
@@ -5627,6 +5852,21 @@ export function lowerAtomicsCall(lowerer, call, access) {
5627
5852
  export function lowerBuiltinExtraProperty(lowerer, expr) {
5628
5853
  if (expr.questionDotToken && !lowerer.chainHandled.has(expr))
5629
5854
  return null;
5855
+ const codec = storedTextCodecClassOf(lowerer, expr.expression);
5856
+ if (codec && lowerer.isStdlibMember(expr) && ["encoding", "fatal", "ignoreBOM"].includes(expr.name.text)) {
5857
+ const receiver = lowerer.lowerExpr(expr.expression);
5858
+ if (receiver.type.kind !== "record")
5859
+ lowerer.badType(expr.expression, lowerer.typeOf(expr.expression));
5860
+ const loc = locOf(expr);
5861
+ if (codec === "TextEncoder" && expr.name.text === "encoding") {
5862
+ return { kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: receiver, loc }], result: strLit("utf-8", loc), type: STRING, loc };
5863
+ }
5864
+ if (codec === "TextDecoder") {
5865
+ const field = expr.name.text === "encoding" ? "%TextDecoder" : `%${expr.name.text}`;
5866
+ const value = { kind: "recordGet", obj: receiver, shapeId: receiver.type.shapeId, field, type: expr.name.text === "encoding" ? F64 : BOOL, loc };
5867
+ return expr.name.text === "encoding" ? { kind: "libCall", fn: "text.decoderName", args: [value], type: STRING, loc } : value;
5868
+ }
5869
+ }
5630
5870
  // decoder.encoding on a StringDecoder-typed receiver: the record's
5631
5871
  // hidden canonical-name field (construction folded the aliases —
5632
5872
  // exactly what Node's normalized `.encoding` answers).
@@ -5637,6 +5877,15 @@ export function lowerBuiltinExtraProperty(lowerer, expr) {
5637
5877
  return { kind: "recordGet", obj: receiver, shapeId: receiver.type.shapeId, field: "%enc", type: STRING, loc: locOf(expr) };
5638
5878
  }
5639
5879
  const kind = lowerer.mapTypeOf(lowerer.typeOf(expr.expression))?.kind;
5880
+ if (kind === "record" && ["read", "written"].includes(expr.name.text) && lowerer.isStdlibMember(expr)) {
5881
+ const receiver = lowerer.lowerExpr(expr.expression);
5882
+ if (receiver.type.kind === "record") {
5883
+ const fields = lowerer.shapes.get(receiver.type.shapeId)?.fields;
5884
+ if (fields?.length === 2 && fields.every((field) => ["read", "written"].includes(field.name) && field.type.kind === "f64")) {
5885
+ return { kind: "recordGet", obj: receiver, shapeId: receiver.type.shapeId, field: expr.name.text, type: F64, loc: locOf(expr) };
5886
+ }
5887
+ }
5888
+ }
5640
5889
  if (kind !== "stats" && kind !== "fileHandle" && kind !== "spawnRes" && kind !== "child" && kind !== "childWriter")
5641
5890
  return null;
5642
5891
  if (kind === "child" ? !isChildSurfaceMember(lowerer, expr) : !lowerer.isStdlibMember(expr))
@@ -5817,7 +6066,7 @@ export function lowerChildMethodCall(lowerer, call, access) {
5817
6066
  if ((name === "on" || name === "once") && call.arguments.length === 2) {
5818
6067
  const evT = lowerer.typeOf(call.arguments[0]);
5819
6068
  const event = evT.isStringLiteralType() ? evT.value : null;
5820
- if (event !== "exit" && event !== "close" && event !== "error" && event !== "message" && event !== "disconnect") {
6069
+ if (event !== "spawn" && event !== "exit" && event !== "close" && event !== "error" && event !== "message" && event !== "disconnect") {
5821
6070
  lowerer.noLowering(`child.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, call.arguments[0], '"exit", "close", "error", "message", and "disconnect" are the supported child events (as literals)');
5822
6071
  }
5823
6072
  if (!ts.isExpressionStatement(call.parent)) {
@@ -5843,7 +6092,34 @@ export function lowerChildMethodCall(lowerer, call, access) {
5843
6092
  loc,
5844
6093
  };
5845
6094
  }
6095
+ const listenerNode = stripTypeCasts(call.arguments[1]);
6096
+ if (isJsSourceFile(listenerNode.getSourceFile()) &&
6097
+ (ts.isArrowFunction(listenerNode) || ts.isFunctionExpression(listenerNode)) &&
6098
+ listenerNode.parameters.some((param) => param.dotDotDotToken) &&
6099
+ listenerNode.parameters.every((param) => !param.type) &&
6100
+ !/@(?:param|type)\b/.test(listenerNode.getSourceFile().text.slice(listenerNode.pos, listenerNode.getStart()))) {
6101
+ for (const param of listenerNode.parameters)
6102
+ lowerer.checkedCallbackParams.add(param);
6103
+ }
5846
6104
  const cb = lowerer.lowerExpr(call.arguments[1]);
6105
+ if (isJsSourceFile(listenerNode.getSourceFile()) && cb.type.kind === "dyn" ||
6106
+ cb.type.kind === "func" && (cb.type.rest || isJsSourceFile(listenerNode.getSourceFile()) && cb.type.params.some((param) => param.kind === "dyn"))) {
6107
+ if (cb.type.kind !== "dyn" && !canBoxFuncIntoDyn(cb.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
6108
+ lowerer.noLowering("child event listeners with non-representable parameters", call.arguments[1]);
6109
+ }
6110
+ return {
6111
+ kind: "libCall", fn: "child.onDyn",
6112
+ args: [receiver, { kind: "strLit", value: event, type: STRING, loc },
6113
+ cb.type.kind === "dyn" ? cb : { kind: "dynFrom", value: cb, type: DYN, loc }],
6114
+ type: VOID, loc,
6115
+ };
6116
+ }
6117
+ if (event === "spawn") {
6118
+ if (cb.type.kind !== "func" || cb.type.params.length !== 0 || cb.type.ret.kind !== "void") {
6119
+ lowerer.noLowering("spawn event listeners with parameters or a returned value", call.arguments[1]);
6120
+ }
6121
+ return { kind: "libCall", fn: "child.onSpawn", args: [receiver, cb], type: VOID, loc };
6122
+ }
5847
6123
  if (cb.type.kind !== "func" || cb.type.params.length > (event === "error" ? 1 : 2)) {
5848
6124
  lowerer.unsupported("SC1090", call.arguments[1], event !== "error"
5849
6125
  ? `${event} listeners with more than two parameters (use (code, signal), (code), or ())`
@@ -5918,9 +6194,9 @@ export function lowerChildMethodCall(lowerer, call, access) {
5918
6194
  // child.unref(): drops the child from the event loop's keep-alive set
5919
6195
  // (the process may exit while the child runs — Node's semantics; the
5920
6196
  // child is still reaped while the loop runs for other reasons).
5921
- if (name === "unref" && call.arguments.length === 0) {
6197
+ if ((name === "unref" || name === "ref") && call.arguments.length === 0) {
5922
6198
  const receiver = lowerer.lowerExpr(access.expression);
5923
- return { kind: "libCall", fn: "child.unref", args: [receiver], type: VOID, loc };
6199
+ return { kind: "libCall", fn: name === "ref" ? "child.ref" : "child.unref", args: [receiver], type: VOID, loc };
5924
6200
  }
5925
6201
  lowerer.noLowering(`ChildProcess.${name}`, call, "send(), connected, disconnect(), on/once(\"message\" | \"disconnect\" | \"exit\" | \"close\" | \"error\", cb), pid, exitCode, killed, kill(signal?), and unref() are supported", lowerer.checker.getSymbolAtLocation(access.name));
5926
6202
  }
@@ -6217,7 +6493,8 @@ export function lowerErrorCodeProperty(lowerer, expr) {
6217
6493
  return null;
6218
6494
  if (!lowerer.isStdlibMember(expr))
6219
6495
  return null;
6220
- const receiver = lowerer.lowerExpr(expr.expression);
6496
+ const rawReceiver = lowerer.lowerExpr(expr.expression);
6497
+ const receiver = rawReceiver.type.kind === "dyn" ? lowerer.coerceInto(expr.expression, rawReceiver, recvT) : rawReceiver;
6221
6498
  return {
6222
6499
  kind: "libCall",
6223
6500
  fn: expr.name.text === "stack" ? "error.stack" : expr.name.text === "cause" ? "error.cause" : "error.code",
@@ -6259,10 +6536,10 @@ export function lowerFsConstantsProperty(lowerer, expr) {
6259
6536
  const bi = lowerer.builtinImportOf(expr.expression);
6260
6537
  if (!bi || bi.module !== "fs" || bi.member !== "constants")
6261
6538
  return null;
6262
- const MODES = { F_OK: 0, X_OK: 1, W_OK: 2, R_OK: 4 };
6539
+ const MODES = { F_OK: 0, X_OK: 1, W_OK: 2, R_OK: 4, COPYFILE_EXCL: 1, COPYFILE_FICLONE: 2, COPYFILE_FICLONE_FORCE: 4 };
6263
6540
  const value = own(MODES, expr.name.text);
6264
6541
  if (value === undefined) {
6265
- lowerer.noLowering(`fs.constants.${expr.name.text}`, expr, "F_OK, R_OK, W_OK, and X_OK are the lowered constants");
6542
+ lowerer.noLowering(`fs.constants.${expr.name.text}`, expr, "F_OK, R_OK, W_OK, X_OK, and COPYFILE_* are the lowered constants");
6266
6543
  }
6267
6544
  return { kind: "numLit", value, type: F64, loc: locOf(expr) };
6268
6545
  }
@@ -6917,6 +7194,19 @@ export function lowerProcessEnvGet(lowerer, expr) {
6917
7194
  const key = { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) };
6918
7195
  return { kind: "libCall", fn: "process.envGet", args: [key], type: lowerer.envValueType(), loc };
6919
7196
  }
7197
+ function lowerProcessLoadEnvFile(lowerer, call) {
7198
+ if (call.arguments.length > 1 || call.arguments.some(ts.isSpreadElement)) {
7199
+ lowerer.noLowering("process.loadEnvFile with spread or extra arguments", call);
7200
+ }
7201
+ const loc = locOf(call);
7202
+ const path = call.arguments[0] ? lowerer.lowerExprExpecting(call.arguments[0], DYN)
7203
+ : { kind: "dynFrom", value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, type: DYN, loc };
7204
+ const load = { kind: "libCall", fn: "process.loadEnvFile", args: [path], type: VOID, loc };
7205
+ if (ts.isExpressionStatement(call.parent))
7206
+ return load;
7207
+ return { kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: load, loc }],
7208
+ result: { kind: "dynFrom", value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, type: DYN, loc }, type: DYN, loc };
7209
+ }
6920
7210
  /** `process.exit(code)` / `process.cwd()` → libCall. The fallback
6921
7211
  * declaration makes exit's code required; @types/node declares it
6922
7212
  * optional. A bare `process.exit()` uses the current exitCode, or zero
@@ -6934,6 +7224,8 @@ export function lowerProcessMethodCall(lowerer, call, access) {
6934
7224
  }
6935
7225
  }
6936
7226
  const directProcessMember = lowerer.stdlibGlobalMember(access, "process");
7227
+ if (directProcessMember === "loadEnvFile")
7228
+ return lowerProcessLoadEnvFile(lowerer, call);
6937
7229
  if (directProcessMember === "hrtime") {
6938
7230
  if (call.arguments.some(ts.isSpreadElement))
6939
7231
  lowerer.noLowering("process.hrtime with spread arguments", call);
@@ -7777,7 +8069,7 @@ export function lowerDateCall(lowerer, call, access) {
7777
8069
  export function lowerTextCodecNew(lowerer, ctor, cls) {
7778
8070
  const args = ctor.arguments ?? [];
7779
8071
  const loc = locOf(ctor);
7780
- let encoding = -1;
8072
+ let encoding = { kind: "numLit", value: -1, type: F64, loc };
7781
8073
  let label = null;
7782
8074
  if (cls === "TextEncoder") {
7783
8075
  if (args.length !== 0)
@@ -7786,17 +8078,39 @@ export function lowerTextCodecNew(lowerer, ctor, cls) {
7786
8078
  else if (args.length !== 0) {
7787
8079
  const labelT = lowerer.typeOf(args[0]);
7788
8080
  const parsed = labelT.isStringLiteralType() ? staticTextDecoderEncoding(labelT.value) : null;
7789
- if (args.length !== 1 || parsed === null) {
7790
- lowerer.noLowering("new TextDecoder with runtime-valued options or an unknown label", ctor, "a recognized literal WHATWG label with default options compiles");
8081
+ if (args.length > 2)
8082
+ lowerer.noLowering("new TextDecoder with extra arguments", ctor);
8083
+ if (parsed === null) {
8084
+ encoding = { kind: "libCall", fn: "text.decoderEncoding", args: [lowerer.lowerExprExpecting(args[0], DYN)], type: F64, loc };
8085
+ }
8086
+ else {
8087
+ encoding = { kind: "numLit", value: parsed.kind === "utf8" ? -1 : parsed.id, type: F64, loc };
8088
+ label = lowerer.lowerExprExpecting(args[0], STRING);
8089
+ }
8090
+ }
8091
+ const options = args[1] ? stripTypeCasts(args[1]) : null;
8092
+ const flags = new Map();
8093
+ for (const name of ["fatal", "ignoreBOM"])
8094
+ flags.set(name, { kind: "boolLit", value: false, type: BOOL, loc });
8095
+ if (options) {
8096
+ if (!ts.isObjectLiteralExpression(options))
8097
+ lowerer.noLowering("TextDecoder options outside an object literal", options);
8098
+ for (const property of options.properties) {
8099
+ if ((!ts.isPropertyAssignment(property) && !ts.isShorthandPropertyAssignment(property)) ||
8100
+ !ts.isIdentifier(property.name) || !flags.has(property.name.text))
8101
+ lowerer.noLowering("unknown TextDecoder option", property);
8102
+ const value = ts.isPropertyAssignment(property) ? property.initializer : property.name;
8103
+ flags.set(property.name.text, lowerer.lowerExprExpecting(value, BOOL));
7791
8104
  }
7792
- encoding = parsed.kind === "utf8" ? -1 : parsed.id;
7793
- label = lowerer.lowerExprExpecting(args[0], STRING);
7794
8105
  }
7795
8106
  const type = lowerer.mapTypeOf(lowerer.typeOf(ctor));
7796
8107
  if (type?.kind !== "record")
7797
8108
  lowerer.badType(ctor, lowerer.typeOf(ctor));
7798
8109
  const result = {
7799
- kind: "recordLit", fields: [{ name: `%${cls}`, value: { kind: "numLit", value: encoding, type: F64, loc } }], type, loc,
8110
+ kind: "recordLit", fields: [{ name: `%${cls}`, value: encoding }, ...(cls === "TextDecoder" ? [
8111
+ ...[...flags].map(([name, value]) => ({ name: `%${name}`, value })),
8112
+ { name: "%state", value: { kind: "dynObjLit", fields: [], type: DYN, loc } },
8113
+ ] : [])], type, loc,
7800
8114
  };
7801
8115
  return label === null || label.kind === "strLit" ? result : {
7802
8116
  kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: label, loc }], result, type, loc,
@@ -7814,17 +8128,32 @@ function lowerStoredTextCodecCall(lowerer, call, access) {
7814
8128
  return null;
7815
8129
  if (access.name.text !== (cls === "TextEncoder" ? "encode" : "decode"))
7816
8130
  return null;
7817
- if (call.arguments.length > 1) {
7818
- lowerer.noLowering(cls === "TextDecoder" ? "decode with a stream option" : "TextEncoder.encode with extra arguments", call);
8131
+ if (call.arguments.length > (cls === "TextDecoder" ? 2 : 1)) {
8132
+ lowerer.noLowering(`${cls}.${access.name.text} with extra arguments`, call);
7819
8133
  }
7820
8134
  const loc = locOf(call);
8135
+ let stream = { kind: "boolLit", value: false, type: BOOL, loc };
8136
+ if (cls === "TextDecoder" && call.arguments[1]) {
8137
+ const options = stripTypeCasts(call.arguments[1]);
8138
+ if (!ts.isObjectLiteralExpression(options))
8139
+ lowerer.noLowering("TextDecoder.decode options outside an object literal", options);
8140
+ for (const property of options.properties) {
8141
+ if ((!ts.isPropertyAssignment(property) && !ts.isShorthandPropertyAssignment(property)) ||
8142
+ !ts.isIdentifier(property.name) || property.name.text !== "stream")
8143
+ lowerer.noLowering("unknown TextDecoder.decode option", property);
8144
+ stream = lowerer.lowerExprExpecting(ts.isPropertyAssignment(property) ? property.initializer : property.name, BOOL);
8145
+ }
8146
+ }
7821
8147
  const receiver = lowerer.lowerExpr(access.expression);
7822
8148
  if (receiver.type.kind !== "record")
7823
8149
  lowerer.badType(access.expression, lowerer.typeOf(access.expression));
7824
- const arg = call.arguments.length === 0
8150
+ let arg = call.arguments.length === 0
7825
8151
  ? cls === "TextEncoder" ? strLit("", loc)
7826
8152
  : { kind: "bytesNew", source: null, type: BYTES_U8, loc }
7827
8153
  : cls === "TextEncoder" ? lowerer.lowerExprExpecting(call.arguments[0], STRING) : lowerer.lowerExpr(call.arguments[0]);
8154
+ if (cls === "TextDecoder" && (arg.type.kind === "dyn" || arg.type.kind === "bytes" && arg.type.elem !== "u8")) {
8155
+ arg = { kind: "libCall", fn: "bytes.bufferSource", args: [lowerer.coerceInto(call.arguments[0], arg, DYN)], type: BYTES_U8, loc };
8156
+ }
7828
8157
  if (cls === "TextDecoder" && !(arg.type.kind === "bytes" && arg.type.elem === "u8")) {
7829
8158
  lowerer.noLowering(`TextDecoder.decode of '${lowerer.fmt(arg.type)}' values`, call, "Uint8Array/Buffer input decodes (ArrayBuffer values have no representation)");
7830
8159
  }
@@ -7837,22 +8166,22 @@ function lowerStoredTextCodecCall(lowerer, call, access) {
7837
8166
  const input = varRef("input.0", arg.type, loc);
7838
8167
  const result = cls === "TextEncoder"
7839
8168
  ? { kind: "libCall", fn: "buffer.fromStr", args: [input, { kind: "strLit", value: "utf8", type: STRING, loc }], type: BYTES_U8, loc }
7840
- : {
7841
- kind: "ternary",
7842
- cond: { kind: "bin", op: "<", left: { kind: "recordGet", obj: varRef("codec.0", recT, loc), shapeId: recT.shapeId, field: "%TextDecoder", type: F64, loc }, right: { kind: "numLit", value: 0, type: F64, loc }, type: BOOL, loc },
7843
- then: { kind: "libCall", fn: "text.decode", args: [input], type: STRING, loc },
7844
- else_: { kind: "libCall", fn: "text.decodeLegacy", args: [input, { kind: "recordGet", obj: varRef("codec.0", recT, loc), shapeId: recT.shapeId, field: "%TextDecoder", type: F64, loc }], type: STRING, loc },
7845
- type: STRING, loc,
7846
- };
8169
+ : { kind: "libCall", fn: "text.decodeStream", args: [
8170
+ { kind: "recordGet", obj: varRef("codec.0", recT, loc), shapeId: recT.shapeId, field: "%state", type: DYN, loc },
8171
+ input,
8172
+ { kind: "recordGet", obj: varRef("codec.0", recT, loc), shapeId: recT.shapeId, field: "%TextDecoder", type: F64, loc },
8173
+ ...["%fatal", "%ignoreBOM"].map((field) => ({ kind: "recordGet", obj: varRef("codec.0", recT, loc), shapeId: recT.shapeId, field, type: BOOL, loc })),
8174
+ varRef("stream.0", BOOL, loc),
8175
+ ], type: STRING, loc };
7847
8176
  lowerer.liftedFns.push({
7848
8177
  name,
7849
- params: [{ localId: "codec.0", name: "codec", type: recT }, { localId: "input.0", name: "input", type: arg.type }],
8178
+ params: [{ localId: "codec.0", name: "codec", type: recT }, { localId: "input.0", name: "input", type: arg.type }, { localId: "stream.0", name: "stream", type: BOOL }],
7850
8179
  returnType: result.type,
7851
- locals: [{ id: "codec.0", name: "codec", type: recT, mutable: false }, { id: "input.0", name: "input", type: arg.type, mutable: false }],
8180
+ locals: [{ id: "codec.0", name: "codec", type: recT, mutable: false }, { id: "input.0", name: "input", type: arg.type, mutable: false }, { id: "stream.0", name: "stream", type: BOOL, mutable: false }],
7852
8181
  body: [{ kind: "return", value: result, loc }], loc,
7853
8182
  });
7854
8183
  }
7855
- return { kind: "call", callee: name, args: [receiver, arg], type: cls === "TextEncoder" ? BYTES_U8 : STRING, loc };
8184
+ return { kind: "call", callee: name, args: [receiver, arg, stream], type: cls === "TextEncoder" ? BYTES_U8 : STRING, loc };
7856
8185
  }
7857
8186
  /** A direct construction of THE stdlib TextEncoder/TextDecoder, through
7858
8187
  * type-only wrappers. Name alone is never enough: a user class with the
@@ -7885,6 +8214,18 @@ export function lowerTextCodecCall(lowerer, call, access) {
7885
8214
  if (call.questionDotToken || access.questionDotToken)
7886
8215
  return null;
7887
8216
  const member = access.name.text;
8217
+ if (member === "encodeInto" && storedTextCodecClassOf(lowerer, access.expression) === "TextEncoder" && lowerer.isStdlibMember(access)) {
8218
+ if (call.arguments.length !== 2 || call.arguments.some(ts.isSpreadElement))
8219
+ lowerer.noLowering("TextEncoder.encodeInto with this argument shape", call);
8220
+ const loc = locOf(call);
8221
+ const receiver = lowerer.lowerExpr(access.expression);
8222
+ const result = { kind: "libCall", fn: "text.encodeInto", args: call.arguments.map((arg) => lowerer.lowerExprExpecting(stripTypeCasts(arg), DYN)), type: DYN, loc };
8223
+ const type = lowerer.mapTypeOf(lowerer.typeOf(call));
8224
+ if (!type)
8225
+ lowerer.badType(call, lowerer.typeOf(call));
8226
+ const checked = lowerer.coerceInto(call, result, type);
8227
+ return { kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: receiver, loc }], result: checked, type, loc };
8228
+ }
7888
8229
  if (member !== "decode" && member !== "encode")
7889
8230
  return null;
7890
8231
  const info = directTextCodecCtorOf(lowerer, access.expression);
@@ -7893,6 +8234,8 @@ export function lowerTextCodecCall(lowerer, call, access) {
7893
8234
  if (!lowerer.isStdlibMember(access))
7894
8235
  return null;
7895
8236
  const { cls, ctor: recv } = info;
8237
+ if (cls === "TextDecoder" && ((recv.arguments?.length ?? 0) > 1 || call.arguments.length > 1))
8238
+ return lowerStoredTextCodecCall(lowerer, call, access);
7896
8239
  if (!(cls === "TextDecoder" && member === "decode") && !(cls === "TextEncoder" && member === "encode")) {
7897
8240
  return null;
7898
8241
  }
@@ -7909,7 +8252,7 @@ export function lowerTextCodecCall(lowerer, call, access) {
7909
8252
  ? staticTextDecoderEncoding(labelT.value)
7910
8253
  : null;
7911
8254
  if (ctorArgs.length > 1 || encoding === null) {
7912
- lowerer.noLowering("new TextDecoder with runtime-valued options or an unknown label", recv, "a recognized literal WHATWG label with default options compiles");
8255
+ return lowerStoredTextCodecCall(lowerer, call, access);
7913
8256
  }
7914
8257
  const labelEffect = ctorArgs.length === 1
7915
8258
  ? lowerer.lowerExprExpecting(ctorArgs[0], STRING)
@@ -7931,7 +8274,10 @@ export function lowerTextCodecCall(lowerer, call, access) {
7931
8274
  lowerer.noLowering("decode with a stream option", call, "streaming decode has no lowering — decode whole buffers");
7932
8275
  }
7933
8276
  const argNode = call.arguments[0];
7934
- const arg = lowerer.lowerExpr(argNode);
8277
+ let arg = lowerer.lowerExpr(argNode);
8278
+ if (arg.type.kind === "dyn" || arg.type.kind === "bytes" && arg.type.elem !== "u8") {
8279
+ arg = { kind: "libCall", fn: "bytes.bufferSource", args: [lowerer.coerceInto(argNode, arg, DYN)], type: BYTES_U8, loc };
8280
+ }
7935
8281
  if (!(arg.type.kind === "bytes" && arg.type.elem === "u8")) {
7936
8282
  lowerer.noLowering(`TextDecoder.decode of '${lowerer.fmt(arg.type)}' values`, argNode, "Uint8Array/Buffer input decodes (ArrayBuffer values have no representation)");
7937
8283
  }
@@ -8159,7 +8505,7 @@ export function lowerPromiseStaticCall(lowerer, call, access) {
8159
8505
  // reads are the routed keyed ops). All-static tuples keep the
8160
8506
  // typed fence hint below. --dynamic only by construction: jsval
8161
8507
  // entries exist only there.
8162
- if (elems.some((e) => e.type.kind === "jsval")) {
8508
+ if (lowerer.dynamic && elems.some((e) => e.type.kind === "jsval" || e.type.kind === "dyn")) {
8163
8509
  const diagsBefore = lowerer.diags.length;
8164
8510
  try {
8165
8511
  const marshaled = argNode.elements.map((el, i) => lowerer.jsvalIn(elems[i], el));
@@ -8183,16 +8529,21 @@ export function lowerPromiseStaticCall(lowerer, call, access) {
8183
8529
  lowerer.diags.splice(diagsBefore);
8184
8530
  }
8185
8531
  }
8532
+ if (!lowerer.dynamic && isJsSourceFile(call.getSourceFile()) && elems.every((entry) => lowerer.dynConvertible(entry.type))) {
8533
+ return checkedPromiseAll(lowerer, { kind: "arrayLit", elems: elems.map((entry) => lowerer.coerceToExpected(entry, DYN)), type: arrayOf(DYN), loc }, loc);
8534
+ }
8186
8535
  lowerer.noLowering("Promise.all over this argument shape", argNode, "the entries must share ONE promise type — Promise.all([p, q]) lowers when p and q are the same Promise<T>");
8187
8536
  }
8188
8537
  const entries = lowerer.lowerExpr(argNode);
8538
+ if (!lowerer.dynamic && isJsSourceFile(call.getSourceFile()) && entries.type.kind === "dyn")
8539
+ return checkedPromiseAll(lowerer, entries, loc);
8189
8540
  // A NON-literal island argument (`Promise.all(plugins.map((p) =>
8190
8541
  // loadPlugin(p)))` — the loadPlugins shape, where the checker
8191
8542
  // spells `any[]`): the ENGINE's own Promise.all runs over the
8192
8543
  // marshaled array (an 'any' value passes through; an `any[]` value
8193
8544
  // lifts per element by reference), the result staying an island
8194
8545
  // value the static side awaits through the island→static bridge.
8195
- if (entries.type.kind === "jsval" ||
8546
+ if (entries.type.kind === "jsval" || lowerer.dynamic && entries.type.kind === "dyn" ||
8196
8547
  (entries.type.kind === "array" && entries.type.elem.kind === "jsval")) {
8197
8548
  const diagsBefore = lowerer.diags.length;
8198
8549
  try {
@@ -8368,11 +8719,12 @@ export function lowerPromiseStaticCall(lowerer, call, access) {
8368
8719
  return { kind: "intrinsic", name: "promise.resolve", args: [], type: { kind: "promise", inner: VOID }, loc };
8369
8720
  }
8370
8721
  if (resultT.inner.kind === "void") {
8371
- // Promise.resolve(expr) at a void-promise type: the argument's
8372
- // effects must still run — no statement slot exists here for
8373
- // them, so only effect-free spellings could drop it honestly;
8374
- // fence rather than model that corner.
8375
- lowerer.noLowering("Promise.resolve with an argument at a void-promise type", call);
8722
+ return {
8723
+ kind: "seqExpr",
8724
+ stmts: [lowerer.lowerExprStatement(argNode)],
8725
+ result: { kind: "intrinsic", name: "promise.resolve", args: [], type: resultT, loc },
8726
+ type: resultT, loc,
8727
+ };
8376
8728
  }
8377
8729
  if (isUnitType(resultT.inner)) {
8378
8730
  // A unit payload (Promise<undefined>/Promise<null>) has no
@@ -8392,6 +8744,9 @@ export function lowerNumberStaticProperty(lowerer, expr) {
8392
8744
  const member = lowerer.stdlibGlobalMember(expr, "Number");
8393
8745
  if (member === null)
8394
8746
  return null;
8747
+ const predicate = own(NUMBER_STATIC_PREDICATES, member);
8748
+ if (predicate)
8749
+ return lowerCheckedPredicateValue(lowerer, `Number.${member}`, "number", locOf(expr), predicate);
8395
8750
  const value = own(NUMBER_CONSTANTS, member);
8396
8751
  if (value === undefined)
8397
8752
  return null;