@scriptc/compiler 0.2.1 → 0.2.3

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 (315) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +158 -31
  2. package/dist/backend/cycle-analysis.js +63 -50
  3. package/dist/backend/cycle-analysis.js.map +1 -1
  4. package/dist/backend/cycle-analysis.test.js +51 -0
  5. package/dist/backend/cycle-analysis.test.js.map +1 -1
  6. package/dist/backend/llvm/borrowed-receivers.d.ts +9 -0
  7. package/dist/backend/llvm/borrowed-receivers.js +58 -0
  8. package/dist/backend/llvm/borrowed-receivers.js.map +1 -0
  9. package/dist/backend/llvm/call-lifetimes.d.ts +20 -0
  10. package/dist/backend/llvm/call-lifetimes.js +179 -0
  11. package/dist/backend/llvm/call-lifetimes.js.map +1 -0
  12. package/dist/backend/llvm/call-lifetimes.test.d.ts +1 -0
  13. package/dist/backend/llvm/call-lifetimes.test.js +205 -0
  14. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -0
  15. package/dist/backend/llvm/dyn.d.ts +5 -2
  16. package/dist/backend/llvm/dyn.js +163 -47
  17. package/dist/backend/llvm/dyn.js.map +1 -1
  18. package/dist/backend/llvm/emitter.d.ts +37 -1
  19. package/dist/backend/llvm/emitter.js +209 -21
  20. package/dist/backend/llvm/emitter.js.map +1 -1
  21. package/dist/backend/llvm/emitter.test.js +29 -2
  22. package/dist/backend/llvm/emitter.test.js.map +1 -1
  23. package/dist/backend/llvm/expr-async.js +1 -1
  24. package/dist/backend/llvm/expr-async.js.map +1 -1
  25. package/dist/backend/llvm/expr-calls.js +42 -5
  26. package/dist/backend/llvm/expr-calls.js.map +1 -1
  27. package/dist/backend/llvm/expr-containers.js +75 -13
  28. package/dist/backend/llvm/expr-containers.js.map +1 -1
  29. package/dist/backend/llvm/expr-dynamic.js +31 -6
  30. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  31. package/dist/backend/llvm/expr-primitives.js +6 -5
  32. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  33. package/dist/backend/llvm/expr-records.js +1 -1
  34. package/dist/backend/llvm/expr-records.js.map +1 -1
  35. package/dist/backend/llvm/expr-stream-bridges.js +75 -19
  36. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  37. package/dist/backend/llvm/expr-stream-callbacks.d.ts +2 -2
  38. package/dist/backend/llvm/expr-stream-callbacks.js +7 -57
  39. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  40. package/dist/backend/llvm/lib-dispatch.js +41 -3
  41. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  42. package/dist/backend/llvm/lib-filesystem.js +12 -9
  43. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  44. package/dist/backend/llvm/lib-shared.js +70 -2
  45. package/dist/backend/llvm/lib-shared.js.map +1 -1
  46. package/dist/backend/llvm/local-array-reads.d.ts +44 -0
  47. package/dist/backend/llvm/local-array-reads.js +313 -0
  48. package/dist/backend/llvm/local-array-reads.js.map +1 -0
  49. package/dist/backend/llvm/local-array-reads.test.d.ts +1 -0
  50. package/dist/backend/llvm/local-array-reads.test.js +446 -0
  51. package/dist/backend/llvm/local-array-reads.test.js.map +1 -0
  52. package/dist/backend/llvm/map-read-lifetimes.d.ts +36 -0
  53. package/dist/backend/llvm/map-read-lifetimes.js +128 -0
  54. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -0
  55. package/dist/backend/llvm/map-read-lifetimes.test.d.ts +1 -0
  56. package/dist/backend/llvm/map-read-lifetimes.test.js +123 -0
  57. package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -0
  58. package/dist/backend/llvm/shapes.js +1 -0
  59. package/dist/backend/llvm/shapes.js.map +1 -1
  60. package/dist/backend/llvm/split.js +15 -5
  61. package/dist/backend/llvm/split.js.map +1 -1
  62. package/dist/backend/llvm/split.test.js +17 -0
  63. package/dist/backend/llvm/split.test.js.map +1 -1
  64. package/dist/backend/llvm/stack-unions.d.ts +20 -0
  65. package/dist/backend/llvm/stack-unions.js +61 -0
  66. package/dist/backend/llvm/stack-unions.js.map +1 -0
  67. package/dist/backend/llvm/stack-unions.test.d.ts +1 -0
  68. package/dist/backend/llvm/stack-unions.test.js +241 -0
  69. package/dist/backend/llvm/stack-unions.test.js.map +1 -0
  70. package/dist/backend/llvm/string-lifetimes.d.ts +12 -0
  71. package/dist/backend/llvm/string-lifetimes.js +70 -0
  72. package/dist/backend/llvm/string-lifetimes.js.map +1 -0
  73. package/dist/backend/llvm/string-lifetimes.test.d.ts +1 -0
  74. package/dist/backend/llvm/string-lifetimes.test.js +230 -0
  75. package/dist/backend/llvm/string-lifetimes.test.js.map +1 -0
  76. package/dist/backend/mangle.d.ts +2 -0
  77. package/dist/backend/mangle.js +4 -0
  78. package/dist/backend/mangle.js.map +1 -1
  79. package/dist/backend/may-throw.js +71 -29
  80. package/dist/backend/may-throw.js.map +1 -1
  81. package/dist/backend/may-throw.test.js +104 -1
  82. package/dist/backend/may-throw.test.js.map +1 -1
  83. package/dist/backend/native-codegen.d.ts +1 -1
  84. package/dist/backend/native-codegen.js +4 -3
  85. package/dist/backend/native-codegen.js.map +1 -1
  86. package/dist/backend/native-codegen.test.js +11 -0
  87. package/dist/backend/native-codegen.test.js.map +1 -1
  88. package/dist/backend/native-toolchain.d.ts +2 -2
  89. package/dist/backend/native-toolchain.js +2 -0
  90. package/dist/backend/native-toolchain.js.map +1 -1
  91. package/dist/backend/target-diagnostics.d.ts +5 -0
  92. package/dist/backend/target-diagnostics.js +72 -1
  93. package/dist/backend/target-diagnostics.js.map +1 -1
  94. package/dist/backend/target-diagnostics.test.d.ts +1 -0
  95. package/dist/backend/target-diagnostics.test.js +68 -0
  96. package/dist/backend/target-diagnostics.test.js.map +1 -0
  97. package/dist/coverage/surface-manifest.js +5 -3
  98. package/dist/coverage/surface-manifest.js.map +1 -1
  99. package/dist/executable/executable-cache.d.ts +7 -3
  100. package/dist/executable/executable-cache.js +47 -11
  101. package/dist/executable/executable-cache.js.map +1 -1
  102. package/dist/executable/executable-cache.test.js +109 -2
  103. package/dist/executable/executable-cache.test.js.map +1 -1
  104. package/dist/executable/prepare.js +2 -1
  105. package/dist/executable/prepare.js.map +1 -1
  106. package/dist/frontend/builtin-modules.d.ts +1 -1
  107. package/dist/frontend/builtin-modules.js +1 -1
  108. package/dist/frontend/builtin-modules.js.map +1 -1
  109. package/dist/frontend/function-completion.d.ts +6 -0
  110. package/dist/frontend/function-completion.js +50 -0
  111. package/dist/frontend/function-completion.js.map +1 -0
  112. package/dist/frontend/input-tracker.js +3 -3
  113. package/dist/frontend/input-tracker.js.map +1 -1
  114. package/dist/frontend/input-tracker.test.js +38 -2
  115. package/dist/frontend/input-tracker.test.js.map +1 -1
  116. package/dist/frontend/lowering/abstract-equality.js +5 -1
  117. package/dist/frontend/lowering/abstract-equality.js.map +1 -1
  118. package/dist/frontend/lowering/checked-iterable-spread.d.ts +4 -0
  119. package/dist/frontend/lowering/checked-iterable-spread.js +30 -0
  120. package/dist/frontend/lowering/checked-iterable-spread.js.map +1 -0
  121. package/dist/frontend/lowering/checked-promise-all.d.ts +5 -0
  122. package/dist/frontend/lowering/checked-promise-all.js +31 -0
  123. package/dist/frontend/lowering/checked-promise-all.js.map +1 -0
  124. package/dist/frontend/lowering/class-callbacks.d.ts +1 -1
  125. package/dist/frontend/lowering/class-callbacks.js +7 -6
  126. package/dist/frontend/lowering/class-callbacks.js.map +1 -1
  127. package/dist/frontend/lowering/class-construction.d.ts +2 -0
  128. package/dist/frontend/lowering/class-construction.js +34 -5
  129. package/dist/frontend/lowering/class-construction.js.map +1 -1
  130. package/dist/frontend/lowering/class-descriptors.d.ts +1 -1
  131. package/dist/frontend/lowering/class-descriptors.js +12 -5
  132. package/dist/frontend/lowering/class-descriptors.js.map +1 -1
  133. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +25 -0
  134. package/dist/frontend/lowering/class-dynamic-dispatch.js +597 -78
  135. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  136. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +64 -2
  137. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  138. package/dist/frontend/lowering/class-instance-constructor.d.ts +1 -1
  139. package/dist/frontend/lowering/class-instance-constructor.js +11 -41
  140. package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
  141. package/dist/frontend/lowering/class-method-values.d.ts +16 -0
  142. package/dist/frontend/lowering/class-method-values.js +60 -29
  143. package/dist/frontend/lowering/class-method-values.js.map +1 -1
  144. package/dist/frontend/lowering/class-prototypes.d.ts +5 -1
  145. package/dist/frontend/lowering/class-prototypes.js +69 -10
  146. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  147. package/dist/frontend/lowering/class-runtime-statics.d.ts +4 -4
  148. package/dist/frontend/lowering/class-runtime-statics.js +26 -8
  149. package/dist/frontend/lowering/class-runtime-statics.js.map +1 -1
  150. package/dist/frontend/lowering/class-static-data.d.ts +1 -0
  151. package/dist/frontend/lowering/class-static-data.js +4 -2
  152. package/dist/frontend/lowering/class-static-data.js.map +1 -1
  153. package/dist/frontend/lowering/collection-ingestion.d.ts +31 -0
  154. package/dist/frontend/lowering/collection-ingestion.js +215 -0
  155. package/dist/frontend/lowering/collection-ingestion.js.map +1 -0
  156. package/dist/frontend/lowering/containers/bytes.js +19 -4
  157. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  158. package/dist/frontend/lowering/containers/string-and-regexp.js +6 -1
  159. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  160. package/dist/frontend/lowering/deferred-module-initializers.d.ts +13 -0
  161. package/dist/frontend/lowering/deferred-module-initializers.js +410 -0
  162. package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -0
  163. package/dist/frontend/lowering/deferred-module-initializers.test.d.ts +1 -0
  164. package/dist/frontend/lowering/deferred-module-initializers.test.js +92 -0
  165. package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -0
  166. package/dist/frontend/lowering/expressions/object-literals.js +31 -1
  167. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  168. package/dist/frontend/lowering/expressions/optional-chains.js +3 -3
  169. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  170. package/dist/frontend/lowering/import-meta.d.ts +10 -0
  171. package/dist/frontend/lowering/import-meta.js +52 -0
  172. package/dist/frontend/lowering/import-meta.js.map +1 -0
  173. package/dist/frontend/lowering/lower-assert.js +105 -41
  174. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  175. package/dist/frontend/lowering/lower-builtin-values.d.ts +2 -0
  176. package/dist/frontend/lowering/lower-builtin-values.js +22 -1
  177. package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
  178. package/dist/frontend/lowering/lower-builtins.d.ts +7 -22
  179. package/dist/frontend/lowering/lower-builtins.js +439 -95
  180. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  181. package/dist/frontend/lowering/lower-calls.js +289 -76
  182. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  183. package/dist/frontend/lowering/lower-classes.d.ts +5 -0
  184. package/dist/frontend/lowering/lower-classes.js +443 -29
  185. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  186. package/dist/frontend/lowering/lower-containers.d.ts +6 -2
  187. package/dist/frontend/lowering/lower-containers.js +79 -20
  188. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  189. package/dist/frontend/lowering/lower-exprs.d.ts +10 -6
  190. package/dist/frontend/lowering/lower-exprs.js +329 -170
  191. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  192. package/dist/frontend/lowering/lower-generators.js +5 -1
  193. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  194. package/dist/frontend/lowering/lower-inspect.js +58 -1
  195. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  196. package/dist/frontend/lowering/lower-island.js +4 -0
  197. package/dist/frontend/lowering/lower-island.js.map +1 -1
  198. package/dist/frontend/lowering/lower-island.test.d.ts +1 -0
  199. package/dist/frontend/lowering/lower-island.test.js +51 -0
  200. package/dist/frontend/lowering/lower-island.test.js.map +1 -0
  201. package/dist/frontend/lowering/lower-modules.d.ts +1 -3
  202. package/dist/frontend/lowering/lower-modules.js +186 -82
  203. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  204. package/dist/frontend/lowering/lower-modules.test.js +69 -1
  205. package/dist/frontend/lowering/lower-modules.test.js.map +1 -1
  206. package/dist/frontend/lowering/lower-stmts.js +172 -103
  207. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  208. package/dist/frontend/lowering/lower-stmts.test.d.ts +1 -0
  209. package/dist/frontend/lowering/lower-stmts.test.js +77 -0
  210. package/dist/frontend/lowering/lower-stmts.test.js.map +1 -0
  211. package/dist/frontend/lowering/lower-stream.js +2 -0
  212. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  213. package/dist/frontend/lowering/lower-system-errors.d.ts +6 -0
  214. package/dist/frontend/lowering/lower-system-errors.js +29 -0
  215. package/dist/frontend/lowering/lower-system-errors.js.map +1 -0
  216. package/dist/frontend/lowering/lower-url.d.ts +2 -1
  217. package/dist/frontend/lowering/lower-url.js +32 -9
  218. package/dist/frontend/lowering/lower-url.js.map +1 -1
  219. package/dist/frontend/lowering/lowerer.d.ts +30 -12
  220. package/dist/frontend/lowering/lowerer.js +268 -49
  221. package/dist/frontend/lowering/lowerer.js.map +1 -1
  222. package/dist/frontend/lowering/lowerer.test.js +38 -0
  223. package/dist/frontend/lowering/lowerer.test.js.map +1 -1
  224. package/dist/frontend/lowering/module-namespace-elements.d.ts +7 -0
  225. package/dist/frontend/lowering/module-namespace-elements.js +54 -0
  226. package/dist/frontend/lowering/module-namespace-elements.js.map +1 -0
  227. package/dist/frontend/lowering/object-factory-new.d.ts +4 -3
  228. package/dist/frontend/lowering/object-factory-new.js +27 -14
  229. package/dist/frontend/lowering/object-factory-new.js.map +1 -1
  230. package/dist/frontend/lowering/surfaces.d.ts +3 -2
  231. package/dist/frontend/lowering/surfaces.js +93 -33
  232. package/dist/frontend/lowering/surfaces.js.map +1 -1
  233. package/dist/frontend/lowering/text-decoder-encoding.js +3 -0
  234. package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -1
  235. package/dist/frontend/lowering/text-decoder-encoding.test.js +2 -1
  236. package/dist/frontend/lowering/text-decoder-encoding.test.js.map +1 -1
  237. package/dist/frontend/module-syntax.d.ts +1 -1
  238. package/dist/frontend/module-syntax.js +8 -1
  239. package/dist/frontend/module-syntax.js.map +1 -1
  240. package/dist/frontend/module-syntax.test.js +10 -0
  241. package/dist/frontend/module-syntax.test.js.map +1 -1
  242. package/dist/frontend/npm.d.ts +4 -0
  243. package/dist/frontend/npm.js +86 -33
  244. package/dist/frontend/npm.js.map +1 -1
  245. package/dist/frontend/npm.test.js +103 -0
  246. package/dist/frontend/npm.test.js.map +1 -1
  247. package/dist/frontend/pipeline-native.js +2 -1
  248. package/dist/frontend/pipeline-native.js.map +1 -1
  249. package/dist/frontend/program.js +4 -2
  250. package/dist/frontend/program.js.map +1 -1
  251. package/dist/frontend/services-node.js +3 -2
  252. package/dist/frontend/services-node.js.map +1 -1
  253. package/dist/frontend/services.d.ts +5 -1
  254. package/dist/frontend/services.js +9 -1
  255. package/dist/frontend/services.js.map +1 -1
  256. package/dist/frontend/services.test.js +21 -0
  257. package/dist/frontend/services.test.js.map +1 -1
  258. package/dist/frontend/ts7/ast-node.d.ts +2 -0
  259. package/dist/frontend/ts7/ast-node.js +30 -4
  260. package/dist/frontend/ts7/ast-node.js.map +1 -1
  261. package/dist/frontend/ts7/ast-node.test.js +60 -1
  262. package/dist/frontend/ts7/ast-node.test.js.map +1 -1
  263. package/dist/frontend/type-mapper.js +89 -14
  264. package/dist/frontend/type-mapper.js.map +1 -1
  265. package/dist/frontend/union-discriminants.js +22 -7
  266. package/dist/frontend/union-discriminants.js.map +1 -1
  267. package/dist/index.js +19 -12
  268. package/dist/index.js.map +1 -1
  269. package/dist/ir/analysis.js +1 -0
  270. package/dist/ir/analysis.js.map +1 -1
  271. package/dist/ir/integer-loops.d.ts +7 -0
  272. package/dist/ir/integer-loops.js +23 -0
  273. package/dist/ir/integer-loops.js.map +1 -1
  274. package/dist/ir/integer-loops.test.d.ts +1 -0
  275. package/dist/ir/integer-loops.test.js +41 -0
  276. package/dist/ir/integer-loops.test.js.map +1 -0
  277. package/dist/ir/ir.d.ts +44 -26
  278. package/dist/ir/ir.js +69 -11
  279. package/dist/ir/ir.js.map +1 -1
  280. package/dist/ir/ir.test.js +18 -0
  281. package/dist/ir/ir.test.js.map +1 -1
  282. package/dist/ir/serialize.js +21 -1
  283. package/dist/ir/serialize.js.map +1 -1
  284. package/dist/ir/serialize.test.js +21 -0
  285. package/dist/ir/serialize.test.js.map +1 -1
  286. package/dist/ir/traverse.d.ts +0 -3
  287. package/dist/ir/traverse.js +33 -20
  288. package/dist/ir/traverse.js.map +1 -1
  289. package/dist/ir/validate.js +216 -80
  290. package/dist/ir/validate.js.map +1 -1
  291. package/dist/ir/validate.test.js +244 -1
  292. package/dist/ir/validate.test.js.map +1 -1
  293. package/dist/library/compiler-self-identity.js +1 -1
  294. package/dist/library/compiler-self-identity.test.js +2 -2
  295. package/dist/library/compiler-self-identity.test.js.map +1 -1
  296. package/dist/library/fence-eval.js +9 -2
  297. package/dist/library/fence-eval.js.map +1 -1
  298. package/dist/library/fence-eval.test.d.ts +1 -0
  299. package/dist/library/fence-eval.test.js +21 -0
  300. package/dist/library/fence-eval.test.js.map +1 -0
  301. package/dist/library/int-infer.d.ts +2 -2
  302. package/dist/library/int-infer.js +10 -7
  303. package/dist/library/int-infer.js.map +1 -1
  304. package/dist/library/int-infer.test.js +44 -0
  305. package/dist/library/int-infer.test.js.map +1 -1
  306. package/dist/library/prepare.js +2 -1
  307. package/dist/library/prepare.js.map +1 -1
  308. package/dist/native/runtime-typescript.d.ts +4 -0
  309. package/dist/native/runtime-typescript.js +61 -0
  310. package/dist/native/runtime-typescript.js.map +1 -0
  311. package/dist/native/runtime-typescript.test.d.ts +1 -0
  312. package/dist/native/runtime-typescript.test.js +41 -0
  313. package/dist/native/runtime-typescript.test.js.map +1 -0
  314. package/package.json +20 -20
  315. package/surface-manifest.json +385 -29
