@scriptc/compiler 0.4.1 → 0.4.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 (999) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +977 -113
  2. package/dist/backend/cycle-analysis.d.ts +5 -1
  3. package/dist/backend/cycle-analysis.js +6 -4
  4. package/dist/backend/cycle-analysis.js.map +1 -1
  5. package/dist/backend/cycle-analysis.test.js +55 -0
  6. package/dist/backend/cycle-analysis.test.js.map +1 -1
  7. package/dist/backend/cycle-mutability.d.ts +9 -1
  8. package/dist/backend/cycle-mutability.js +21 -3
  9. package/dist/backend/cycle-mutability.js.map +1 -1
  10. package/dist/backend/executable-features.js +6 -1
  11. package/dist/backend/executable-features.js.map +1 -1
  12. package/dist/backend/immutability.d.ts +7 -3
  13. package/dist/backend/immutability.js +33 -29
  14. package/dist/backend/immutability.js.map +1 -1
  15. package/dist/backend/library-pack.js +5 -0
  16. package/dist/backend/library-pack.js.map +1 -1
  17. package/dist/backend/llvm/alloc.d.ts +23 -4
  18. package/dist/backend/llvm/alloc.js +61 -8
  19. package/dist/backend/llvm/alloc.js.map +1 -1
  20. package/dist/backend/llvm/appended-array-literals.d.ts +2 -1
  21. package/dist/backend/llvm/appended-array-literals.js +44 -36
  22. package/dist/backend/llvm/appended-array-literals.js.map +1 -1
  23. package/dist/backend/llvm/appended-array-literals.test.js +4 -3
  24. package/dist/backend/llvm/appended-array-literals.test.js.map +1 -1
  25. package/dist/backend/llvm/array-search.d.ts +4 -3
  26. package/dist/backend/llvm/array-search.js +23 -10
  27. package/dist/backend/llvm/array-search.js.map +1 -1
  28. package/dist/backend/llvm/blocks.d.ts +1 -1
  29. package/dist/backend/llvm/blocks.js +2 -2
  30. package/dist/backend/llvm/blocks.js.map +1 -1
  31. package/dist/backend/llvm/byte-windows.js +2 -0
  32. package/dist/backend/llvm/byte-windows.js.map +1 -1
  33. package/dist/backend/llvm/bytes-alias.d.ts +6 -1
  34. package/dist/backend/llvm/bytes-alias.js +8 -2
  35. package/dist/backend/llvm/bytes-alias.js.map +1 -1
  36. package/dist/backend/llvm/bytes-loop-versions.d.ts +70 -7
  37. package/dist/backend/llvm/bytes-loop-versions.js +567 -30
  38. package/dist/backend/llvm/bytes-loop-versions.js.map +1 -1
  39. package/dist/backend/llvm/bytes-loop-versions.test.js +389 -2
  40. package/dist/backend/llvm/bytes-loop-versions.test.js.map +1 -1
  41. package/dist/backend/llvm/checked-value-lifetimes.js +2 -0
  42. package/dist/backend/llvm/checked-value-lifetimes.js.map +1 -1
  43. package/dist/backend/llvm/classes.d.ts +74 -1
  44. package/dist/backend/llvm/classes.js +364 -54
  45. package/dist/backend/llvm/classes.js.map +1 -1
  46. package/dist/backend/llvm/classes.test.js +384 -17
  47. package/dist/backend/llvm/classes.test.js.map +1 -1
  48. package/dist/backend/llvm/common.d.ts +10 -6
  49. package/dist/backend/llvm/common.js +10 -6
  50. package/dist/backend/llvm/common.js.map +1 -1
  51. package/dist/backend/llvm/constant-callbacks.d.ts +2 -1
  52. package/dist/backend/llvm/constant-callbacks.js +91 -56
  53. package/dist/backend/llvm/constant-callbacks.js.map +1 -1
  54. package/dist/backend/llvm/constant-callbacks.test.js +4 -4
  55. package/dist/backend/llvm/constant-callbacks.test.js.map +1 -1
  56. package/dist/backend/llvm/counted-loops.d.ts +11 -1
  57. package/dist/backend/llvm/counted-loops.js +80 -23
  58. package/dist/backend/llvm/counted-loops.js.map +1 -1
  59. package/dist/backend/llvm/dense-array-access.d.ts +39 -8
  60. package/dist/backend/llvm/dense-array-access.js +222 -52
  61. package/dist/backend/llvm/dense-array-access.js.map +1 -1
  62. package/dist/backend/llvm/dense-array-access.test.js +36 -0
  63. package/dist/backend/llvm/dense-array-access.test.js.map +1 -1
  64. package/dist/backend/llvm/dense-array-loops.d.ts +35 -16
  65. package/dist/backend/llvm/dense-array-loops.js +237 -12
  66. package/dist/backend/llvm/dense-array-loops.js.map +1 -1
  67. package/dist/backend/llvm/dense-array-loops.test.js +140 -15
  68. package/dist/backend/llvm/dense-array-loops.test.js.map +1 -1
  69. package/dist/backend/llvm/dyn-handle-tags.test.js +6 -1
  70. package/dist/backend/llvm/dyn-handle-tags.test.js.map +1 -1
  71. package/dist/backend/llvm/dyn.d.ts +51 -1
  72. package/dist/backend/llvm/dyn.js +683 -69
  73. package/dist/backend/llvm/dyn.js.map +1 -1
  74. package/dist/backend/llvm/emit-function.js +33 -26
  75. package/dist/backend/llvm/emit-function.js.map +1 -1
  76. package/dist/backend/llvm/emit-journal.d.ts +93 -0
  77. package/dist/backend/llvm/emit-journal.js +170 -0
  78. package/dist/backend/llvm/emit-journal.js.map +1 -0
  79. package/dist/backend/llvm/emit-module.js +208 -34
  80. package/dist/backend/llvm/emit-module.js.map +1 -1
  81. package/dist/backend/llvm/emit-statements.d.ts +0 -27
  82. package/dist/backend/llvm/emit-statements.js +577 -93
  83. package/dist/backend/llvm/emit-statements.js.map +1 -1
  84. package/dist/backend/llvm/emitter-state.d.ts +7 -0
  85. package/dist/backend/llvm/emitter-state.js +14 -0
  86. package/dist/backend/llvm/emitter-state.js.map +1 -0
  87. package/dist/backend/llvm/emitter.d.ts +314 -49
  88. package/dist/backend/llvm/emitter.js +1241 -129
  89. package/dist/backend/llvm/emitter.js.map +1 -1
  90. package/dist/backend/llvm/emitter.test.js +54 -5
  91. package/dist/backend/llvm/emitter.test.js.map +1 -1
  92. package/dist/backend/llvm/expr-async.js +19 -0
  93. package/dist/backend/llvm/expr-async.js.map +1 -1
  94. package/dist/backend/llvm/expr-bytes.d.ts +5 -2
  95. package/dist/backend/llvm/expr-bytes.js +144 -52
  96. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  97. package/dist/backend/llvm/expr-callbacks.js +47 -0
  98. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  99. package/dist/backend/llvm/expr-calls.d.ts +1 -1
  100. package/dist/backend/llvm/expr-calls.js +62 -36
  101. package/dist/backend/llvm/expr-calls.js.map +1 -1
  102. package/dist/backend/llvm/expr-containers.d.ts +14 -2
  103. package/dist/backend/llvm/expr-containers.js +148 -40
  104. package/dist/backend/llvm/expr-containers.js.map +1 -1
  105. package/dist/backend/llvm/expr-context.d.ts +14 -0
  106. package/dist/backend/llvm/expr-control.js +2 -3
  107. package/dist/backend/llvm/expr-control.js.map +1 -1
  108. package/dist/backend/llvm/expr-dynamic.js +71 -16
  109. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  110. package/dist/backend/llvm/expr-primitives.js +126 -36
  111. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  112. package/dist/backend/llvm/expr-primitives.test.js +11 -6
  113. package/dist/backend/llvm/expr-primitives.test.js.map +1 -1
  114. package/dist/backend/llvm/expr-records.d.ts +12 -0
  115. package/dist/backend/llvm/expr-records.js +106 -0
  116. package/dist/backend/llvm/expr-records.js.map +1 -1
  117. package/dist/backend/llvm/expr-stream-bridges.d.ts +2 -2
  118. package/dist/backend/llvm/expr-stream-bridges.js +225 -64
  119. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  120. package/dist/backend/llvm/expr-stream-bridges.test.js +1 -1
  121. package/dist/backend/llvm/expr-stream-bridges.test.js.map +1 -1
  122. package/dist/backend/llvm/expr-stream-callbacks.d.ts +2 -2
  123. package/dist/backend/llvm/expr-stream-callbacks.js +200 -50
  124. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  125. package/dist/backend/llvm/int32-kind-loops.d.ts +39 -0
  126. package/dist/backend/llvm/int32-kind-loops.js +106 -0
  127. package/dist/backend/llvm/int32-kind-loops.js.map +1 -0
  128. package/dist/backend/llvm/integer-or-nan-indexes.test.d.ts +1 -0
  129. package/dist/backend/llvm/integer-or-nan-indexes.test.js +118 -0
  130. package/dist/backend/llvm/integer-or-nan-indexes.test.js.map +1 -0
  131. package/dist/backend/llvm/integer-values.d.ts +20 -1
  132. package/dist/backend/llvm/integer-values.js +71 -0
  133. package/dist/backend/llvm/integer-values.js.map +1 -1
  134. package/dist/backend/llvm/js-ic.d.ts +1 -1
  135. package/dist/backend/llvm/js-ic.js +1 -1
  136. package/dist/backend/llvm/js-ic.js.map +1 -1
  137. package/dist/backend/llvm/key-orders.d.ts +7 -0
  138. package/dist/backend/llvm/key-orders.js +33 -0
  139. package/dist/backend/llvm/key-orders.js.map +1 -0
  140. package/dist/backend/llvm/lib-connect.js +4 -0
  141. package/dist/backend/llvm/lib-connect.js.map +1 -1
  142. package/dist/backend/llvm/lib-datagram.js +11 -0
  143. package/dist/backend/llvm/lib-datagram.js.map +1 -1
  144. package/dist/backend/llvm/lib-dispatch.js +90 -2
  145. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  146. package/dist/backend/llvm/lib-filesystem.js +65 -4
  147. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  148. package/dist/backend/llvm/lib-http2.d.ts +4 -0
  149. package/dist/backend/llvm/lib-http2.js +24 -17
  150. package/dist/backend/llvm/lib-http2.js.map +1 -1
  151. package/dist/backend/llvm/lib-lookup.js +16 -6
  152. package/dist/backend/llvm/lib-lookup.js.map +1 -1
  153. package/dist/backend/llvm/lib-process.js +65 -14
  154. package/dist/backend/llvm/lib-process.js.map +1 -1
  155. package/dist/backend/llvm/lib-shared.js +126 -3
  156. package/dist/backend/llvm/lib-shared.js.map +1 -1
  157. package/dist/backend/llvm/lib-stream.js +97 -30
  158. package/dist/backend/llvm/lib-stream.js.map +1 -1
  159. package/dist/backend/llvm/lib-tls.js +23 -0
  160. package/dist/backend/llvm/lib-tls.js.map +1 -1
  161. package/dist/backend/llvm/local-array-reads.js +181 -64
  162. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  163. package/dist/backend/llvm/local-array-reads.test.js +28 -0
  164. package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
  165. package/dist/backend/llvm/loop-state.d.ts +33 -0
  166. package/dist/backend/llvm/loop-state.js +42 -0
  167. package/dist/backend/llvm/loop-state.js.map +1 -0
  168. package/dist/backend/llvm/map-number-lookup.d.ts +26 -8
  169. package/dist/backend/llvm/map-number-lookup.js +91 -31
  170. package/dist/backend/llvm/map-number-lookup.js.map +1 -1
  171. package/dist/backend/llvm/map-number-lookup.test.js +55 -0
  172. package/dist/backend/llvm/map-number-lookup.test.js.map +1 -1
  173. package/dist/backend/llvm/map-read-lifetimes.js +4 -2
  174. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
  175. package/dist/backend/llvm/nullable-unions.d.ts +2 -1
  176. package/dist/backend/llvm/nullable-unions.js +15 -3
  177. package/dist/backend/llvm/nullable-unions.js.map +1 -1
  178. package/dist/backend/llvm/publish.d.ts +18 -1
  179. package/dist/backend/llvm/publish.js +76 -25
  180. package/dist/backend/llvm/publish.js.map +1 -1
  181. package/dist/backend/llvm/publish.test.js +3 -0
  182. package/dist/backend/llvm/publish.test.js.map +1 -1
  183. package/dist/backend/llvm/receivers.js +7 -2
  184. package/dist/backend/llvm/receivers.js.map +1 -1
  185. package/dist/backend/llvm/record-results.d.ts +1 -9
  186. package/dist/backend/llvm/record-results.js +2 -11
  187. package/dist/backend/llvm/record-results.js.map +1 -1
  188. package/dist/backend/llvm/reference-writes.d.ts +7 -2
  189. package/dist/backend/llvm/reference-writes.js +91 -72
  190. package/dist/backend/llvm/reference-writes.js.map +1 -1
  191. package/dist/backend/llvm/regex-matchers.js +161 -14
  192. package/dist/backend/llvm/regex-matchers.js.map +1 -1
  193. package/dist/backend/llvm/regex-matchers.test.js +18 -0
  194. package/dist/backend/llvm/regex-matchers.test.js.map +1 -1
  195. package/dist/backend/llvm/running-extrema.d.ts +11 -0
  196. package/dist/backend/llvm/running-extrema.js +115 -0
  197. package/dist/backend/llvm/running-extrema.js.map +1 -0
  198. package/dist/backend/llvm/running-extrema.test.d.ts +1 -0
  199. package/dist/backend/llvm/running-extrema.test.js +89 -0
  200. package/dist/backend/llvm/running-extrema.test.js.map +1 -0
  201. package/dist/backend/llvm/shapes.d.ts +79 -21
  202. package/dist/backend/llvm/shapes.js +233 -42
  203. package/dist/backend/llvm/shapes.js.map +1 -1
  204. package/dist/backend/llvm/shapes.test.js +53 -7
  205. package/dist/backend/llvm/shapes.test.js.map +1 -1
  206. package/dist/backend/llvm/speculative-integers.d.ts +6 -0
  207. package/dist/backend/llvm/speculative-integers.js +2 -2
  208. package/dist/backend/llvm/speculative-integers.js.map +1 -1
  209. package/dist/backend/llvm/stack-objects.d.ts +3 -2
  210. package/dist/backend/llvm/stack-objects.js +5 -2
  211. package/dist/backend/llvm/stack-objects.js.map +1 -1
  212. package/dist/backend/llvm/string-lifetimes.test.js +2 -1
  213. package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
  214. package/dist/backend/llvm/string-reads.d.ts +15 -0
  215. package/dist/backend/llvm/string-reads.js +128 -0
  216. package/dist/backend/llvm/string-reads.js.map +1 -1
  217. package/dist/backend/llvm/walk-borrows.d.ts +3 -0
  218. package/dist/backend/llvm/walk-borrows.js +46 -41
  219. package/dist/backend/llvm/walk-borrows.js.map +1 -1
  220. package/dist/backend/llvm/walkers.d.ts +3 -0
  221. package/dist/backend/llvm/walkers.js +88 -65
  222. package/dist/backend/llvm/walkers.js.map +1 -1
  223. package/dist/backend/llvm/wasm-modules.d.ts +6 -5
  224. package/dist/backend/llvm/wasm-modules.js +32 -9
  225. package/dist/backend/llvm/wasm-modules.js.map +1 -1
  226. package/dist/backend/llvm/wrapping-sums.d.ts +16 -1
  227. package/dist/backend/llvm/wrapping-sums.js +126 -0
  228. package/dist/backend/llvm/wrapping-sums.js.map +1 -1
  229. package/dist/backend/mangle.d.ts +3 -0
  230. package/dist/backend/mangle.js +5 -0
  231. package/dist/backend/mangle.js.map +1 -1
  232. package/dist/backend/may-throw.d.ts +8 -10
  233. package/dist/backend/may-throw.js +14 -10
  234. package/dist/backend/may-throw.js.map +1 -1
  235. package/dist/backend/native/contracts.d.ts +27 -4
  236. package/dist/backend/native/executable.js +31 -8
  237. package/dist/backend/native/executable.js.map +1 -1
  238. package/dist/backend/native/library.js +1 -0
  239. package/dist/backend/native/library.js.map +1 -1
  240. package/dist/backend/native/runtime-inputs.d.ts +1 -1
  241. package/dist/backend/native/runtime-inputs.js +1 -0
  242. package/dist/backend/native/runtime-inputs.js.map +1 -1
  243. package/dist/backend/native-codegen.d.ts +11 -6
  244. package/dist/backend/native-codegen.js +36 -9
  245. package/dist/backend/native-codegen.js.map +1 -1
  246. package/dist/backend/native-codegen.test.js +0 -23
  247. package/dist/backend/native-codegen.test.js.map +1 -1
  248. package/dist/backend/native-link-info-core.d.ts +18 -4
  249. package/dist/backend/native-link-info-core.js.map +1 -1
  250. package/dist/backend/optimization.d.ts +2 -2
  251. package/dist/backend/publication.d.ts +12 -1
  252. package/dist/backend/publication.js +37 -14
  253. package/dist/backend/publication.js.map +1 -1
  254. package/dist/backend/publication.test.js +30 -0
  255. package/dist/backend/publication.test.js.map +1 -1
  256. package/dist/backend/result-slots.d.ts +16 -0
  257. package/dist/backend/result-slots.js +23 -0
  258. package/dist/backend/result-slots.js.map +1 -0
  259. package/dist/backend/runtime-abi.d.ts +2 -2
  260. package/dist/backend/runtime-abi.js +2 -2
  261. package/dist/backend/runtime-pack-core.d.ts +2 -1
  262. package/dist/backend/runtime-pack-core.js +2 -1
  263. package/dist/backend/runtime-pack-core.js.map +1 -1
  264. package/dist/backend/runtime-pack-targets.test.js +5 -1
  265. package/dist/backend/runtime-pack-targets.test.js.map +1 -1
  266. package/dist/backend/runtime-pack.d.ts +0 -21
  267. package/dist/backend/runtime-pack.js +0 -29
  268. package/dist/backend/runtime-pack.js.map +1 -1
  269. package/dist/backend/runtime-pack.test.js +10 -69
  270. package/dist/backend/runtime-pack.test.js.map +1 -1
  271. package/dist/backend/stack-observations.d.ts +2 -1
  272. package/dist/backend/stack-observations.js +67 -42
  273. package/dist/backend/stack-observations.js.map +1 -1
  274. package/dist/backend/target-diagnostics.js +33 -1
  275. package/dist/backend/target-diagnostics.js.map +1 -1
  276. package/dist/backend/warm-cache.js +4 -0
  277. package/dist/backend/warm-cache.js.map +1 -1
  278. package/dist/cli/command.js +26 -6
  279. package/dist/cli/command.js.map +1 -1
  280. package/dist/cli/usage.d.ts +5 -1
  281. package/dist/cli/usage.js +10 -5
  282. package/dist/cli/usage.js.map +1 -1
  283. package/dist/compat/fetch-profile.js +1 -1
  284. package/dist/compat/fetch-profile.js.map +1 -1
  285. package/dist/contracts/check.js +5 -4
  286. package/dist/contracts/check.js.map +1 -1
  287. package/dist/contracts/int32-elements.js +10 -2
  288. package/dist/contracts/int32-elements.js.map +1 -1
  289. package/dist/coverage/report.d.ts +7 -2
  290. package/dist/coverage/report.js +30 -3
  291. package/dist/coverage/report.js.map +1 -1
  292. package/dist/coverage/verdict-cache.d.ts +1 -0
  293. package/dist/coverage/verdict-cache.js +4 -0
  294. package/dist/coverage/verdict-cache.js.map +1 -1
  295. package/dist/coverage/verdict-semantic.js +4 -0
  296. package/dist/coverage/verdict-semantic.js.map +1 -1
  297. package/dist/diagnostics/diagnostic.d.ts +4 -0
  298. package/dist/diagnostics/diagnostic.js.map +1 -1
  299. package/dist/diagnostics/dynamic-tier.d.ts +40 -0
  300. package/dist/diagnostics/dynamic-tier.js +57 -0
  301. package/dist/diagnostics/dynamic-tier.js.map +1 -0
  302. package/dist/diagnostics/envelope.d.ts +5 -1
  303. package/dist/diagnostics/envelope.js +6 -2
  304. package/dist/diagnostics/envelope.js.map +1 -1
  305. package/dist/executable/executable-cache.d.ts +25 -1
  306. package/dist/executable/executable-cache.js +60 -7
  307. package/dist/executable/executable-cache.js.map +1 -1
  308. package/dist/executable/executable-cache.test.js +46 -3
  309. package/dist/executable/executable-cache.test.js.map +1 -1
  310. package/dist/executable/prepare.js +3 -1
  311. package/dist/executable/prepare.js.map +1 -1
  312. package/dist/frontend/analysis.js +1 -0
  313. package/dist/frontend/analysis.js.map +1 -1
  314. package/dist/frontend/decl-projection.d.ts +41 -0
  315. package/dist/frontend/decl-projection.js +854 -0
  316. package/dist/frontend/decl-projection.js.map +1 -0
  317. package/dist/frontend/decl-projection.test.d.ts +1 -0
  318. package/dist/frontend/decl-projection.test.js +30 -0
  319. package/dist/frontend/decl-projection.test.js.map +1 -0
  320. package/dist/frontend/dispose-hook.d.ts +2 -0
  321. package/dist/frontend/dispose-hook.js +14 -0
  322. package/dist/frontend/dispose-hook.js.map +1 -0
  323. package/dist/frontend/dts-paths.d.ts +15 -0
  324. package/dist/frontend/dts-paths.js +25 -0
  325. package/dist/frontend/dts-paths.js.map +1 -1
  326. package/dist/frontend/input-tracker.d.ts +6 -0
  327. package/dist/frontend/input-tracker.js +51 -28
  328. package/dist/frontend/input-tracker.js.map +1 -1
  329. package/dist/frontend/input-tracker.test.js +19 -0
  330. package/dist/frontend/input-tracker.test.js.map +1 -1
  331. package/dist/frontend/jsx-entities.d.ts +4 -0
  332. package/dist/frontend/jsx-entities.js +259 -0
  333. package/dist/frontend/jsx-entities.js.map +1 -0
  334. package/dist/frontend/jsx-source.d.ts +71 -0
  335. package/dist/frontend/jsx-source.js +781 -0
  336. package/dist/frontend/jsx-source.js.map +1 -0
  337. package/dist/frontend/jsx-source.test.d.ts +1 -0
  338. package/dist/frontend/jsx-source.test.js +200 -0
  339. package/dist/frontend/jsx-source.test.js.map +1 -0
  340. package/dist/frontend/literal-values.test.js +8 -9
  341. package/dist/frontend/literal-values.test.js.map +1 -1
  342. package/dist/frontend/lowering/array-indexed-mutation.js +2 -1
  343. package/dist/frontend/lowering/array-indexed-mutation.js.map +1 -1
  344. package/dist/frontend/lowering/array-values.js +103 -4
  345. package/dist/frontend/lowering/array-values.js.map +1 -1
  346. package/dist/frontend/lowering/binding-analysis.d.ts +1 -1
  347. package/dist/frontend/lowering/binding-analysis.js +2 -2
  348. package/dist/frontend/lowering/binding-analysis.js.map +1 -1
  349. package/dist/frontend/lowering/builtins/arguments.d.ts +3 -0
  350. package/dist/frontend/lowering/builtins/arguments.js +30 -15
  351. package/dist/frontend/lowering/builtins/arguments.js.map +1 -1
  352. package/dist/frontend/lowering/builtins/atomics.js +10 -6
  353. package/dist/frontend/lowering/builtins/atomics.js.map +1 -1
  354. package/dist/frontend/lowering/builtins/child-process-async.js +2 -1
  355. package/dist/frontend/lowering/builtins/child-process-async.js.map +1 -1
  356. package/dist/frontend/lowering/builtins/child-process-methods.js +46 -15
  357. package/dist/frontend/lowering/builtins/child-process-methods.js.map +1 -1
  358. package/dist/frontend/lowering/builtins/child-process-sync.js +2 -1
  359. package/dist/frontend/lowering/builtins/child-process-sync.js.map +1 -1
  360. package/dist/frontend/lowering/builtins/child-process.js +13 -2
  361. package/dist/frontend/lowering/builtins/child-process.js.map +1 -1
  362. package/dist/frontend/lowering/builtins/crypto.d.ts +4 -2
  363. package/dist/frontend/lowering/builtins/crypto.js +136 -5
  364. package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
  365. package/dist/frontend/lowering/builtins/date-classes.d.ts +46 -0
  366. package/dist/frontend/lowering/builtins/date-classes.js +477 -0
  367. package/dist/frontend/lowering/builtins/date-classes.js.map +1 -0
  368. package/dist/frontend/lowering/builtins/dates.d.ts +11 -1
  369. package/dist/frontend/lowering/builtins/dates.js +55 -26
  370. package/dist/frontend/lowering/builtins/dates.js.map +1 -1
  371. package/dist/frontend/lowering/builtins/dh.d.ts +15 -0
  372. package/dist/frontend/lowering/builtins/dh.js +151 -0
  373. package/dist/frontend/lowering/builtins/dh.js.map +1 -0
  374. package/dist/frontend/lowering/builtins/disposable-stack.js +2 -1
  375. package/dist/frontend/lowering/builtins/disposable-stack.js.map +1 -1
  376. package/dist/frontend/lowering/builtins/ecdh.d.ts +12 -1
  377. package/dist/frontend/lowering/builtins/ecdh.js +7 -7
  378. package/dist/frontend/lowering/builtins/ecdh.js.map +1 -1
  379. package/dist/frontend/lowering/builtins/errors.d.ts +15 -0
  380. package/dist/frontend/lowering/builtins/errors.js +110 -0
  381. package/dist/frontend/lowering/builtins/errors.js.map +1 -1
  382. package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +1 -1
  383. package/dist/frontend/lowering/builtins/filesystem-calls.js +23 -17
  384. package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
  385. package/dist/frontend/lowering/builtins/filesystem.js +6 -4
  386. package/dist/frontend/lowering/builtins/filesystem.js.map +1 -1
  387. package/dist/frontend/lowering/builtins/fs-paths.d.ts +15 -0
  388. package/dist/frontend/lowering/builtins/fs-paths.js +209 -0
  389. package/dist/frontend/lowering/builtins/fs-paths.js.map +1 -0
  390. package/dist/frontend/lowering/builtins/global-namespace-keys.d.ts +3 -0
  391. package/dist/frontend/lowering/builtins/global-namespace-keys.js +122 -0
  392. package/dist/frontend/lowering/builtins/global-namespace-keys.js.map +1 -0
  393. package/dist/frontend/lowering/builtins/hash-stream.d.ts +16 -4
  394. package/dist/frontend/lowering/builtins/hash-stream.js +86 -23
  395. package/dist/frontend/lowering/builtins/hash-stream.js.map +1 -1
  396. package/dist/frontend/lowering/builtins/json.js +2 -1
  397. package/dist/frontend/lowering/builtins/json.js.map +1 -1
  398. package/dist/frontend/lowering/builtins/key-object.d.ts +2 -1
  399. package/dist/frontend/lowering/builtins/key-object.js +20 -7
  400. package/dist/frontend/lowering/builtins/key-object.js.map +1 -1
  401. package/dist/frontend/lowering/builtins/module-calls.js +11 -4
  402. package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
  403. package/dist/frontend/lowering/builtins/numbers.js +18 -6
  404. package/dist/frontend/lowering/builtins/numbers.js.map +1 -1
  405. package/dist/frontend/lowering/builtins/operating-system.js +4 -3
  406. package/dist/frontend/lowering/builtins/operating-system.js.map +1 -1
  407. package/dist/frontend/lowering/builtins/performance.js +3 -2
  408. package/dist/frontend/lowering/builtins/performance.js.map +1 -1
  409. package/dist/frontend/lowering/builtins/process.js +3 -2
  410. package/dist/frontend/lowering/builtins/process.js.map +1 -1
  411. package/dist/frontend/lowering/builtins/promises.d.ts +6 -0
  412. package/dist/frontend/lowering/builtins/promises.js +91 -4
  413. package/dist/frontend/lowering/builtins/promises.js.map +1 -1
  414. package/dist/frontend/lowering/builtins/promisify-callback.js +2 -1
  415. package/dist/frontend/lowering/builtins/promisify-callback.js.map +1 -1
  416. package/dist/frontend/lowering/builtins/readline.d.ts +7 -2
  417. package/dist/frontend/lowering/builtins/readline.js +58 -9
  418. package/dist/frontend/lowering/builtins/readline.js.map +1 -1
  419. package/dist/frontend/lowering/builtins/strings.js +13 -5
  420. package/dist/frontend/lowering/builtins/strings.js.map +1 -1
  421. package/dist/frontend/lowering/builtins/text-codecs.js +2 -1
  422. package/dist/frontend/lowering/builtins/text-codecs.js.map +1 -1
  423. package/dist/frontend/lowering/builtins/timers.js +1 -1
  424. package/dist/frontend/lowering/builtins/timers.js.map +1 -1
  425. package/dist/frontend/lowering/builtins/url.js +28 -4
  426. package/dist/frontend/lowering/builtins/url.js.map +1 -1
  427. package/dist/frontend/lowering/builtins/v8.js +2 -1
  428. package/dist/frontend/lowering/builtins/v8.js.map +1 -1
  429. package/dist/frontend/lowering/builtins/webassembly.js +6 -3
  430. package/dist/frontend/lowering/builtins/webassembly.js.map +1 -1
  431. package/dist/frontend/lowering/builtins/webcrypto.js +39 -20
  432. package/dist/frontend/lowering/builtins/webcrypto.js.map +1 -1
  433. package/dist/frontend/lowering/call-arguments.js +2 -1
  434. package/dist/frontend/lowering/call-arguments.js.map +1 -1
  435. package/dist/frontend/lowering/call-signatures.js +13 -6
  436. package/dist/frontend/lowering/call-signatures.js.map +1 -1
  437. package/dist/frontend/lowering/caught-value-dispatch.d.ts +18 -1
  438. package/dist/frontend/lowering/caught-value-dispatch.js +201 -32
  439. package/dist/frontend/lowering/caught-value-dispatch.js.map +1 -1
  440. package/dist/frontend/lowering/class-assertions.js +3 -2
  441. package/dist/frontend/lowering/class-assertions.js.map +1 -1
  442. package/dist/frontend/lowering/class-callbacks.d.ts +5 -2
  443. package/dist/frontend/lowering/class-callbacks.js +82 -12
  444. package/dist/frontend/lowering/class-callbacks.js.map +1 -1
  445. package/dist/frontend/lowering/class-construction.d.ts +6 -2
  446. package/dist/frontend/lowering/class-construction.js +25 -16
  447. package/dist/frontend/lowering/class-construction.js.map +1 -1
  448. package/dist/frontend/lowering/class-descriptors.js +1 -1
  449. package/dist/frontend/lowering/class-descriptors.js.map +1 -1
  450. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +73 -2
  451. package/dist/frontend/lowering/class-dynamic-dispatch.js +1334 -259
  452. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  453. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +124 -0
  454. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  455. package/dist/frontend/lowering/class-iterables.d.ts +2 -1
  456. package/dist/frontend/lowering/class-iterables.js +9 -1
  457. package/dist/frontend/lowering/class-iterables.js.map +1 -1
  458. package/dist/frontend/lowering/class-method-mutations.js +35 -9
  459. package/dist/frontend/lowering/class-method-mutations.js.map +1 -1
  460. package/dist/frontend/lowering/class-method-values.js +1 -1
  461. package/dist/frontend/lowering/class-method-values.js.map +1 -1
  462. package/dist/frontend/lowering/class-protocols.d.ts +7 -0
  463. package/dist/frontend/lowering/class-protocols.js +64 -4
  464. package/dist/frontend/lowering/class-protocols.js.map +1 -1
  465. package/dist/frontend/lowering/class-prototypes.d.ts +5 -0
  466. package/dist/frontend/lowering/class-prototypes.js +67 -5
  467. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  468. package/dist/frontend/lowering/class-runtime-statics.d.ts +9 -3
  469. package/dist/frontend/lowering/class-runtime-statics.js +29 -4
  470. package/dist/frontend/lowering/class-runtime-statics.js.map +1 -1
  471. package/dist/frontend/lowering/class-to-primitive.js +25 -5
  472. package/dist/frontend/lowering/class-to-primitive.js.map +1 -1
  473. package/dist/frontend/lowering/class-unions.js +2 -1
  474. package/dist/frontend/lowering/class-unions.js.map +1 -1
  475. package/dist/frontend/lowering/coercions/function-adapters.js +6 -5
  476. package/dist/frontend/lowering/coercions/function-adapters.js.map +1 -1
  477. package/dist/frontend/lowering/coercions/structural-plans.js +48 -1
  478. package/dist/frontend/lowering/coercions/structural-plans.js.map +1 -1
  479. package/dist/frontend/lowering/coercions/structural.js +99 -8
  480. package/dist/frontend/lowering/coercions/structural.js.map +1 -1
  481. package/dist/frontend/lowering/coercions/unions.js +8 -7
  482. package/dist/frontend/lowering/coercions/unions.js.map +1 -1
  483. package/dist/frontend/lowering/collection-ingestion.js +2 -1
  484. package/dist/frontend/lowering/collection-ingestion.js.map +1 -1
  485. package/dist/frontend/lowering/containers/array-callback-call.js +2 -2
  486. package/dist/frontend/lowering/containers/array-callback-call.js.map +1 -1
  487. package/dist/frontend/lowering/containers/array-callbacks.d.ts +7 -0
  488. package/dist/frontend/lowering/containers/array-callbacks.js +352 -31
  489. package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
  490. package/dist/frontend/lowering/containers/array-concat.js +12 -1
  491. package/dist/frontend/lowering/containers/array-concat.js.map +1 -1
  492. package/dist/frontend/lowering/containers/array-construction.js +25 -4
  493. package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
  494. package/dist/frontend/lowering/containers/array-methods.js +21 -5
  495. package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
  496. package/dist/frontend/lowering/containers/array-pipelines.js +21 -9
  497. package/dist/frontend/lowering/containers/array-pipelines.js.map +1 -1
  498. package/dist/frontend/lowering/containers/bytes.d.ts +1 -1
  499. package/dist/frontend/lowering/containers/bytes.js +131 -29
  500. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  501. package/dist/frontend/lowering/containers/callback-arguments.js +55 -2
  502. package/dist/frontend/lowering/containers/callback-arguments.js.map +1 -1
  503. package/dist/frontend/lowering/containers/collection-grouping.js +3 -2
  504. package/dist/frontend/lowering/containers/collection-grouping.js.map +1 -1
  505. package/dist/frontend/lowering/containers/collection-methods.js +15 -9
  506. package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
  507. package/dist/frontend/lowering/containers/filter-predicates.d.ts +6 -0
  508. package/dist/frontend/lowering/containers/filter-predicates.js +205 -0
  509. package/dist/frontend/lowering/containers/filter-predicates.js.map +1 -0
  510. package/dist/frontend/lowering/containers/indexed-objects.d.ts +0 -12
  511. package/dist/frontend/lowering/containers/indexed-objects.js +54 -14
  512. package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
  513. package/dist/frontend/lowering/containers/iterator-helpers.d.ts +32 -1
  514. package/dist/frontend/lowering/containers/iterator-helpers.js +6 -5
  515. package/dist/frontend/lowering/containers/iterator-helpers.js.map +1 -1
  516. package/dist/frontend/lowering/containers/string-and-regexp.js +87 -14
  517. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  518. package/dist/frontend/lowering/containers/string-replacement.js +45 -20
  519. package/dist/frontend/lowering/containers/string-replacement.js.map +1 -1
  520. package/dist/frontend/lowering/cycle-initialization.js +25 -4
  521. package/dist/frontend/lowering/cycle-initialization.js.map +1 -1
  522. package/dist/frontend/lowering/deferred-module-initializers.d.ts +18 -1
  523. package/dist/frontend/lowering/deferred-module-initializers.js +226 -115
  524. package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -1
  525. package/dist/frontend/lowering/deferred-module-initializers.test.js +28 -0
  526. package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -1
  527. package/dist/frontend/lowering/dispatch-sites.d.ts +59 -0
  528. package/dist/frontend/lowering/dispatch-sites.js +218 -0
  529. package/dist/frontend/lowering/dispatch-sites.js.map +1 -0
  530. package/dist/frontend/lowering/dispatch-sites.test.d.ts +1 -0
  531. package/dist/frontend/lowering/dispatch-sites.test.js +59 -0
  532. package/dist/frontend/lowering/dispatch-sites.test.js.map +1 -0
  533. package/dist/frontend/lowering/divergences.js +9 -1
  534. package/dist/frontend/lowering/divergences.js.map +1 -1
  535. package/dist/frontend/lowering/dyn-streams.d.ts +3 -0
  536. package/dist/frontend/lowering/dyn-streams.js +1 -1
  537. package/dist/frontend/lowering/dyn-streams.js.map +1 -1
  538. package/dist/frontend/lowering/dynamic-tier.d.ts +25 -0
  539. package/dist/frontend/lowering/dynamic-tier.js +327 -0
  540. package/dist/frontend/lowering/dynamic-tier.js.map +1 -0
  541. package/dist/frontend/lowering/error-methods.js +51 -2
  542. package/dist/frontend/lowering/error-methods.js.map +1 -1
  543. package/dist/frontend/lowering/expressions/array-literals.js +62 -0
  544. package/dist/frontend/lowering/expressions/array-literals.js.map +1 -1
  545. package/dist/frontend/lowering/expressions/binary.js +81 -5
  546. package/dist/frontend/lowering/expressions/binary.js.map +1 -1
  547. package/dist/frontend/lowering/expressions/element-access.js +107 -14
  548. package/dist/frontend/lowering/expressions/element-access.js.map +1 -1
  549. package/dist/frontend/lowering/expressions/identifiers.js +79 -11
  550. package/dist/frontend/lowering/expressions/identifiers.js.map +1 -1
  551. package/dist/frontend/lowering/expressions/narrowing.js +130 -6
  552. package/dist/frontend/lowering/expressions/narrowing.js.map +1 -1
  553. package/dist/frontend/lowering/expressions/nullish-assignment.js +3 -1
  554. package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
  555. package/dist/frontend/lowering/expressions/object-literals.d.ts +10 -3
  556. package/dist/frontend/lowering/expressions/object-literals.js +164 -56
  557. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  558. package/dist/frontend/lowering/expressions/optional-chains.js +17 -5
  559. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  560. package/dist/frontend/lowering/expressions/property-access.d.ts +0 -4
  561. package/dist/frontend/lowering/expressions/property-access.js +211 -17
  562. package/dist/frontend/lowering/expressions/property-access.js.map +1 -1
  563. package/dist/frontend/lowering/expressions/relational.js +267 -30
  564. package/dist/frontend/lowering/expressions/relational.js.map +1 -1
  565. package/dist/frontend/lowering/expressions/union-fields.js +4 -0
  566. package/dist/frontend/lowering/expressions/union-fields.js.map +1 -1
  567. package/dist/frontend/lowering/expressions/updates.js +85 -12
  568. package/dist/frontend/lowering/expressions/updates.js.map +1 -1
  569. package/dist/frontend/lowering/frozen-records.d.ts +28 -0
  570. package/dist/frontend/lowering/frozen-records.js +322 -0
  571. package/dist/frontend/lowering/frozen-records.js.map +1 -0
  572. package/dist/frontend/lowering/function-returns.js +49 -0
  573. package/dist/frontend/lowering/function-returns.js.map +1 -1
  574. package/dist/frontend/lowering/generator-dynamic-dispatch.d.ts +6 -1
  575. package/dist/frontend/lowering/generator-dynamic-dispatch.js +20 -30
  576. package/dist/frontend/lowering/generator-dynamic-dispatch.js.map +1 -1
  577. package/dist/frontend/lowering/generic-functions.d.ts +42 -1
  578. package/dist/frontend/lowering/generic-functions.js +455 -20
  579. package/dist/frontend/lowering/generic-functions.js.map +1 -1
  580. package/dist/frontend/lowering/intern-tables.js +2 -1
  581. package/dist/frontend/lowering/intern-tables.js.map +1 -1
  582. package/dist/frontend/lowering/iterable-values.d.ts +49 -0
  583. package/dist/frontend/lowering/iterable-values.js +297 -0
  584. package/dist/frontend/lowering/iterable-values.js.map +1 -0
  585. package/dist/frontend/lowering/iterator-adapters.js +195 -9
  586. package/dist/frontend/lowering/iterator-adapters.js.map +1 -1
  587. package/dist/frontend/lowering/js-class-fields.d.ts +8 -0
  588. package/dist/frontend/lowering/js-class-fields.js +45 -10
  589. package/dist/frontend/lowering/js-class-fields.js.map +1 -1
  590. package/dist/frontend/lowering/js-dynamic-objects.js +3 -2
  591. package/dist/frontend/lowering/js-dynamic-objects.js.map +1 -1
  592. package/dist/frontend/lowering/json-require.js +2 -1
  593. package/dist/frontend/lowering/json-require.js.map +1 -1
  594. package/dist/frontend/lowering/key-order-witness.d.ts +24 -4
  595. package/dist/frontend/lowering/key-order-witness.js +790 -25
  596. package/dist/frontend/lowering/key-order-witness.js.map +1 -1
  597. package/dist/frontend/lowering/key-order-witness.test.js +466 -10
  598. package/dist/frontend/lowering/key-order-witness.test.js.map +1 -1
  599. package/dist/frontend/lowering/lifetime-regions.js +2 -1
  600. package/dist/frontend/lowering/lifetime-regions.js.map +1 -1
  601. package/dist/frontend/lowering/lower-assert.js +6 -5
  602. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  603. package/dist/frontend/lowering/lower-async-iteration.js +7 -2
  604. package/dist/frontend/lowering/lower-async-iteration.js.map +1 -1
  605. package/dist/frontend/lowering/lower-calls.d.ts +11 -0
  606. package/dist/frontend/lowering/lower-calls.js +776 -126
  607. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  608. package/dist/frontend/lowering/lower-classes.d.ts +29 -2
  609. package/dist/frontend/lowering/lower-classes.js +581 -46
  610. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  611. package/dist/frontend/lowering/lower-dgram.js +6 -3
  612. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  613. package/dist/frontend/lowering/lower-event-emitter.d.ts +14 -0
  614. package/dist/frontend/lowering/lower-event-emitter.js +267 -20
  615. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  616. package/dist/frontend/lowering/lower-exprs.d.ts +19 -2
  617. package/dist/frontend/lowering/lower-exprs.js +126 -13
  618. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  619. package/dist/frontend/lowering/lower-functions.d.ts +11 -0
  620. package/dist/frontend/lowering/lower-functions.js +387 -72
  621. package/dist/frontend/lowering/lower-functions.js.map +1 -1
  622. package/dist/frontend/lowering/lower-generators.js +41 -31
  623. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  624. package/dist/frontend/lowering/lower-global-value.js +6 -3
  625. package/dist/frontend/lowering/lower-global-value.js.map +1 -1
  626. package/dist/frontend/lowering/lower-inspect.js +28 -12
  627. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  628. package/dist/frontend/lowering/lower-mixins.js +2 -1
  629. package/dist/frontend/lowering/lower-mixins.js.map +1 -1
  630. package/dist/frontend/lowering/lower-mock.js +2 -1
  631. package/dist/frontend/lowering/lower-mock.js.map +1 -1
  632. package/dist/frontend/lowering/lower-modules.js +47 -5
  633. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  634. package/dist/frontend/lowering/lower-modules.test.js +2 -2
  635. package/dist/frontend/lowering/lower-modules.test.js.map +1 -1
  636. package/dist/frontend/lowering/lower-namespaces.d.ts +2 -1
  637. package/dist/frontend/lowering/lower-namespaces.js +9 -4
  638. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  639. package/dist/frontend/lowering/lower-server.d.ts +10 -0
  640. package/dist/frontend/lowering/lower-server.js +239 -61
  641. package/dist/frontend/lowering/lower-server.js.map +1 -1
  642. package/dist/frontend/lowering/lower-stdlib.d.ts +5 -0
  643. package/dist/frontend/lowering/lower-stdlib.js +42 -10
  644. package/dist/frontend/lowering/lower-stdlib.js.map +1 -1
  645. package/dist/frontend/lowering/lower-stmts.d.ts +23 -0
  646. package/dist/frontend/lowering/lower-stmts.js +622 -68
  647. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  648. package/dist/frontend/lowering/lower-stmts.test.js +1 -1
  649. package/dist/frontend/lowering/lower-stmts.test.js.map +1 -1
  650. package/dist/frontend/lowering/lower-stream.d.ts +20 -2
  651. package/dist/frontend/lowering/lower-stream.js +2055 -318
  652. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  653. package/dist/frontend/lowering/lower-timers.js +4 -3
  654. package/dist/frontend/lowering/lower-timers.js.map +1 -1
  655. package/dist/frontend/lowering/lowerer.d.ts +197 -29
  656. package/dist/frontend/lowering/lowerer.js +862 -84
  657. package/dist/frontend/lowering/lowerer.js.map +1 -1
  658. package/dist/frontend/lowering/lowerer.test.js +21 -9
  659. package/dist/frontend/lowering/lowerer.test.js.map +1 -1
  660. package/dist/frontend/lowering/module-namespace-elements.d.ts +11 -1
  661. package/dist/frontend/lowering/module-namespace-elements.js +82 -5
  662. package/dist/frontend/lowering/module-namespace-elements.js.map +1 -1
  663. package/dist/frontend/lowering/narrowing-stability.js +5 -0
  664. package/dist/frontend/lowering/narrowing-stability.js.map +1 -1
  665. package/dist/frontend/lowering/native-ffi.js +1 -1
  666. package/dist/frontend/lowering/native-ffi.js.map +1 -1
  667. package/dist/frontend/lowering/new-target.d.ts +12 -0
  668. package/dist/frontend/lowering/new-target.js +280 -0
  669. package/dist/frontend/lowering/new-target.js.map +1 -0
  670. package/dist/frontend/lowering/object-enumeration-receiver.js +2 -1
  671. package/dist/frontend/lowering/object-enumeration-receiver.js.map +1 -1
  672. package/dist/frontend/lowering/pairs-snapshot.js +2 -1
  673. package/dist/frontend/lowering/pairs-snapshot.js.map +1 -1
  674. package/dist/frontend/lowering/private-brands.d.ts +9 -0
  675. package/dist/frontend/lowering/private-brands.js +66 -15
  676. package/dist/frontend/lowering/private-brands.js.map +1 -1
  677. package/dist/frontend/lowering/promise-executor-adapter.js +2 -1
  678. package/dist/frontend/lowering/promise-executor-adapter.js.map +1 -1
  679. package/dist/frontend/lowering/require-initialization.js +2 -1
  680. package/dist/frontend/lowering/require-initialization.js.map +1 -1
  681. package/dist/frontend/lowering/runtime-optional-elements.d.ts +5 -0
  682. package/dist/frontend/lowering/runtime-optional-elements.js +17 -1
  683. package/dist/frontend/lowering/runtime-optional-elements.js.map +1 -1
  684. package/dist/frontend/lowering/runtime-optional-records.d.ts +2 -0
  685. package/dist/frontend/lowering/runtime-optional-records.js +18 -5
  686. package/dist/frontend/lowering/runtime-optional-records.js.map +1 -1
  687. package/dist/frontend/lowering/site-dependencies.d.ts +35 -0
  688. package/dist/frontend/lowering/site-dependencies.js +84 -0
  689. package/dist/frontend/lowering/site-dependencies.js.map +1 -0
  690. package/dist/frontend/lowering/site-dependencies.test.d.ts +1 -0
  691. package/dist/frontend/lowering/site-dependencies.test.js +53 -0
  692. package/dist/frontend/lowering/site-dependencies.test.js.map +1 -0
  693. package/dist/frontend/lowering/stable-names.d.ts +11 -0
  694. package/dist/frontend/lowering/stable-names.js +35 -0
  695. package/dist/frontend/lowering/stable-names.js.map +1 -0
  696. package/dist/frontend/lowering/static-typeof.d.ts +2 -2
  697. package/dist/frontend/lowering/static-typeof.js +42 -3
  698. package/dist/frontend/lowering/static-typeof.js.map +1 -1
  699. package/dist/frontend/lowering/strict-equality.js +2 -1
  700. package/dist/frontend/lowering/strict-equality.js.map +1 -1
  701. package/dist/frontend/lowering/structural-positions.d.ts +32 -0
  702. package/dist/frontend/lowering/structural-positions.js +108 -0
  703. package/dist/frontend/lowering/structural-positions.js.map +1 -0
  704. package/dist/frontend/lowering/surfaces.d.ts +3 -0
  705. package/dist/frontend/lowering/surfaces.js +60 -32
  706. package/dist/frontend/lowering/surfaces.js.map +1 -1
  707. package/dist/frontend/lowering/undefined-index.d.ts +27 -0
  708. package/dist/frontend/lowering/undefined-index.js +82 -0
  709. package/dist/frontend/lowering/undefined-index.js.map +1 -0
  710. package/dist/frontend/lowering/var-hoisting.js +66 -16
  711. package/dist/frontend/lowering/var-hoisting.js.map +1 -1
  712. package/dist/frontend/lowering/width-lift.d.ts +18 -0
  713. package/dist/frontend/npm-static-bundled-chunks.js +9 -11
  714. package/dist/frontend/npm-static-bundled-chunks.js.map +1 -1
  715. package/dist/frontend/npm-static-bundled-chunks.test.js +6 -5
  716. package/dist/frontend/npm-static-bundled-chunks.test.js.map +1 -1
  717. package/dist/frontend/npm-static-rewrite-syntax.js +9 -1
  718. package/dist/frontend/npm-static-rewrite-syntax.js.map +1 -1
  719. package/dist/frontend/npm-static-tsc-helpers.d.ts +5 -0
  720. package/dist/frontend/npm-static-tsc-helpers.js +106 -0
  721. package/dist/frontend/npm-static-tsc-helpers.js.map +1 -0
  722. package/dist/frontend/npm-static-tsc-helpers.test.d.ts +1 -0
  723. package/dist/frontend/npm-static-tsc-helpers.test.js +58 -0
  724. package/dist/frontend/npm-static-tsc-helpers.test.js.map +1 -0
  725. package/dist/frontend/npm-static-type-exports-host.d.ts +8 -0
  726. package/dist/frontend/npm-static-type-exports-host.js +214 -0
  727. package/dist/frontend/npm-static-type-exports-host.js.map +1 -0
  728. package/dist/frontend/npm-static-type-exports-host.test.d.ts +1 -0
  729. package/dist/frontend/npm-static-type-exports-host.test.js +53 -0
  730. package/dist/frontend/npm-static-type-exports-host.test.js.map +1 -0
  731. package/dist/frontend/npm-static-type-exports.d.ts +52 -0
  732. package/dist/frontend/npm-static-type-exports.js +261 -0
  733. package/dist/frontend/npm-static-type-exports.js.map +1 -0
  734. package/dist/frontend/npm-static-type-exports.test.d.ts +1 -0
  735. package/dist/frontend/npm-static-type-exports.test.js +103 -0
  736. package/dist/frontend/npm-static-type-exports.test.js.map +1 -0
  737. package/dist/frontend/npm-static-umd.d.ts +6 -0
  738. package/dist/frontend/npm-static-umd.js +203 -0
  739. package/dist/frontend/npm-static-umd.js.map +1 -0
  740. package/dist/frontend/npm-static-umd.test.d.ts +1 -0
  741. package/dist/frontend/npm-static-umd.test.js +105 -0
  742. package/dist/frontend/npm-static-umd.test.js.map +1 -0
  743. package/dist/frontend/npm-static.d.ts +8 -0
  744. package/dist/frontend/npm-static.js +51 -22
  745. package/dist/frontend/npm-static.js.map +1 -1
  746. package/dist/frontend/package-shims.d.ts +3 -0
  747. package/dist/frontend/package-shims.js +71 -8
  748. package/dist/frontend/package-shims.js.map +1 -1
  749. package/dist/frontend/pipeline.js +18 -10
  750. package/dist/frontend/pipeline.js.map +1 -1
  751. package/dist/frontend/process-fork.d.ts +25 -0
  752. package/dist/frontend/process-fork.js +2 -0
  753. package/dist/frontend/process-fork.js.map +1 -0
  754. package/dist/frontend/program.d.ts +21 -1
  755. package/dist/frontend/program.js +586 -74
  756. package/dist/frontend/program.js.map +1 -1
  757. package/dist/frontend/program.test.js +44 -4
  758. package/dist/frontend/program.test.js.map +1 -1
  759. package/dist/frontend/services.d.ts +6 -0
  760. package/dist/frontend/services.js +18 -0
  761. package/dist/frontend/services.js.map +1 -1
  762. package/dist/frontend/token-equivalence.d.ts +3 -0
  763. package/dist/frontend/token-equivalence.js +409 -0
  764. package/dist/frontend/token-equivalence.js.map +1 -0
  765. package/dist/frontend/token-equivalence.test.d.ts +1 -0
  766. package/dist/frontend/token-equivalence.test.js +67 -0
  767. package/dist/frontend/token-equivalence.test.js.map +1 -0
  768. package/dist/frontend/ts7/ast-node.d.ts +43 -7
  769. package/dist/frontend/ts7/ast-node.js +1176 -129
  770. package/dist/frontend/ts7/ast-node.js.map +1 -1
  771. package/dist/frontend/ts7/ast-node.test.js +84 -0
  772. package/dist/frontend/ts7/ast-node.test.js.map +1 -1
  773. package/dist/frontend/ts7/ast-wire.d.ts +29 -3
  774. package/dist/frontend/ts7/ast-wire.js +144 -31
  775. package/dist/frontend/ts7/ast-wire.js.map +1 -1
  776. package/dist/frontend/ts7/ast-wire.test.js +23 -0
  777. package/dist/frontend/ts7/ast-wire.test.js.map +1 -1
  778. package/dist/frontend/ts7/ast.d.ts +23 -2
  779. package/dist/frontend/ts7/ast.js +143 -2
  780. package/dist/frontend/ts7/ast.js.map +1 -1
  781. package/dist/frontend/ts7/checker-backend.d.ts +3 -4
  782. package/dist/frontend/ts7/checker-backend.js +2 -2
  783. package/dist/frontend/ts7/checker-backend.js.map +1 -1
  784. package/dist/frontend/ts7/checker-backend.test.js +5 -9
  785. package/dist/frontend/ts7/checker-backend.test.js.map +1 -1
  786. package/dist/frontend/ts7/checker.d.ts +17 -1
  787. package/dist/frontend/ts7/checker.js +82 -1
  788. package/dist/frontend/ts7/checker.js.map +1 -1
  789. package/dist/frontend/ts7/checker.test.js +9 -6
  790. package/dist/frontend/ts7/checker.test.js.map +1 -1
  791. package/dist/frontend/ts7/enums.d.ts +3 -3
  792. package/dist/frontend/ts7/enums.generated.d.ts +10 -0
  793. package/dist/frontend/ts7/enums.generated.js +21 -0
  794. package/dist/frontend/ts7/enums.generated.js.map +1 -1
  795. package/dist/frontend/ts7/enums.js +19 -0
  796. package/dist/frontend/ts7/enums.js.map +1 -1
  797. package/dist/frontend/ts7/lib-diagnostics.d.ts +24 -0
  798. package/dist/frontend/ts7/lib-diagnostics.js +307 -0
  799. package/dist/frontend/ts7/lib-diagnostics.js.map +1 -0
  800. package/dist/frontend/ts7/lib-diagnostics.test.d.ts +1 -0
  801. package/dist/frontend/ts7/lib-diagnostics.test.js +199 -0
  802. package/dist/frontend/ts7/lib-diagnostics.test.js.map +1 -0
  803. package/dist/frontend/ts7/program-host.d.ts +7 -0
  804. package/dist/frontend/ts7/program-host.js +30 -4
  805. package/dist/frontend/ts7/program-host.js.map +1 -1
  806. package/dist/frontend/ts7/semantic-checker.d.ts +10 -0
  807. package/dist/frontend/ts7/semantic-checker.js +25 -20
  808. package/dist/frontend/ts7/semantic-checker.js.map +1 -1
  809. package/dist/frontend/ts7/semantic-json.d.ts +13 -0
  810. package/dist/frontend/ts7/semantic-json.js +146 -0
  811. package/dist/frontend/ts7/semantic-json.js.map +1 -1
  812. package/dist/frontend/ts7/semantic-json.test.js +57 -1
  813. package/dist/frontend/ts7/semantic-json.test.js.map +1 -1
  814. package/dist/frontend/ts7/semantic-model.d.ts +15 -0
  815. package/dist/frontend/ts7/semantic-model.js +67 -19
  816. package/dist/frontend/ts7/semantic-model.js.map +1 -1
  817. package/dist/frontend/ts7/semantic-model.test.js +3 -2
  818. package/dist/frontend/ts7/semantic-model.test.js.map +1 -1
  819. package/dist/frontend/ts7/session.d.ts +14 -1
  820. package/dist/frontend/ts7/session.js +23 -1
  821. package/dist/frontend/ts7/session.js.map +1 -1
  822. package/dist/frontend/tsc-codes.d.ts +1 -1
  823. package/dist/frontend/tsc-codes.js +7 -0
  824. package/dist/frontend/tsc-codes.js.map +1 -1
  825. package/dist/frontend/type-mapper.d.ts +51 -7
  826. package/dist/frontend/type-mapper.js +456 -43
  827. package/dist/frontend/type-mapper.js.map +1 -1
  828. package/dist/frontend/type-mapper.test.js +1 -1
  829. package/dist/frontend/type-mapper.test.js.map +1 -1
  830. package/dist/frontend-process-args.d.ts +4 -0
  831. package/dist/frontend-process-args.js +52 -0
  832. package/dist/frontend-process-args.js.map +1 -0
  833. package/dist/frontend-process-args.test.d.ts +1 -0
  834. package/dist/frontend-process-args.test.js +47 -0
  835. package/dist/frontend-process-args.test.js.map +1 -0
  836. package/dist/frontend-process.d.ts +1 -0
  837. package/dist/frontend-process.js +23 -0
  838. package/dist/frontend-process.js.map +1 -0
  839. package/dist/heap-collection.d.ts +16 -0
  840. package/dist/heap-collection.js +42 -0
  841. package/dist/heap-collection.js.map +1 -0
  842. package/dist/heap-collection.test.d.ts +1 -0
  843. package/dist/heap-collection.test.js +59 -0
  844. package/dist/heap-collection.test.js.map +1 -0
  845. package/dist/heap-pressure.d.ts +2 -0
  846. package/dist/heap-pressure.js +12 -0
  847. package/dist/heap-pressure.js.map +1 -0
  848. package/dist/index.d.ts +2 -0
  849. package/dist/index.js +435 -89
  850. package/dist/index.js.map +1 -1
  851. package/dist/ir/analysis.js +5 -3
  852. package/dist/ir/analysis.js.map +1 -1
  853. package/dist/ir/array-length-stability.d.ts +4 -0
  854. package/dist/ir/array-length-stability.js +26 -6
  855. package/dist/ir/array-length-stability.js.map +1 -1
  856. package/dist/ir/array-length-stability.test.js +49 -0
  857. package/dist/ir/array-length-stability.test.js.map +1 -1
  858. package/dist/ir/builtin-effects.d.ts +7 -0
  859. package/dist/ir/builtin-effects.js +80 -0
  860. package/dist/ir/builtin-effects.js.map +1 -1
  861. package/dist/ir/builtin-signatures.d.ts +7 -1
  862. package/dist/ir/builtin-signatures.js +303 -21
  863. package/dist/ir/builtin-signatures.js.map +1 -1
  864. package/dist/ir/callback-specialization.d.ts +2 -1
  865. package/dist/ir/callback-specialization.js +23 -18
  866. package/dist/ir/callback-specialization.js.map +1 -1
  867. package/dist/ir/char-unit-locals.d.ts +19 -0
  868. package/dist/ir/char-unit-locals.js +185 -0
  869. package/dist/ir/char-unit-locals.js.map +1 -0
  870. package/dist/ir/char-unit-locals.test.d.ts +1 -0
  871. package/dist/ir/char-unit-locals.test.js +94 -0
  872. package/dist/ir/char-unit-locals.test.js.map +1 -0
  873. package/dist/ir/final-fields.d.ts +3 -1
  874. package/dist/ir/final-fields.js +15 -17
  875. package/dist/ir/final-fields.js.map +1 -1
  876. package/dist/ir/function-references.d.ts +2 -0
  877. package/dist/ir/function-references.js +2 -0
  878. package/dist/ir/function-references.js.map +1 -1
  879. package/dist/ir/function-references.test.js +5 -0
  880. package/dist/ir/function-references.test.js.map +1 -1
  881. package/dist/ir/initializer-bindings.d.ts +2 -1
  882. package/dist/ir/initializer-bindings.js +27 -20
  883. package/dist/ir/initializer-bindings.js.map +1 -1
  884. package/dist/ir/int32-arrays.d.ts +108 -0
  885. package/dist/ir/int32-arrays.js +831 -0
  886. package/dist/ir/int32-arrays.js.map +1 -0
  887. package/dist/ir/int32-slots.d.ts +36 -6
  888. package/dist/ir/int32-slots.js +370 -171
  889. package/dist/ir/int32-slots.js.map +1 -1
  890. package/dist/ir/int32-slots.test.js +3 -1
  891. package/dist/ir/int32-slots.test.js.map +1 -1
  892. package/dist/ir/integer-loop-facts.d.ts +9 -4
  893. package/dist/ir/integer-loop-facts.js +93 -18
  894. package/dist/ir/integer-loop-facts.js.map +1 -1
  895. package/dist/ir/integer-loops.d.ts +49 -0
  896. package/dist/ir/integer-loops.js +202 -40
  897. package/dist/ir/integer-loops.js.map +1 -1
  898. package/dist/ir/integer-loops.test.js +211 -1
  899. package/dist/ir/integer-loops.test.js.map +1 -1
  900. package/dist/ir/integer-ranges.d.ts +5 -0
  901. package/dist/ir/integer-ranges.js +125 -12
  902. package/dist/ir/integer-ranges.js.map +1 -1
  903. package/dist/ir/integer-ranges.test.js +94 -0
  904. package/dist/ir/integer-ranges.test.js.map +1 -1
  905. package/dist/ir/ir.d.ts +87 -9
  906. package/dist/ir/ir.js +61 -2
  907. package/dist/ir/ir.js.map +1 -1
  908. package/dist/ir/ir.test.js +21 -1
  909. package/dist/ir/ir.test.js.map +1 -1
  910. package/dist/ir/js-ic.d.ts +19 -2
  911. package/dist/ir/js-ic.js +95 -11
  912. package/dist/ir/js-ic.js.map +1 -1
  913. package/dist/ir/js-ic.test.js +188 -0
  914. package/dist/ir/js-ic.test.js.map +1 -1
  915. package/dist/ir/node-index.d.ts +57 -0
  916. package/dist/ir/node-index.js +215 -0
  917. package/dist/ir/node-index.js.map +1 -0
  918. package/dist/ir/paired-while-loops.d.ts +25 -0
  919. package/dist/ir/paired-while-loops.js +335 -0
  920. package/dist/ir/paired-while-loops.js.map +1 -0
  921. package/dist/ir/paired-while-loops.test.d.ts +1 -0
  922. package/dist/ir/paired-while-loops.test.js +163 -0
  923. package/dist/ir/paired-while-loops.test.js.map +1 -0
  924. package/dist/ir/parameter-versions.d.ts +25 -0
  925. package/dist/ir/parameter-versions.js +300 -0
  926. package/dist/ir/parameter-versions.js.map +1 -0
  927. package/dist/ir/runtime-features.d.ts +60 -15
  928. package/dist/ir/runtime-features.js +276 -35
  929. package/dist/ir/runtime-features.js.map +1 -1
  930. package/dist/ir/serialize.d.ts +12 -2
  931. package/dist/ir/serialize.js +16 -3
  932. package/dist/ir/serialize.js.map +1 -1
  933. package/dist/ir/serialize.test.js +17 -0
  934. package/dist/ir/serialize.test.js.map +1 -1
  935. package/dist/ir/tiers.js +1 -0
  936. package/dist/ir/tiers.js.map +1 -1
  937. package/dist/ir/traverse.d.ts +2 -0
  938. package/dist/ir/traverse.js +29 -5
  939. package/dist/ir/traverse.js.map +1 -1
  940. package/dist/ir/validate.js +171 -45
  941. package/dist/ir/validate.js.map +1 -1
  942. package/dist/library/ir-policy.js +12 -0
  943. package/dist/library/ir-policy.js.map +1 -1
  944. package/dist/library/library-cache.d.ts +2 -0
  945. package/dist/library/library-cache.js.map +1 -1
  946. package/dist/library/prepare.js +2 -0
  947. package/dist/library/prepare.js.map +1 -1
  948. package/dist/native/cache.d.ts +6 -1
  949. package/dist/native/cache.js +28 -5
  950. package/dist/native/cache.js.map +1 -1
  951. package/dist/native/cache.test.js +16 -2
  952. package/dist/native/cache.test.js.map +1 -1
  953. package/dist/native/cli.js +26 -1
  954. package/dist/native/cli.js.map +1 -1
  955. package/dist/native/compiler.js +8 -6
  956. package/dist/native/compiler.js.map +1 -1
  957. package/dist/native/executable-cache.d.ts +1 -1
  958. package/dist/native/executable-cache.js +2 -2
  959. package/dist/native/executable-cache.js.map +1 -1
  960. package/dist/native/prepare.d.ts +3 -1
  961. package/dist/native/prepare.js +123 -31
  962. package/dist/native/prepare.js.map +1 -1
  963. package/dist/native/prepare.test.js +78 -18
  964. package/dist/native/prepare.test.js.map +1 -1
  965. package/dist/native/sanitizer.test.js +6 -1
  966. package/dist/native/sanitizer.test.js.map +1 -1
  967. package/dist/native/text-file.d.ts +13 -3
  968. package/dist/native/text-file.js +63 -9
  969. package/dist/native/text-file.js.map +1 -1
  970. package/dist/native/text-file.test.d.ts +1 -0
  971. package/dist/native/text-file.test.js +49 -0
  972. package/dist/native/text-file.test.js.map +1 -0
  973. package/dist/native/toolchain.js +4 -4
  974. package/dist/native/toolchain.js.map +1 -1
  975. package/dist/native/toolchain.test.js +3 -3
  976. package/dist/native/toolchain.test.js.map +1 -1
  977. package/dist/startup-cache.d.ts +1 -0
  978. package/dist/startup-cache.js +1 -0
  979. package/dist/startup-cache.js.map +1 -1
  980. package/dist/text-parts.d.ts +7 -0
  981. package/dist/text-parts.js +44 -0
  982. package/dist/text-parts.js.map +1 -1
  983. package/dist/text-parts.test.d.ts +1 -0
  984. package/dist/text-parts.test.js +46 -0
  985. package/dist/text-parts.test.js.map +1 -0
  986. package/dist/timing.d.ts +9 -2
  987. package/dist/timing.js +7 -4
  988. package/dist/timing.js.map +1 -1
  989. package/dist/wasm/translate.d.ts +4 -0
  990. package/dist/wasm/translate.js +2 -2
  991. package/dist/wasm/translate.js.map +1 -1
  992. package/package.json +21 -21
  993. package/shims/chalk/v5.ts +688 -0
  994. package/shims/hono-node-server/v2.ts +645 -0
  995. package/shims/hot-shots/client.ts +1126 -0
  996. package/shims/hot-shots/v8-unix-dgram.ts +8 -0
  997. package/shims/hot-shots/v8.ts +8 -0
  998. package/shims/undici/core/client.ts +4 -4
  999. package/surface-manifest.json +44 -52