@@ -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
@@ -20,6 +21,7 @@ import { builtinModuleFnOf, FS_READDIR_DOCUMENTED_OPTIONS, FS_WATCH_DOCUMENTED_O
20
21
  import { lowerAbsenceProbe } from "./lower-exprs.js";
21
22
  import { conditionalSpreadOf, lowerDynObjectLiteral } from "./expressions/object-literals.js";
22
23
  import { isSafeToDiscard } from "./expressions/evaluation-safety.js";
24
+ import { tryLowerExpression } from "./expressions/try-lower-expression.js";
23
25
  import { defaultAfterUndefined, lowerOptionalArgument, lowerStaticallyUndefinedArgument, lowerStringSearchArgument } from "./optional-arguments.js";
24
26
  import { HTTP2_CONSTANTS } from "./http2-constants.js";
25
27
  import { CRYPTO_CIPHERS, CRYPTO_CONSTANTS, CRYPTO_CURVES, CRYPTO_HASHES } from "./crypto-tables.js";
@@ -44,6 +46,67 @@ function optionalStringTags(lowerer, type) {
44
46
  const undefinedTag = lowerer.armTag(type.unionId, UNDEFINED_T);
45
47
  return stringTag >= 0 && undefinedTag >= 0 ? { stringTag, undefinedTag } : null;
46
48
  }
49
+ /** URL component assignment captures its receiver and RHS once, and yields
50
+ * the original RHS after the setter performs string conversion. */
51
+ export function lowerUrlAssignment(lowerer, expr) {
52
+ let target = expr.left;
53
+ while (ts.isParenthesizedExpression(target))
54
+ target = target.expression;
55
+ if ((!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) || target.questionDotToken)
56
+ return null;
57
+ const receiverType = lowerer.typeOf(target.expression);
58
+ const native = lowerer.mapTypeOf(receiverType)?.kind === "url";
59
+ if (!native && !(receiverType.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)))
60
+ return null;
61
+ const receiver = native ? lowerer.lowerExpr(target.expression) : tryLowerExpression(lowerer, target.expression);
62
+ if (!receiver || receiver.type.kind !== "url")
63
+ return null;
64
+ const name = ts.isPropertyAccessExpression(target) ? target.name.text : lowerer.foldedStringKeyOf(target.argumentExpression);
65
+ const getters = {
66
+ href: "url.href", pathname: "url.pathname", search: "url.search", hash: "url.hash",
67
+ protocol: "url.protocol", username: "url.username", password: "url.password",
68
+ host: "url.host", hostname: "url.hostname", port: "url.port",
69
+ };
70
+ if (name === null || name === undefined || !Object.hasOwn(getters, name)) {
71
+ lowerer.unsupported("SC1090", target, "URL assignments to read-only members or runtime property keys");
72
+ }
73
+ const op = expr.operatorToken.kind;
74
+ if (op !== ts.SyntaxKind.EqualsToken && op !== ts.SyntaxKind.PlusEqualsToken) {
75
+ lowerer.unsupported("SC1090", expr, "URL setter assignment operators beyond = and +=");
76
+ }
77
+ const loc = locOf(expr);
78
+ const recv = lowerer.declareHiddenLocal("%urlReceiver", receiver.type);
79
+ const recvRef = varRef(recv.id, receiver.type, loc);
80
+ const stmts = [{ kind: "varDecl", localId: recv.id, init: receiver, loc }];
81
+ let prior = null;
82
+ if (op === ts.SyntaxKind.PlusEqualsToken) {
83
+ const old = lowerer.declareHiddenLocal("%urlOld", STRING);
84
+ const fn = getters[name];
85
+ stmts.push({ kind: "varDecl", localId: old.id, init: { kind: "libCall", fn, args: [recvRef], type: STRING, loc }, loc });
86
+ prior = varRef(old.id, STRING, loc);
87
+ }
88
+ const raw = lowerer.lowerExpr(expr.right);
89
+ if (prior && raw.type.kind !== "string" && raw.type.kind !== "f64" && raw.type.kind !== "bool" && raw.type.kind !== "bigint" && !isUnitType(raw.type)) {
90
+ lowerer.unsupported("SC1090", expr.right, "URL += operands requiring object-to-primitive conversion (assign an explicit string)");
91
+ }
92
+ const value = lowerer.declareHiddenLocal("%urlValue", raw.type);
93
+ stmts.push({ kind: "varDecl", localId: value.id, init: raw, loc });
94
+ const valueRef = varRef(value.id, raw.type, loc);
95
+ let result = valueRef;
96
+ let assigned = valueRef;
97
+ if (prior) {
98
+ const text = raw.type.kind === "string" ? valueRef : {
99
+ kind: "libCall", fn: "dyn.toStringCoerce", args: [lowerer.coerceInto(expr.right, valueRef, DYN)], type: STRING, loc,
100
+ };
101
+ const joined = lowerer.declareHiddenLocal("%urlJoined", STRING);
102
+ stmts.push({ kind: "varDecl", localId: joined.id, init: { kind: "strConcat", left: prior, right: text, type: STRING, loc }, loc });
103
+ result = varRef(joined.id, STRING, loc);
104
+ assigned = result;
105
+ }
106
+ const checked = !prior && raw.type.kind !== "string";
107
+ stmts.push({ kind: "exprStmt", expr: { kind: "libCall", fn: checked ? "url.setChecked" : "url.set", args: [recvRef, strLit(name, loc), checked ? lowerer.coerceInto(expr.right, valueRef, DYN) : assigned], type: VOID, loc }, loc });
108
+ return { kind: "seqExpr", stmts, result, type: result.type, loc };
109
+ }
47
110
  /** timers/promises.setInterval(delay, value), the first Node API built on
48
111
  * the generic async-generator protocol. The supported form has an explicit
49
112
  * value and no AbortSignal options. It lowers to a generated typed async
@@ -1140,17 +1203,26 @@ function lowerFsSyncBufferWindow(lowerer, expr, loc, fn, source, supported) {
1140
1203
  * Node's exact ERR_INVALID_ARG_TYPE. The argument crosses as a dyn
1141
1204
  * value so the runtime renders the Received tail. Null when this is
1142
1205
  * not that call (the table fence stays for other shapes). */