@@ -1,5 +1,6 @@
1
+ import { keyedHelperName } from "./stable-names.js";
1
2
  import { nodeThrowExpr, boolLit, numLit, strLit } from "../../ir/build.js";
2
- import { hashStreamOf, isHashValueType } from "./builtins/hash-stream.js";
3
+ import { isValueStream, valueStreamOf } from "./builtins/hash-stream.js";
3
4
  import { InternalCompilerError } from "../../errors.js";
4
5
  /* The node:stream lowering (the spoke-module pattern, like
5
6
  * lower-event-emitter.ts): construction of the five runtime stream classes
@@ -43,8 +44,12 @@ import { dynUndefinedExpr, varRef } from "../../ir/build.js";
43
44
  import { genResultRecord } from "../type-mapper.js";
44
45
  import { noteUntypedStreamFlow, requestGeneralStreamSurface } from "./general-streams.js";
45
46
  import { dynNativeBranch } from "./dyn-streams.js";
47
+ import { bindingNeverReassigned } from "./binding-analysis.js";
46
48
  import { extractIteratorValue, genStep, genValue, stepDrivable } from "./lower-generators.js";
47
- import { BOOL, DYN, F64, RUNTIME_STREAM_CLASSES, STRING, VOID, arrayOf, BYTES_U8, canBoxFuncIntoDyn, canConvertToDyn, funcOf, typeEquals, typeKey, } from "../../ir/ir.js";
49
+ import { LiftedFrame, driveGenerator } from "./containers/iterator-helpers.js";
50
+ import { lowerArrayIteratorValue, lowerStringIteratorValue } from "./iterator-adapters.js";
51
+ import { staticReadableStreamElementType } from "./lower-stdlib.js";
52
+ import { BOOL, DYN, F64, RUNTIME_STREAM_CLASSES, STRING, VOID, arrayOf, BYTES_U8, canBoxFuncIntoDyn, canConvertToDyn, funcOf, typeEquals, typeKey, UNDEFINED_T, } from "../../ir/ir.js";
48
53
  const BYTES = BYTES_U8;
49
54
  /** An expression that only reads bindings and properties (no calls,
50
55
  * assignments or construction): reading it a step later observes the
@@ -66,6 +71,55 @@ function pureRead(node) {
66
71
  }
67
72
  return false;
68
73
  }
74
+ /** A literal, `undefined`, or a function expression: a value that reads
75
+ * no binding or property. */
76
+ function constantOptionValue(node) {
77
+ let e = node;
78
+ while (ts.isParenthesizedExpression(e) || ts.isAsExpression(e) || ts.isTypeAssertion(e))
79
+ e = e.expression;
80
+ if (ts.isIdentifier(e))
81
+ return e.text === "undefined";
82
+ if (ts.isPrefixUnaryExpression(e) &&
83
+ (e.operator === ts.SyntaxKind.MinusToken ||
84
+ e.operator === ts.SyntaxKind.PlusToken ||
85
+ e.operator === ts.SyntaxKind.ExclamationToken))
86
+ return constantOptionValue(e.operand);
87
+ return (ts.isStringLiteralLike(e) ||
88
+ ts.isNumericLiteral(e) ||
89
+ ts.isBigIntLiteral(e) ||
90
+ e.kind === ts.SyntaxKind.TrueKeyword ||
91
+ e.kind === ts.SyntaxKind.FalseKeyword ||
92
+ e.kind === ts.SyntaxKind.NullKeyword ||
93
+ ts.isArrowFunction(e) ||
94
+ ts.isFunctionExpression(e));
95
+ }
96
+ /** Whether a runtime decodeStrings or defaultEncoding value (`prop`'s
97
+ * `value`) may be read before the other option members. Those values are
98
+ * read into locals before the constructor evaluates the other members,
99
+ * while Node evaluates the members in order, so every earlier member must
100
+ * evaluate without effects, and when the value itself has effects, every
101
+ * earlier member must also read nothing those effects could change. */
102
+ function earlierOptionsPure(options, prop, value) {
103
+ const valueHasEffects = !sideEffectFreeOptionValue(value) && !pureRead(value);
104
+ for (const member of options.properties.nodes) {
105
+ if (member === prop)
106
+ return true;
107
+ if (ts.isPropertyAssignment(member)) {
108
+ const init = member.initializer;
109
+ if (valueHasEffects
110
+ ? !constantOptionValue(init)
111
+ : !sideEffectFreeOptionValue(init) && !pureRead(init))
112
+ return false;
113
+ }
114
+ else if (ts.isShorthandPropertyAssignment(member)) {
115
+ if (valueHasEffects)
116
+ return false;
117
+ }
118
+ else if (ts.isSpreadAssignment(member))
119
+ return false;
120
+ }
121
+ return true;
122
+ }
69
123
  /** The stream sides of a receiver class: the nearest stream-class
70
124
  * ancestor's, or null off the stream hierarchy. */