1206
+ function lowerFsTimestampValue(lowerer, node, loc) {
1207
+ if (!node)
1208
+ return dynUndefinedExpr(loc);
1209
+ const box = (value) => {
1210
+ if (value.type.kind === "date") {
1211
+ const milliseconds = { kind: "libCall", fn: "date.getTime", args: [value], type: F64, loc };
1212
+ return { kind: "libCall", fn: "date.nativeNew", args: [{ kind: "dynArrLit", elems: [
1213
+ { kind: "dynFrom", value: milliseconds, type: DYN, loc },
1214
+ ], type: DYN, loc }], type: DYN, loc };
1215
+ }
1216
+ return lowerer.coerceInto(node, value, DYN);
1217
+ };
1218
+ return box(lowerer.lowerExpr(node));
1219
+ }
1143
1220
  export function lowerFsToUnixTimestampCall(lowerer, expr, bi, loc) {
1144
1221
  if (bi.module !== "fs" || bi.member !== "_toUnixTimestamp")
1145
1222
  return null;
1146
1223
  if (expr.arguments.length !== 1 || ts.isSpreadElement(expr.arguments[0]))
1147
1224
  return null;
1148
- const raw = lowerer.lowerExpr(expr.arguments[0]);
1149
- if (raw.type.kind === "dyn" || raw.kind === "unitLit" || lowerer.dynConvertible(raw.type)) {
1150
- const arg = raw.type.kind === "dyn" ? raw : { kind: "dynFrom", value: raw, type: DYN, loc };
1151
- return { kind: "libCall", fn: "fs.toUnixTimestamp", args: [arg], type: F64, loc };
1152
- }
1153
- return null;
1225
+ return { kind: "libCall", fn: "fs.toUnixTimestamp", args: [lowerFsTimestampValue(lowerer, expr.arguments[0], loc)], type: F64, loc };
1154
1226
  }
1155
1227
  /** The fs validation-ladder spoke (checked-dynamic lane, JS sources
1156
1228
  * only — TypeScript keeps its compile fences): implemented-namespace
@@ -1414,12 +1486,76 @@ function lowerZlibModuleCall(lowerer, expr, bi, loc) {
1414
1486
  }
1415
1487
  export function lowerBuiltinModuleCall(lowerer, expr, bi, fn, loc) {
1416
1488
  const name = expr.expression.getText();
1489
+ if (bi.module === "util/types") {
1490
+ if (expr.arguments.some(ts.isSpreadElement))
1491
+ lowerer.noLowering(`${name} with spread arguments`, expr);
1492
+ const input = expr.arguments[0] ? lowerer.lowerExprExpecting(expr.arguments[0], DYN) : dynUndefinedExpr(loc);
1493
+ const saved = lowerer.declareHiddenLocal("%utilTypeInput", DYN);
1494
+ return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: saved.id, init: input, loc },
1495
+ ...expr.arguments.slice(1).map((arg) => ({ kind: "exprStmt", expr: lowerer.lowerExpr(arg), loc }))],
1496
+ result: { kind: "libCall", fn: "util.typeIs", args: [varRef(saved.id, DYN, loc), strLit(bi.member, loc)], type: BOOL, loc }, type: BOOL, loc };
1497
+ }
1498
+ if (bi.module === "process" && bi.member === "loadEnvFile")
1499
+ return lowerProcessLoadEnvFile(lowerer, expr);
1500
+ if (bi.module === "buffer" && ["isAscii", "isUtf8", "transcode"].includes(bi.member)) {
1501
+ if (expr.arguments.some(ts.isSpreadElement))
1502
+ lowerer.noLowering("buffer encoding call with spread arguments", expr);
1503
+ const arity = bi.member === "transcode" ? 3 : 1;
1504
+ const args = Array.from({ length: arity }, (_, index) => expr.arguments[index]
1505
+ ? lowerer.lowerExprExpecting(stripTypeCasts(expr.arguments[index]), DYN) : dynUndefinedExpr(loc));
1506
+ if (expr.arguments.length > arity)
1507
+ lowerer.noLowering("buffer encoding call with extra arguments", expr);
1508
+ return { kind: "libCall", fn: fn.fn, args, type: fn.result, loc };
1509
+ }
1417
1510
  if (fn.fn === "fs.callbackCall" && bi.member !== "rename") {
1418
1511
  if (expr.arguments.some(ts.isSpreadElement))
1419
1512
  lowerer.noLowering("filesystem callback call with spread arguments", expr);
1420
- const args = { kind: "dynArrLit", elems: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
1513
+ const timestamp = ["utimes", "futimes", "lutimes"].includes(bi.member);
1514
+ const args = { kind: "dynArrLit", elems: expr.arguments.map((arg, index) => timestamp && (index === 1 || index === 2)
1515
+ ? lowerFsTimestampValue(lowerer, arg, loc) : lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
1421
1516
  return { kind: "libCall", fn: "fs.callbackCall", args: [{ kind: "strLit", value: bi.member, type: STRING, loc }, args], type: DYN, loc };
1422
1517
  }
1518
+ if ((bi.module === "fs" && ["linkSync", "symlinkSync", "readlinkSync", "statfsSync"].includes(bi.member)) ||
1519
+ (bi.module === "fs/promises" && ["link", "symlink", "readlink", "statfs"].includes(bi.member))) {
1520
+ const symbolic = bi.member === "symlinkSync" || bi.member === "symlink";
1521
+ const reading = bi.member === "readlinkSync" || bi.member === "readlink";
1522
+ const arity = symbolic ? 3 : 2;
1523
+ if (expr.arguments.length > arity || expr.arguments.some(ts.isSpreadElement))
1524
+ lowerer.noLowering(`${name} with this argument shape`, expr);
1525
+ const args = Array.from({ length: arity }, (_, index) => expr.arguments[index]
1526
+ ? lowerer.lowerExprExpecting(expr.arguments[index], DYN) : dynUndefinedExpr(loc));
1527
+ if (reading) {
1528
+ const promise = bi.module === "fs/promises";
1529
+ const result = lowerer.mapTypeOf(lowerer.typeOf(expr)) ?? fn.result;
1530
+ const inner = result.kind === "promise" ? result.inner : result;
1531
+ const bytes = inner.kind === "bytes";
1532
+ const text = inner.kind === "string";
1533
+ const selected = promise ? bytes ? "fsp.readlinkBuffer" : text ? "fsp.readlinkStr" : "fsp.readlink"
1534
+ : bytes ? "fs.readlinkSyncBuffer" : text ? "fs.readlinkSyncStr" : "fs.readlinkSync";
1535
+ const valueType = bytes ? BYTES_U8 : text ? STRING : DYN;
1536
+ return { kind: "libCall", fn: selected, args, type: promise ? { kind: "promise", inner: valueType } : valueType, loc };
1537
+ }
1538
+ return { kind: "libCall", fn: fn.fn, args, type: fn.result, loc };
1539
+ }
1540
+ if ((bi.module === "fs" && ["utimesSync", "futimesSync", "lutimesSync"].includes(bi.member)) ||
1541
+ (bi.module === "fs/promises" && ["utimes", "lutimes"].includes(bi.member))) {
1542
+ if (expr.arguments.length > 3 || expr.arguments.some(ts.isSpreadElement))
1543
+ lowerer.noLowering(`${name} with this argument shape`, expr);
1544
+ const path = expr.arguments[0] ? lowerer.lowerExprExpecting(expr.arguments[0], DYN) : dynUndefinedExpr(loc);
1545
+ return { kind: "libCall", fn: fn.fn, args: [path, lowerFsTimestampValue(lowerer, expr.arguments[1], loc), lowerFsTimestampValue(lowerer, expr.arguments[2], loc)], type: fn.result, loc };
1546
+ }
1547
+ if (bi.module === "fs" && (bi.member === "readvSync" || bi.member === "writevSync" || bi.member === "ftruncateSync")) {
1548
+ const vector = bi.member !== "ftruncateSync";
1549
+ const required = vector ? 2 : 1;
1550
+ if (expr.arguments.length < required || expr.arguments.length > required + 1 || expr.arguments.some(ts.isSpreadElement))
1551
+ lowerer.noLowering(`${name} with this argument shape`, expr);
1552
+ const args = [lowerer.lowerExprExpecting(expr.arguments[0], F64)];
1553
+ if (vector)
1554
+ args.push(lowerer.lowerExprExpecting(expr.arguments[1], arrayOf(BYTES_U8)));
1555
+ const optional = expr.arguments[required];
1556
+ args.push(optional ? lowerBuiltinOptionalDefault(lowerer, optional, F64, numLit(vector ? -1 : 0, loc), vector) : numLit(vector ? -1 : 0, loc));
1557
+ return { kind: "libCall", fn: fn.fn, args, type: vector ? F64 : VOID, loc };
1558
+ }
1423
1559
  // Numeric open flags are interpreted symbolically at the call site. The
1424
1560
  // O_* bit values differ between Darwin and Linux, so emit a stable mask
1425
1561
  // and let the target runtime select its own native constants.
@@ -2221,29 +2357,28 @@ export function lowerBuiltinModuleCall(lowerer, expr, bi, fn, loc) {
2221
2357
  }
2222
2358
  const required = fn.params.length - (fn.defaults?.length ?? 0);
2223
2359
  const hasSpread = expr.arguments.some(ts.isSpreadElement);
2224
- if (!hasSpread && bi.module === "url" && bi.member === "pathToFileURL" && expr.arguments.length === 2) {
2225
- let options = expr.arguments[1];
2226
- while (ts.isParenthesizedExpression(options) || ts.isSatisfiesExpression(options))
2227
- options = options.expression;
2228
- if (!ts.isObjectLiteralExpression(options) || options.properties.length > 1) {
2229
- lowerer.noLowering("pathToFileURL with these options", options, "use a literal { windows: boolean } options object");
2230
- }
2231
- let windowsNode = null;
2232
- const property = options.properties[0];
2233
- if (property) {
2234
- if ((!ts.isPropertyAssignment(property) && !ts.isShorthandPropertyAssignment(property)) ||
2235
- (!ts.isIdentifier(property.name) && !ts.isStringLiteral(property.name)) || property.name.text !== "windows") {
2236
- lowerer.noLowering("pathToFileURL with these options", property, "use a literal { windows: boolean } options object");
2360
+ if (bi.module === "url" && ["fileURLToPath", "fileURLToPathBuffer", "pathToFileURL"].includes(bi.member)) {
2361
+ if (hasSpread || expr.arguments.length > 2) {
2362
+ lowerer.noLowering(`${bi.member} with these arguments`, expr, "pass a path and optional options object directly");
2363
+ }
2364
+ // Keep the established typed one-argument paths free of boxing. The
2365
+ // checked variants preserve each converter's validation/getter order.
2366
+ if (expr.arguments.length === 1 && bi.member !== "fileURLToPathBuffer") {
2367
+ const arg = lowerer.lowerExpr(expr.arguments[0]);
2368
+ if (bi.member === "fileURLToPath") {
2369
+ if (arg.type.kind === "url")
2370
+ return { kind: "libCall", fn: "url.fileURLToPathUrl", args: [arg], type: STRING, loc };
2371
+ if (arg.type.kind === "string")
2372
+ return { kind: "libCall", fn: "url.fileURLToPathStr", args: [arg], type: STRING, loc };
2237
2373
  }
2238
- windowsNode = ts.isPropertyAssignment(property) ? property.initializer : property.name;
2374
+ else if (arg.type.kind === "string") {
2375
+ return { kind: "libCall", fn: lowerer.targetPlatform === "win32" ? "url.pathToFileURLWin32" : "url.pathToFileURL", args: [arg], type: fn.result, loc };
2376
+ }
2377
+ return { kind: "libCall", fn: fn.fn, args: [lowerer.coerceToExpected(arg, DYN), dynUndefinedExpr(loc)], type: fn.result, loc };
2239
2378
  }
2240
- const path = lowerer.lowerExprExpecting(expr.arguments[0], STRING);
2241
- const defaultWindows = { kind: "boolLit", value: lowerer.targetPlatform === "win32", type: BOOL, loc };
2242
- const windows = windowsNode ? lowerOptionalArgument(lowerer, windowsNode, BOOL, defaultWindows) : defaultWindows;
2243
- return { kind: "libCall", fn: "url.pathToFileURLPlatform", args: [path, windows], type: fn.result, loc };
2244
- }
2245
- if (hasSpread && bi.module === "url" && bi.member === "fileURLToPath") {
2246
- lowerer.noLowering("fileURLToPath with spread arguments", expr, "call fileURLToPath(value) directly so the URL-or-string overload remains statically visible");
2379
+ const args = [0, 1].map((index) => expr.arguments[index]
2380
+ ? lowerer.lowerExprExpecting(expr.arguments[index], DYN) : dynUndefinedExpr(loc));
2381
+ return { kind: "libCall", fn: fn.fn, args, type: fn.result, loc };
2247
2382
  }
2248
2383
  if (hasSpread &&
2249
2384
  ((bi.module === "fs" && bi.member === "readFileSync") ||
@@ -2255,22 +2390,6 @@ export function lowerBuiltinModuleCall(lowerer, expr, bi, fn, loc) {
2255
2390
  ? `pass the encoding: ${bi.member}(path, "utf8") — Buffer reads and options objects have no lowering`
2256
2391
  : `the supported form takes ${fn.params.length} argument${fn.params.length === 1 ? "" : "s"} (no options objects)`);
2257
2392
  }
2258
- if (!hasSpread && bi.module === "url" && bi.member === "fileURLToPath") {
2259
- // Node accepts a URL value or a URL string — one libFn per receiver
2260
- // form, picked by the argument's static type. Unions (URL |
2261
- // undefined, ...) must narrow first, like everywhere else.
2262
- const argNode = expr.arguments[0];
2263
- const arg = lowerer.lowerExpr(argNode);
2264
- if (arg.type.kind === "dyn")
2265
- return { kind: "libCall", fn: "url.fileURLToPathChecked", args: [arg], type: STRING, loc };
2266
- if (arg.type.kind === "url") {
2267
- return { kind: "libCall", fn: "url.fileURLToPathUrl", args: [arg], type: STRING, loc };
2268
- }
2269
- if (arg.type.kind === "string") {
2270
- return { kind: "libCall", fn: "url.fileURLToPathStr", args: [arg], type: STRING, loc };
2271
- }
2272
- lowerer.noLowering(`fileURLToPath of '${lowerer.fmt(arg.type)}' values`, argNode, "pass a URL value or a URL string (narrow unions first)");
2273
- }
2274
2393
  if (!hasSpread && ((bi.module === "fs" && bi.member === "readFileSync") ||
2275
2394
  (bi.module === "fs/promises" && bi.member === "readFile"))) {
2276
2395
  // The runtime reads utf8 unconditionally; any other encoding would
@@ -2344,6 +2463,19 @@ export function lowerReflectCall(lowerer, call, access) {
2344
2463
  }
2345
2464
  if (call.questionDotToken)
2346
2465
  return null;
2466
+ const reflectMember = lowerer.stdlibGlobalMember(access, "Reflect");
2467
+ if (reflectMember === "get" || reflectMember === "set") {
2468
+ const required = reflectMember === "get" ? 2 : 3;
2469
+ if (call.arguments.length < required || call.arguments.length > required + 1 || call.arguments.some(ts.isSpreadElement)) {
2470
+ lowerer.noLowering(`Reflect.${reflectMember} with this argument shape`, call, `use Reflect.${reflectMember}(target, key${reflectMember === "set" ? ", value" : ""}, receiver?)`);
2471
+ }
2472
+ const loc = locOf(call);
2473
+ const args = call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN));
2474
+ const target = call.arguments.length === required ? lowerer.declareHiddenLocal("%reflectTarget", DYN) : null;
2475
+ const operation = { kind: "libCall", fn: reflectMember === "get" ? "dyn.reflectGet" : "dyn.reflectSet",
2476
+ args: target ? [varRef(target.id, DYN, loc), ...args.slice(1), varRef(target.id, DYN, loc)] : args, type: reflectMember === "get" ? DYN : BOOL, loc };
2477
+ return target ? { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: target.id, init: args[0], loc }], result: operation, type: operation.type, loc } : operation;
2478
+ }
2347
2479
  if (lowerer.stdlibGlobalMember(access, "Reflect") !== "apply")
2348
2480
  return null;
2349
2481
  const loc = locOf(call);
@@ -3491,6 +3623,11 @@ export function registerBuiltinCallableAlias(lowerer, nameNode, init) {
3491
3623
  : lowerer.builtinImportOf(targetExpr);
3492
3624
  if (!target || !builtinModuleFnOf(lowerer, target.module, target.member))
3493
3625
  return false;
3626
+ // These checked native functions retain a runtime slot in JavaScript so
3627
+ // aliases can escape without narrowing their arguments to string.
3628
+ if (isJsSourceFile(nameNode.getSourceFile()) && target.module === "util" &&
3629
+ ["stripVTControlCharacters", "toUSVString", "isDeepStrictEqual", "styleText"].includes(target.member))
3630
+ return false;
3494
3631
  if (lowerer.checker.getCallSignatures(lowerer.typeOf(nameNode)).length === 0)
3495
3632
  return false;
3496
3633
  const symbol = lowerer.checker.getSymbolAtLocation(nameNode);
@@ -4188,13 +4325,8 @@ function isStringDecoderTyped(lowerer, node) {
4188
4325
  return lowerer.checker.declarationsOf(sym).some((d) => (ts.isClassDeclaration(d) || ts.isInterfaceDeclaration(d)) &&
4189
4326
  lowerer.isStdlibFile(d.getSourceFile()));
4190
4327
  }
4191
- /** Method calls on StringDecoder receivers: `d.write(chunk)` decodes the
4192
- * complete prefix of pending+chunk and re-buffers the trailing partial
4193
- * sequence; `d.end()` flushes the buffered partial as its replacement
4194
- * chars — Node's utf8 StringDecoder exactly (SEMANTICS.md), through the
4195
- * interned %strdec helpers over the packed-f64 pending field. end(buf)
4196
- * and the rest of @types/node's surface fence per member. Null for
4197
- * non-decoder receivers. */
4328
+ /** StringDecoder writes preserve pending bytes; end(input) performs the
4329
+ * final write and flushes the state. String input passes through unchanged. */
4198
4330
  export function lowerStringDecoderMethodCall(lowerer, call, access) {
4199
4331
  if (call.questionDotToken || access.questionDotToken)
4200
4332
  return null;
@@ -4204,29 +4336,37 @@ export function lowerStringDecoderMethodCall(lowerer, call, access) {
4204
4336
  return null;
4205
4337
  const name = access.name.text;
4206
4338
  const loc = locOf(call);
4207
- if (name === "write" && call.arguments.length === 1) {
4208
- const receiver = lowerer.lowerExpr(access.expression);
4209
- if (receiver.type.kind !== "record")
4210
- lowerer.badType(access.expression, lowerer.typeOf(access.expression));
4211
- let chunk = lowerBuiltinValuePreservingUndefined(lowerer, call.arguments[0]);
4212
- chunk = checkedOptionalBuiltinArm(lowerer, chunk, BYTES_U8) ?? chunk;
4213
- if (!(chunk.type.kind === "bytes" && chunk.type.elem === "u8")) {
4214
- lowerer.noLowering(`StringDecoder.write of '${lowerer.fmt(chunk.type)}' data`, call.arguments[0], "Buffer/Uint8Array chunks decode (narrow unions first)");
4215
- }
4216
- const helper = lowerer.strdecHelper("write", receiver.type.shapeId, loc);
4217
- return { kind: "call", callee: helper, args: [receiver, chunk], type: STRING, loc };
4339
+ if ((name !== "write" && name !== "end") || call.arguments.length > 1 ||
4340
+ (name === "write" && call.arguments.length !== 1) || call.arguments.some(ts.isSpreadElement)) {
4341
+ lowerer.noLowering(`StringDecoder.${name}`, call, "use write(input) or end(input?)", lowerer.checker.getSymbolAtLocation(access.name));
4218
4342
  }
4219
- if (name === "end") {
4220
- if (call.arguments.length !== 0) {
4221
- lowerer.noLowering("StringDecoder.end with a buffer argument", call, "write the buffer, then end(): d.write(buf) + d.end() is Node's own equivalence");
4222
- }
4223
- const receiver = lowerer.lowerExpr(access.expression);
4224
- if (receiver.type.kind !== "record")
4225
- lowerer.badType(access.expression, lowerer.typeOf(access.expression));
4226
- const helper = lowerer.strdecHelper("end", receiver.type.shapeId, loc);
4227
- return { kind: "call", callee: helper, args: [receiver], type: STRING, loc };
4343
+ const receiver = lowerer.lowerExpr(access.expression);
4344
+ if (receiver.type.kind !== "record")
4345
+ lowerer.badType(access.expression, lowerer.typeOf(access.expression));
4346
+ if (call.arguments.length === 0) {
4347
+ return { kind: "call", callee: lowerer.strdecHelper("end", receiver.type.shapeId, loc), args: [receiver], type: STRING, loc };
4348
+ }
4349
+ const node = call.arguments[0];
4350
+ const undefinedArg = name === "end" ? lowerStaticallyUndefinedArgument(lowerer, node) : null;
4351
+ if (undefinedArg) {
4352
+ const saved = lowerer.declareHiddenLocal("%strdecRecv", receiver.type);
4353
+ const result = { kind: "call", callee: lowerer.strdecHelper("end", receiver.type.shapeId, loc), args: [varRef(saved.id, receiver.type, loc)], type: STRING, loc };
4354
+ return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: saved.id, init: receiver, loc }], result: defaultAfterUndefined(undefinedArg, result), type: STRING, loc };
4355
+ }
4356
+ let chunk = lowerBuiltinValuePreservingUndefined(lowerer, node);
4357
+ if (chunk.type.kind === "string") {
4358
+ const op = name === "end" ? "endString" : "writeString";
4359
+ return { kind: "call", callee: lowerer.strdecHelper(op, receiver.type.shapeId, loc), args: [receiver, chunk], type: STRING, loc };
4360
+ }
4361
+ chunk = checkedOptionalBuiltinArm(lowerer, chunk, BYTES_U8) ?? chunk;
4362
+ if (chunk.type.kind === "bytes" && chunk.type.elem !== "u8") {
4363
+ chunk = { kind: "libCall", fn: "bytes.bufferSource", args: [lowerer.coerceInto(node, chunk, DYN)], type: BYTES_U8, loc };
4228
4364
  }
4229
- lowerer.noLowering(`StringDecoder.${name}`, call, "write(buffer) and end() are the supported StringDecoder members", lowerer.checker.getSymbolAtLocation(access.name));
4365
+ if (!(chunk.type.kind === "bytes" && chunk.type.elem === "u8")) {
4366
+ lowerer.noLowering(`StringDecoder.${name} of '${lowerer.fmt(chunk.type)}' data`, node, "pass a string or typed-array view (narrow unions first)");
4367
+ }
4368
+ const helper = lowerer.strdecHelper(name === "end" ? "endChunk" : "write", receiver.type.shapeId, loc);
4369
+ return { kind: "call", callee: helper, args: [receiver, chunk], type: STRING, loc };
4230
4370
  }