71
125
  export function streamSidesOf(lowerer, info) {
@@ -131,10 +185,23 @@ export const UNDERSCORE_METHODS = new Map([
131
185
  ["transform", "_transform"],
132
186
  ["flush", "_flush"],
133
187
  ]);
188
+ /** The option callbacks applied after construction rather than through
189
+ * the constructor's callback slots (option name → method name): construct
190
+ * on every stream class, and writev on every class with a writable side
191
+ * (a Transform's batches reach writev, not the transform, as in Node). */
192
+ export const STREAM_EXTRA_CALLBACKS = new Map([
193
+ ["construct", "_construct"],
194
+ ["writev", "_writev"],
195
+ ]);
196
+ export function streamExtraCallbacks(cls) {
197
+ return cls === "%Readable" ? ["construct"] : ["construct", "writev"];
198
+ }
134
199
  /** The completion callback's parameter position in each underscore
135
200
  * method that takes one (cbTuples' "fn" positions). */
136
201
  export const STREAM_COMPLETION_CALLBACK_INDEX = new Map([
137
202
  ["_write", 2],
203
+ ["_writev", 1],
204
+ ["_construct", 0],
138
205
  ["_final", 0],
139
206
  ["_destroy", 1],
140
207
  ["_transform", 2],
@@ -229,7 +296,7 @@ export function streamForcedTuple(lowerer, info, name) {
229
296
  * (Node calls them stream-bound); arrows keep lexical `this` (the hidden
230
297
  * leading param is ABI-only). The declared parameters must be a
231
298
  * typeEquals PREFIX of the callback's Node signature. */
232
- function lowerStreamCallback(lowerer, which, node, thisType, fullTuple) {
299
+ function lowerStreamCallback(lowerer, which, node, thisType, fullTuple, chunkValues = true) {
233
300
  const loc = locOf(node);
234
301
  const { shapes, funcType } = lowerer.lambdaSignature(node);
235
302
  if (node.modifiers?.nodes.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword)) {
@@ -245,11 +312,26 @@ function lowerStreamCallback(lowerer, which, node, thisType, fullTuple) {
245
312
  // callable dyn whose glue dispatches to the runtime's *_done).
246
313
  if (funcType.params[i].kind === "dyn")
247
314
  continue;
315
+ // A write or transform chunk of another type converts from the
316
+ // chunk's value when the callback runs (an object-mode side's value),
317
+ // or throws a TypeError there — on a side known to be byte mode the
318
+ // chunk is a Buffer, so the declared type must be Node's or a
319
+ // supertype of it (`Buffer | string`); an encoding of another type
320
+ // (`string | null | undefined`) converts from the encoding argument's
321
+ // value.
322
+ if (((((i === 0 &&
323
+ (chunkValues || widensInto(lowerer, fullTuple[0], funcType.params[0], loc))) ||
324
+ i === 1) &&
325
+ (which === "write" || which === "transform")) ||
326
+ (i === 0 && which === "writev")) &&
327
+ funcType.params[i].kind !== "func" &&
328
+ canConvertToDyn(funcType.params[i], (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)))
329
+ continue;
248
330
  if (!typeEquals(funcType.params[i], fullTuple[i])) {
249
331
  lowerer.noLowering(`a '${which}' callback whose parameter ${i} is '${lowerer.fmt(funcType.params[i])}' where Node passes '${lowerer.fmt(fullTuple[i])}'`, node, "annotate the parameter with the Node signature's type (chunks are Buffers here)");
250
332
  }
251
333
  }
252
- const fnName = `%fn${lowerer.lambdaCounter++}_${which}cb`;
334
+ const fnName = lowerer.closureName(loc, `_${which}cb`);
253
335
  const fnCtx = newFnCtx(true, null, funcType, funcType.ret);
254
336
  lowerer.fnStack.push(fnCtx);
255
337
  try {
@@ -311,6 +393,58 @@ function lowerStreamCallback(lowerer, which, node, thisType, fullTuple) {
311
393
  lowerer.fnStack.pop();
312
394
  }
313
395
  }
396
+ /** The objectMode, readableObjectMode and writableObjectMode members of a
397
+ * stream options literal (boolean literals; the sided keys count only on
398
+ * a Duplex, Transform or PassThrough, as in Node). */
399
+ function streamObjectModes(lowerer, ctorName, optsLit) {
400
+ const out = { readable: false, writable: false };
401
+ const duplexish = ctorName !== "Readable" && ctorName !== "Writable";
402
+ for (const prop of optsLit?.properties?.nodes ?? []) {
403
+ if (!ts.isPropertyAssignment(prop))
404
+ continue;
405
+ const name = ts.isIdentifier(prop.name) || ts.isStringLiteral(prop.name) ? prop.name.text : null;
406
+ if (name !== "objectMode" && name !== "readableObjectMode" && name !== "writableObjectMode")
407
+ continue;
408
+ const value = prop.initializer;
409
+ if (value.kind === ts.SyntaxKind.FalseKeyword)
410
+ continue;
411
+ if (value.kind !== ts.SyntaxKind.TrueKeyword) {
412
+ lowerer.noLowering(`${ctorName} with a runtime '${name}' value`, prop, `write '${name}: true' or '${name}: false'`);
413
+ }
414
+ if (name === "objectMode") {
415
+ out.readable = true;
416
+ out.writable = true;
417
+ }
418
+ else if (duplexish) {
419
+ if (name === "readableObjectMode")
420
+ out.readable = true;
421
+ else
422
+ out.writable = true;
423
+ }
424
+ }
425
+ return out;
426
+ }
427
+ /** Whether an options literal makes the writable side hold values: its
428
+ * object mode set with a `true` literal (objectMode, or writableObjectMode
429
+ * on a duplex stream), or decodeStrings: false (strings stay strings).
430
+ * Reports nothing: the options parse fences the other value forms. */
431
+ function literalWritesValues(opts, duplexish) {
432
+ for (const prop of opts.properties?.nodes ?? []) {
433
+ if (!ts.isPropertyAssignment(prop))
434
+ continue;
435
+ const name = ts.isIdentifier(prop.name) || ts.isStringLiteral(prop.name) ? prop.name.text : null;
436
+ if (name === "decodeStrings") {
437
+ if (prop.initializer.kind !== ts.SyntaxKind.TrueKeyword)
438
+ return true;
439
+ continue;
440
+ }
441
+ if (name !== "objectMode" && !(duplexish && name === "writableObjectMode"))
442
+ continue;
443
+ if (prop.initializer.kind !== ts.SyntaxKind.FalseKeyword)
444
+ return true;
445
+ }
446
+ return false;
447
+ }
314
448
  /** The full Node parameter tuples of the option callbacks, given the
315
449
  * concrete stream's `this` type. The trailing completion callbacks keep
316
450
  * whatever func type the checker contextually gave the user's parameter
@@ -321,6 +455,8 @@ function cbTuples(lowerer) {
321
455
  read: [F64],
322
456
  write: [BYTES, STRING, "fn"],
323
457
  final: ["fn"],
458
+ construct: ["fn"],
459
+ writev: [DYN, "fn"],
324
460
  destroy: [errorOrNull(lowerer), "fn"],
325
461
  transform: [BYTES, STRING, "fn"],
326
462
  flush: ["fn"],
@@ -514,10 +650,57 @@ function pinAnyDataCompletion(lowerer, which, fnNode) {
514
650
  const declared = lowerer.paramShape(param).type;
515
651
  if (declared.kind !== "func" || declared.rest || declared.params[1]?.kind !== "dyn")
516
652
  return null;
653
+ // Only when every use calls the callback with a Buffer, a string or
654
+ // nothing as `data`: another value (or a callback that escapes) keeps
655
+ // `data` checked-dynamic, so the runtime pushes it as push(data) does
656
+ // and reports ERR_INVALID_ARG_TYPE through 'error', as Node does.
657
+ if (fnNode.body === undefined || !completionDataIsChunk(lowerer, fnNode.body, symbol, param.name))
658
+ return null;
517
659
  const data = unionOf(lowerer, [BYTES, STRING, { kind: "undefinedT" }]);
518
660
  lowerer.stageSourceTypes.set(symbol, funcOf([declared.params[0], data, ...declared.params.slice(2)], declared.ret));
519
661
  return symbol;
520
662
  }
663
+ /** Whether every reference to the completion callback `symbol` in `body`
664
+ * calls it with a `data` argument that is a Buffer, a string, null or
665
+ * undefined (or with no data). */
666
+ function completionDataIsChunk(lowerer, body, symbol, declaration) {
667
+ let ok = true;
668
+ const visit = (node) => {
669
+ if (!ok)
670
+ return;
671
+ if (ts.isIdentifier(node) &&
672
+ node !== declaration &&
673
+ lowerer.checker.getSymbolAtLocation(node) === symbol) {
674
+ const call = node.parent;
675
+ if (!call || !ts.isCallExpression(call) || call.expression !== node) {
676
+ ok = false;
677
+ return;
678
+ }
679
+ const data = call.arguments.nodes[1];
680
+ if (data !== undefined) {
681
+ let t;
682
+ try {
683
+ t = lowerer.mapTypeOf(lowerer.typeOf(data));
684
+ }
685
+ catch {
686
+ t = null;
687
+ }
688
+ const arms = t?.kind === "union" ? (lowerer.unions.get(t.unionId)?.arms ?? null) : t ? [t] : null;
689
+ if (arms === null ||
690
+ !arms.every((a) => (a.kind === "bytes" && a.elem === "u8") ||
691
+ a.kind === "string" ||
692
+ a.kind === "undefinedT" ||
693
+ a.kind === "nullT")) {
694
+ ok = false;
695
+ return;
696
+ }
697
+ }
698
+ }
699
+ ts.forEachChild(node, visit);
700
+ };
701
+ visit(body);
702
+ return ok;
703
+ }
521
704
  /** Parses the options object literal of a stream constructor. `which`
522
705
  * names the callbacks this class accepts, in canonical flag order. */
523
706
  function parseStreamOptions(lowerer, ctorName, arg, thisType, accepted, loc,
@@ -538,14 +721,50 @@ fallbackCb) {
538
721
  badEncoding: null,
539
722
  pushEncoding: null,
540
723
  signal: null,
724
+ valueDecls: [],
725
+ decodeStringsValue: null,
726
+ defaultEncodingValue: null,
727
+ readableObject: false,
728
+ writableObject: false,
729
+ decodeStringsOff: false,
730
+ writeEncoding: null,
731
+ extras: [],
541
732
  flags: 0,
542
733
  cbs: [],
543
734
  };
735
+ const extraNames = streamExtraCallbacks(`%${ctorName}`);
736
+ const writableClass = ctorName !== "Readable";
544
737
  const followed = followOptionsArg(lowerer, arg);
545
738
  const optsLit = followed === null ? undefined : followed;
546
739
  if (optsLit !== undefined && !ts.isObjectLiteralExpression(optsLit)) {
547
740
  lowerer.noLowering(`new ${ctorName} with a non-literal options argument`, optsLit, "the options must be an object literal, inline or through const-initialized bindings (the callbacks lower as compile-time closures)");
548
741
  }
742
+ // Read before the callbacks lower: an object-mode readable side keeps a
743
+ // completion callback's `data: any` (its values are not only strings and
744
+ // Buffers). An object-mode side's high-water mark defaults to 16.
745
+ const objectModes = streamObjectModes(lowerer, ctorName, optsLit !== undefined && ts.isObjectLiteralExpression(optsLit) ? optsLit : undefined);
746
+ out.readableObject = objectModes.readable;
747
+ out.writableObject = objectModes.writable;
748
+ // the chunk an option callback receives can be another value than a
749
+ // Buffer (literalWritesValues), read before any callback lowers
750
+ const writesValues = optsLit !== undefined &&
751
+ ts.isObjectLiteralExpression(optsLit) &&
752
+ literalWritesValues(optsLit, ctorName !== "Readable" && ctorName !== "Writable");
753
+ // In JavaScript a decodeStrings value known only at run time may let
754
+ // string writes through, so the write and transform callbacks' chunk
755
+ // parameters read as any (the declarations type it Buffer).
756
+ const runtimeDecodeStrings = optsLit !== undefined &&
757
+ isJsSourceFile(ts.getSourceFileOfNode(optsLit)) &&
758
+ ts.isObjectLiteralExpression(optsLit) &&
759
+ (optsLit.properties?.nodes ?? []).some((p) => ts.isPropertyAssignment(p) &&
760
+ (ts.isIdentifier(p.name) || ts.isStringLiteral(p.name)) &&
761
+ p.name.text === "decodeStrings" &&
762
+ p.initializer.kind !== ts.SyntaxKind.TrueKeyword &&
763
+ p.initializer.kind !== ts.SyntaxKind.FalseKeyword);
764
+ if (out.readableObject)
765
+ out.hwmR = numLit(16, loc);
766
+ if (out.writableObject)
767
+ out.hwmW = numLit(16, loc);
549
768
  const tuples = cbTuples(lowerer);
550
769
  const present = new Map();
551
770
  for (const prop of optsLit?.properties?.nodes ?? []) {
@@ -559,7 +778,7 @@ fallbackCb) {
559
778
  lowerer.unsupported("SC1090", prop, `computed or spread members in ${ctorName} options`);
560
779
  }
561
780
  // Callback members: shorthand methods and function-valued properties.
562
- if (accepted.includes(name)) {
781
+ if (accepted.includes(name) || extraNames.includes(name)) {
563
782
  let fnNode = null;
564
783
  if (ts.isMethodDeclaration(prop))
565
784
  fnNode = prop;
@@ -583,7 +802,8 @@ fallbackCb) {
583
802
  continue;
584
803
  }
585
804
  const full = tuples[name].map((t) => (t === "fn" ? null : t));
586
- const pinned = pinAnyDataCompletion(lowerer, name, fnNode);
805
+ const pinned = out.readableObject ? null : pinAnyDataCompletion(lowerer, name, fnNode);
806
+ let anyChunk;
587
807
  try {
588
808
  // The completion-callback tail: typed by the checker contextually;
589
809
  // accept the user's declared func type as the tuple's entry so the
@@ -598,11 +818,22 @@ fallbackCb) {
598
818
  }
599
819
  return declared ?? funcOf([], VOID);
600
820
  });
601
- present.set(name, lowerStreamCallback(lowerer, name, fnNode, thisType, tuple));
821
+ const chunkParam = runtimeDecodeStrings && (name === "write" || name === "transform")
822
+ ? fnNode.parameters.nodes[0]
823
+ : undefined;
824
+ anyChunk =
825
+ chunkParam !== undefined && ts.isIdentifier(chunkParam.name) && !chunkParam.type
826
+ ? lowerer.checker.getSymbolAtLocation(chunkParam.name)
827
+ : undefined;
828
+ if (anyChunk)
829
+ lowerer.anySymbols.add(anyChunk);
830
+ present.set(name, lowerStreamCallback(lowerer, name, fnNode, thisType, tuple, writesValues));
602
831
  }
603
832
  finally {
604
833
  if (pinned)
605
834
  lowerer.stageSourceTypes.delete(pinned);
835
+ if (anyChunk)
836
+ lowerer.anySymbols.delete(anyChunk);
606
837
  }
607
838
  continue;
608
839
  }
@@ -641,17 +872,33 @@ fallbackCb) {
641
872
  break;
642
873
  case "objectMode":
643
874
  case "readableObjectMode":
644
- case "writableObjectMode": {
645
- // `objectMode: false` is the byte default — admit the literal.
646
- if (value.kind === ts.SyntaxKind.FalseKeyword)
647
- break;
648
- lowerer.noLowering(`${ctorName} in objectMode`, prop, "object-mode streams have no static chunk type yet — chunks are Buffers (utf8 strings convert at push/write)");
875
+ case "writableObjectMode":
876
+ // read up front (streamObjectModes)
649
877
  break;
650
- }
651
878
  case "decodeStrings": {
879
+ // WritableState's `options.decodeStrings === false`; a Readable
880
+ // ignores the option
652
881
  if (value.kind === ts.SyntaxKind.TrueKeyword)
653
882
  break; // Node's default
654
- lowerer.noLowering(`${ctorName} with decodeStrings: false`, prop, "chunks always decode to Buffers here (Node's default)");
883
+ if (value.kind === ts.SyntaxKind.FalseKeyword) {
884
+ if (writableClass)
885
+ out.decodeStringsOff = true;
886
+ break;
887
+ }
888
+ // a runtime value: WritableState's `options.decodeStrings !== false`
889
+ if (optsLit !== undefined &&
890
+ ts.isObjectLiteralExpression(optsLit) &&
891
+ !earlierOptionsPure(optsLit, prop, value))
892
+ lowerer.noLowering(`the ${ctorName} option 'decodeStrings' with a runtime value that an earlier option value could observe or change`, prop, "compute the option values into consts before the options object (the runtime value is read before the other options run)");
893
+ const local = lowerer.declareHiddenLocal("%decodeStrings", DYN);
894
+ out.valueDecls.push({
895
+ kind: "varDecl",
896
+ localId: local.id,
897
+ init: lowerer.lowerExprExpecting(value, DYN),
898
+ loc,
899
+ });
900
+ if (writableClass)
901
+ out.decodeStringsValue = varRef(local.id, DYN, loc);
655
902
  break;
656
903
  }
657
904
  case "encoding": {
@@ -687,12 +934,45 @@ fallbackCb) {
687
934
  out.badEncoding = t.value;
688
935
  break;
689
936
  }
690
- if (t.isStringLiteralType() && ctorName === "Readable") {
691
- out.pushEncoding = knownBufEncoding(t.value);
937
+ if (t.isStringLiteralType()) {
938
+ // the readable side decodes push(string) with it, and the
939
+ // writable side encodes write(string) with it (the name as
940
+ // written reaches _write when decodeStrings is false)
941
+ if (ctorName !== "Writable" && !out.readableObject)
942
+ out.pushEncoding = knownBufEncoding(t.value);
943
+ if (writableClass)
944
+ out.writeEncoding = t.value;
692
945
  break;
693
946
  }
694
947
  }
695
- lowerer.noLowering(`the ${ctorName} option 'defaultEncoding'`, prop, "utf8 (the default) is the supported write-side string encoding");
948
+ {
949
+ // a runtime value: null, undefined and utf8 are the default,
950
+ // another name Buffer.isEncoding knows is kept as given, and any
951
+ // other value throws ERR_UNKNOWN_ENCODING before construction
952
+ if (optsLit !== undefined &&
953
+ ts.isObjectLiteralExpression(optsLit) &&
954
+ !earlierOptionsPure(optsLit, prop, value))
955
+ lowerer.noLowering(`the ${ctorName} option 'defaultEncoding' with a runtime value that an earlier option value could observe or change`, prop, "compute the option values into consts before the options object (the runtime value is read before the other options run)");
956
+ const local = lowerer.declareHiddenLocal("%defaultEncoding", DYN);
957
+ const ref = varRef(local.id, DYN, loc);
958
+ out.valueDecls.push({
959
+ kind: "varDecl",
960
+ localId: local.id,
961
+ init: lowerer.lowerExprExpecting(value, DYN),
962
+ loc,
963
+ }, {
964
+ kind: "exprStmt",
965
+ expr: {
966
+ kind: "libCall",
967
+ fn: "stream.checkEncodingOption",
968
+ args: [ref],
969
+ type: VOID,
970
+ loc,
971
+ },
972
+ loc,
973
+ });
974
+ out.defaultEncodingValue = ref;
975
+ }
696
976
  break;
697
977
  case "signal": {
698
978
  // `if (options.signal) addAbortSignal(options.signal, this)`:
@@ -742,11 +1022,8 @@ fallbackCb) {
742
1022
  : "the final callback is supported on Writable and Duplex");
743
1023
  break;
744
1024
  }
745
- case "construct":
746
- lowerer.noLowering(`the ${ctorName} option 'construct'`, prop, "deferred construction (_construct) is not lowered yet");
747
- break;
748
1025
  case "writev":
749
- lowerer.noLowering(`the ${ctorName} option 'writev'`, prop, "batched writes (_writev) are not lowered yet — writes deliver one chunk at a time");
1026
+ lowerer.noLowering(`the ${ctorName} option 'writev'`, prop, "a Readable has no writable side");
750
1027
  break;
751
1028
  default:
752
1029
  lowerer.noLowering(`the ${ctorName} option '${name}'`, prop);
@@ -762,6 +1039,11 @@ fallbackCb) {
762
1039
  out.cbs.push(cb);
763
1040
  }
764
1041
  }