4231
4371
  /** The interned %strdec helpers: write(d, chunk) returns the decoded
4232
4372
  * complete prefix and re-buffers the trailing partial into the pending
@@ -4264,7 +4404,7 @@ export function strdecHelper(lowerer, op, shapeId, loc) {
4264
4404
  { id: "s.0", name: "s", type: STRING, mutable: false },
4265
4405
  ];
4266
4406
  let body;
4267
- if (op === "write") {
4407
+ if (op === "write" || op === "endChunk") {
4268
4408
  params.push({ localId: "chunk.0", name: "chunk", type: BYTES_U8 });
4269
4409
  locals.splice(1, 0, { id: "chunk.0", name: "chunk", type: BYTES_U8, mutable: false });
4270
4410
  body = [
@@ -4304,6 +4444,24 @@ export function strdecHelper(lowerer, op, shapeId, loc) {
4304
4444
  { kind: "return", value: varRef("s.0", STRING, loc), loc },
4305
4445
  ];
4306
4446
  }
4447
+ if (op === "endString" || op === "writeString") {
4448
+ const inputT = STRING;
4449
+ params.push({ localId: "chunk.0", name: "chunk", type: inputT });
4450
+ locals.push({ id: "chunk.0", name: "chunk", type: inputT, mutable: false });
4451
+ if (op === "writeString")
4452
+ body = [{ kind: "return", value: varRef("chunk.0", STRING, loc), loc }];
4453
+ if (op === "endString")
4454
+ body[body.length - 1] = { kind: "return", value: {
4455
+ kind: "strConcat", left: varRef("chunk.0", STRING, loc), right: varRef("s.0", STRING, loc), type: STRING, loc,
4456
+ }, loc };
4457
+ }
4458
+ if (op === "endChunk") {
4459
+ locals.push({ id: "tail.0", name: "tail", type: STRING, mutable: false });
4460
+ 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 });
4461
+ body[body.length - 1] = { kind: "return", value: {
4462
+ kind: "strConcat", left: varRef("s.0", STRING, loc), right: varRef("tail.0", STRING, loc), type: STRING, loc,
4463
+ }, loc };
4464
+ }
4307
4465
  lowerer.liftedFns.push({ name, params, returnType: STRING, locals, body, loc });
4308
4466
  return name;
4309
4467
  }
@@ -4400,11 +4558,11 @@ export function lowerJsonMethodCall(lowerer, call, access) {
4400
4558
  const optionalString = lowerOptionalStringifyRoot(lowerer, value, indent, loc);
4401
4559
  if (optionalString)
4402
4560
  return optionalString;
4403
- if (value.type.kind === "dyn" || isJsonStringifyDynamicType(value.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
4561
+ if (value.type.kind === "url" || value.type.kind === "dyn" || isJsonStringifyDynamicType(value.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
4404
4562
  // Keep the original containers live while the runtime visits them:
4405
4563
  // a toJSON callback can mutate a later field, and shared/cyclic
4406
4564
  // references must retain their identities throughout traversal.
4407
- const boxed = value.type.kind === "dyn" ? value : { kind: "dynFrom", value, liveRef: true, type: DYN, loc };
4565
+ const boxed = value.type.kind === "dyn" ? value : { kind: "dynFrom", value, ...(value.type.kind === "url" ? {} : { liveRef: true }), type: DYN, loc };
4408
4566
  const raw = {
4409
4567
  kind: "libCall", fn: "json.stringifyReplacer",
4410
4568
  args: [boxed, dynUndefinedExpr(loc), { kind: "strLit", value: indent, type: STRING, loc }],
@@ -4742,8 +4900,8 @@ function cryptoEncoding(lowerer, node, use) {
4742
4900
  }
4743
4901
  function cryptoAlgorithm(lowerer, node, use) {
4744
4902
  const type = lowerer.typeOf(node);
4745
- if (type.isStringLiteralType() && !["md5", "sha1", "sha256"].includes(type.value.toLowerCase())) {
4746
- lowerer.noLowering(`${use} with algorithm '${type.value}'`, node, "md5, sha1, and sha256 are the lowered digest algorithms");
4903
+ if (type.isStringLiteralType() && !["md5", "sha1", "sha224", "sha256", "sha384", "sha512"].includes(type.value.toLowerCase())) {
4904
+ lowerer.noLowering(`${use} with algorithm '${type.value}'`, node, "md5, sha1, sha224, sha256, sha384, and sha512 are the lowered digest algorithms");
4747
4905
  }
4748
4906
  return lowerer.lowerExprExpecting(node, STRING);
4749
4907
  }
@@ -4762,7 +4920,19 @@ function cryptoInputBytes(lowerer, node, loc) {
4762
4920
  }
4763
4921
  lowerer.noLowering(`crypto byte input of '${lowerer.fmt(value.type)}' values`, node, "string and Buffer/Uint8Array values are supported");
4764
4922
  }
4765
- function errorFirstBytesCallback(lowerer, node, api) {
4923
+ function cryptoKdfInput(lowerer, node) {
4924
+ const loc = locOf(node);
4925
+ const type = lowerer.mapTypeOf(lowerer.typeOf(node));
4926
+ if (type?.kind === "string" || (type?.kind === "bytes" && type.elem === "u8"))
4927
+ return cryptoInputBytes(lowerer, node, loc);
4928
+ const symbol = lowerer.typeOf(node).getSymbol();
4929
+ if (type?.kind === "bytes" || (symbol?.name === "ArrayBuffer" && lowerer.isStdlibSymbol(symbol))) {
4930
+ const value = lowerer.coerceInto(node, lowerer.lowerExpr(node), DYN);
4931
+ return { kind: "libCall", fn: "bytes.bufferSource", args: [value], type: BYTES_U8, loc };
4932
+ }
4933
+ 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");
4934
+ }
4935
+ function errorFirstBytesCallback(lowerer, node, api, arrayBuffer = false) {
4766
4936
  let callback = lowerer.lowerExpr(node);
4767
4937
  if (callback.type.kind === "dyn") {
4768
4938
  callback = { kind: "dynCheck", value: callback, type: funcOf([DYN, DYN], VOID), loc: locOf(node) };
@@ -4784,8 +4954,8 @@ function errorFirstBytesCallback(lowerer, node, api) {
4784
4954
  lowerer.unsupported("SC1090", node, `${api} callback error parameters must be Error | null`);
4785
4955
  }
4786
4956
  const value = callback.type.params[1];
4787
- if (value !== undefined && value.kind !== "dyn" && !(value.kind === "bytes" && value.elem === "u8")) {
4788
- lowerer.unsupported("SC1090", node, `${api} callback result parameters must be Buffer/Uint8Array values`);
4957
+ if (value !== undefined && value.kind !== "dyn" && (arrayBuffer || !(value.kind === "bytes" && value.elem === "u8"))) {
4958
+ lowerer.unsupported("SC1090", node, `${api} callback result parameters must be ${arrayBuffer ? "ArrayBuffer" : "Buffer/Uint8Array"} values`);
4789
4959
  }
4790
4960
  return voidizedCallback(lowerer, callback, locOf(node));
4791
4961
  }
@@ -4833,6 +5003,31 @@ export function lowerCryptoModuleCall(lowerer, expr, bi, loc) {
4833
5003
  loc,
4834
5004
  };
4835
5005
  }
5006
+ if (bi.member === "hkdf" || bi.member === "hkdfSync") {
5007
+ const async = bi.member === "hkdf";
5008
+ if (args.length !== (async ? 6 : 5))
5009
+ lowerer.noLowering(`crypto.${bi.member} with ${args.length} arguments`, expr);
5010
+ const values = [
5011
+ cryptoAlgorithm(lowerer, args[0], `crypto.${bi.member}`),
5012
+ cryptoKdfInput(lowerer, args[1]), cryptoKdfInput(lowerer, args[2]), cryptoKdfInput(lowerer, args[3]),
5013
+ lowerer.lowerExprExpecting(args[4], F64),
5014
+ ];
5015
+ if (async)
5016
+ values.push(errorFirstBytesCallback(lowerer, args[5], "crypto.hkdf", true));
5017
+ return { kind: "libCall", fn: async ? "crypto.hkdfCb" : "crypto.hkdf", args: values, type: async ? VOID : DYN, loc };
5018
+ }
5019
+ if (bi.member === "scrypt" || bi.member === "scryptSync") {
5020
+ const async = bi.member === "scrypt";
5021
+ const minimum = async ? 4 : 3;
5022
+ if (args.length < minimum || args.length > minimum + 1)
5023
+ lowerer.noLowering(`crypto.${bi.member} with ${args.length} arguments`, expr);
5024
+ const values = [cryptoKdfInput(lowerer, args[0]), cryptoKdfInput(lowerer, args[1]), lowerer.lowerExprExpecting(args[2], F64)];
5025
+ const options = args.length > minimum ? args[3] : undefined;
5026
+ values.push(options ? lowerer.coerceInto(options, lowerer.lowerExpr(options), DYN) : dynUndefinedExpr(loc));
5027
+ if (async)
5028
+ values.push(errorFirstBytesCallback(lowerer, args[args.length - 1], "crypto.scrypt"));
5029
+ return { kind: "libCall", fn: async ? "crypto.scryptCb" : "crypto.scrypt", args: values, type: async ? VOID : BYTES_U8, loc };
5030
+ }
4836
5031
  if (bi.member === "createHash") {
4837
5032
  if (args.length !== 1) {
4838
5033
  lowerer.noLowering(`crypto.createHash with ${args.length} arguments`, expr, "createHash(algorithm) is supported; options are not yet lowered");
@@ -4940,7 +5135,7 @@ export function lowerCryptoModuleCall(lowerer, expr, bi, loc) {
4940
5135
  loc,
4941
5136
  };
4942
5137
  }
4943
- /** Method calls on URL-typed receivers: `u.toString()` is Node's href
5138
+ /** Method calls on URL-typed receivers: `u.toString()` and `u.toJSON()` are Node's href
4944
5139
  * serialization (the href getter's libCall). Everything else the lib
4945
5140
  * declares fences member-qualified. Null for non-URL receivers. */