1042
+ for (const name of extraNames) {
1043
+ const cb = present.get(name) ?? fallbackCb?.(name) ?? null;
1044
+ if (cb)
1045
+ out.extras.push({ name, cb });
1046
+ }
765
1047
  return out;
766
1048
  }
767
1049
  /** The head + flags argument list of a stream construction/initialization
@@ -788,8 +1070,66 @@ function streamCtorArgs(lowerer, cls, arg, thisType, loc, fallbackCb) {
788
1070
  badEncoding: o.badEncoding,
789
1071
  pushEncoding: o.pushEncoding,
790
1072
  signal: o.signal,
1073
+ valueDecls: o.valueDecls,
1074
+ decodeStringsValue: o.decodeStringsValue,
1075
+ defaultEncodingValue: o.defaultEncodingValue,
1076
+ readableObject: o.readableObject,
1077
+ writableObject: o.writableObject,
1078
+ decodeStringsOff: o.decodeStringsOff,
1079
+ writeEncoding: o.writeEncoding,
1080
+ extras: o.extras,
791
1081
  };
792
1082
  }
1083
+ /** The follow-ups a stream's options apply over the fresh stream `recv`
1084
+ * after the chained ones: decodeStrings, the writable defaultEncoding,
1085
+ * then writev and construct (Node's constructors schedule construct
1086
+ * last). */
1087
+ function streamOptionFollowUps(parsed, recv, thisType, loc, writevFn = "stream.setWritev") {
1088
+ const out = [];
1089
+ if (parsed.decodeStringsOff) {
1090
+ out.push({
1091
+ kind: "exprStmt",
1092
+ expr: {
1093
+ kind: "libCall",
1094
+ fn: "stream.decodeStrings",
1095
+ args: [recv(), boolLit(false, loc)],
1096
+ type: thisType,
1097
+ loc,
1098
+ },
1099
+ loc,
1100
+ });
1101
+ }
1102
+ if (parsed.writeEncoding !== null) {
1103
+ out.push({
1104
+ kind: "exprStmt",
1105
+ expr: {
1106
+ kind: "libCall",
1107
+ fn: "writable.writeEncoding",
1108
+ args: [recv(), strLit(parsed.writeEncoding, loc)],
1109
+ type: thisType,
1110
+ loc,
1111
+ },
1112
+ loc,
1113
+ });
1114
+ }
1115
+ for (const name of ["writev", "construct"]) {
1116
+ const extra = parsed.extras.find((x) => x.name === name);
1117
+ if (!extra)
1118
+ continue;
1119
+ out.push({
1120
+ kind: "exprStmt",
1121
+ expr: {
1122
+ kind: "libCall",
1123
+ fn: name === "writev" ? writevFn : "stream.setConstruct",
1124
+ args: [recv(), extra.cb],
1125
+ type: VOID,
1126
+ loc,
1127
+ },
1128
+ loc,
1129
+ });
1130
+ }
1131
+ return out;
1132
+ }
793
1133
  /** `new Readable(opts?)` and friends — called from lowerNew once the
794
1134
  * callee resolved to a builtin stream class. */
795
1135
  export function lowerStreamNew(lowerer, expr, info) {
@@ -822,6 +1162,29 @@ export function lowerStreamNew(lowerer, expr, info) {
822
1162
  return nodeThrowExpr(1, "ERR_UNKNOWN_ENCODING", `Unknown encoding: ${parsed.badEncoding}`, thisType, loc);
823
1163
  }
824
1164
  let built = { kind: "libCall", fn, args: parsed.args, type: thisType, loc };
1165
+ if (parsed.readableObject || parsed.writableObject) {
1166
+ // { objectMode }: applied before any other follow-up (answers the
1167
+ // receiver +1).
1168
+ built = {
1169
+ kind: "libCall",
1170
+ fn: "stream.objectMode",
1171
+ args: [built, boolLit(parsed.readableObject, loc), boolLit(parsed.writableObject, loc)],
1172
+ type: thisType,
1173
+ loc,
1174
+ };
1175
+ }
1176
+ const values = optionValuesArgs(parsed, loc);
1177
+ if (values) {
1178
+ // runtime decodeStrings and defaultEncoding values (answers the
1179
+ // receiver +1)
1180
+ built = {
1181
+ kind: "libCall",
1182
+ fn: "stream.optionValues",
1183
+ args: [built, ...values],
1184
+ type: thisType,
1185
+ loc,
1186
+ };
1187
+ }
825
1188
  if (parsed.pushEncoding !== null) {
826
1189
  // { defaultEncoding }: chain the push-side decode default (the
827
1190
  // setEncoding chaining shape — answers the receiver +1).
@@ -844,17 +1207,45 @@ export function lowerStreamNew(lowerer, expr, info) {
844
1207
  loc,
845
1208
  };
846
1209
  }
847
- if (parsed.signal === null)
848
- return built;
849
- // { signal }: addAbortSignal over the fresh stream (answers it +1).
1210
+ if (parsed.signal !== null) {
1211
+ // { signal }: addAbortSignal over the fresh stream (answers it +1).
1212
+ built = {
1213
+ kind: "libCall",
1214
+ fn: "stream.addAbortSignal",
1215
+ args: [built, parsed.signal],
1216
+ type: thisType,
1217
+ loc,
1218
+ };
1219
+ }
1220
+ if (!parsed.decodeStringsOff && parsed.writeEncoding === null && parsed.extras.length === 0) {
1221
+ return parsed.valueDecls.length > 0
1222
+ ? { kind: "seqExpr", stmts: parsed.valueDecls, result: built, type: thisType, loc }
1223
+ : built;
1224
+ }
1225
+ const fresh = lowerer.declareHiddenLocal("%stream", thisType);
1226
+ const followUps = streamOptionFollowUps(parsed, () => varRef(fresh.id, thisType, loc), thisType, loc);
850
1227
  return {
851
- kind: "libCall",
852
- fn: "stream.addAbortSignal",
853
- args: [built, parsed.signal],
1228
+ kind: "seqExpr",
1229
+ stmts: [
1230
+ ...parsed.valueDecls,
1231
+ { kind: "varDecl", localId: fresh.id, init: built, loc },
1232
+ ...followUps,
1233
+ ],
1234
+ result: varRef(fresh.id, thisType, loc),
854
1235
  type: thisType,
855
1236
  loc,
856
1237
  };
857
1238
  }
1239
+ /** stream.optionValues' (decodeStrings, defaultEncoding) arguments, or
1240
+ * null when both options are literals or absent. */
1241
+ function optionValuesArgs(parsed, loc) {
1242
+ if (parsed.decodeStringsValue === null && parsed.defaultEncodingValue === null)
1243
+ return null;
1244
+ return [
1245
+ parsed.decodeStringsValue ?? dynUndefinedExpr(loc),
1246
+ parsed.defaultEncodingValue ?? dynUndefinedExpr(loc),
1247
+ ];
1248
+ }
858
1249
  /** True when a value of Node's argument type `passed` widens implicitly
859
1250
  * into the declared parameter type `declared` (one of its union arms, or a
860
1251
  * sub-union of it). */
@@ -871,7 +1262,7 @@ function widensInto(lowerer, passed, declared, loc) {
871
1262
  * overrides it (the ordinary devirtualization rule), so an inherited
872
1263
  * constructor still binds the DYNAMIC class's override. The method may
873
1264
  * declare any PREFIX of its Node signature (the option-callback rule). */
874
- function streamMethodWrapper(lowerer, info, which, methodName, thisType, loc, blame) {
1265
+ function streamMethodWrapper(lowerer, info, which, methodName, thisType, loc, blame, chunkValues = true) {
875
1266
  const found = lowerer.findMethodOn(info, methodName);
876
1267
  if (!found) {
877
1268
  // A DESCENDANT-only declaration (the base chain never declares it):
@@ -914,6 +1305,18 @@ function streamMethodWrapper(lowerer, info, which, methodName, thisType, loc, bl
914
1305
  }
915
1306
  }
916
1307
  else if (!typeEquals(got.type, want)) {
1308
+ // A write or transform encoding of another type (`string | null |
1309
+ // undefined`) converts from the encoding argument's value: an
1310
+ // object-mode write passes undefined, null or the name. A chunk of
1311
+ // another type (`string | Buffer` under decodeStrings: false)
1312
+ // converts from the chunk's value.
1313
+ if ((i === 1 || (i === 0 && (chunkValues || which === "writev"))) &&
1314
+ (which === "write" || which === "transform" || which === "writev") &&
1315
+ got.type.kind !== "func" &&
1316
+ canConvertToDyn(got.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
1317
+ paramTypes.push(got.type);
1318
+ continue;
1319
+ }
917
1320
  // A declared supertype of what Node passes (`chunk: Buffer | string`)
918
1321
  // is sound: the wrapper takes Node's value and widens it into the
919
1322
  // declared parameter.
@@ -921,12 +1324,22 @@ function streamMethodWrapper(lowerer, info, which, methodName, thisType, loc, bl
921
1324
  paramTypes.push(want);
922
1325
  continue;
923
1326
  }
1327
+ // A write or transform chunk of another type converts from the
1328
+ // chunk's value when the method runs (an object-mode side's value),
1329
+ // or throws a TypeError there; a byte-mode side's chunk is a Buffer.
1330
+ if (i === 0 &&
1331
+ (which === "writev" || (chunkValues && (which === "write" || which === "transform"))) &&
1332
+ got.type.kind !== "func" &&
1333
+ canConvertToDyn(got.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
1334
+ paramTypes.push(got.type);
1335
+ continue;
1336
+ }
924
1337
  lowerer.noLowering(`a '${methodName}' method whose parameter ${i} is '${lowerer.fmt(got.type)}' where Node passes '${lowerer.fmt(want)}'`, blame, "annotate the parameter with the Node signature's type or a supertype of it (chunks are Buffers here)");
925
1338
  }
926
1339
  paramTypes.push(got.type);
927
1340
  }
928
1341
  const ret = found.sig.ret;
929
- const fnName = `%fn${lowerer.lambdaCounter++}_${which}vt`;
1342
+ const fnName = lowerer.closureName(loc, `_${which}vt`);
930
1343
  const funcType = funcOf([thisType, ...paramTypes], ret);
931
1344
  lowerer.fnStack.push(newFnCtx(true, null, funcType, ret));
932
1345
  try {
@@ -996,10 +1409,21 @@ export function lowerStreamSuperCall(lowerer, info, base, argNodes, thisLocal, l
996
1409
  lowerer.noLowering(`super(...) with ${argNodes.length} arguments in a ${cls.slice(1)} subclass`, blame, "the supported form takes one inline options object (or none)");
997
1410
  }
998
1411
  const shape = streamCtorShape(cls);
1412
+ // Whether the writable side holds values: options read at run time may
1413
+ // set objectMode, and a literal says so with objectMode (or a Duplex's
1414
+ // writableObjectMode) true; otherwise _write and _transform receive
1415
+ // Buffers.
1416
+ // super(undefined) and super(null) pass no options (followOptionsArg
1417
+ // answers null), so their sides are byte mode too.
1418
+ const optsNode = argNodes[0] !== undefined ? followOptionsArg(lowerer, argNodes[0]) : null;
1419
+ const chunkValues = optsNode !== null &&
1420
+ optsNode !== undefined &&
1421
+ (!ts.isObjectLiteralExpression(optsNode) ||
1422
+ literalWritesValues(optsNode, cls !== "%Readable" && cls !== "%Writable"));
999
1423
  const fallback = (name) => {
1000
- const methodName = UNDERSCORE_METHODS.get(name);
1424
+ const methodName = UNDERSCORE_METHODS.get(name) ?? STREAM_EXTRA_CALLBACKS.get(name);
1001
1425
  return methodName
1002
- ? streamMethodWrapper(lowerer, info, name, methodName, thisType, loc, blame)
1426
+ ? streamMethodWrapper(lowerer, info, name, methodName, thisType, loc, blame, chunkValues)
1003
1427
  : null;
1004
1428
  };
1005
1429
  const thisRef = () => ({ kind: "varRef", localId: thisLocal.id, type: thisType, loc });
@@ -1018,6 +1442,14 @@ export function lowerStreamSuperCall(lowerer, info, base, argNodes, thisLocal, l
1018
1442
  cbs.push(cb);
1019
1443
  }
1020
1444
  }
1445
+ // The class's _writev and _construct ride the same way: an options
1446
+ // writev or construct (applied by initDyn) wins.
1447
+ const extras = [];
1448
+ for (const name of streamExtraCallbacks(cls)) {
1449
+ const cb = fallback(name);
1450
+ if (cb)
1451
+ extras.push({ name, cb });
1452
+ }
1021
1453
  return [
1022
1454
  {
1023
1455
  kind: "exprStmt",
@@ -1030,6 +1462,7 @@ export function lowerStreamSuperCall(lowerer, info, base, argNodes, thisLocal, l
1030
1462
  },
1031
1463
  loc,
1032
1464
  },
1465
+ ...streamOptionFollowUps({ decodeStringsOff: false, writeEncoding: null, extras }, thisRef, thisType, loc, "stream.setWritevDefault"),
1033
1466
  ];
1034
1467
  }
1035
1468
  }
@@ -1046,6 +1479,7 @@ export function lowerStreamSuperCall(lowerer, info, base, argNodes, thisLocal, l
1046
1479
  ];
1047
1480
  }
1048
1481
  const out = [
1482
+ ...parsed.valueDecls,
1049
1483
  {
1050
1484
  kind: "exprStmt",
1051
1485
  expr: {
@@ -1058,6 +1492,33 @@ export function lowerStreamSuperCall(lowerer, info, base, argNodes, thisLocal, l
1058
1492
  loc,
1059
1493
  },
1060
1494
  ];
1495
+ if (parsed.readableObject || parsed.writableObject) {
1496
+ out.push({
1497
+ kind: "exprStmt",
1498
+ expr: {
1499
+ kind: "libCall",
1500
+ fn: "stream.objectMode",
1501
+ args: [thisRef(), boolLit(parsed.readableObject, loc), boolLit(parsed.writableObject, loc)],
1502
+ type: thisType,
1503
+ loc,
1504
+ },
1505
+ loc,
1506
+ });
1507
+ }
1508
+ const values = optionValuesArgs(parsed, loc);
1509
+ if (values) {
1510
+ out.push({
1511
+ kind: "exprStmt",
1512
+ expr: {
1513
+ kind: "libCall",
1514
+ fn: "stream.optionValues",
1515
+ args: [thisRef(), ...values],
1516
+ type: thisType,
1517
+ loc,
1518
+ },
1519
+ loc,
1520
+ });
1521
+ }
1061
1522
  if (parsed.pushEncoding !== null) {
1062
1523
  out.push({
1063
1524
  kind: "exprStmt",
@@ -1097,6 +1558,7 @@ export function lowerStreamSuperCall(lowerer, info, base, argNodes, thisLocal, l
1097
1558
  loc,
1098
1559
  });
1099
1560
  }
1561
+ out.push(...streamOptionFollowUps(parsed, thisRef, thisType, loc));
1100
1562
  return out;
1101
1563
  }
1102
1564
  /* ── the underscore-method assignment surface ─────────────────────────── */
@@ -1140,14 +1602,16 @@ export function lowerStreamUnderscoreAssign(lowerer, expr) {
1140
1602
  const loc = locOf(expr);
1141
1603
  const cls = base.def.name;
1142
1604
  const clsName = cls.slice(1);
1143
- if (methodName === "_writev" || methodName === "_construct") {
1144
- lowerer.noLowering(`assigning '${methodName}' on a ${clsName}`, expr.left, methodName === "_writev"
1145
- ? "batched writes (_writev) are not lowered yet — writes deliver one chunk at a time"
1146
- : "deferred construction (_construct) is not lowered yet");
1147
- }
1148
- const which = optionByMethod.get(methodName);
1605
+ // `_construct`: Node's constructNT reads it on the construction tick, so
1606
+ // an assignment before that tick replaces a scheduled hook
1607
+ // (stream.replaceConstruct) and has no effect after it or without one.
1608
+ const which = methodName === "_writev"
1609
+ ? "writev"
1610
+ : methodName === "_construct"
1611
+ ? "construct"
1612
+ : optionByMethod.get(methodName);
1149
1613
  const { accepted } = streamCtorShape(cls);
1150
- if (!accepted.includes(which)) {
1614
+ if (!accepted.includes(which) && !streamExtraCallbacks(cls).includes(which)) {
1151
1615
  lowerer.noLowering(`assigning '${methodName}' on a ${clsName}`, expr.left, `a ${clsName}'s machinery consumes ${accepted.map((a) => `'${UNDERSCORE_METHODS.get(a)}'`).join("/")} — '${methodName}' would ride machinery with no lowering here`);
1152
1616
  }
1153
1617
  const thisType = recv.type;
@@ -1178,6 +1642,8 @@ export function lowerStreamUnderscoreAssign(lowerer, expr) {
1178
1642
  destroy: "stream.setDestroy",
1179
1643
  transform: "stream.setTransform",
1180
1644
  flush: "stream.setFlush",
1645
+ writev: "stream.setWritev",
1646
+ construct: "stream.replaceConstruct",
1181
1647
  };
1182
1648
  return {
1183
1649
  kind: "exprStmt",
@@ -1235,25 +1701,165 @@ export function lowerStreamStaticCall(lowerer, call, access) {
1235
1701
  }
1236
1702
  }
1237
1703
  }
1704
+ if (member === "fromWeb" && cls === "%Readable")
1705
+ return lowerReadableFromWeb(lowerer, call, loc);
1238
1706
  if (member !== "from") {
1239
1707
  lowerer.noLowering(`${cls.slice(1)}.${member}`, call);
1240
1708
  }
1709
+ if (cls === "%Duplex") {
1710
+ const fromArgs = call.arguments.nodes;
1711
+ if (fromArgs.length !== 1) {
1712
+ lowerer.noLowering(`Duplex.from with ${fromArgs.length} arguments`, call, "Duplex.from takes one body");
1713
+ }
1714
+ return duplexFromBody(lowerer, fromArgs[0], locOf(call));
1715
+ }
1241
1716
  if (cls !== "%Readable") {
1242
- lowerer.noLowering(`${cls.slice(1)}.from`, call, "Readable.from is the lowered form");
1717
+ lowerer.noLowering(`${cls.slice(1)}.from`, call, "Readable.from and Duplex.from are the lowered forms");
1243
1718
  }
1244
1719
  const args = call.arguments.nodes;
1245
1720
  if (args.length > 2) {
1246
1721
  lowerer.noLowering(`Readable.from with ${args.length} arguments`, call, "Readable.from(iterable, options) is the supported form");
1247
1722
  }
1248
- const type = { kind: "object", className: "%Readable" };
1723
+ return lowerFromSource(lowerer, call, args[0], args[1], false);
1724
+ }
1725
+ /** Readable.fromWeb(readableStream, options): Node's adapter over the web
1726
+ * stream's reader (scr_stream_from_web.c). The options are an object
1727
+ * literal: objectMode a boolean literal, highWaterMark a number, encoding
1728
+ * a literal name, and signal a variable or property read, applied with
1729
+ * addAbortSignal as the constructors do. */
1730
+ function lowerReadableFromWeb(lowerer, call, loc) {
1731
+ const args = call.arguments.nodes;
1732
+ const readable = { kind: "object", className: "%Readable" };
1733
+ if (args.length === 0 || args.length > 2 || args.some((a) => ts.isSpreadElement(a))) {
1734
+ lowerer.noLowering(`Readable.fromWeb with ${args.length} arguments`, call, "the supported form is Readable.fromWeb(readableStream, options)");
1735
+ }
1736
+ const web = lowerer.lowerExprExpecting(args[0], DYN);
1737
+ let objectMode = false;
1738
+ let hwm = numLit(-1, loc);
1739
+ let encoding = "";
1740
+ let signal = null;
1741
+ const options = args[1];
1742
+ if (options !== undefined) {
1743
+ if (!ts.isObjectLiteralExpression(options)) {
1744
+ lowerer.noLowering("Readable.fromWeb options that are not an object literal", options, "pass { objectMode, highWaterMark, encoding, signal } as an object literal");
1745
+ }
1746
+ for (const p of options.properties.nodes) {
1747
+ const key = (ts.isPropertyAssignment(p) || ts.isShorthandPropertyAssignment(p)) &&
1748
+ ts.isIdentifier(p.name)
1749
+ ? p.name.text
1750
+ : null;
1751
+ const value = key === null
1752
+ ? null
1753
+ : ts.isShorthandPropertyAssignment(p)
1754
+ ? p.name
1755
+ : p.initializer;
1756
+ if (key === "objectMode" && value) {
1757
+ if (value.kind === ts.SyntaxKind.TrueKeyword)
1758
+ objectMode = true;
1759
+ else if (value.kind !== ts.SyntaxKind.FalseKeyword)
1760
+ lowerer.noLowering("the Readable.fromWeb option 'objectMode' with this value", p, "write true or false");
1761
+ continue;
1762
+ }
1763
+ if (key === "highWaterMark" && value) {
1764
+ hwm = lowerer.lowerExprExpecting(value, F64);
1765
+ continue;
1766
+ }
1767
+ if (key === "encoding" && value) {
1768
+ const t = lowerer.typeOf(value);
1769
+ if (t.isStringLiteralType() && knownBufEncoding(t.value) === undefined) {
1770
+ return nodeThrowExpr(1, "ERR_INVALID_ARG_VALUE", `The property 'options.encoding' is invalid. Received '${t.value}'`, readable, loc);
1771
+ }
1772
+ encoding = bufEncoding(lowerer, "the Readable.fromWeb option 'encoding'", value);
1773
+ continue;
1774
+ }
1775
+ if (key === "signal" && value) {
1776
+ if (!sideEffectFreeOptionValue(value) && !pureRead(value)) {
1777
+ lowerer.noLowering("the Readable.fromWeb option 'signal' with this value", p, "pass a variable or property read (const signal = controller.signal)");
1778
+ }
1779
+ signal = lowerer.lowerExprExpecting(value, DYN);
1780
+ continue;
1781
+ }
1782
+ lowerer.noLowering(key === null
1783
+ ? "Readable.fromWeb options with this member"
1784
+ : `the Readable.fromWeb option '${key}'`, p, "objectMode, highWaterMark, encoding and signal are the Readable.fromWeb options");
1785
+ }
1786
+ }
1787
+ const built = {
1788
+ kind: "libCall",
1789
+ fn: "fetch.readableFromWeb",
1790
+ args: [web, boolLit(objectMode, loc), hwm, strLit(encoding, loc)],
1791
+ type: readable,
1792
+ loc,
1793
+ };
1794
+ if (signal === null)
1795
+ return built;
1796
+ return {
1797
+ kind: "libCall",
1798
+ fn: "stream.addAbortSignal",
1799
+ args: [built, signal],
1800
+ type: readable,
1801
+ loc,
1802
+ };
1803
+ }
1804
+ /** Readable.from(source, options), and for Duplex.from over an iterable
1805
+ * (duplex) duplexify.js's from(Duplexify, body, { objectMode: true,
1806
+ * writable: false }): the same builders with SCR_FROM_DUPLEX, answering a
1807
+ * Duplexify without a writable side. */
1808
+ function lowerFromSource(lowerer, at, srcNode, optsNode, duplex) {
1809
+ const loc = locOf(at);
1810
+ const call = at;
1811
+ const type = { kind: "object", className: duplex ? "%Duplex" : "%Readable" };
1812
+ const what = duplex ? "Duplex.from" : "Readable.from";
1813
+ // SCR_FROM_DUPLEX
1814
+ const duplexFlag = duplex ? 32 : 0;
1249
1815
  const js = isJsSourceFile(ts.getSourceFileOfNode(call));
1250
- const srcNode = args[0];
1251
- const optsNode = args[1];
1816
+ // A web ReadableStream is async iterable: from.js reads its iterator.
1817
+ // Duplex.from takes _duplexify({ readable: Readable.fromWeb(body) }).
1818
+ const webElem = srcNode ? staticReadableStreamElementType(lowerer, srcNode) : null;
1819
+ if (srcNode && webElem !== null && duplex) {
1820
+ const fromWeb = {
1821
+ kind: "libCall",
1822
+ fn: "fetch.readableFromWeb",
1823
+ args: [
1824
+ lowerer.lowerExprExpecting(srcNode, DYN),
1825
+ boolLit(false, loc),
1826
+ numLit(-1, loc),
1827
+ strLit("", loc),
1828
+ ],
1829
+ type: { kind: "object", className: "%Readable" },
1830
+ loc,
1831
+ };
1832
+ return { kind: "libCall", fn: "stream.duplexifyReadable", args: [fromWeb], type, loc };
1833
+ }
1834
+ if (srcNode && webElem !== null) {
1835
+ const source = lowerWebStreamSource(lowerer, srcNode, webElem, loc);
1836
+ const helpers = source ? fromGenHelpers(lowerer, source.out, loc) : null;
1837
+ const opts = optsNode ? fromOptions(lowerer, optsNode) : { flags: 0, hwm: null };
1838
+ if (!source || !helpers || !opts || !fromGenChunk(lowerer, webElem)) {
1839
+ lowerer.noLowering(`Readable.from over a web ReadableStream of '${lowerer.fmt(webElem)}'`, srcNode);
1840
+ }
1841
+ const hwm = opts.hwm ? lowerer.lowerExprExpecting(opts.hwm, F64) : numLit(0, loc);
1842
+ const gen = {
1843
+ kind: "callValue",
1844
+ callee: source.closure,
1845
+ args: [],
1846
+ type: source.out,
1847
+ loc,
1848
+ };
1849
+ return {
1850
+ kind: "libCall",
1851
+ fn: "readable.fromAsyncGen",
1852
+ args: [gen, ...helpers, numLit(opts.flags, loc), hwm],
1853
+ type,
1854
+ loc,
1855
+ };
1856
+ }
1252
1857
  const srcT = srcNode ? lowerer.mapTypeOf(lowerer.typeOf(srcNode)) : null;
1253
1858
  const typedElem = (t) => t?.kind === "string" ? "string" : t?.kind === "bytes" && t.elem === "u8" ? "bytes" : null;
1254
1859
  const single = typedElem(srcT);
1255
1860
  const elem = srcT?.kind === "array" ? typedElem(srcT.elem) : null;
1256
- const opts = optsNode ? fromOptions(lowerer, optsNode) : { flags: 0, hwm: null };
1861
+ const opts0 = optsNode ? fromOptions(lowerer, optsNode) : { flags: 0, hwm: null };
1862
+ const opts = opts0 ? { ...opts0, flags: opts0.flags | duplexFlag } : opts0;
1257
1863
  // A class whose [Symbol.iterator]() or [Symbol.asyncIterator]() is a
1258
1864
  // generator method: from.js calls the method when the stream is built,
1259
1865
  // then reads the generator like any other.
@@ -1330,7 +1936,13 @@ export function lowerStreamStaticCall(lowerer, call, access) {
1330
1936
  };
1331
1937
  }
1332
1938
  const anySrc = srcT?.kind === "dyn" ||
1333
- (srcT?.kind === "set" && typedElem(srcT.elem) !== null) ||
1939
+ // a Set or Map (entry arrays) of other values: the checked-dynamic
1940
+ // view iterates the collection itself
1941
+ ((srcT?.kind === "set" || srcT?.kind === "map") &&
1942
+ canConvertToDyn(srcT, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) ||
1943
+ // an array of other values: the object-mode entries come from its
1944
+ // checked-dynamic copy
1945
+ (srcT?.kind === "array" && fromGenChunk(lowerer, srcT.elem) && typedElem(srcT.elem) === null) ||
1334
1946
  (srcNode !== undefined &&
1335
1947
  srcT === null &&
1336
1948
  (lowerer.typeOf(srcNode).flags & ts.TypeFlags.Any) !== 0);
@@ -1338,25 +1950,25 @@ export function lowerStreamStaticCall(lowerer, call, access) {
1338
1950
  // The checked-dynamic form: the runtime takes from.js's ladder
1339
1951
  // (ERR_INVALID_ARG_TYPE for a non-iterable, the options, null values).
1340
1952
  const src = srcNode ? lowerer.lowerExprExpecting(srcNode, DYN) : dynUndefinedExpr(loc);
1953
+ if (duplex)
1954
+ return { kind: "libCall", fn: "stream.duplexFromDyn", args: [src], type, loc };
1341
1955
  const o = lowerOperatorValue(lowerer, optsNode, "Readable.from options", loc, true);
1342
1956
  return { kind: "libCall", fn: "readable.fromDyn", args: [src, o], type, loc };
1343
1957
  }
1344
1958
  if (srcNode && (single || elem)) {
1345
1959
  lowerer.noLowering("Readable.from with these options", optsNode, "an object literal with 'objectMode' (true or false) and a number 'highWaterMark' is supported");
1346
1960
  }
1347
- lowerer.noLowering(`Readable.from over a '${srcT ? lowerer.fmt(srcT) : "?"}' source`, srcNode ?? call, "the supported sources are a string or Buffer, and arrays, Sets, generators and class iterables of strings or Buffers");
1961
+ lowerer.noLowering(`${what} over a '${srcT ? lowerer.fmt(srcT) : "?"}' source`, srcNode ?? call, "the supported sources are a string or Buffer, and arrays, Sets, Maps, generators and class iterables of values that convert to checked-dynamic values");
1348
1962
  }
1349
- /** Whether a generator's yields are stream chunks: strings, Buffers, a
1350
- * union of them (null included: the runtime destroys the stream with
1351
- * ERR_STREAM_NULL_VALUES), or checked-dynamic values (checked when
1352
- * pushed). */
1963
+ /** Whether a generator's yields can be stream chunks: values that box
1964
+ * into checked-dynamic values (null included: the runtime destroys the
1965
+ * stream with ERR_STREAM_NULL_VALUES). An object-mode stream takes any of
1966
+ * them; a byte-mode one checks them when they are pushed or written. */
1353
1967
  function fromGenChunk(lowerer, t) {
1354
- const chunk = (a) => a.kind === "string" || (a.kind === "bytes" && a.elem === "u8") || a.kind === "nullT";
1355
- if (t.kind === "dyn" || (chunk(t) && t.kind !== "nullT"))
1356
- return true;
1357
- if (t.kind !== "union")
1968
+ if (t.kind === "nullT" || t.kind === "void" || t.kind === "func")
1358
1969
  return false;
1359
- return lowerer.unions.get(t.unionId)?.arms.every(chunk) ?? false;
1970
+ return (t.kind === "dyn" ||
1971
+ canConvertToDyn(t, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)));
1360
1972
  }
1361
1973
  /** The helpers Readable.from pulls a compiled generator through, as
1362
1974
  * closures in libcall order: a sync generator's next/return/throw answer
@@ -1399,7 +2011,7 @@ function fromGenHelpers(lowerer, gen, loc) {
1399
2011
  const key = `streamFromGen:${role}:${typeKey(gen)}`;
1400
2012
  let name = lowerer.valueHelpers.get(key);
1401
2013
  if (!name) {
1402
- name = `%stream.fromGen.${role}.${lowerer.valueHelpers.size}`;
2014
+ name = keyedHelperName(lowerer, `%stream.fromGen.${role}`, key);
1403
2015
  lowerer.valueHelpers.set(key, name);
1404
2016
  lowerer.liftedFns.push({
1405
2017
  name,
@@ -1480,7 +2092,7 @@ function classIteratorObject(lowerer, cit, iter, loc) {
1480
2092
  const key = `streamFromIter:${cit.iterT.className}`;
1481
2093
  let name = lowerer.valueHelpers.get(key);
1482
2094
  if (!name) {
1483
- name = `%stream.fromIter.${lowerer.valueHelpers.size}`;
2095
+ name = keyedHelperName(lowerer, "%stream.fromIter", key);
1484
2096
  lowerer.valueHelpers.set(key, name);
1485
2097
  const nextName = `${name}.next`;
1486
2098
  const nextT = funcOf([], DYN);
@@ -1624,7 +2236,7 @@ function classAsyncIteratorObject(lowerer, cit, recv, loc) {
1624
2236
  const key = `streamFromAsyncIter:${cit.className}`;
1625
2237
  let name = lowerer.valueHelpers.get(key);
1626
2238
  if (!name) {
1627
- name = `%stream.fromAsyncIter.${lowerer.valueHelpers.size}`;
2239
+ name = keyedHelperName(lowerer, "%stream.fromAsyncIter", key);
1628
2240
  lowerer.valueHelpers.set(key, name);
1629
2241
  const it = { id: "it.0", name: "it", type: cit.iterT, mutable: false, boxed: true };
1630
2242
  const src = {
@@ -1743,10 +2355,10 @@ const PIPELINE_STAGE_EXPECTED = "of type function or an instance of Blob, Readab
1743
2355
  * a ladder Node never throws. */
1744
2356
  function lowerStreamArg(lowerer, node, what) {
1745
2357
  const lowered = lowerer.lowerExpr(node);
1746
- // A Hash or Hmac stage is its Transform; pipeline and compose stages
1747
- // keep the value alive until the stream settles.
1748
- const v = isHashValueType(lowered.type)
1749
- ? hashStreamOf(lowered, what === "pipeline" || what === "compose")
2358
+ // A Hash, Hmac, Cipheriv or Decipheriv stage is its Transform; pipeline
2359
+ // and compose stages keep the value alive until the stream settles.
2360
+ const v = isValueStream(lowerer, node)
2361
+ ? valueStreamOf(lowered, what === "pipeline" || what === "compose")
1750
2362
  : lowered;
1751
2363
  // A checked-dynamic pipeline stage (an untyped source or destination):
1752
2364
  // a boxed native stream unwraps at run time; other values (iterables,
@@ -1827,6 +2439,24 @@ class StreamArgTypeThrow extends Error {
1827
2439
  this.expr = expr;
1828
2440
  }
1829
2441
  }
2442
+ /** Whether a checked-dynamic pipeline callback can take undefined as its
2443
+ * error: a callback that is already checked-dynamic, one without
2444
+ * parameters, and one whose first parameter (or rest element) type holds
2445
+ * undefined. */
2446
+ function callbackErrorAdmitsUndefined(lowerer, cb) {
2447
+ if (cb.kind !== "dynFrom" || cb.value.type.kind !== "func")
2448
+ return true;
2449
+ const fnT = cb.value.type;
2450
+ const first = fnT.params[0];
2451
+ if (first === undefined)
2452
+ return true;
2453
+ const p0 = fnT.rest === true && fnT.params.length === 1 && first.kind === "array" ? first.elem : first;
2454
+ if (p0.kind === "dyn" || p0.kind === "jsval" || p0.kind === "undefinedT")
2455
+ return true;
2456
+ if (p0.kind !== "union")
2457
+ return false;
2458
+ return lowerer.unions.get(p0.unionId)?.arms.some((a) => a.kind === "undefinedT") ?? false;
2459
+ }
1830
2460
  /** The finished/pipeline completion callback: an inline function lowers
1831
2461
  * through the option-callback machinery (leading `this`, an `Error |
1832
2462
  * null` prefix — Node binds the stream and passes the error); any other
@@ -2025,19 +2655,29 @@ export function lowerStreamModuleCall(lowerer, call, bi, loc) {
2025
2655
  ? pipelineOptions(lowerer, lastArg)
2026
2656
  : null;
2027
2657
  const stageArgs = opts ? args.slice(0, -1) : args;
2028
- if (stageArgs.some(isPipelineFunctionStage)) {
2029
- if (opts) {
2030
- lowerer.noLowering("pipeline with function stages and options", lastArg, "pipeline(source, async function* (source) { ... }, destination) without options is supported");
2031
- }
2658
+ if (hasPipelineFunctionStage(lowerer, stageArgs)) {
2032
2659
  const staged = lowerPipelineStages(lowerer, stageArgs, loc);
2660
+ const type = staged.destPromise ?? { kind: "promise", inner: VOID };
2033
2661
  // A promise destination's value settles the result (same type).
2034
- return staged.wrap({
2035
- kind: "libCall",
2036
- fn: "sp.pipelineStages",
2037
- args: staged.args,
2038
- type: staged.destPromise ?? { kind: "promise", inner: VOID },
2039
- loc,
2040
- });
2662
+ if (!opts) {
2663
+ return staged.wrap({
2664
+ kind: "libCall",
2665
+ fn: "sp.pipelineStages",
2666
+ args: staged.args,
2667
+ type,
2668
+ loc,
2669
+ });
2670
+ }
2671
+ // the options: end, and the signal (flags bit 6)
2672
+ const flagsArg = staged.args[3];
2673
+ if (flagsArg.kind !== "numLit")
2674
+ throw new InternalCompilerError("pipeline flags not a literal");
2675
+ const args = [...staged.args, boolLit(opts.end, loc)];
2676
+ if (opts.signal) {
2677
+ args[3] = numLit(flagsArg.value | 64, loc);
2678
+ args.push(opts.signal);
2679
+ }
2680
+ return staged.wrap({ kind: "libCall", fn: "sp.pipelineStagesOpts", args, type, loc });
2041
2681
  }
2042
2682
  let streams;
2043
2683
  try {
@@ -2091,7 +2731,10 @@ export function lowerStreamModuleCall(lowerer, call, bi, loc) {
2091
2731
  // (finished/pipeline throw synchronously; consumers do not). A
2092
2732
  // sync throw here would be observably wrong timing, so the
2093
2733
  // provable case takes the named fence instead.
2094
- const argV = lowerer.lowerExpr(args[0]);
2734
+ // A Hash, Hmac, Cipheriv or Decipheriv is read through its Transform.
2735
+ const argV = isValueStream(lowerer, args[0])
2736
+ ? valueStreamOf(lowerer.lowerExpr(args[0]))
2737
+ : lowerer.lowerExpr(args[0]);
2095
2738
  const argInfo = argV.type.kind === "object" ? lowerer.classes.get(argV.type.className) : undefined;
2096
2739
  if (argV.type.kind !== "dyn" && !streamSidesOf(lowerer, argInfo)) {
2097
2740
  lowerer.noLowering(`stream/consumers.${bi.member} over a value that is not a stream`, call, "Node rejects the promise with 'stream is not async iterable' — pass a readable stream");
@@ -2190,20 +2833,30 @@ export function lowerStreamModuleCall(lowerer, call, bi, loc) {
2190
2833
  if (args.length < 3) {
2191
2834
  lowerer.noLowering(`pipeline with ${args.length} arguments`, call, "the supported form is pipeline(source, ...streams, callback)");
2192
2835
  }
2193
- if (args.slice(0, -1).some(isPipelineFunctionStage)) {
2836
+ if (hasPipelineFunctionStage(lowerer, args.slice(0, -1))) {
2194
2837
  const staged = lowerPipelineStages(lowerer, args.slice(0, -1), loc);
2195
- if (staged.dest !== 0) {
2196
- // callback(err, value): the destination's value reaches the
2197
- // callback through the checked-dynamic path. Node answers an
2198
- // object-mode PassThrough here; reading it has no lowering.
2199
- if (!ts.isExpressionStatement(call.parent)) {
2200
- lowerer.noLowering("using the PassThrough that pipeline() answers for a function destination", call, "read the destination's value in the callback");
2201
- }
2838
+ const cbNode = args[args.length - 1];
2839
+ const cbParams = ts.isArrowFunction(cbNode) || ts.isFunctionExpression(cbNode)
2840
+ ? cbNode.parameters.nodes.length
2841
+ : 0;
2842
+ if (staged.dest === 2 || (staged.dest === 1 && cbParams > 1)) {
2843
+ // callback(err, value): the destination's value (undefined for
2844
+ // an async generator) reaches the callback through the
2845
+ // checked-dynamic path.
2202
2846
  const cb = lowerer.lowerExprExpecting(args[args.length - 1], DYN);
2847
+ // SCR_PIPE_TYPED_CB: a typed callback whose error parameter cannot
2848
+ // hold undefined takes null for no error; others take undefined.
2849
+ const stagedArgs = [...staged.args];
2850
+ const flagsArg = stagedArgs[3];
2851
+ if (flagsArg.kind !== "numLit")
2852
+ throw new InternalCompilerError("pipeline flags not a literal");
2853
+ if (!isJsSourceFile(ts.getSourceFileOfNode(call)) &&
2854
+ !callbackErrorAdmitsUndefined(lowerer, cb))
2855
+ stagedArgs[3] = numLit(flagsArg.value | 128, loc);
2203
2856
  return staged.wrap({
2204
2857
  kind: "libCall",
2205
2858
  fn: "stream.pipelineStagesDyn",
2206
- args: [...staged.args, cb],
2859
+ args: [...stagedArgs, cb],
2207
2860
  type: staged.last,
2208
2861
  loc,
2209
2862
  });
@@ -2236,136 +2889,578 @@ export function lowerStreamModuleCall(lowerer, call, bi, loc) {
2236
2889
  loc,
2237
2890
  };
2238
2891
  }
2239
- if (bi.member === "compose")
2240
- return lowerStreamCompose(lowerer, call, loc);
2892
+ if (bi.member === "compose") {
2893
+ if (call.arguments.nodes.some((a) => ts.isSpreadElement(a))) {
2894
+ lowerer.noLowering("compose with spread arguments", call, "pass the streams directly");
2895
+ }
2896
+ return lowerStreamCompose(lowerer, call.arguments.nodes, loc);
2897
+ }
2241
2898
  return null;
2242
2899
  }
2243
- /** A pipeline() argument written as a function: an async generator
2244
- * function stage. */
2245
- function isPipelineFunctionStage(node) {
2246
- return ts.isFunctionExpression(node) || ts.isArrowFunction(node);
2247
- }
2248
- /** pipeline(...) with one run of function stages (pipeline.js). The run
2249
- * may start the pipeline (a source function, called with `{ signal }`)
2250
- * and may end it (a destination function: an async generator pumped into
2251
- * a PassThrough, or an async function whose promise's value reaches the
2252
- * callback or the promise). Each stage's `source` parameter is typed as
2253
- * what the pipeline passes it: makeAsyncIterable answers the previous
2254
- * stream itself (a Readable is async iterable) or the previous stage's
2255
- * generator. */
2256
- function lowerPipelineStages(lowerer, stageArgs, loc) {
2257
- const first = stageArgs.findIndex(isPipelineFunctionStage);
2258
- let end = first;
2259
- while (end < stageArgs.length && isPipelineFunctionStage(stageArgs[end]))
2260
- end++;
2261
- if (stageArgs.slice(end).some(isPipelineFunctionStage)) {
2262
- lowerer.noLowering("pipeline with function stages separated by streams", stageArgs[end], "one run of function stages is supported");
2263
- }
2264
- const source = first === 0;
2265
- const destFn = end === stageArgs.length;
2266
- const before = [];
2267
- const after = [];
2900
+ /** The function a pipeline() argument writes or names, or null when the
2901
+ * argument is not a function stage. */
2902
+ function pipelineStageFunction(lowerer, node) {
2903
+ if (ts.isFunctionExpression(node) || ts.isArrowFunction(node))
2904
+ return node;
2905
+ if (!ts.isIdentifier(node))
2906
+ return null;
2907
+ // The stage lowers the declaration's body again with its source typed
2908
+ // by the pipeline, so resolving it here must not report what collecting
2909
+ // the declaration's own signature deferred (resolveValueSymbol would).
2910
+ const resolve = (ident) => {
2911
+ const found = lowerer.checker.getSymbolAtLocation(ident);
2912
+ return found && found.flags & ts.SymbolFlags.Alias
2913
+ ? lowerer.checker.getAliasedSymbol(found)
2914
+ : found;
2915
+ };
2916
+ const symbol = resolve(node);
2917
+ const declarations = symbol?.declarations ?? [];
2918
+ const bodies = declarations.filter((d) => !ts.isFunctionDeclaration(d) || d.body !== undefined);
2919
+ if (!symbol || bodies.length !== 1)
2920
+ return null;
2921
+ const decl = bodies[0];
2922
+ if (lowerer.isStdlibFile(ts.getSourceFileOfNode(decl)))
2923
+ return null;
2924
+ if (ts.isFunctionDeclaration(decl)) {
2925
+ return bindingNeverReassigned(lowerer, symbol, decl, resolve) ? decl : null;
2926
+ }
2927
+ if (ts.isVariableDeclaration(decl) &&
2928
+ decl.initializer &&
2929
+ ts.isVariableDeclarationList(decl.parent) &&
2930
+ (decl.parent.flags & ts.NodeFlags.Const) !== 0) {
2931
+ let init = decl.initializer;
2932
+ while (ts.isParenthesizedExpression(init))
2933
+ init = init.expression;
2934
+ if (ts.isFunctionExpression(init) || ts.isArrowFunction(init))
2935
+ return init;
2936
+ }
2937
+ return null;
2938
+ }
2939
+ function hasPipelineFunctionStage(lowerer, args) {
2940
+ return (args.some((a) => pipelineStageFunction(lowerer, a) !== null) ||
2941
+ (args.length > 0 && iterableSourceType(lowerer, args[0]) !== null));
2942
+ }
2943
+ /** The element type of a pipeline source that is an iterable value (an
2944
+ * array, a string or a synchronous generator object), or null. */
2945
+ function iterableSourceType(lowerer, node) {
2946
+ if (pipelineStageFunction(lowerer, node) !== null)
2947
+ return null;
2948
+ const webElem = staticReadableStreamElementType(lowerer, node);
2949
+ if (webElem !== null)
2950
+ return webElem;
2951
+ let t;
2268
2952
  try {
2269
- for (const a of stageArgs.slice(0, first))
2270
- before.push(lowerStreamArg(lowerer, a, "pipeline"));
2953
+ t = lowerer.mapTypeOf(lowerer.typeOf(node));
2271
2954
  }
2272
- catch (e) {
2273
- if (e instanceof StreamArgTypeThrow)
2274
- lowerer.noLowering("pipeline over this value", stageArgs[0]);
2275
- throw e;
2955
+ catch {
2956
+ return null;
2276
2957
  }
2277
- let srcT = source ? null : before[before.length - 1].type;
2278
- const stages = [];
2279
- let mask = 0;
2280
- let dest = 0;
2281
- let destPromise = null;
2282
- for (let i = first; i < end; i++) {
2283
- const fn = stageArgs[i];
2284
- const isLast = destFn && i === end - 1;
2285
- const isAsync = (fn.modifiers?.nodes ?? []).some((m) => m.kind === ts.SyntaxKind.AsyncKeyword);
2286
- const isGen = ts.isFunctionExpression(fn) && fn.asteriskToken !== undefined;
2287
- if (isLast && isGen) {
2288
- // pipeline() pumps it into an object-mode PassThrough, whose
2289
- // buffering decides when the pipeline finishes
2290
- lowerer.noLowering("a pipeline destination that is an async generator function", fn, "end the pipeline with a stream or an async function (source) { for await (const chunk of source) ... }");
2291
- }
2292
- if (!isAsync || (!isGen && !isLast)) {
2293
- lowerer.noLowering(isLast
2294
- ? "a pipeline destination that is not an async function"
2295
- : srcT === null
2296
- ? "a pipeline source function that is not an async generator function"
2297
- : "pipeline stages that are not async generator functions", fn, "write the stage as async function* (source) { for await (const chunk of source) ... }");
2298
- }
2299
- const optionsAt = srcT === null ? 0 : 1;
2300
- if (fn.parameters.nodes.length > optionsAt + 1) {
2301
- lowerer.noLowering("pipeline stages with parameters after the options argument", fn.parameters.nodes[optionsAt + 1], "a stage takes the source and { signal }");
2302
- }
2303
- const lowered = lowerStageFunction(lowerer, fn, srcT);
2304
- const params = lowered.closure.type.kind === "func" ? lowered.closure.type.params : [];
2305
- if (params.length > optionsAt) {
2306
- if (params[optionsAt].kind !== "dyn") {
2307
- lowerer.noLowering("a pipeline stage's options argument with this type", fn.parameters.nodes[optionsAt], "type it as { signal: AbortSignal }");
2308
- }
2309
- mask |= 1 << (i - first);
2958
+ if (t?.kind === "array")
2959
+ return t.elem;
2960
+ if (t?.kind === "string")
2961
+ return STRING;
2962
+ if (t?.kind === "generator" && t.async !== true && stepDrivable(t))
2963
+ return t.yieldT;
2964
+ return null;
2965
+ }
2966
+ /** A pipeline source that is an iterable value or a synchronous generator
2967
+ * function without parameters, as an async generator closure that steps
2968
+ * the value's iterator (or the generator the function returns) and yields
2969
+ * each element. Node's pipeline iterates such a source with `for await`,
2970
+ * through an async-from-sync iterator, and an async generator that
2971
+ * yields the same elements resumes its consumer on the same ticks. Null
2972
+ * when the source has no such lowering. */
2973
+ /** A web ReadableStream source, as an async generator closure over its
2974
+ * reader: each pass awaits reader.read() and yields the chunk, as the
2975
+ * stream's async iterator does; leaving early cancels the stream (its
2976
+ * iterator's return()), and the reader's lock is released either way. */
2977
+ function lowerWebStreamSource(lowerer, node, elemT, loc) {
2978
+ const resultT = genResultRecord(elemT, VOID, lowerer.shapes, lowerer.unions);
2979
+ if (!resultT)
2980
+ return null;
2981
+ const valueField = lowerer.shapes.get(resultT.shapeId)?.fields.find((f) => f.name === "value");
2982
+ if (!valueField)
2983
+ return null;
2984
+ const out = {
2985
+ kind: "generator",
2986
+ async: true,
2987
+ yieldT: elemT,
2988
+ retT: VOID,
2989
+ nextT: UNDEFINED_T,
2990
+ };
2991
+ const genResultT = genResultRecord(elemT, VOID, lowerer.shapes, lowerer.unions);
2992
+ if (!genResultT)
2993
+ return null;
2994
+ const value = lowerer.lowerExprExpecting(node, DYN);
2995
+ const key = `webStreamSource:${typeKey(elemT)}`;
2996
+ let maker = lowerer.valueHelpers.get(key);
2997
+ if (!maker) {
2998
+ maker = `%stream.webStreamSource.${lowerer.valueHelpers.size}`;
2999
+ const genName = `${maker}.gen`;
3000
+ const frame = new LiftedFrame(loc);
3001
+ const srcId = frame.local("src", DYN, false);
3002
+ const readerId = frame.local("reader", DYN, false);
3003
+ const activeId = frame.local("active", BOOL, true);
3004
+ const promiseT = { kind: "promise", inner: resultT };
3005
+ const pId = frame.local("p", promiseT, false);
3006
+ const rId = frame.local("r", resultT, false);
3007
+ const reader = () => varRef(readerId, DYN, loc);
3008
+ const r = () => varRef(rId, resultT, loc);
3009
+ const setActive = (on) => ({
3010
+ kind: "assign",
3011
+ localId: activeId,
3012
+ value: { kind: "boolLit", value: on, type: BOOL, loc },
3013
+ loc,
3014
+ });
3015
+ const extracted = extractIteratorValue(lowerer, elemT, valueField.type, {
3016
+ kind: "recordGet",
3017
+ obj: r(),
3018
+ shapeId: resultT.shapeId,
3019
+ field: "value",
3020
+ type: valueField.type,
3021
+ loc,
3022
+ }, loc);
3023
+ if (!extracted)
3024
+ return null;
3025
+ const invoke = (method, args, calleeName) => ({
3026
+ kind: "dynInvoke",
3027
+ recv: reader(),
3028
+ method,
3029
+ calleeName,
3030
+ args,
3031
+ type: DYN,
3032
+ loc,
3033
+ });
3034
+ const body = [
3035
+ {
3036
+ kind: "varDecl",
3037
+ localId: readerId,
3038
+ init: {
3039
+ kind: "dynInvoke",
3040
+ recv: varRef(srcId, DYN, loc),
3041
+ method: "getReader",
3042
+ calleeName: "ReadableStream async iterator",
3043
+ args: [],
3044
+ type: DYN,
3045
+ loc,
3046
+ },
3047
+ loc,
3048
+ },
3049
+ {
3050
+ kind: "varDecl",
3051
+ localId: activeId,
3052
+ init: { kind: "boolLit", value: false, type: BOOL, loc },
3053
+ loc,
3054
+ },
3055
+ {
3056
+ kind: "tryCatch",
3057
+ tryBody: [
3058
+ {
3059
+ kind: "while",
3060
+ cond: { kind: "boolLit", value: true, type: BOOL, loc },
3061
+ body: [
3062
+ setActive(false),
3063
+ {
3064
+ kind: "varDecl",
3065
+ localId: pId,
3066
+ init: {
3067
+ kind: "libCall",
3068
+ fn: "fetch.readerRead",
3069
+ args: [reader()],
3070
+ type: promiseT,
3071
+ loc,
3072
+ },
3073
+ loc,
3074
+ },
3075
+ {
3076
+ kind: "varDecl",
3077
+ localId: rId,
3078
+ init: { kind: "awaitExpr", value: varRef(pId, promiseT, loc), type: resultT, loc },
3079
+ loc,
3080
+ },
3081
+ {
3082
+ kind: "if",
3083
+ cond: {
3084
+ kind: "recordGet",
3085
+ obj: r(),
3086
+ shapeId: resultT.shapeId,
3087
+ field: "done",
3088
+ type: BOOL,
3089
+ loc,
3090
+ },
3091
+ then: [{ kind: "break", loc }],
3092
+ else_: null,
3093
+ loc,
3094
+ },
3095
+ setActive(true),
3096
+ {
3097
+ kind: "exprStmt",
3098
+ expr: { kind: "yieldExpr", value: extracted, type: VOID, loc },
3099
+ loc,
3100
+ },
3101
+ ],
3102
+ loc,
3103
+ },
3104
+ ],
3105
+ catchBody: null,
3106
+ catchLocalId: null,
3107
+ finallyBody: [
3108
+ {
3109
+ kind: "tryCatch",
3110
+ tryBody: [
3111
+ {
3112
+ kind: "if",
3113
+ cond: varRef(activeId, BOOL, loc),
3114
+ then: [
3115
+ {
3116
+ kind: "exprStmt",
3117
+ expr: {
3118
+ kind: "libCall",
3119
+ fn: "async.awaitDyn",
3120
+ args: [
3121
+ invoke("cancel", [dynUndefinedExpr(loc)], "ReadableStream async iterator return"),
3122
+ ],
3123
+ type: DYN,
3124
+ loc,
3125
+ },
3126
+ loc,
3127
+ },
3128
+ ],
3129
+ else_: null,
3130
+ loc,
3131
+ },
3132
+ ],
3133
+ catchBody: null,
3134
+ catchLocalId: null,
3135
+ finallyBody: [
3136
+ {
3137
+ kind: "exprStmt",
3138
+ expr: invoke("releaseLock", [], "ReadableStream async iterator releaseLock"),
3139
+ loc,
3140
+ },
3141
+ ],
3142
+ loc,
3143
+ },
3144
+ ],
3145
+ loc,
3146
+ },
3147
+ { kind: "return", value: null, loc },
3148
+ ];
3149
+ const srcLocal = frame.locals.find((l) => l.id === srcId);
3150
+ srcLocal.boxed = true;
3151
+ lowerer.valueHelpers.set(key, maker);
3152
+ lowerer.liftedFns.push({
3153
+ name: genName,
3154
+ params: [],
3155
+ returnType: VOID,
3156
+ async: true,
3157
+ captures: [{ localId: srcId, name: "src", type: DYN }],
3158
+ locals: frame.locals,
3159
+ body,
3160
+ generator: { yieldT: elemT, nextT: UNDEFINED_T, resultType: genResultT },
3161
+ loc,
3162
+ });
3163
+ const makerSrc = { id: "src.0", name: "src", type: DYN, mutable: false, boxed: true };
3164
+ lowerer.liftedFns.push({
3165
+ name: maker,
3166
+ params: [{ localId: makerSrc.id, name: makerSrc.name, type: DYN }],
3167
+ returnType: funcOf([], out),
3168
+ locals: [makerSrc],
3169
+ body: [
3170
+ {
3171
+ kind: "return",
3172
+ value: {
3173
+ kind: "closure",
3174
+ fnName: genName,
3175
+ captures: [makerSrc.id],
3176
+ type: funcOf([], out),
3177
+ loc,
3178
+ },
3179
+ loc,
3180
+ },
3181
+ ],
3182
+ loc,
3183
+ });
3184
+ }
3185
+ return {
3186
+ closure: { kind: "call", callee: maker, args: [value], type: funcOf([], out), loc },
3187
+ out,
3188
+ };
3189
+ }
3190
+ function lowerIterableSource(lowerer, node, fn, loc) {
3191
+ if (fn === null) {
3192
+ const webElem = staticReadableStreamElementType(lowerer, node);
3193
+ if (webElem !== null)
3194
+ return lowerWebStreamSource(lowerer, node, webElem, loc);
3195
+ }
3196
+ let value;
3197
+ if (fn !== null) {
3198
+ if (fn.parameters.nodes.length > 0) {
3199
+ lowerer.noLowering("a synchronous generator function pipeline source with parameters", fn.parameters.nodes[0], "declare the source without parameters, or make it an async generator function");
2310
3200
  }
3201
+ value = lowerer.lowerLambda(fn);
3202
+ if (value.type.kind !== "func" || value.type.ret.kind !== "generator")
3203
+ return null;
3204
+ }
3205
+ else {
3206
+ value = lowerer.lowerExpr(node);
3207
+ }
3208
+ const srcT = value.type;
3209
+ const elemT = srcT.kind === "func" && srcT.ret.kind === "generator"
3210
+ ? srcT.ret.yieldT
3211
+ : srcT.kind === "array"
3212
+ ? srcT.elem
3213
+ : srcT.kind === "string"
3214
+ ? STRING
3215
+ : srcT.kind === "generator" && srcT.async !== true
3216
+ ? srcT.yieldT
3217
+ : null;
3218
+ if (elemT === null)
3219
+ return null;
3220
+ const out = {
3221
+ kind: "generator",
3222
+ async: true,
3223
+ yieldT: elemT,
3224
+ retT: VOID,
3225
+ nextT: UNDEFINED_T,
3226
+ };
3227
+ const resultType = genResultRecord(elemT, VOID, lowerer.shapes, lowerer.unions);
3228
+ if (!resultType)
3229
+ return null;
3230
+ const key = `pipelineSource:${typeKey(srcT)}`;
3231
+ let maker = lowerer.valueHelpers.get(key);
3232
+ if (!maker) {
3233
+ maker = `%stream.pipelineSource.${lowerer.valueHelpers.size}`;
3234
+ const genName = `${maker}.gen`;
3235
+ // The generator: g = the source's iterator; for (v of g) yield v.
3236
+ const frame = new LiftedFrame(loc);
3237
+ const srcId = frame.local("src", srcT, false);
3238
+ const src = varRef(srcId, srcT, loc);
3239
+ const syncT = {
3240
+ kind: "generator",
3241
+ yieldT: elemT,
3242
+ retT: VOID,
3243
+ nextT: UNDEFINED_T,
3244
+ };
3245
+ let iterator;
3246
+ if (srcT.kind === "func") {
3247
+ iterator = { kind: "callValue", callee: src, args: [], type: srcT.ret, loc };
3248
+ }
3249
+ else if (srcT.kind === "array") {
3250
+ iterator = lowerArrayIteratorValue(lowerer, src, "values", syncT, loc);
3251
+ }
3252
+ else if (srcT.kind === "string") {
3253
+ iterator = lowerStringIteratorValue(lowerer, src, syncT, loc);
3254
+ }
3255
+ else {
3256
+ iterator = src;
3257
+ }
3258
+ if (iterator === null || iterator.type.kind !== "generator" || !stepDrivable(iterator.type))
3259
+ return null;
3260
+ const iterT = iterator.type;
3261
+ const gId = frame.local("g", iterT, false);
3262
+ const body = [
3263
+ { kind: "varDecl", localId: gId, init: iterator, loc },
3264
+ ...driveGenerator(lowerer, frame, gId, iterT, elemT, [], (v) => [{ kind: "exprStmt", expr: { kind: "yieldExpr", value: v, type: VOID, loc }, loc }], loc),
3265
+ { kind: "return", value: null, loc },
3266
+ ];
3267
+ const srcLocal = frame.locals.find((l) => l.id === srcId);
3268
+ srcLocal.boxed = true;
3269
+ lowerer.valueHelpers.set(key, maker);
3270
+ lowerer.liftedFns.push({
3271
+ name: genName,
3272
+ params: [],
3273
+ returnType: VOID,
3274
+ async: true,
3275
+ captures: [{ localId: srcId, name: "src", type: srcT }],
3276
+ locals: frame.locals,
3277
+ body,
3278
+ generator: { yieldT: elemT, nextT: UNDEFINED_T, resultType },
3279
+ loc,
3280
+ });
3281
+ // The maker: (src) => the generator function closed over src.
3282
+ const makerSrc = { id: "src.0", name: "src", type: srcT, mutable: false, boxed: true };
3283
+ lowerer.liftedFns.push({
3284
+ name: maker,
3285
+ params: [{ localId: makerSrc.id, name: makerSrc.name, type: srcT }],
3286
+ returnType: funcOf([], out),
3287
+ locals: [makerSrc],
3288
+ body: [
3289
+ {
3290
+ kind: "return",
3291
+ value: {
3292
+ kind: "closure",
3293
+ fnName: genName,
3294
+ captures: [makerSrc.id],
3295
+ type: funcOf([], out),
3296
+ loc,
3297
+ },
3298
+ loc,
3299
+ },
3300
+ ],
3301
+ loc,
3302
+ });
3303
+ }
3304
+ return {
3305
+ closure: { kind: "call", callee: maker, args: [value], type: funcOf([], out), loc },
3306
+ out,
3307
+ };
3308
+ }
3309
+ /** pipeline(...) with function stages (pipeline.js). A function may
3310
+ * start the pipeline (a source function, called with `{ signal }`), may
3311
+ * end it (an async function whose promise's value reaches the callback or
3312
+ * the promise, or an async generator function), and runs of async
3313
+ * generator functions may sit between streams; the last generator of a
3314
+ * run that a stream follows is pumped into that stream. A function
3315
+ * destination feeds the object-mode PassThrough that pipeline() answers. Each stage's `source` parameter is typed as what the
3316
+ * pipeline passes it: makeAsyncIterable answers the previous stream
3317
+ * itself (a Readable is async iterable) or the previous stage's
3318
+ * generator. */
3319
+ function lowerPipelineStages(lowerer, stageArgs, loc, preLowered) {
3320
+ if (stageArgs.length > 52) {
3321
+ lowerer.noLowering("pipeline with function stages and more than 52 stages", stageArgs[52], "split the pipeline");
3322
+ }
3323
+ const streams = [];
3324
+ const stages = [];
3325
+ const helperArgs = [];
3326
+ let positions = 0;
3327
+ let mask = 0;
3328
+ let dest = 0;
3329
+ let destPromise = null;
3330
+ // What the next function stage receives: null before the first stage,
3331
+ // else the previous stream's type or the previous stage's generator.
3332
+ let srcT = null;
3333
+ // The streams and stages in argument order: the head lists all streams
3334
+ // before all stages, so when a stage precedes a stream the arguments
3335
+ // are bound to locals first, keeping JavaScript's evaluation order.
3336
+ const argOrder = [];
3337
+ for (let j = 0; j < stageArgs.length; j++) {
3338
+ const arg = stageArgs[j];
3339
+ // compose's head and tail functions arrive as Duplex.from streams
3340
+ const fn = preLowered?.has(j) ? null : pipelineStageFunction(lowerer, arg);
3341
+ const syncSourceFn = j === 0 &&
3342
+ fn !== null &&
3343
+ !ts.isArrowFunction(fn) &&
3344
+ fn.asteriskToken !== undefined &&
3345
+ !(fn.modifiers?.nodes ?? []).some((m) => m.kind === ts.SyntaxKind.AsyncKeyword);
3346
+ if (j === 0 &&
3347
+ !preLowered?.has(j) &&
3348
+ (syncSourceFn || (fn === null && iterableSourceType(lowerer, arg) !== null))) {
3349
+ const source = lowerIterableSource(lowerer, arg, syncSourceFn ? fn : null, loc);
3350
+ if (source === null)
3351
+ lowerer.noLowering("pipeline over this source", arg);
3352
+ positions += 1;
3353
+ argOrder.push({ list: stages, index: stages.length });
3354
+ stages.push(source.closure);
3355
+ srcT = source.out;
3356
+ continue;
3357
+ }
3358
+ if (fn === null) {
3359
+ if (srcT?.kind === "generator") {
3360
+ // the generator before this stream, pumped into it
3361
+ if (!fromGenChunk(lowerer, srcT.yieldT)) {
3362
+ lowerer.noLowering(`a pipeline stage yielding '${lowerer.fmt(srcT.yieldT)}'`, stageArgs[j - 1], "stage values written to a stream are strings or Buffers");
3363
+ }
3364
+ const helpers = fromGenHelpers(lowerer, srcT, loc);
3365
+ if (!helpers)
3366
+ lowerer.noLowering("a pipeline stage with this generator type", stageArgs[j - 1]);
3367
+ helperArgs.push(helpers[0], helpers[1], helpers[2]);
3368
+ }
3369
+ let stream;
3370
+ try {
3371
+ stream = preLowered?.get(j) ?? lowerStreamArg(lowerer, arg, "pipeline");
3372
+ }
3373
+ catch (e) {
3374
+ if (e instanceof StreamArgTypeThrow)
3375
+ lowerer.noLowering("pipeline over this value", arg);
3376
+ throw e;
3377
+ }
3378
+ argOrder.push({ list: streams, index: streams.length });
3379
+ streams.push(stream);
3380
+ srcT = stream.type;
3381
+ continue;
3382
+ }
3383
+ const isLast = j === stageArgs.length - 1;
3384
+ const isAsync = (fn.modifiers?.nodes ?? []).some((m) => m.kind === ts.SyntaxKind.AsyncKeyword);
3385
+ const isGen = !ts.isArrowFunction(fn) && fn.asteriskToken !== undefined;
3386
+ if (!isAsync || (!isGen && !isLast)) {
3387
+ lowerer.noLowering(isLast
3388
+ ? "a pipeline destination that is not an async function"
3389
+ : srcT === null
3390
+ ? "a pipeline source function that is not an async generator function"
3391
+ : "pipeline stages that are not async generator functions", arg, "write the stage as async function* (source) { for await (const chunk of source) ... }");
3392
+ }
3393
+ const optionsAt = srcT === null ? 0 : 1;
3394
+ if (fn.parameters.nodes.length > optionsAt + 1) {
3395
+ lowerer.noLowering("pipeline stages with parameters after the options argument", fn.parameters.nodes[optionsAt + 1], "a stage takes the source and { signal }");
3396
+ }
3397
+ const lowered = lowerStageFunction(lowerer, fn, srcT);
3398
+ const params = lowered.closure.type.kind === "func" ? lowered.closure.type.params : [];
3399
+ if (params.length > optionsAt) {
3400
+ if (params[optionsAt].kind !== "dyn") {
3401
+ lowerer.noLowering("a pipeline stage's options argument with this type", fn.parameters.nodes[optionsAt], "type it as { signal: AbortSignal }");
3402
+ }
3403
+ mask |= 1 << stages.length;
3404
+ }
3405
+ positions += 2 ** j;
3406
+ argOrder.push({ list: stages, index: stages.length });
2311
3407
  stages.push(lowered.closure);
2312
3408
  if (lowered.out.kind === "promise") {
2313
3409
  dest = 2;
2314
3410
  destPromise = lowered.out;
2315
3411
  srcT = null;
2316
3412
  }
3413
+ else if (isLast) {
3414
+ // an async generator destination: pumped into the object-mode
3415
+ // PassThrough that pipeline() answers
3416
+ const helpers = fromGenHelpers(lowerer, lowered.out, loc);
3417
+ if (!helpers)
3418
+ lowerer.noLowering("a pipeline destination with this generator type", arg);
3419
+ helperArgs.push(helpers[0], helpers[1], helpers[2]);
3420
+ dest = 1;
3421
+ srcT = null;
3422
+ }
2317
3423
  else {
2318
3424
  srcT = lowered.out;
2319
3425
  }
2320
3426
  }
2321
- try {
2322
- for (const a of stageArgs.slice(end))
2323
- after.push(lowerStreamArg(lowerer, a, "pipeline"));
2324
- }
2325
- catch (e) {
2326
- if (e instanceof StreamArgTypeThrow)
2327
- lowerer.noLowering("pipeline over this value", stageArgs[end]);
2328
- throw e;
2329
- }
2330
- const helperArgs = [];
2331
- if (dest !== 2) {
2332
- // the generator pumped into the next stream or the PassThrough
2333
- const lastGen = srcT;
2334
- if (!fromGenChunk(lowerer, lastGen.yieldT)) {
2335
- lowerer.noLowering(`a pipeline stage yielding '${lowerer.fmt(lastGen.yieldT)}'`, stageArgs[end - 1], "stage values written to a stream are strings or Buffers");
2336
- }
2337
- const helpers = fromGenHelpers(lowerer, lastGen, loc);
2338
- if (!helpers)
2339
- lowerer.noLowering("a pipeline stage with this generator type", stageArgs[end - 1]);
2340
- helperArgs.push(helpers[0], helpers[1], helpers[2]);
2341
- }
2342
- else {
3427
+ if (dest === 2) {
2343
3428
  const valueT = destPromise.inner;
2344
3429
  if (valueT.kind !== "void" &&
2345
3430
  !canConvertToDyn(valueT, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
2346
- lowerer.noLowering(`a pipeline destination resolving to '${lowerer.fmt(valueT)}'`, stageArgs[end - 1]);
3431
+ lowerer.noLowering(`a pipeline destination resolving to '${lowerer.fmt(valueT)}'`, stageArgs[stageArgs.length - 1]);
2347
3432
  }
2348
3433
  helperArgs.push(pipelineBoxHelper(lowerer, destPromise, loc));
2349
3434
  }
2350
- const streams = [...before, ...after];
2351
- // SCR_PIPE_* flags: bit 0 a source function, bits 1-2 the destination,
2352
- // bit 3 the helpers, bit 4 the box, bit 5 the signal and abort.
2353
- const flags = (source ? 1 : 0) | (dest << 1) | (dest !== 2 ? 8 : 16) | (mask !== 0 ? 32 : 0);
3435
+ const argDecls = [];
3436
+ const firstStage = argOrder.findIndex((a) => a.list === stages);
3437
+ if (firstStage >= 0 && argOrder.slice(firstStage).some((a) => a.list === streams)) {
3438
+ for (const a of argOrder) {
3439
+ const init = a.list[a.index];
3440
+ const local = lowerer.declareHiddenLocal("%pipelineArg", init.type);
3441
+ argDecls.push({ kind: "varDecl", localId: local.id, init, loc: init.loc });
3442
+ a.list[a.index] = varRef(local.id, init.type, init.loc);
3443
+ }
3444
+ }
3445
+ const bindArgs = (call) => argDecls.length === 0
3446
+ ? call
3447
+ : { kind: "seqExpr", stmts: argDecls, result: call, type: call.type, loc };
3448
+ // SCR_PIPE_* flags: bits 1-2 the destination, bit 5 the signal and
3449
+ // abort (bit 6, the promise form's options signal, is set by its caller).
3450
+ const flags = (dest << 1) | (mask !== 0 ? 32 : 0);
2354
3451
  const head = [
2355
3452
  numLit(streams.length, loc),
2356
- numLit(before.length, loc),
2357
3453
  numLit(stages.length, loc),
3454
+ numLit(positions, loc),
2358
3455
  numLit(flags, loc),
2359
3456
  numLit(mask, loc),
2360
3457
  ...streams,
2361
3458
  ...stages,
2362
3459
  ...helperArgs,
2363
3460
  ];
2364
- const last = destFn
2365
- ? { kind: "object", className: "%PassThrough" }
2366
- : streams[streams.length - 1].type;
3461
+ const last = dest !== 0 ? { kind: "object", className: "%PassThrough" } : streams[streams.length - 1].type;
2367
3462
  if (mask === 0)
2368
- return { args: head, last, dest, destPromise, wrap: (call) => call };
3463
+ return { args: head, last, dest, destPromise, wrap: bindArgs };
2369
3464
  // const ac = new AbortController(): its signal goes to the stages, and
2370
3465
  // finishImpl's ac.abort() runs through the abort closure.
2371
3466
  const ac = lowerer.declareHiddenLocal("%pipelineAbort", DYN);
@@ -2382,7 +3477,7 @@ function lowerPipelineStages(lowerer, stageArgs, loc) {
2382
3477
  last,
2383
3478
  dest,
2384
3479
  destPromise,
2385
- wrap: (call) => ({
3480
+ wrap: (call) => bindArgs({
2386
3481
  kind: "seqExpr",
2387
3482
  stmts: [
2388
3483
  {
@@ -2405,7 +3500,7 @@ function pipelineBoxHelper(lowerer, promiseT, loc) {
2405
3500
  const key = `pipelineBox:${typeKey(promiseT)}`;
2406
3501
  let name = lowerer.valueHelpers.get(key);
2407
3502
  if (!name) {
2408
- name = `%stream.pipelineBox.${lowerer.valueHelpers.size}`;
3503
+ name = keyedHelperName(lowerer, "%stream.pipelineBox", key);
2409
3504
  lowerer.valueHelpers.set(key, name);
2410
3505
  lowerer.liftedFns.push({
2411
3506
  name,
@@ -2426,21 +3521,22 @@ function pipelineBoxHelper(lowerer, promiseT, loc) {
2426
3521
  }
2427
3522
  /** `() => ac.abort()` over the pipeline's AbortController: an interned
2428
3523
  * lifted function takes the controller and answers the closure. */
2429
- function pipelineAbortHelper(lowerer, ac, loc) {
2430
- const key = "pipelineAbort";
3524
+ function pipelineAbortHelper(lowerer, ac, loc, withReason = false) {
3525
+ const key = withReason ? "pipelineAbortReason" : "pipelineAbort";
2431
3526
  let name = lowerer.valueHelpers.get(key);
2432
- const abortT = funcOf([], VOID);
3527
+ const abortT = funcOf(withReason ? [DYN] : [], VOID);
2433
3528
  if (!name) {
2434
- name = `%stream.pipelineAbort.${lowerer.valueHelpers.size}`;
3529
+ name = keyedHelperName(lowerer, "%stream.pipelineAbort", key);
2435
3530
  lowerer.valueHelpers.set(key, name);
2436
3531
  const acLocal = { id: "ac.0", name: "ac", type: DYN, mutable: false, boxed: true };
2437
3532
  const acRef = varRef(acLocal.id, DYN, loc);
3533
+ const reasonLocal = { id: "reason.0", name: "reason", type: DYN, mutable: false };
2438
3534
  lowerer.liftedFns.push({
2439
3535
  name: `${name}.abort`,
2440
- params: [],
3536
+ params: withReason ? [{ localId: reasonLocal.id, name: reasonLocal.name, type: DYN }] : [],
2441
3537
  returnType: VOID,
2442
3538
  captures: [{ localId: acLocal.id, name: acLocal.name, type: DYN }],
2443
- locals: [acLocal],
3539
+ locals: withReason ? [acLocal, reasonLocal] : [acLocal],
2444
3540
  body: [
2445
3541
  {
2446
3542
  kind: "exprStmt",
@@ -2449,7 +3545,7 @@ function pipelineAbortHelper(lowerer, ac, loc) {
2449
3545
  recv: acRef,
2450
3546
  method: "abort",
2451
3547
  calleeName: "ac.abort",
2452
- args: [],
3548
+ args: withReason ? [varRef(reasonLocal.id, DYN, loc)] : [],
2453
3549
  type: DYN,
2454
3550
  loc,
2455
3551
  },
@@ -2494,6 +3590,8 @@ function lowerStageFunction(lowerer, fn, srcT) {
2494
3590
  if (param && !symbol) {
2495
3591
  lowerer.noLowering("pipeline stage parameters that are patterns", param, "name the source parameter");
2496
3592
  }
3593
+ // The loop variables of the `for await` loops over the source.
3594
+ const chunkSymbols = [];
2497
3595
  if (symbol && fn.body) {
2498
3596
  const visit = (node) => {
2499
3597
  if (ts.isIdentifier(node) &&
@@ -2506,6 +3604,14 @@ function lowerStageFunction(lowerer, fn, srcT) {
2506
3604
  parent.expression === node)) {
2507
3605
  lowerer.noLowering("a pipeline stage's source used outside a for await loop head", node, "iterate the source with for await (const chunk of source)");
2508
3606
  }
3607
+ const binding = ts.isVariableDeclarationList(parent.initializer)
3608
+ ? parent.initializer.declarations.nodes[0]?.name
3609
+ : undefined;
3610
+ const chunk = binding && ts.isIdentifier(binding)
3611
+ ? lowerer.checker.getSymbolAtLocation(binding)
3612
+ : undefined;
3613
+ if (chunk)
3614
+ chunkSymbols.push(chunk);
2509
3615
  }
2510
3616
  ts.forEachChild(node, visit);
2511
3617
  };
@@ -2513,8 +3619,22 @@ function lowerStageFunction(lowerer, fn, srcT) {
2513
3619
  }
2514
3620
  if (symbol)
2515
3621
  lowerer.stageSourceTypes.set(symbol, srcT);
3622
+ // In JavaScript the checker types the chunks of a source that is the
3623
+ // previous stage's generator `any`; they read as the strings or Buffers
3624
+ // the generator yields, so their members take the string and Buffer
3625
+ // lowerings.
3626
+ const previousImplicit = lowerer.implicitParamTypes;
3627
+ const chunkType = srcT?.kind === "generator" && isJsSourceFile(ts.getSourceFileOfNode(fn))
3628
+ ? stageChunkCheckerType(lowerer, srcT.yieldT, fn)
3629
+ : null;
3630
+ if (chunkType && chunkSymbols.length > 0) {
3631
+ const implicit = new Map(previousImplicit ?? []);
3632
+ for (const chunk of chunkSymbols)
3633
+ implicit.set(chunk, chunkType);
3634
+ lowerer.implicitParamTypes = implicit;
3635
+ }
2516
3636
  try {
2517
- const closure = lowerer.lowerExpr(fn);
3637
+ const closure = lowerer.lowerLambda(fn);
2518
3638
  const out = closure.type.kind === "func" ? closure.type.ret : null;
2519
3639
  if (!(out?.kind === "generator" && out.async) && out?.kind !== "promise") {
2520
3640
  lowerer.noLowering("a pipeline stage that does not return an async generator", fn);
@@ -2524,25 +3644,391 @@ function lowerStageFunction(lowerer, fn, srcT) {
2524
3644
  finally {
2525
3645
  if (symbol)
2526
3646
  lowerer.stageSourceTypes.delete(symbol);
3647
+ lowerer.implicitParamTypes = previousImplicit;
3648
+ }
3649
+ }
3650
+ /** The async generator a Duplex.from body iterates (duplexify.js's
3651
+ * fromAsyncGen source), as a closure the runtime calls with next() and
3652
+ * ack(): each pass awaits next() (the deferred a write or the final
3653
+ * settles), calls ack() (process.nextTick(cb) and a fresh deferred),
3654
+ * returns at the done marker, and yields the chunk. */
3655
+ function duplexSourceHelper(lowerer, genT, loc) {
3656
+ const nextT = funcOf([], { kind: "promise", inner: DYN });
3657
+ const ackT = funcOf([], VOID);
3658
+ const type = funcOf([nextT, ackT], genT);
3659
+ const key = "duplexSource";
3660
+ let name = lowerer.valueHelpers.get(key);
3661
+ if (!name) {
3662
+ const resultType = genResultRecord(DYN, VOID, lowerer.shapes, lowerer.unions);
3663
+ if (!resultType)
3664
+ return null;
3665
+ name = `%stream.duplexSource.${lowerer.valueHelpers.size}`;
3666
+ const frame = new LiftedFrame(loc);
3667
+ const nextId = frame.param("next", nextT);
3668
+ const ackId = frame.param("ack", ackT);
3669
+ const valueId = frame.local("value", DYN, false);
3670
+ const value = varRef(valueId, DYN, loc);
3671
+ const body = [
3672
+ {
3673
+ kind: "while",
3674
+ cond: { kind: "boolLit", value: true, type: BOOL, loc },
3675
+ body: [
3676
+ {
3677
+ kind: "varDecl",
3678
+ localId: valueId,
3679
+ init: {
3680
+ kind: "awaitExpr",
3681
+ value: {
3682
+ kind: "callValue",
3683
+ callee: varRef(nextId, nextT, loc),
3684
+ args: [],
3685
+ type: { kind: "promise", inner: DYN },
3686
+ loc,
3687
+ },
3688
+ type: DYN,
3689
+ loc,
3690
+ },
3691
+ loc,
3692
+ },
3693
+ {
3694
+ kind: "exprStmt",
3695
+ expr: {
3696
+ kind: "callValue",
3697
+ callee: varRef(ackId, ackT, loc),
3698
+ args: [],
3699
+ type: VOID,
3700
+ loc,
3701
+ },
3702
+ loc,
3703
+ },
3704
+ {
3705
+ kind: "if",
3706
+ cond: { kind: "libCall", fn: "stream.chunkDone", args: [value], type: BOOL, loc },
3707
+ then: [{ kind: "return", value: null, loc }],
3708
+ else_: null,
3709
+ loc,
3710
+ },
3711
+ { kind: "exprStmt", expr: { kind: "yieldExpr", value, type: VOID, loc }, loc },
3712
+ ],
3713
+ loc,
3714
+ },
3715
+ { kind: "return", value: null, loc },
3716
+ ];
3717
+ lowerer.valueHelpers.set(key, name);
3718
+ lowerer.liftedFns.push({
3719
+ name,
3720
+ params: frame.params,
3721
+ returnType: VOID,
3722
+ async: true,
3723
+ locals: frame.locals,
3724
+ body,
3725
+ generator: { yieldT: DYN, nextT: UNDEFINED_T, resultType },
3726
+ loc,
3727
+ });
2527
3728
  }
3729
+ return { kind: "closure", fnName: name, captures: [], type, loc };
3730
+ }
3731
+ /** Duplex.from(body) (duplexify.js) for the bodies with a lowering: an
3732
+ * async generator function, whose source generator the Duplex's writes
3733
+ * feed (stream.duplexFromGen); a duplex stream, which answers itself; and
3734
+ * the bodies Readable.from reads (iterables, strings, generators), as a
3735
+ * Duplexify that is not writable. */
3736
+ function duplexFromBody(lowerer, node, loc) {
3737
+ const duplex = { kind: "object", className: "%Duplex" };
3738
+ const fn = pipelineStageFunction(lowerer, node);
3739
+ if (fn !== null) {
3740
+ const isAsync = (fn.modifiers?.nodes ?? []).some((m) => m.kind === ts.SyntaxKind.AsyncKeyword);
3741
+ const isGen = !ts.isArrowFunction(fn) && fn.asteriskToken !== undefined;
3742
+ if (!isAsync) {
3743
+ lowerer.noLowering("Duplex.from over a function that is not async", node, "write the body as async function* (source) { ... } or async function (source) { ... }");
3744
+ }
3745
+ if (fn.parameters.nodes.length > 2) {
3746
+ lowerer.noLowering("a Duplex.from body with parameters after the options argument", fn.parameters.nodes[2], "the body takes the source and { signal }");
3747
+ }
3748
+ const sourceT = {
3749
+ kind: "generator",
3750
+ async: true,
3751
+ yieldT: DYN,
3752
+ retT: VOID,
3753
+ nextT: UNDEFINED_T,
3754
+ };
3755
+ const lowered = lowerStageFunction(lowerer, fn, sourceT);
3756
+ const params = lowered.closure.type.kind === "func" ? lowered.closure.type.params : [];
3757
+ // fromAsyncGen calls the body with { signal } of an AbortController
3758
+ // that destroy aborts with its error.
3759
+ let signalArgs = [];
3760
+ let signalDecls = [];
3761
+ if (params.length > 1) {
3762
+ if (params[1].kind !== "dyn") {
3763
+ lowerer.noLowering("a Duplex.from body's options argument with this type", fn.parameters.nodes[1], "type it as { signal: AbortSignal }");
3764
+ }
3765
+ const acLocal = lowerer.declareHiddenLocal("%duplexAbort", DYN);
3766
+ const ac = varRef(acLocal.id, DYN, loc);
3767
+ signalDecls = [
3768
+ {
3769
+ kind: "varDecl",
3770
+ localId: acLocal.id,
3771
+ init: { kind: "libCall", fn: "fetch.abortControllerNew", args: [], type: DYN, loc },
3772
+ loc,
3773
+ },
3774
+ ];
3775
+ signalArgs = [
3776
+ pipelineAbortHelper(lowerer, ac, loc, true),
3777
+ { kind: "dynKeyGet", value: ac, key: strLit("signal", loc), type: DYN, loc },
3778
+ ];
3779
+ }
3780
+ const withSignal = (fnName, args) => {
3781
+ const call = {
3782
+ kind: "libCall",
3783
+ fn: signalArgs.length > 0 ? `${fnName}Signal` : fnName,
3784
+ args: [...args, ...signalArgs],
3785
+ type: duplex,
3786
+ loc,
3787
+ };
3788
+ return signalDecls.length > 0
3789
+ ? { kind: "seqExpr", stmts: signalDecls, result: call, type: duplex, loc }
3790
+ : call;
3791
+ };
3792
+ if (!isGen) {
3793
+ // an async function: a writable Duplexify whose final waits for
3794
+ // the function's promise
3795
+ const asyncSource = duplexSourceHelper(lowerer, sourceT, loc);
3796
+ const out = lowered.out;
3797
+ if (out.kind !== "promise" || !asyncSource)
3798
+ return lowerer.noLowering("Duplex.from over a function with this return type", node);
3799
+ if (out.inner.kind !== "void" &&
3800
+ !canConvertToDyn(out.inner, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
3801
+ lowerer.noLowering(`Duplex.from over a function resolving to '${lowerer.fmt(out.inner)}'`, node);
3802
+ }
3803
+ return withSignal("stream.duplexFromAsyncFn", [
3804
+ lowered.closure,
3805
+ asyncSource,
3806
+ pipelineBoxHelper(lowerer, out, loc),
3807
+ ]);
3808
+ }
3809
+ const helpers = lowered.out.kind === "generator" ? fromGenHelpers(lowerer, lowered.out, loc) : null;
3810
+ const source = duplexSourceHelper(lowerer, sourceT, loc);
3811
+ if (!helpers || !source)
3812
+ lowerer.noLowering("Duplex.from over a function with this generator type", node);
3813
+ return withSignal("stream.duplexFromGen", [lowered.closure, source, ...helpers]);
3814
+ }
3815
+ // duplexify.js: a stream answers itself (a Duplex) or is wrapped; any
3816
+ // other body reads as from(Duplexify, body, { objectMode: true,
3817
+ // writable: false })
3818
+ let bodyT;
3819
+ try {
3820
+ bodyT = lowerer.mapTypeOf(lowerer.typeOf(node));
3821
+ }
3822
+ catch {
3823
+ bodyT = null;
3824
+ }
3825
+ const bodySides = bodyT?.kind === "object" ? streamSidesOf(lowerer, lowerer.classes.get(bodyT.className)) : null;
3826
+ let literal = node;
3827
+ while (ts.isParenthesizedExpression(literal))
3828
+ literal = literal.expression;
3829
+ if (bodySides === null && ts.isObjectLiteralExpression(literal))
3830
+ return duplexFromPair(lowerer, literal, loc);
3831
+ if (bodyT?.kind === "promise") {
3832
+ // a Duplexify that reads the promise's value
3833
+ const valueT = bodyT.inner;
3834
+ if (valueT.kind !== "void" &&
3835
+ !canConvertToDyn(valueT, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
3836
+ lowerer.noLowering(`Duplex.from over a promise of '${lowerer.fmt(valueT)}'`, node);
3837
+ }
3838
+ const promise = lowerer.lowerExpr(node);
3839
+ if (promise.type.kind !== "promise") {
3840
+ // a checked-dynamic promise (an untyped function's result)
3841
+ return {
3842
+ kind: "libCall",
3843
+ fn: "stream.duplexFromDyn",
3844
+ args: [lowerer.coerceToExpected(promise, DYN)],
3845
+ type: { kind: "object", className: "%Duplex" },
3846
+ loc,
3847
+ };
3848
+ }
3849
+ return {
3850
+ kind: "libCall",
3851
+ fn: "stream.duplexFromPromise",
3852
+ args: [
3853
+ promise,
3854
+ pipelineBoxHelper(lowerer, promise.type, loc),
3855
+ ],
3856
+ type: { kind: "object", className: "%Duplex" },
3857
+ loc,
3858
+ };
3859
+ }
3860
+ if (bodySides === null)
3861
+ return lowerFromSource(lowerer, node, node, undefined, true);
3862
+ let stream;
3863
+ try {
3864
+ stream = lowerStreamArg(lowerer, node, "compose");
3865
+ }
3866
+ catch (e) {
3867
+ if (e instanceof StreamArgTypeThrow)
3868
+ return e.expr;
3869
+ throw e;
3870
+ }
3871
+ const sides = stream.type.kind === "object"
3872
+ ? streamSidesOf(lowerer, lowerer.classes.get(stream.type.className))
3873
+ : null;
3874
+ // _duplexify({ readable }) / _duplexify({ writable })
3875
+ if (sides === "r" || sides === "w") {
3876
+ return {
3877
+ kind: "libCall",
3878
+ fn: sides === "r" ? "stream.duplexifyReadable" : "stream.duplexifyWritable",
3879
+ args: [stream],
3880
+ type: duplex,
3881
+ loc,
3882
+ };
3883
+ }
3884
+ if (sides !== "rw") {
3885
+ lowerer.noLowering("Duplex.from over a value of this type", node, "an async generator function, an iterable, a stream, or a { readable, writable } pair is the lowered body");
3886
+ }
3887
+ return stream;
3888
+ }
3889
+ /** Duplex.from({ readable, writable }): each member that is a stream with
3890
+ * that side is used as it is, any other member is Duplex.from of it, and
3891
+ * the pair reads and writes through _duplexify (duplexify.js). The
3892
+ * members evaluate in source order. */
3893
+ function duplexFromPair(lowerer, literal, loc) {
3894
+ const duplex = { kind: "object", className: "%Duplex" };
3895
+ const sides = {};
3896
+ // The members in source order; when that is not (readable, writable),
3897
+ // each value is bound to a local first, keeping the literal's
3898
+ // evaluation order.
3899
+ const members = [];
3900
+ for (const p of literal.properties.nodes) {
3901
+ const key = (ts.isPropertyAssignment(p) || ts.isShorthandPropertyAssignment(p)) && ts.isIdentifier(p.name)
3902
+ ? p.name.text
3903
+ : null;
3904
+ if (key !== "readable" && key !== "writable") {
3905
+ lowerer.noLowering("Duplex.from over an object with members other than readable and writable", p, "pass { readable, writable } with streams or Duplex.from bodies");
3906
+ }
3907
+ const value = ts.isShorthandPropertyAssignment(p)
3908
+ ? p.name
3909
+ : p.initializer;
3910
+ let valueT;
3911
+ try {
3912
+ valueT = lowerer.mapTypeOf(lowerer.typeOf(value));
3913
+ }
3914
+ catch {
3915
+ valueT = null;
3916
+ }
3917
+ const valueSides = valueT?.kind === "object"
3918
+ ? streamSidesOf(lowerer, lowerer.classes.get(valueT.className))
3919
+ : null;
3920
+ const wanted = key === "readable" ? "r" : "w";
3921
+ const direct = valueSides === "rw" || valueSides === wanted;
3922
+ members.push({
3923
+ key: key,
3924
+ value: direct
3925
+ ? lowerStreamArg(lowerer, value, "compose")
3926
+ : duplexFromBody(lowerer, value, loc),
3927
+ });
3928
+ }
3929
+ const decls = [];
3930
+ const inOrder = members.length <= 1 ||
3931
+ (members.length === 2 && members[0].key === "readable" && members[1].key === "writable");
3932
+ for (const m of members) {
3933
+ if (inOrder) {
3934
+ sides[m.key] = m.value;
3935
+ continue;
3936
+ }
3937
+ const local = lowerer.declareHiddenLocal(`%duplex${m.key}`, m.value.type);
3938
+ decls.push({ kind: "varDecl", localId: local.id, init: m.value, loc });
3939
+ sides[m.key] = varRef(local.id, m.value.type, loc);
3940
+ }
3941
+ const { readable, writable } = sides;
3942
+ if (readable && writable) {
3943
+ const call = {
3944
+ kind: "libCall",
3945
+ fn: "stream.duplexifyPair",
3946
+ args: [readable, writable],
3947
+ type: duplex,
3948
+ loc,
3949
+ };
3950
+ return decls.length > 0
3951
+ ? { kind: "seqExpr", stmts: decls, result: call, type: duplex, loc }
3952
+ : call;
3953
+ }
3954
+ if (decls.length > 0) {
3955
+ // a repeated member: every value is evaluated, the last one is used
3956
+ const one = readable ?? writable;
3957
+ const call = {
3958
+ kind: "libCall",
3959
+ fn: readable ? "stream.duplexifyReadable" : "stream.duplexifyWritable",
3960
+ args: [one],
3961
+ type: duplex,
3962
+ loc,
3963
+ };
3964
+ return { kind: "seqExpr", stmts: decls, result: call, type: duplex, loc };
3965
+ }
3966
+ if (readable)
3967
+ return { kind: "libCall", fn: "stream.duplexifyReadable", args: [readable], type: duplex, loc };
3968
+ if (writable)
3969
+ return { kind: "libCall", fn: "stream.duplexifyWritable", args: [writable], type: duplex, loc };
3970
+ return lowerer.noLowering("Duplex.from over an object with neither readable nor writable", literal, "pass { readable, writable } with streams or Duplex.from bodies");
3971
+ }
3972
+ /** The checker type of a stage's string or Buffer chunks, or null for
3973
+ * other chunk types. */
3974
+ function stageChunkCheckerType(lowerer, chunk, at) {
3975
+ if (chunk.kind === "string")
3976
+ return lowerer.checker.getStringType();
3977
+ if (chunk.kind !== "bytes")
3978
+ return null;
3979
+ const buffer = lowerer.checker.resolveName("Buffer", ts.SymbolFlags.Type, at, false);
3980
+ return buffer ? lowerer.checker.getDeclaredTypeOfSymbol(buffer) : null;
2528
3981
  }
2529
3982
  /** `stream.compose(...streams)` over stream instances: a Duplex writing
2530
3983
  * to the first stream and reading from the last (scr_stream_compose). The
2531
3984
  * classes fix which positions can be readable and writable; a stream in
2532
3985
  * the wrong position, a single Readable or Writable (Duplex.from wraps
2533
3986
  * those), and functions, iterables or web streams have no lowering. */
2534
- function lowerStreamCompose(lowerer, call, loc) {
2535
- const args = call.arguments.nodes;
3987
+ function lowerStreamCompose(lowerer, args, loc) {
2536
3988
  const duplex = { kind: "object", className: "%Duplex" };
2537
- if (args.some((a) => ts.isSpreadElement(a))) {
2538
- lowerer.noLowering("compose with spread arguments", call, "pass the streams directly");
2539
- }
2540
3989
  if (args.length === 0) {
2541
3990
  return nodeThrowExpr(1, "ERR_MISSING_ARGS", 'The "streams" argument must be specified', duplex, loc);
2542
3991
  }
3992
+ // A web ReadableStream first stage reads as an async iterable (the
3993
+ // pipeline's source), and alone it is Duplex.from of it; a later stage
3994
+ // would be Duplex.fromWeb of it.
3995
+ for (let i = 1; i < args.length; i++) {
3996
+ const a = args[i];
3997
+ // (typeOf on a stage function's name would report what collecting its
3998
+ // declared signature deferred)
3999
+ if (pipelineStageFunction(lowerer, a) !== null)
4000
+ continue;
4001
+ if (staticReadableStreamElementType(lowerer, a) !== null) {
4002
+ lowerer.noLowering("compose with a web ReadableStream after the first stage", a, "a web ReadableStream is supported as the first stage of compose or pipeline, and in Readable.from");
4003
+ }
4004
+ }
4005
+ // Duplex.from(stage) for one stage (duplexify.js), and for a function at
4006
+ // either end; functions between, an iterable first stage or a source
4007
+ // function run as the pipeline's function stages (compose.js)
4008
+ if (args.length === 1)
4009
+ return duplexFromBody(lowerer, args[0], loc);
4010
+ const last = args.length - 1;
4011
+ const isFn = (i) => pipelineStageFunction(lowerer, args[i]) !== null;
4012
+ const pre = new Map();
4013
+ if (isFn(0))
4014
+ pre.set(0, duplexFromBody(lowerer, args[0], loc));
4015
+ if (isFn(last))
4016
+ pre.set(last, duplexFromBody(lowerer, args[last], loc));
4017
+ const staged = args.some((_, i) => !pre.has(i) && isFn(i)) ||
4018
+ (!pre.has(0) && iterableSourceType(lowerer, args[0]) !== null);
4019
+ if (staged) {
4020
+ const lowered = lowerPipelineStages(lowerer, args, loc, pre);
4021
+ return lowered.wrap({
4022
+ kind: "libCall",
4023
+ fn: "stream.composeStages",
4024
+ args: lowered.args,
4025
+ type: duplex,
4026
+ loc,
4027
+ });
4028
+ }
2543
4029
  let streams;
2544
4030
  try {
2545
- streams = args.map((a) => lowerStreamArg(lowerer, a, "compose"));
4031
+ streams = args.map((a, i) => pre.get(i) ?? lowerStreamArg(lowerer, a, "compose"));
2546
4032
  }
2547
4033
  catch (e) {
2548
4034
  if (e instanceof StreamArgTypeThrow)
@@ -2574,6 +4060,28 @@ function lowerStreamCompose(lowerer, call, loc) {
2574
4060
  /* ── the method surface ───────────────────────────────────────────────── */
2575
4061
  /* ── the Readable operators ──────────────────────────────────────────── */
2576
4062
  /** The Readable operators (scr_stream_ops.c — Node's operators.js). */
4063
+ /** A stream member's receiver, lowered: a value the checker types as a
4064
+ * stream class whose lowering is checked-dynamic (a JavaScript binding
4065
+ * that holds an untyped call's result) or a union (an element read)
4066
+ * converts to that class, checked where the member runs. */
4067
+ function streamReceiverExpr(lowerer, node) {
4068
+ const value = lowerer.lowerExpr(node);
4069
+ if (value.type.kind !== "dyn" && value.type.kind !== "union")
4070
+ return value;
4071
+ let classT;
4072
+ try {
4073
+ classT = lowerer.mapTypeOf(lowerer.typeOf(node));
4074
+ }
4075
+ catch {
4076
+ return value;
4077
+ }
4078
+ if (classT?.kind !== "object" ||
4079
+ streamSidesOf(lowerer, lowerer.classes.get(classT.className)) === null)
4080
+ return value;
4081
+ return value.type.kind === "dyn"
4082
+ ? { kind: "dynCheck", value, type: classT, loc: value.loc }
4083
+ : lowerer.coerceToExpected(value, classT);
4084
+ }
2577
4085
  export const STREAM_OPERATORS = new Set([
2578
4086
  "map",
2579
4087
  "filter",
@@ -2587,50 +4095,125 @@ export const STREAM_OPERATORS = new Set([
2587
4095
  "find",
2588
4096
  "reduce",
2589
4097
  ]);
2590
- /** An operator callback as a checked-dynamic function value. Callbacks
2591
- * that declare the options argument ({ signal }) are refused: the
2592
- * AbortSignal Node passes there has no representation. map and flatMap
2593
- * callbacks must produce strings or Buffers (flatMap: arrays of them, or
2594
- * strings) — or checked-dynamic values, which the runtime checks. */
4098
+ /** An operator callback as a checked-dynamic function value, and whether
4099
+ * it declares the options argument ({ signal }), which the runtime then
4100
+ * passes. Its results convert to checked-dynamic values (flatMap's are
4101
+ * iterated with yield*). */
2595
4102
  function lowerOperatorCallback(lowerer, node, member, maxParams) {
2596
4103
  const loc = locOf(node);
2597
- const optionsParam = (at) => lowerer.noLowering(`${member} callbacks that declare the options argument`, at, "the { signal } argument has no lowering — take only the chunk");
2598
- if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) &&
2599
- node.parameters.nodes.length > maxParams) {
2600
- optionsParam(node.parameters.nodes[maxParams]);
4104
+ const optionsParam = (at) => lowerer.noLowering(`${member} callbacks with parameters after the options argument`, at, "the callback takes the chunk and { signal }");
4105
+ let takesOptions = false;
4106
+ if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
4107
+ if (node.parameters.nodes.length > maxParams + 1)
4108
+ optionsParam(node.parameters.nodes[maxParams + 1]);
4109
+ takesOptions = node.parameters.nodes.length > maxParams;
2601
4110
  }
2602
4111
  const v = lowerer.lowerExpr(node);
4112
+ // A checked-dynamic function's parameters are not known here: it gets
4113
+ // the { signal } argument, as Node passes it to every callback.
2603
4114
  if (v.type.kind === "dyn")
2604
- return v;
4115
+ return { fn: v, takesOptions: true };
2605
4116
  if (v.type.kind !== "func" &&
2606
4117
  isJsSourceFile(ts.getSourceFileOfNode(node)) &&
2607
4118
  lowerer.dynConvertible(v.type)) {
2608
4119
  // JavaScript passes any value; Node's validateFunction throws.
2609
- return { kind: "dynFrom", value: v, type: DYN, loc };
4120
+ return { fn: { kind: "dynFrom", value: v, type: DYN, loc }, takesOptions: false };
2610
4121
  }
2611
4122
  if (v.type.kind !== "func") {
2612
4123
  lowerer.noLowering(`${member} with a '${lowerer.fmt(v.type)}' callback`, node, "pass a function");
2613
4124
  }
2614
- if (v.type.params.length > maxParams)
4125
+ if (v.type.params.length > maxParams + 1)
2615
4126
  optionsParam(node);
2616
- if (member === "map" || member === "flatMap") {
2617
- const ret = v.type.ret.kind === "promise" ? v.type.ret.inner : v.type.ret;
2618
- const chunk = (t) => t.kind === "string" || t.kind === "dyn" || (t.kind === "bytes" && t.elem === "u8");
2619
- const ok = member === "map"
2620
- ? chunk(ret)
2621
- : ret.kind === "dyn" || ret.kind === "string" || (ret.kind === "array" && chunk(ret.elem));
2622
- if (!ok) {
2623
- lowerer.noLowering(`${member} callbacks that return '${lowerer.fmt(ret)}'`, node, member === "map"
2624
- ? "map results are stream chunks: strings or Buffers (object-mode streams of other values are not lowered)"
2625
- : "flatMap results are arrays of strings or Buffers, or strings");
2626
- }
2627
- }
4127
+ if (v.type.params.length > maxParams)
4128
+ takesOptions = true;
2628
4129
  const getRecord = (id) => lowerer.shapes.get(id);
2629
4130
  const getUnion = (id) => lowerer.unions.get(id);
2630
4131
  if (!canBoxFuncIntoDyn(v.type, getRecord, getUnion)) {
2631
4132
  lowerer.noLowering(`${member} with this callback`, node, "the callback's parameter and result types must cross the checked-dynamic boundary");
2632
4133
  }
2633
- return { kind: "dynFrom", value: v, type: DYN, loc };
4134
+ const fn = { kind: "dynFrom", value: v, type: DYN, loc };
4135
+ // flatMap over a compiled generator: the runtime steps it through the
4136
+ // helpers over its type
4137
+ if (member === "flatMap" && v.type.ret.kind === "generator")
4138
+ return { fn, takesOptions, gen: v.type.ret };
4139
+ return { fn, takesOptions };
4140
+ }
4141
+ /** The operator callbacks' `{ signal }` (operators.js): map and the
4142
+ * operators over it pass `{ signal: AbortSignal.any([options?.signal]
4143
+ * .filter(Boolean)) }`. options is the operator's options value. */
4144
+ export function operatorSignalOptions(lowerer, options, loc) {
4145
+ void lowerer;
4146
+ const list = {
4147
+ kind: "libCall",
4148
+ fn: "readable.opSignalList",
4149
+ args: [options],
4150
+ type: DYN,
4151
+ loc,
4152
+ };
4153
+ const signal = { kind: "libCall", fn: "fetch.abortAny", args: [list], type: DYN, loc };
4154
+ return { kind: "libCall", fn: "readable.opSignalOpts", args: [signal], type: DYN, loc };
4155
+ }
4156
+ /** reduce's signal for a reducer that reads it (operators.js): `const ac
4157
+ * = new AbortController()`, `options.signal.addEventListener('abort', ()
4158
+ * => ac.abort(), { once: true })`, then reduceSignal's ac.abort() closure
4159
+ * and `{ signal: ac.signal }`. options is the bound options value. */
4160
+ export function reduceSignalSetup(lowerer, options, loc, declare = (name, type) => lowerer.declareHiddenLocal(name, type)) {
4161
+ const acLocal = declare("%opAbort", DYN);
4162
+ const ac = varRef(acLocal.id, DYN, loc);
4163
+ const sigLocal = declare("%opUserSignal", DYN);
4164
+ const sig = varRef(sigLocal.id, DYN, loc);
4165
+ const abort = pipelineAbortHelper(lowerer, ac, loc);
4166
+ const stmts = [
4167
+ {
4168
+ kind: "varDecl",
4169
+ localId: acLocal.id,
4170
+ init: { kind: "libCall", fn: "fetch.abortControllerNew", args: [], type: DYN, loc },
4171
+ loc,
4172
+ },
4173
+ {
4174
+ kind: "varDecl",
4175
+ localId: sigLocal.id,
4176
+ init: { kind: "libCall", fn: "readable.opSignalOf", args: [options], type: DYN, loc },
4177
+ loc,
4178
+ },
4179
+ {
4180
+ kind: "if",
4181
+ cond: { kind: "dynTest", test: "truthy", value: sig, type: BOOL, loc },
4182
+ then: [
4183
+ {
4184
+ kind: "exprStmt",
4185
+ expr: {
4186
+ kind: "dynInvoke",
4187
+ recv: sig,
4188
+ method: "addEventListener",
4189
+ calleeName: "options.signal.addEventListener",
4190
+ args: [
4191
+ { kind: "dynFrom", value: strLit("abort", loc), type: DYN, loc },
4192
+ { kind: "dynFrom", value: pipelineAbortHelper(lowerer, ac, loc), type: DYN, loc },
4193
+ { kind: "libCall", fn: "readable.opOnceOptions", args: [], type: DYN, loc },
4194
+ ],
4195
+ type: DYN,
4196
+ loc,
4197
+ },
4198
+ loc,
4199
+ },
4200
+ ],
4201
+ else_: null,
4202
+ loc,
4203
+ },
4204
+ ];
4205
+ const signal = {
4206
+ kind: "dynKeyGet",
4207
+ value: ac,
4208
+ key: strLit("signal", loc),
4209
+ type: DYN,
4210
+ loc,
4211
+ };
4212
+ return {
4213
+ stmts,
4214
+ abort,
4215
+ cbOpts: { kind: "libCall", fn: "readable.opSignalOpts", args: [signal], type: DYN, loc },
4216
+ };
2634
4217
  }
2635
4218
  /** An operator's options (or reduce's initial value): an object literal
2636
4219
  * becomes a checked-dynamic object, checked-dynamic values pass through,
@@ -2654,21 +4237,37 @@ function lowerOperatorValue(lowerer, node, what, loc, literalObject) {
2654
4237
  function lowerStreamOperator(lowerer, call, access, member) {
2655
4238
  const loc = locOf(call);
2656
4239
  const args = call.arguments.nodes;
2657
- const recv = lowerer.lowerExpr(access.expression);
4240
+ // JS order: the receiver, the callback, then the options; the
4241
+ // callback's { signal } is built over the options value afterwards.
4242
+ const decls = [];
4243
+ const bind = (value, name) => {
4244
+ const local = lowerer.declareHiddenLocal(name, value.type);
4245
+ decls.push({ kind: "varDecl", localId: local.id, init: value, loc });
4246
+ return varRef(local.id, value.type, loc);
4247
+ };
4248
+ const recv = bind(streamReceiverExpr(lowerer, access.expression), "%opRecv");
2658
4249
  const readable = { kind: "object", className: "%Readable" };
2659
4250
  const opts = (i) => lowerOperatorValue(lowerer, args[i], `${member} options`, loc, true);
4251
+ let takesOptions = false;
4252
+ let callbackGen;
2660
4253
  const fnArg = (maxParams) => {
2661
4254
  if (args[0] === undefined)
2662
4255
  return dynUndefinedExpr(loc);
2663
- return lowerOperatorCallback(lowerer, args[0], member, maxParams);
4256
+ const lowered = lowerOperatorCallback(lowerer, args[0], member, maxParams);
4257
+ takesOptions = lowered.takesOptions;
4258
+ callbackGen = lowered.gen;
4259
+ return bind(lowered.fn, "%opFn");
4260
+ };
4261
+ const lib = (fn, a, type) => {
4262
+ const call = { kind: "libCall", fn: fn, args: a, type, loc };
4263
+ return { kind: "seqExpr", stmts: decls, result: call, type, loc };
4264
+ };
4265
+ // the options argument (bound), and the callback's { signal } when it
4266
+ // declares one
4267
+ const withSignal = (optsValue) => {
4268
+ const o = bind(optsValue, "%opOptions");
4269
+ return [o, takesOptions ? operatorSignalOptions(lowerer, o, loc) : dynUndefinedExpr(loc)];
2664
4270
  };
2665
- const lib = (fn, a, type) => ({
2666
- kind: "libCall",
2667
- fn: fn,
2668
- args: a,
2669
- type,
2670
- loc,
2671
- });
2672
4271
  switch (member) {
2673
4272
  case "map":
2674
4273
  case "filter":
@@ -2679,7 +4278,12 @@ function lowerStreamOperator(lowerer, call, access, member) {
2679
4278
  : member === "filter"
2680
4279
  ? "readable.opFilter"
2681
4280
  : "readable.opFlatMap";
2682
- return lib(fnName, [recv, fn, opts(1)], readable);
4281
+ const rest = withSignal(opts(1));
4282
+ const genHelpers = callbackGen ? fromGenHelpers(lowerer, callbackGen, loc) : null;
4283
+ if (callbackGen && genHelpers) {
4284
+ return lib(callbackGen.async ? "readable.opFlatMapAsyncGen" : "readable.opFlatMapSyncGen", [recv, fn, ...rest, ...genHelpers], readable);
4285
+ }
4286
+ return lib(fnName, [recv, fn, ...rest], readable);
2683
4287
  }
2684
4288
  case "drop":
2685
4289
  case "take": {
@@ -2688,12 +4292,17 @@ function lowerStreamOperator(lowerer, call, access, member) {
2688
4292
  }
2689
4293
  case "toArray":
2690
4294
  return lib("readable.opToArray", [recv, opts(0)], { kind: "promise", inner: DYN });
2691
- case "forEach":
2692
- return lib("readable.opForEach", [recv, fnArg(1), opts(1)], { kind: "promise", inner: VOID });
4295
+ case "forEach": {
4296
+ const fn = fnArg(1);
4297
+ return lib("readable.opForEach", [recv, fn, ...withSignal(opts(1))], {
4298
+ kind: "promise",
4299
+ inner: VOID,
4300
+ });
4301
+ }
2693
4302
  case "some":
2694
4303
  case "every": {
2695
4304
  const fn = fnArg(1);
2696
- return lib(member === "some" ? "readable.opSome" : "readable.opEvery", [recv, fn, opts(1)], {
4305
+ return lib(member === "some" ? "readable.opSome" : "readable.opEvery", [recv, fn, ...withSignal(opts(1))], {
2697
4306
  kind: "promise",
2698
4307
  inner: BOOL,
2699
4308
  });
@@ -2704,7 +4313,11 @@ function lowerStreamOperator(lowerer, call, access, member) {
2704
4313
  if (inner && !(inner.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown))) {
2705
4314
  lowerer.noLowering("find with a type-guard callback", call, "the result is a checked-dynamic value — use a boolean predicate and narrow the result");
2706
4315
  }
2707
- return lib("readable.opFind", [recv, fnArg(1), opts(1)], { kind: "promise", inner: DYN });
4316
+ const fn = fnArg(1);
4317
+ return lib("readable.opFind", [recv, fn, ...withSignal(opts(1))], {
4318
+ kind: "promise",
4319
+ inner: DYN,
4320
+ });
2708
4321
  }
2709
4322
  case "reduce": {
2710
4323
  const t = lowerer.typeOf(call);
@@ -2730,20 +4343,21 @@ function lowerStreamOperator(lowerer, call, access, member) {
2730
4343
  }
2731
4344
  }
2732
4345
  const fn = fnArg(2);
2733
- const init = lowerOperatorValue(lowerer, args[1], "reduce's initial value", loc, false);
2734
- return lib("readable.opReduce", [recv, fn, init, boolLit(args.length >= 2, loc), opts(2), numLit(kind, loc)], { kind: "promise", inner });
4346
+ const init = bind(lowerOperatorValue(lowerer, args[1], "reduce's initial value", loc, false), "%opInit");
4347
+ const o = bind(opts(2), "%opOptions");
4348
+ const head = [recv, fn, init, boolLit(args.length >= 2, loc), o, numLit(kind, loc)];
4349
+ if (!takesOptions)
4350
+ return lib("readable.opReduce", head, { kind: "promise", inner });
4351
+ const setup = reduceSignalSetup(lowerer, o, loc);
4352
+ decls.push(...setup.stmts);
4353
+ return lib("readable.opReduceSignal", [...head, setup.abort, setup.cbOpts], {
4354
+ kind: "promise",
4355
+ inner,
4356
+ });
2735
4357
  }
2736
4358
  }
2737
4359
  throw new InternalCompilerError(`unknown stream operator ${member}`);
2738
4360
  }
2739
- /** The literal 'buffer' encoding on write()/end(): Node 24 takes it for a
2740
- * Buffer chunk and throws ERR_UNKNOWN_ENCODING for a string chunk. */
2741
- function isBufferEncoding(lowerer, arg) {
2742
- if (arg === undefined)
2743
- return false;
2744
- const t = lowerer.typeOf(arg);
2745
- return t.isStringLiteralType() && t.value === "buffer";
2746
- }
2747
4361
  /** The one supported encoding argument: utf8 (Node's default), as a
2748
4362
  * compile-time literal or absent. */
2749
4363
  function checkUtf8Encoding(lowerer, member, arg) {
@@ -2779,7 +4393,7 @@ function pipeEndOption(lowerer, options, loc) {
2779
4393
  function pipeIntoStdio(lowerer, call, access, target) {
2780
4394
  const loc = locOf(call);
2781
4395
  // JS order: the receiver, then the destination, then the options.
2782
- const receiverValue = lowerer.lowerExpr(access.expression);
4396
+ const receiverValue = streamReceiverExpr(lowerer, access.expression);
2783
4397
  const source = lowerer.declareHiddenLocal("%pipeSource", receiverValue.type);
2784
4398
  const stdio = lowerer.declareHiddenLocal("%pipeStdio", target.type);
2785
4399
  const options = call.arguments.nodes[1];
@@ -2890,7 +4504,7 @@ function generalPipe(lowerer, dst) {
2890
4504
  function pipeIntoDyn(lowerer, call, access, target) {
2891
4505
  const loc = locOf(call);
2892
4506
  noteUntypedStreamFlow(lowerer, null);
2893
- const receiverValue = lowerer.lowerExpr(access.expression);
4507
+ const receiverValue = streamReceiverExpr(lowerer, access.expression);
2894
4508
  const source = lowerer.declareHiddenLocal("%pipeSource", receiverValue.type);
2895
4509
  const destination = lowerer.declareHiddenLocal("%pipeDestination", target.type);
2896
4510
  const stmts = [
@@ -2976,6 +4590,59 @@ function pipeIntoDyn(lowerer, call, access, target) {
2976
4590
  loc,
2977
4591
  };
2978
4592
  }
4593
+ /** readable.compose(stage, options): compose(this, stage), with
4594
+ * addAbortSignal(options.signal, composed) when the signal is set
4595
+ * (operators.js). */
4596
+ function lowerReadableCompose(lowerer, call, access) {
4597
+ const loc = locOf(call);
4598
+ const args = call.arguments.nodes;
4599
+ if (args.length === 0 || args.length > 2 || args.some((a) => ts.isSpreadElement(a))) {
4600
+ lowerer.noLowering(`readable.compose with ${args.length === 0 ? "no stage" : "these arguments"}`, call, "the supported form is readable.compose(stage) or readable.compose(stage, { signal })");
4601
+ }
4602
+ let signalNode = null;
4603
+ const options = args[1];
4604
+ if (options !== undefined &&
4605
+ options.kind !== ts.SyntaxKind.NullKeyword &&
4606
+ !(ts.isIdentifier(options) && options.text === "undefined")) {
4607
+ if (!ts.isObjectLiteralExpression(options)) {
4608
+ lowerer.noLowering("readable.compose options that are not an object literal", options, "pass { signal } as an object literal");
4609
+ }
4610
+ for (const p of options.properties.nodes) {
4611
+ const key = (ts.isPropertyAssignment(p) || ts.isShorthandPropertyAssignment(p)) &&
4612
+ ts.isIdentifier(p.name)
4613
+ ? p.name.text
4614
+ : null;
4615
+ if (key !== "signal") {
4616
+ lowerer.noLowering(key === null
4617
+ ? "readable.compose options with this member"
4618
+ : `the readable.compose option '${key}'`, p, "signal is the readable.compose option");
4619
+ }
4620
+ const value = ts.isShorthandPropertyAssignment(p)
4621
+ ? p.name
4622
+ : p.initializer;
4623
+ if (value.kind === ts.SyntaxKind.NullKeyword)
4624
+ continue;
4625
+ if (ts.isIdentifier(value) && value.text === "undefined")
4626
+ continue;
4627
+ // The signal is read after compose runs, so only values whose
4628
+ // evaluation has no effects.
4629
+ if (!sideEffectFreeOptionValue(value) && !pureRead(value)) {
4630
+ lowerer.noLowering("the readable.compose option 'signal' with this value", p, "pass a variable or property read (const signal = controller.signal)");
4631
+ }
4632
+ signalNode = value;
4633
+ }
4634
+ }
4635
+ const composed = lowerStreamCompose(lowerer, [access.expression, args[0]], loc);
4636
+ if (signalNode === null)
4637
+ return composed;
4638
+ return {
4639
+ kind: "libCall",
4640
+ fn: "stream.addAbortSignal",
4641
+ args: [composed, lowerer.lowerExprExpecting(signalNode, DYN)],
4642
+ type: composed.type,
4643
+ loc,
4644
+ };
4645
+ }
2979
4646
  export function lowerStreamMethodCall(lowerer, call, access, info) {
2980
4647
  const member = access.name.text;
2981
4648
  if (STREAM_OPERATORS.has(member)) {
@@ -2983,6 +4650,12 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
2983
4650
  if (opSides === "r" || opSides === "rw")
2984
4651
  return lowerStreamOperator(lowerer, call, access, member);
2985
4652
  }
4653
+ if (member === "compose") {
4654
+ const composeSides = streamSidesOf(lowerer, info);
4655
+ return composeSides === "r" || composeSides === "rw"
4656
+ ? lowerReadableCompose(lowerer, call, access)
4657
+ : null;
4658
+ }
2986
4659
  if (!STREAM_API_MEMBERS.has(member))
2987
4660
  return null;
2988
4661
  const sides = streamSidesOf(lowerer, info);
@@ -3037,7 +4710,16 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3037
4710
  if (probed?.type.kind === "nullT")
3038
4711
  return "null";
3039
4712
  }
3040
- lowerer.noLowering(`${member} with a '${t ? lowerer.fmt(t) : "?"}' chunk`, node, "chunks are Buffers or utf8 strings — or unions of those with null (objectMode is not lowered)");
4713
+ // Any other value is a checked-dynamic chunk: one entry on an
4714
+ // object-mode side, Node's chunk type error on a byte-mode one
4715
+ // (undefined, which a byte-mode push ignores, included).
4716
+ if (t?.kind === "void" || t?.kind === "undefinedT")
4717
+ return "dyn";
4718
+ if (t !== null &&
4719
+ t.kind !== "func" &&
4720
+ canConvertToDyn(t, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)))
4721
+ return "dyn";
4722
+ lowerer.noLowering(`${member} with a '${t ? lowerer.fmt(t) : "?"}' chunk`, node, "chunks are values that convert to checked-dynamic values: Buffers, strings, numbers, records, arrays and class instances");
3041
4723
  };
3042
4724
  if (member === "push" || member === "unshift") {
3043
4725
  requireSide(readableSide, member);
@@ -3056,7 +4738,7 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3056
4738
  if (canonical === undefined) {
3057
4739
  return nodeThrowExpr(1, "ERR_UNKNOWN_ENCODING", `Unknown encoding: ${t.value}`, BOOL, loc);
3058
4740
  }
3059
- const receiver = lowerer.lowerExpr(access.expression);
4741
+ const receiver = streamReceiverExpr(lowerer, access.expression);
3060
4742
  const chunk = lowerer.lowerExprExpecting(args[0], STRING);
3061
4743
  return {
3062
4744
  kind: "libCall",
@@ -3070,9 +4752,19 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3070
4752
  checkUtf8Encoding(lowerer, member, args[1]);
3071
4753
  const kind = chunkKind(args[0]);
3072
4754
  if ((kind === "null" || kind === "union" || kind === "dyn") && member === "unshift") {
3073
- lowerer.noLowering(kind === "null" ? "unshift(null)" : "unshift with a nullable or dynamic chunk", call, "EOF signals through push(null)");
4755
+ // unshift(value): an object-mode stream's value at the front, null
4756
+ // the end of the stream, as Node's readableAddChunk takes them
4757
+ const receiver = streamReceiverExpr(lowerer, access.expression);
4758
+ const chunk = lowerer.lowerExprExpecting(args[0], DYN);
4759
+ return {
4760
+ kind: "libCall",
4761
+ fn: "readable.unshiftDyn",
4762
+ args: [receiver, chunk],
4763
+ type: VOID,
4764
+ loc,
4765
+ };
3074
4766
  }
3075
- const receiver = lowerer.lowerExpr(access.expression);
4767
+ const receiver = streamReceiverExpr(lowerer, access.expression);
3076
4768
  if (kind === "null") {
3077
4769
  return { kind: "libCall", fn: "readable.pushNull", args: [receiver], type: BOOL, loc };
3078
4770
  }
@@ -3123,7 +4815,21 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3123
4815
  requireSide(readableSide, "read");
3124
4816
  if (args.length > 1)
3125
4817
  lowerer.noLowering(`read with ${args.length} arguments`, call);
3126
- const receiver = lowerer.lowerExpr(access.expression);
4818
+ const receiver = streamReceiverExpr(lowerer, access.expression);
4819
+ // JavaScript (and a result the declarations type as any) reads any
4820
+ // chunk: a Buffer, a string once encoded, or an object-mode value.
4821
+ const resultTs = lowerer.typeOf(call);
4822
+ if (isJsSourceFile(ts.getSourceFileOfNode(call)) ||
4823
+ (resultTs.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0) {
4824
+ const sizeDyn = args[0] ? lowerer.lowerExprExpecting(args[0], DYN) : dynUndefinedExpr(loc);
4825
+ return {
4826
+ kind: "libCall",
4827
+ fn: "readable.readDyn",
4828
+ args: [receiver, sizeDyn],
4829
+ type: DYN,
4830
+ loc,
4831
+ };
4832
+ }
3127
4833
  const size = args[0] ? lowerer.lowerExprExpecting(args[0], F64) : numLit(-1, loc);
3128
4834
  const type = unionOf(lowerer, [BYTES, { kind: "nullT" }]);
3129
4835
  const read = {
@@ -3139,7 +4845,7 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3139
4845
  requireSide(readableSide, member);
3140
4846
  if (args.length !== 0)
3141
4847
  lowerer.noLowering(`${member} with arguments`, call);
3142
- const receiver = lowerer.lowerExpr(access.expression);
4848
+ const receiver = streamReceiverExpr(lowerer, access.expression);
3143
4849
  return {
3144
4850
  kind: "libCall",
3145
4851
  fn: member === "pause" ? "readable.pause" : "readable.resume",
@@ -3152,7 +4858,7 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3152
4858
  requireSide(readableSide, "isPaused");
3153
4859
  if (args.length !== 0)
3154
4860
  lowerer.noLowering(`isPaused with arguments`, call);
3155
- const receiver = lowerer.lowerExpr(access.expression);
4861
+ const receiver = streamReceiverExpr(lowerer, access.expression);
3156
4862
  return { kind: "libCall", fn: "readable.isPaused", args: [receiver], type: BOOL, loc };
3157
4863
  }
3158
4864
  if (member === "pipe") {
@@ -3160,10 +4866,11 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3160
4866
  if (args.length === 0 || args.length > 2) {
3161
4867
  lowerer.noLowering(`pipe with ${args.length} arguments`, call, "the supported forms are (destination) and (destination, { end })");
3162
4868
  }
3163
- // A Hash or Hmac destination pipes into its Transform, and pipe()
3164
- // answers the Hash itself (the receiver evaluates first, as in JS).
3165
- if (isHashValueType(lowerer.mapTypeOf(lowerer.typeOf(args[0])))) {
3166
- const receiverValue = lowerer.lowerExpr(access.expression);
4869
+ // A Hash, Hmac, Cipheriv or Decipheriv destination pipes into its
4870
+ // Transform, and pipe() answers the value itself (the receiver
4871
+ // evaluates first, as in JS).
4872
+ if (isValueStream(lowerer, args[0])) {
4873
+ const receiverValue = streamReceiverExpr(lowerer, access.expression);
3167
4874
  const source = lowerer.declareHiddenLocal("%pipeSource", receiverValue.type);
3168
4875
  const hashValue = lowerer.lowerExpr(args[0]);
3169
4876
  const hash = lowerer.declareHiddenLocal("%pipeHash", hashValue.type);
@@ -3180,7 +4887,7 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3180
4887
  fn: "readable.pipe",
3181
4888
  args: [
3182
4889
  { kind: "varRef", localId: source.id, type: receiverValue.type, loc },
3183
- hashStreamOf({ kind: "varRef", localId: hash.id, type: hashValue.type, loc }, true),
4890
+ valueStreamOf({ kind: "varRef", localId: hash.id, type: hashValue.type, loc }, true),
3184
4891
  end,
3185
4892
  ],
3186
4893
  type: { kind: "object", className: "%Transform" },
@@ -3207,7 +4914,7 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3207
4914
  lowerer.noLowering(`pipe into a '${lowerer.fmt(dst.type)}'`, args[0], "the destination must be a stream Writable/Duplex, process.stdout or process.stderr (sockets are not pipe destinations yet)");
3208
4915
  }
3209
4916
  const end = pipeEndOption(lowerer, args[1], loc);
3210
- const receiver = lowerer.lowerExpr(access.expression);
4917
+ const receiver = streamReceiverExpr(lowerer, access.expression);
3211
4918
  return {
3212
4919
  kind: "libCall",
3213
4920
  fn: generalPipe(lowerer, dst.type),
@@ -3220,7 +4927,7 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3220
4927
  requireSide(readableSide, "unpipe");
3221
4928
  if (args.length > 1)
3222
4929
  lowerer.noLowering(`unpipe with ${args.length} arguments`, call);
3223
- const receiver = lowerer.lowerExpr(access.expression);
4930
+ const receiver = streamReceiverExpr(lowerer, access.expression);
3224
4931
  if (args[0] !== undefined) {
3225
4932
  const dst = lowerer.lowerExpr(args[0]);
3226
4933
  if (dst.type.kind === "dyn")
@@ -3281,7 +4988,7 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3281
4988
  if (member === "destroy") {
3282
4989
  if (args.length > 1)
3283
4990
  lowerer.noLowering(`destroy with ${args.length} arguments`, call);
3284
- const receiver = lowerer.lowerExpr(access.expression);
4991
+ const receiver = streamReceiverExpr(lowerer, access.expression);
3285
4992
  if (args[0] !== undefined) {
3286
4993
  const err = lowerer.lowerExpr(args[0]);
3287
4994
  const rootsAtError = (t) => {
@@ -3314,10 +5021,51 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3314
5021
  const kind = chunkKind(args[0]);
3315
5022
  if (kind === "null")
3316
5023
  lowerer.noLowering("write(null)", call, "end() finishes a writable");
5024
+ const lowerWriteCb = (cbArg) => {
5025
+ const cb = callbackDeclaresParameters(cbArg)
5026
+ ? null
5027
+ : lowerer.lowerExprExpecting(cbArg, funcOf([], VOID));
5028
+ if (cb === null || cb.type.kind !== "func" || cb.type.params.length > 0) {
5029
+ lowerer.noLowering("write completion callbacks taking the error argument", cbArg, "() => void callbacks are supported (listen for 'error' to observe failures)");
5030
+ }
5031
+ return cb;
5032
+ };
5033
+ // write(chunk, encoding[, cb]), and write(value, cb): the encoding
5034
+ // argument reaches an object-mode side's _write as passed, null when
5035
+ // the callback took its place (a byte-mode side encodes a string
5036
+ // chunk with it).
5037
+ const writeEnc = (encArg, cbArg) => {
5038
+ const receiver = streamReceiverExpr(lowerer, access.expression);
5039
+ const chunk = lowerer.lowerExprExpecting(args[0], DYN);
5040
+ const tail = [];
5041
+ if (encArg !== undefined)
5042
+ tail.push(lowerer.lowerExprExpecting(encArg, DYN));
5043
+ if (cbArg !== undefined)
5044
+ tail.push(lowerWriteCb(cbArg));
5045
+ const flags = (encArg !== undefined ? 1 : 0) | (cbArg !== undefined ? 2 : 0);
5046
+ return {
5047
+ kind: "libCall",
5048
+ fn: "writable.writeEnc",
5049
+ args: [receiver, numLit(flags, loc), chunk, ...tail],
5050
+ type: BOOL,
5051
+ loc,
5052
+ };
5053
+ };
3317
5054
  if (kind === "dyn") {
3318
- if (args.length > 1)
3319
- lowerer.noLowering("write with a dynamic chunk and more arguments", call);
3320
- const receiver = lowerer.lowerExpr(access.expression);
5055
+ if (args.length === 3)
5056
+ return writeEnc(args[1], args[2]);
5057
+ if (args.length === 2) {
5058
+ // Node's write takes a function there as the callback, anything
5059
+ // else as the encoding
5060
+ const t = lowerer.mapTypeOf(lowerer.typeOf(args[1]));
5061
+ if (t?.kind === "func")
5062
+ return writeEnc(undefined, args[1]);
5063
+ if (t === null || t === undefined || t.kind === "dyn") {
5064
+ lowerer.noLowering("write with a dynamic second argument", args[1], "pass an encoding string or a completion callback");
5065
+ }
5066
+ return writeEnc(args[1], undefined);
5067
+ }
5068
+ const receiver = streamReceiverExpr(lowerer, access.expression);
3321
5069
  const chunk = lowerer.lowerExprExpecting(args[0], DYN);
3322
5070
  return { kind: "libCall", fn: "writable.writeDyn", args: [receiver, chunk], type: BOOL, loc };
3323
5071
  }
@@ -3328,7 +5076,7 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3328
5076
  // re-dispatch on its IR type.
3329
5077
  if (args.length > 1)
3330
5078
  lowerer.noLowering("write with a union chunk and more arguments", call);
3331
- const receiver = lowerer.lowerExpr(access.expression);
5079
+ const receiver = streamReceiverExpr(lowerer, access.expression);
3332
5080
  const chunk = lowerer.lowerExpr(args[0]);
3333
5081
  const fn = chunk.type.kind === "union"
3334
5082
  ? "writable.writeU"
@@ -3340,36 +5088,24 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3340
5088
  return { kind: "libCall", fn, args: [receiver, chunk], type: BOOL, loc };
3341
5089
  }
3342
5090
  // Disambiguate (chunk, cb?) vs (chunk, encoding, cb?) by the second
3343
- // argument's static type.
5091
+ // argument's static type. A write with an encoding runs through
5092
+ // writeEnc, whose runtime checks and applies it as Node's _write does.
3344
5093
  let cbArg;
3345
- if (args.length >= 2 && isBufferEncoding(lowerer, args[1])) {
3346
- if (kind !== "bytes")
3347
- return nodeThrowExpr(1, "ERR_UNKNOWN_ENCODING", "Unknown encoding: buffer", BOOL, loc);
3348
- cbArg = args[2];
3349
- }
3350
- else if (args.length === 2) {
5094
+ if (args.length === 3)
5095
+ return writeEnc(args[1], args[2]);
5096
+ if (args.length === 2) {
3351
5097
  const t = lowerer.mapTypeOf(lowerer.typeOf(args[1]));
3352
- if (t?.kind === "string")
3353
- checkUtf8Encoding(lowerer, "write", args[1]);
3354
- else
3355
- cbArg = args[1];
3356
- }
3357
- else if (args.length === 3) {
3358
- checkUtf8Encoding(lowerer, "write", args[1]);
3359
- cbArg = args[2];
5098
+ if (t?.kind === "string" || t?.kind === "nullT" || t?.kind === "undefinedT")
5099
+ return writeEnc(args[1], undefined);
5100
+ cbArg = args[1];
3360
5101
  }
3361
- const receiver = lowerer.lowerExpr(access.expression);
5102
+ const receiver = streamReceiverExpr(lowerer, access.expression);
3362
5103
  const chunk = kind === "bytes"
3363
5104
  ? lowerer.lowerExprExpecting(args[0], BYTES)
3364
5105
  : lowerer.lowerExprExpecting(args[0], STRING);
3365
5106
  const fn = kind === "bytes" ? "writable.write" : "writable.writeStr";
3366
5107
  if (cbArg !== undefined) {
3367
- const cb = callbackDeclaresParameters(cbArg)
3368
- ? null
3369
- : lowerer.lowerExprExpecting(cbArg, funcOf([], VOID));
3370
- if (cb === null || cb.type.kind !== "func" || cb.type.params.length > 0) {
3371
- lowerer.noLowering("write completion callbacks taking the error argument", cbArg, "() => void callbacks are supported (listen for 'error' to observe failures)");
3372
- }
5108
+ const cb = lowerWriteCb(cbArg);
3373
5109
  return { kind: "libCall", fn, args: [receiver, chunk, cb], type: BOOL, loc };
3374
5110
  }
3375
5111
  return { kind: "libCall", fn, args: [receiver, chunk], type: BOOL, loc };
@@ -3381,6 +5117,7 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3381
5117
  // Forms: (), (cb), (chunk), (chunk, cb), (chunk, encoding, cb).
3382
5118
  let chunkNode;
3383
5119
  let cbArg;
5120
+ let encNode;
3384
5121
  if (args.length === 1) {
3385
5122
  const t = lowerer.mapTypeOf(lowerer.typeOf(args[0]));
3386
5123
  if (t?.kind === "func")
@@ -3388,35 +5125,26 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3388
5125
  else
3389
5126
  chunkNode = args[0];
3390
5127
  }
3391
- else if (args.length >= 2 && isBufferEncoding(lowerer, args[1])) {
3392
- chunkNode = args[0];
3393
- const endKind = chunkKind(args[0]);
3394
- if (endKind === "string") {
3395
- const endT = lowerer.mapTypeOf(lowerer.typeOf(call)) ?? DYN;
3396
- return nodeThrowExpr(1, "ERR_UNKNOWN_ENCODING", "Unknown encoding: buffer", endT, loc);
3397
- }
3398
- if (endKind !== "bytes")
3399
- checkUtf8Encoding(lowerer, "end", args[1]);
3400
- cbArg = args[2];
3401
- }
3402
5128
  else if (args.length === 2) {
3403
5129
  chunkNode = args[0];
3404
5130
  const t = lowerer.mapTypeOf(lowerer.typeOf(args[1]));
3405
- if (t?.kind === "string")
3406
- checkUtf8Encoding(lowerer, "end", args[1]);
5131
+ if (t?.kind === "string" || t?.kind === "nullT" || t?.kind === "undefinedT")
5132
+ encNode = args[1];
3407
5133
  else
3408
5134
  cbArg = args[1];
3409
5135
  }
3410
5136
  else if (args.length === 3) {
3411
5137
  chunkNode = args[0];
3412
- checkUtf8Encoding(lowerer, "end", args[1]);
5138
+ encNode = args[1];
3413
5139
  cbArg = args[2];
3414
5140
  }
3415
- const receiver = lowerer.lowerExpr(access.expression);
5141
+ const receiver = streamReceiverExpr(lowerer, access.expression);
3416
5142
  let flags = 0;
3417
5143
  const tail = [];
3418
5144
  if (chunkNode !== undefined) {
3419
- const kind = chunkKind(chunkNode);
5145
+ // end(chunk, encoding[, cb]) writes the chunk with the encoding
5146
+ // argument as passed (flags 16), through the dyn write
5147
+ const kind = encNode !== undefined ? "dyn" : chunkKind(chunkNode);
3420
5148
  if (kind === "null" || kind === "union")
3421
5149
  lowerer.noLowering("end(null)", call);
3422
5150
  flags |= kind === "bytes" ? 1 : kind === "dyn" ? 8 : 2;
@@ -3425,6 +5153,10 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3425
5153
  : kind === "dyn"
3426
5154
  ? lowerer.lowerExprExpecting(chunkNode, DYN)
3427
5155
  : lowerer.lowerExprExpecting(chunkNode, STRING));
5156
+ if (encNode !== undefined) {
5157
+ flags |= 16;
5158
+ tail.push(lowerer.lowerExprExpecting(encNode, DYN));
5159
+ }
3428
5160
  }
3429
5161
  if (cbArg !== undefined) {
3430
5162
  const cb = callbackDeclaresParameters(cbArg)
@@ -3448,7 +5180,7 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3448
5180
  requireSide(writableSide, member);
3449
5181
  if (args.length !== 0)
3450
5182
  lowerer.noLowering(`${member} with arguments`, call);
3451
- const receiver = lowerer.lowerExpr(access.expression);
5183
+ const receiver = streamReceiverExpr(lowerer, access.expression);
3452
5184
  return {
3453
5185
  kind: "libCall",
3454
5186
  fn: member === "cork" ? "writable.cork" : "writable.uncork",
@@ -3463,7 +5195,7 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3463
5195
  lowerer.noLowering(`setEncoding with ${args.length} arguments`, call, "one literal encoding is the supported form");
3464
5196
  }
3465
5197
  const enc = bufEncoding(lowerer, "setEncoding", args[0]);
3466
- const receiver = lowerer.lowerExpr(access.expression);
5198
+ const receiver = streamReceiverExpr(lowerer, access.expression);
3467
5199
  return {
3468
5200
  kind: "libCall",
3469
5201
  fn: "readable.setEncoding",
@@ -3473,14 +5205,20 @@ export function lowerStreamMethodCall(lowerer, call, access, info) {
3473
5205
  };
3474
5206
  }
3475
5207
  if (member === "setDefaultEncoding") {
3476
- // The write-side default: utf8 IS the default — admit it; other
3477
- // encodings would change what write(string) means.
5208
+ // The write-side default: lowercased and validated (ERR_UNKNOWN_ENCODING,
5209
+ // thrown) at run time; answers the stream.
3478
5210
  requireSide(writableSide, "setDefaultEncoding");
3479
- const t = args[0] ? lowerer.typeOf(args[0]) : null;
3480
- if (t?.isStringLiteralType() && (t.value === "utf8" || t.value === "utf-8")) {
3481
- return lowerer.lowerExpr(access.expression);
3482
- }
3483
- lowerer.noLowering("setDefaultEncoding", call, "utf8 (the default, as a compile-time literal) is the supported write-side string encoding");
5211
+ if (args.length > 1)
5212
+ lowerer.noLowering(`setDefaultEncoding with ${args.length} arguments`, call);
5213
+ const receiver = streamReceiverExpr(lowerer, access.expression);
5214
+ const enc = args[0] ? lowerer.lowerExprExpecting(args[0], DYN) : dynUndefinedExpr(loc);
5215
+ return {
5216
+ kind: "libCall",
5217
+ fn: "writable.setDefaultEncoding",
5218
+ args: [receiver, enc],
5219
+ type: receiver.type,
5220
+ loc,
5221
+ };
3484
5222
  }
3485
5223
  return null;
3486
5224
  }
@@ -3613,7 +5351,7 @@ export function lowerStreamProperty(lowerer, expr, info) {
3613
5351
  const propCall = (type) => ({
3614
5352
  kind: "libCall",
3615
5353
  fn: "stream.prop",
3616
- args: [lowerer.lowerExpr(expr.expression), strLit(name, loc)],
5354
+ args: [streamReceiverExpr(lowerer, expr.expression), strLit(name, loc)],
3617
5355
  type,
3618
5356
  loc,
3619
5357
  });
@@ -3631,7 +5369,7 @@ export function lowerStreamProperty(lowerer, expr, info) {
3631
5369
  const read = {
3632
5370
  kind: "libCall",
3633
5371
  fn: "readable.flowing",
3634
- args: [lowerer.lowerExpr(expr.expression)],
5372
+ args: [streamReceiverExpr(lowerer, expr.expression)],
3635
5373
  type,
3636
5374
  loc,
3637
5375
  };
@@ -3645,7 +5383,7 @@ export function lowerStreamProperty(lowerer, expr, info) {
3645
5383
  const read = {
3646
5384
  kind: "libCall",
3647
5385
  fn: "stream.errored",
3648
- args: [lowerer.lowerExpr(expr.expression)],
5386
+ args: [streamReceiverExpr(lowerer, expr.expression)],
3649
5387
  type,
3650
5388
  loc,
3651
5389
  };
@@ -3656,8 +5394,7 @@ export function lowerStreamProperty(lowerer, expr, info) {
3656
5394
  return propCall(BOOL);
3657
5395
  }
3658
5396
  if (name === "writableObjectMode" && writableSide) {
3659
- // objectMode construction fences, so the answer is compile-time false.
3660
- return boolLit(false, loc);
5397
+ return propCall(BOOL);
3661
5398
  }
3662
5399
  if (name === "allowHalfOpen" && sides === "rw") {
3663
5400
  return propCall(BOOL);