4946
5141
  export function lowerUrlMethodCall(lowerer, call, access) {
@@ -4951,11 +5146,11 @@ export function lowerUrlMethodCall(lowerer, call, access) {
4951
5146
  if (!lowerer.isStdlibMember(access))
4952
5147
  return null;
4953
5148
  const name = access.name.text;
4954
- if (name === "toString" && call.arguments.length === 0) {
5149
+ if ((name === "toString" || name === "toJSON") && call.arguments.length === 0) {
4955
5150
  const receiver = lowerer.lowerExpr(access.expression);
4956
5151
  return { kind: "libCall", fn: "url.href", args: [receiver], type: STRING, loc: locOf(call) };
4957
5152
  }
4958
- 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));
5153
+ 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));
4959
5154
  }
4960
5155
  /** `new URLSearchParams(init?)` — the WHATWG constructor's lowered init
4961
5156
  * shapes: omitted / literal `undefined` (empty list), a string (parsed,
@@ -5329,18 +5524,21 @@ export function lowerFileHandleMethodCall(lowerer, call, access) {
5329
5524
  const loc = locOf(call);
5330
5525
  const receiver = () => lowerer.lowerExprExpecting(access.expression, FILEHANDLE_T);
5331
5526
  const promise = (inner) => ({ kind: "promise", inner });
5332
- const num = (node, dflt) => {
5527
+ const num = (node, dflt, lowered) => {
5333
5528
  const defaultValue = { kind: "numLit", value: dflt, type: F64, loc };
5334
- if (!node)
5529
+ if (!node && !lowered)
5335
5530
  return { value: defaultValue, defaulted: boolLit(true, loc) };
5336
- const undefinedArg = lowerStaticallyUndefinedArgument(lowerer, node);
5531
+ if (lowered && isUnitType(lowered.type)) {
5532
+ return { value: defaultAfterUndefined(lowered, defaultValue), defaulted: boolLit(true, loc) };
5533
+ }
5534
+ const undefinedArg = !lowered && node ? lowerStaticallyUndefinedArgument(lowerer, node) : null;
5337
5535
  if (undefinedArg) {
5338
5536
  return { value: defaultAfterUndefined(undefinedArg, defaultValue), defaulted: boolLit(true, loc) };
5339
5537
  }
5340
- if ((lowerer.typeOf(node).flags & ts.TypeFlags.Null) !== 0) {
5538
+ if (!lowered && node && (lowerer.typeOf(node).flags & ts.TypeFlags.Null) !== 0) {
5341
5539
  return { value: defaultAfterUndefined(lowerer.lowerExpr(node), defaultValue), defaulted: boolLit(true, loc) };
5342
5540
  }
5343
- const value = lowerer.lowerExpr(node);
5541
+ const value = lowered ?? lowerer.lowerExpr(node);
5344
5542
  if (value.type.kind === "union") {
5345
5543
  const def = lowerer.unions.get(value.type.unionId);
5346
5544
  const units = def?.arms.filter(isUnitType) ?? [];
@@ -5386,7 +5584,7 @@ export function lowerFileHandleMethodCall(lowerer, call, access) {
5386
5584
  };
5387
5585
  }
5388
5586
  }
5389
- return { value: lowerer.coerceInto(node, value, F64), defaulted: boolLit(false, loc) };
5587
+ return { value: lowerer.coerceInto(node ?? call, value, F64), defaulted: boolLit(false, loc) };
5390
5588
  };
5391
5589
  const utf8 = (node) => {
5392
5590
  const dflt = { kind: "strLit", value: "utf8", type: STRING, loc };
@@ -5401,6 +5599,35 @@ export function lowerFileHandleMethodCall(lowerer, call, access) {
5401
5599
  }
5402
5600
  return lowerBuiltinOptionalDefault(lowerer, node, STRING, dflt, true);
5403
5601
  };
5602
+ if (name === "sync" || name === "datasync") {
5603
+ if (call.arguments.length !== 0)
5604
+ lowerer.noLowering(`FileHandle.${name} with arguments`, call);
5605
+ return { kind: "libCall", fn: name === "sync" ? "fileHandle.sync" : "fileHandle.datasync", args: [receiver()], type: promise(VOID), loc };
5606
+ }
5607
+ if (name === "truncate" || name === "chmod") {
5608
+ if (call.arguments.length > 1 || (name === "chmod" && call.arguments.length !== 1))
5609
+ lowerer.noLowering(`FileHandle.${name} with ${call.arguments.length} arguments`, call);
5610
+ return {
5611
+ kind: "libCall", fn: name === "truncate" ? "fileHandle.truncate" : "fileHandle.chmod",
5612
+ args: [receiver(), num(call.arguments[0], 0).value], type: promise(VOID), loc,
5613
+ };
5614
+ }
5615
+ if (name === "utimes") {
5616
+ if (call.arguments.length !== 2 || call.arguments.some(ts.isSpreadElement))
5617
+ lowerer.noLowering("FileHandle.utimes with this argument shape", call);
5618
+ return { kind: "libCall", fn: "fileHandle.utimes", args: [receiver(), lowerFsTimestampValue(lowerer, call.arguments[0], loc), lowerFsTimestampValue(lowerer, call.arguments[1], loc)], type: promise(VOID), loc };
5619
+ }
5620
+ if (name === "readv" || name === "writev") {
5621
+ if (call.arguments.length < 1 || call.arguments.length > 2)
5622
+ lowerer.noLowering(`FileHandle.${name} with ${call.arguments.length} arguments`, call);
5623
+ const type = lowerer.mapTypeOf(lowerer.typeOf(call));
5624
+ if (type?.kind !== "promise" || type.inner.kind !== "record")
5625
+ lowerer.badType(call, lowerer.typeOf(call));
5626
+ return {
5627
+ kind: "libCall", fn: name === "readv" ? "fileHandle.readv" : "fileHandle.writev",
5628
+ args: [receiver(), lowerer.lowerExprExpecting(call.arguments[0], arrayOf(BYTES_U8)), num(call.arguments[1], -1).value], type, loc,
5629
+ };
5630
+ }
5404
5631
  if (name === "close" || name === "stat") {
5405
5632
  if (call.arguments.length !== 0)
5406
5633
  lowerer.noLowering(`FileHandle.${name} with arguments`, call);
@@ -5458,6 +5685,65 @@ export function lowerFileHandleMethodCall(lowerer, call, access) {
5458
5685
  }
5459
5686
  lowerer.noLowering(`FileHandle.${name} of '${dataT ? lowerer.fmt(dataT) : lowerer.checker.typeToString(lowerer.typeOf(dataNode))}' data`, dataNode, "string and Uint8Array data are supported");
5460
5687
  }
5688
+ if (name === "read" || name === "write") {
5689
+ const firstNode = call.arguments[0];
5690
+ const firstT = firstNode ? lowerer.mapTypeOf(lowerer.typeOf(firstNode)) : undefined;
5691
+ const secondT = call.arguments[1] ? lowerer.mapTypeOf(lowerer.typeOf(call.arguments[1])) : undefined;
5692
+ const readOptions = name === "read" && (!firstNode || firstT?.kind === "record" || (firstT && isUnitType(firstT)));
5693
+ const bufferOptions = firstT?.kind === "bytes" && firstT.elem === "u8" && secondT?.kind === "record";
5694
+ if (readOptions || bufferOptions) {
5695
+ if (call.arguments.length > (bufferOptions ? 2 : 1))
5696
+ lowerer.noLowering(`FileHandle.${name} options with extra arguments`, call);
5697
+ const type = lowerer.mapTypeOf(lowerer.typeOf(call));
5698
+ if (type?.kind !== "promise" || type.inner.kind !== "record")
5699
+ lowerer.badType(call, lowerer.typeOf(call));
5700
+ const stmts = [];
5701
+ const stage = (value, label) => {
5702
+ const local = lowerer.declareHiddenLocal(label, value.type);
5703
+ stmts.push({ kind: "varDecl", localId: local.id, init: value, loc: value.loc });
5704
+ return varRef(local.id, local.type, loc);
5705
+ };
5706
+ const handle = stage(receiver(), "%fhWindowReceiver");
5707
+ let buffer = bufferOptions ? stage(lowerer.lowerExprExpecting(firstNode, BYTES_U8), "%fhWindowBuffer") : undefined;
5708
+ const optionsNode = bufferOptions ? call.arguments[1] : firstNode;
5709
+ const options = optionsNode ? stage(lowerer.lowerExpr(optionsNode), "%fhWindowOptions") : undefined;
5710
+ const field = (key) => {
5711
+ if (options?.type.kind !== "record")
5712
+ return undefined;
5713
+ const fields = lowerer.shapes.get(options.type.shapeId)?.fields;
5714
+ const getter = fields?.find((f) => f.name === `%get:${key}`);
5715
+ if (getter?.type.kind === "func") {
5716
+ const callee = { kind: "recordGet", obj: options, shapeId: options.type.shapeId, field: getter.name, type: getter.type, loc };
5717
+ return { kind: "callValue", callee, args: [], type: getter.type.ret, loc };
5718
+ }
5719
+ const member = fields?.find((f) => f.name === key);
5720
+ return member ? { kind: "recordGet", obj: options, shapeId: options.type.shapeId, field: key, type: member.type, loc } : undefined;
5721
+ };
5722
+ if (!buffer) {
5723
+ const supplied = field("buffer");
5724
+ const fresh = { kind: "bytesNew", source: numLit(16384, loc), type: BYTES_U8, loc };
5725
+ if (!supplied || isUnitType(supplied.type))
5726
+ buffer = supplied ? defaultAfterUndefined(supplied, fresh) : fresh;
5727
+ else if (supplied.type.kind === "union") {
5728
+ const arms = lowerer.unions.get(supplied.type.unionId)?.arms;
5729
+ if (!arms?.every((arm) => typeEquals(arm, BYTES_U8) || isUnitType(arm)))
5730
+ lowerer.noLowering("FileHandle.read with this buffer type", call);
5731
+ buffer = { kind: "nullish", left: supplied, right: fresh, type: BYTES_U8, loc };
5732
+ }
5733
+ else
5734
+ buffer = lowerer.coerceInto(call, supplied, BYTES_U8);
5735
+ buffer = stage(buffer, "%fhWindowBuffer");
5736
+ }
5737
+ const offset = num(undefined, 0, field("offset"));
5738
+ const length = num(undefined, -1, field("length"));
5739
+ const position = num(undefined, -1, field("position"));
5740
+ const result = {
5741
+ kind: "libCall", fn: name === "read" ? "fileHandle.read" : "fileHandle.writeBytes",
5742
+ args: [handle, buffer, offset.value, length.value, position.value, length.defaulted], type, loc,
5743
+ };
5744
+ return { kind: "seqExpr", stmts, result, type, loc };
5745
+ }
5746
+ }
5461
5747
  if (name === "read") {
5462
5748
  if (call.arguments.length < 1 || call.arguments.length > 4) {
5463
5749
  lowerer.noLowering(`FileHandle.read with ${call.arguments.length} arguments`, call, "use read(buffer[, offset[, length[, position]]])");
@@ -5516,7 +5802,7 @@ export function lowerFileHandleMethodCall(lowerer, call, access) {
5516
5802
  }
5517
5803
  lowerer.noLowering(`FileHandle.write of '${dataT ? lowerer.fmt(dataT) : lowerer.checker.typeToString(lowerer.typeOf(dataNode))}' data`, dataNode, "string and Uint8Array data are supported");
5518
5804
  }
5519
- lowerer.noLowering(`FileHandle.${name}`, call, "fd, close(), read(), write(), readFile(), writeFile(), appendFile(), and stat() are the supported FileHandle members", lowerer.checker.getSymbolAtLocation(access.name));
5805
+ 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));
5520
5806
  }
5521
5807
  /** Method calls on Stats-typed receivers: isFile()/isDirectory()/
5522
5808
  * isSymbolicLink() are pure reads on the stat snapshot (a followed
@@ -5670,6 +5956,21 @@ export function lowerAtomicsCall(lowerer, call, access) {
5670
5956
  export function lowerBuiltinExtraProperty(lowerer, expr) {
5671
5957
  if (expr.questionDotToken && !lowerer.chainHandled.has(expr))
5672
5958
  return null;
5959
+ const codec = storedTextCodecClassOf(lowerer, expr.expression);
5960
+ if (codec && lowerer.isStdlibMember(expr) && ["encoding", "fatal", "ignoreBOM"].includes(expr.name.text)) {
5961
+ const receiver = lowerer.lowerExpr(expr.expression);
5962
+ if (receiver.type.kind !== "record")
5963
+ lowerer.badType(expr.expression, lowerer.typeOf(expr.expression));
5964
+ const loc = locOf(expr);
5965
+ if (codec === "TextEncoder" && expr.name.text === "encoding") {
5966
+ return { kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: receiver, loc }], result: strLit("utf-8", loc), type: STRING, loc };
5967
+ }
5968
+ if (codec === "TextDecoder") {
5969
+ const field = expr.name.text === "encoding" ? "%TextDecoder" : `%${expr.name.text}`;
5970
+ const value = { kind: "recordGet", obj: receiver, shapeId: receiver.type.shapeId, field, type: expr.name.text === "encoding" ? F64 : BOOL, loc };
5971
+ return expr.name.text === "encoding" ? { kind: "libCall", fn: "text.decoderName", args: [value], type: STRING, loc } : value;
5972
+ }
5973
+ }
5673
5974
  // decoder.encoding on a StringDecoder-typed receiver: the record's
5674
5975
  // hidden canonical-name field (construction folded the aliases —
5675
5976
  // exactly what Node's normalized `.encoding` answers).
@@ -5680,6 +5981,15 @@ export function lowerBuiltinExtraProperty(lowerer, expr) {
5680
5981
  return { kind: "recordGet", obj: receiver, shapeId: receiver.type.shapeId, field: "%enc", type: STRING, loc: locOf(expr) };
5681
5982
  }
5682
5983
  const kind = lowerer.mapTypeOf(lowerer.typeOf(expr.expression))?.kind;
5984
+ if (kind === "record" && ["read", "written"].includes(expr.name.text) && lowerer.isStdlibMember(expr)) {
5985
+ const receiver = lowerer.lowerExpr(expr.expression);
5986
+ if (receiver.type.kind === "record") {
5987
+ const fields = lowerer.shapes.get(receiver.type.shapeId)?.fields;
5988
+ if (fields?.length === 2 && fields.every((field) => ["read", "written"].includes(field.name) && field.type.kind === "f64")) {
5989
+ return { kind: "recordGet", obj: receiver, shapeId: receiver.type.shapeId, field: expr.name.text, type: F64, loc: locOf(expr) };
5990
+ }
5991
+ }
5992
+ }
5683
5993
  if (kind !== "stats" && kind !== "fileHandle" && kind !== "spawnRes" && kind !== "child" && kind !== "childWriter")
5684
5994
  return null;
5685
5995
  if (kind === "child" ? !isChildSurfaceMember(lowerer, expr) : !lowerer.isStdlibMember(expr))
@@ -5896,14 +6206,15 @@ export function lowerChildMethodCall(lowerer, call, access) {
5896
6206
  lowerer.checkedCallbackParams.add(param);
5897
6207
  }
5898
6208
  const cb = lowerer.lowerExpr(call.arguments[1]);
5899
- if (cb.type.kind === "func" && cb.type.rest) {
5900
- if (!canBoxFuncIntoDyn(cb.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
5901
- lowerer.noLowering("child event rest listeners with non-representable parameters", call.arguments[1]);
6209
+ if (isJsSourceFile(listenerNode.getSourceFile()) && cb.type.kind === "dyn" ||
6210
+ cb.type.kind === "func" && (cb.type.rest || isJsSourceFile(listenerNode.getSourceFile()) && cb.type.params.some((param) => param.kind === "dyn"))) {
6211
+ if (cb.type.kind !== "dyn" && !canBoxFuncIntoDyn(cb.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
6212
+ lowerer.noLowering("child event listeners with non-representable parameters", call.arguments[1]);
5902
6213
  }
5903
6214
  return {
5904
6215
  kind: "libCall", fn: "child.onDyn",
5905
6216
  args: [receiver, { kind: "strLit", value: event, type: STRING, loc },
5906
- { kind: "dynFrom", value: cb, type: DYN, loc }],
6217
+ cb.type.kind === "dyn" ? cb : { kind: "dynFrom", value: cb, type: DYN, loc }],
5907
6218
  type: VOID, loc,
5908
6219
  };
5909
6220
  }
@@ -6286,7 +6597,8 @@ export function lowerErrorCodeProperty(lowerer, expr) {
6286
6597
  return null;
6287
6598
  if (!lowerer.isStdlibMember(expr))
6288
6599
  return null;
6289
- const receiver = lowerer.lowerExpr(expr.expression);
6600
+ const rawReceiver = lowerer.lowerExpr(expr.expression);
6601
+ const receiver = rawReceiver.type.kind === "dyn" ? lowerer.coerceInto(expr.expression, rawReceiver, recvT) : rawReceiver;
6290
6602
  return {
6291
6603
  kind: "libCall",
6292
6604
  fn: expr.name.text === "stack" ? "error.stack" : expr.name.text === "cause" ? "error.cause" : "error.code",
@@ -6986,6 +7298,19 @@ export function lowerProcessEnvGet(lowerer, expr) {
6986
7298
  const key = { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) };
6987
7299
  return { kind: "libCall", fn: "process.envGet", args: [key], type: lowerer.envValueType(), loc };
6988
7300
  }
7301
+ function lowerProcessLoadEnvFile(lowerer, call) {
7302
+ if (call.arguments.length > 1 || call.arguments.some(ts.isSpreadElement)) {
7303
+ lowerer.noLowering("process.loadEnvFile with spread or extra arguments", call);
7304
+ }
7305
+ const loc = locOf(call);
7306
+ const path = call.arguments[0] ? lowerer.lowerExprExpecting(call.arguments[0], DYN)
7307
+ : { kind: "dynFrom", value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, type: DYN, loc };
7308
+ const load = { kind: "libCall", fn: "process.loadEnvFile", args: [path], type: VOID, loc };
7309
+ if (ts.isExpressionStatement(call.parent))
7310
+ return load;
7311
+ return { kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: load, loc }],
7312
+ result: { kind: "dynFrom", value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, type: DYN, loc }, type: DYN, loc };
7313
+ }
6989
7314
  /** `process.exit(code)` / `process.cwd()` → libCall. The fallback
6990
7315
  * declaration makes exit's code required; @types/node declares it
6991
7316
  * optional. A bare `process.exit()` uses the current exitCode, or zero
@@ -7003,6 +7328,8 @@ export function lowerProcessMethodCall(lowerer, call, access) {
7003
7328
  }
7004
7329
  }
7005
7330
  const directProcessMember = lowerer.stdlibGlobalMember(access, "process");
7331
+ if (directProcessMember === "loadEnvFile")
7332
+ return lowerProcessLoadEnvFile(lowerer, call);
7006
7333
  if (directProcessMember === "hrtime") {
7007
7334
  if (call.arguments.some(ts.isSpreadElement))
7008
7335
  lowerer.noLowering("process.hrtime with spread arguments", call);
@@ -7991,6 +8318,18 @@ export function lowerTextCodecCall(lowerer, call, access) {
7991
8318
  if (call.questionDotToken || access.questionDotToken)
7992
8319
  return null;
7993
8320
  const member = access.name.text;
8321
+ if (member === "encodeInto" && storedTextCodecClassOf(lowerer, access.expression) === "TextEncoder" && lowerer.isStdlibMember(access)) {
8322
+ if (call.arguments.length !== 2 || call.arguments.some(ts.isSpreadElement))
8323
+ lowerer.noLowering("TextEncoder.encodeInto with this argument shape", call);
8324
+ const loc = locOf(call);
8325
+ const receiver = lowerer.lowerExpr(access.expression);
8326
+ const result = { kind: "libCall", fn: "text.encodeInto", args: call.arguments.map((arg) => lowerer.lowerExprExpecting(stripTypeCasts(arg), DYN)), type: DYN, loc };
8327
+ const type = lowerer.mapTypeOf(lowerer.typeOf(call));
8328
+ if (!type)
8329
+ lowerer.badType(call, lowerer.typeOf(call));
8330
+ const checked = lowerer.coerceInto(call, result, type);
8331
+ return { kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: receiver, loc }], result: checked, type, loc };
8332
+ }
7994
8333
  if (member !== "decode" && member !== "encode")
7995
8334
  return null;
7996
8335
  const info = directTextCodecCtorOf(lowerer, access.expression);
@@ -8294,9 +8633,14 @@ export function lowerPromiseStaticCall(lowerer, call, access) {
8294
8633
  lowerer.diags.splice(diagsBefore);
8295
8634
  }
8296
8635
  }
8636
+ if (!lowerer.dynamic && isJsSourceFile(call.getSourceFile()) && elems.every((entry) => lowerer.dynConvertible(entry.type))) {
8637
+ return checkedPromiseAll(lowerer, { kind: "arrayLit", elems: elems.map((entry) => lowerer.coerceToExpected(entry, DYN)), type: arrayOf(DYN), loc }, loc);
8638
+ }
8297
8639
  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>");
8298
8640
  }
8299
8641
  const entries = lowerer.lowerExpr(argNode);
8642
+ if (!lowerer.dynamic && isJsSourceFile(call.getSourceFile()) && entries.type.kind === "dyn")
8643
+ return checkedPromiseAll(lowerer, entries, loc);
8300
8644
  // A NON-literal island argument (`Promise.all(plugins.map((p) =>
8301
8645
  // loadPlugin(p)))` — the loadPlugins shape, where the checker
8302
8646
  // spells `any[]`): the ENGINE's own Promise.all runs over the