@hyperfrontend/builder 0.1.0

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 (561) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/FUNDING.md +141 -0
  3. package/LICENSE.md +21 -0
  4. package/README.md +162 -0
  5. package/SECURITY.md +82 -0
  6. package/THIRD_PARTY_LICENSES.md +13 -0
  7. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/array/index.cjs.js +7 -0
  8. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/array/index.esm.js +5 -0
  9. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/console/index.cjs.js +13 -0
  10. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/console/index.esm.js +8 -0
  11. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/date/index.cjs.js +5 -0
  12. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/date/index.esm.js +4 -0
  13. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/encoding/index.cjs.js +1 -0
  14. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/encoding/index.esm.js +1 -0
  15. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/error/index.cjs.js +6 -0
  16. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/error/index.esm.js +5 -0
  17. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/function/index.cjs.js +1 -0
  18. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/function/index.esm.js +1 -0
  19. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/json/index.cjs.js +7 -0
  20. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/json/index.esm.js +5 -0
  21. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/map/index.cjs.js +6 -0
  22. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/map/index.esm.js +5 -0
  23. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/math/index.cjs.js +7 -0
  24. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/math/index.esm.js +5 -0
  25. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/messaging/index.cjs.js +1 -0
  26. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/messaging/index.esm.js +1 -0
  27. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/number/index.cjs.js +1 -0
  28. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/number/index.esm.js +1 -0
  29. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/object/index.cjs.js +13 -0
  30. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/object/index.esm.js +8 -0
  31. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/promise/index.cjs.js +6 -0
  32. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/promise/index.esm.js +5 -0
  33. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/reflect/index.cjs.js +1 -0
  34. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/reflect/index.esm.js +1 -0
  35. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/regexp/index.cjs.js +6 -0
  36. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/regexp/index.esm.js +5 -0
  37. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/index.cjs.js +6 -0
  38. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/index.esm.js +5 -0
  39. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/string/index.cjs.js +1 -0
  40. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/string/index.esm.js +1 -0
  41. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/symbol/index.cjs.js +1 -0
  42. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/symbol/index.esm.js +1 -0
  43. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/timers/index.cjs.js +13 -0
  44. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/timers/index.esm.js +10 -0
  45. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/typed-arrays/index.cjs.js +1 -0
  46. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/typed-arrays/index.esm.js +1 -0
  47. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/url/index.cjs.js +6 -0
  48. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/url/index.esm.js +5 -0
  49. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/weak-map/index.cjs.js +1 -0
  50. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/weak-map/index.esm.js +1 -0
  51. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/weak-set/index.cjs.js +1 -0
  52. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/weak-set/index.esm.js +1 -0
  53. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/websocket/index.cjs.js +1 -0
  54. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/websocket/index.esm.js +1 -0
  55. package/_dependencies/@hyperfrontend/immutable-api-utils/index.cjs.js +1 -0
  56. package/_dependencies/@hyperfrontend/immutable-api-utils/index.esm.js +1 -0
  57. package/_dependencies/@hyperfrontend/immutable-api-utils/locked/index.cjs.js +1 -0
  58. package/_dependencies/@hyperfrontend/immutable-api-utils/locked/index.esm.js +1 -0
  59. package/_dependencies/@hyperfrontend/immutable-api-utils/locked-prop-descriptors/index.cjs.js +1 -0
  60. package/_dependencies/@hyperfrontend/immutable-api-utils/locked-prop-descriptors/index.esm.js +1 -0
  61. package/_dependencies/@hyperfrontend/immutable-api-utils/locked-props/index.cjs.js +1 -0
  62. package/_dependencies/@hyperfrontend/immutable-api-utils/locked-props/index.esm.js +1 -0
  63. package/_dependencies/@hyperfrontend/logging/index.cjs.js +191 -0
  64. package/_dependencies/@hyperfrontend/logging/index.esm.js +186 -0
  65. package/_dependencies/@hyperfrontend/project-scope/cli/index.cjs.js +196 -0
  66. package/_dependencies/@hyperfrontend/project-scope/cli/index.esm.js +196 -0
  67. package/_dependencies/@hyperfrontend/project-scope/core/encoding/index.cjs.js +82 -0
  68. package/_dependencies/@hyperfrontend/project-scope/core/encoding/index.esm.js +82 -0
  69. package/_dependencies/@hyperfrontend/project-scope/core/fs/index.cjs.js +154 -0
  70. package/_dependencies/@hyperfrontend/project-scope/core/fs/index.esm.js +149 -0
  71. package/_dependencies/@hyperfrontend/project-scope/core/index.cjs.js +459 -0
  72. package/_dependencies/@hyperfrontend/project-scope/core/index.esm.js +440 -0
  73. package/_dependencies/@hyperfrontend/project-scope/core/logger/index.cjs.js +84 -0
  74. package/_dependencies/@hyperfrontend/project-scope/core/logger/index.esm.js +80 -0
  75. package/_dependencies/@hyperfrontend/project-scope/core/path/index.cjs.js +26 -0
  76. package/_dependencies/@hyperfrontend/project-scope/core/path/index.esm.js +22 -0
  77. package/_dependencies/@hyperfrontend/project-scope/core/platform/index.cjs.js +1 -0
  78. package/_dependencies/@hyperfrontend/project-scope/core/platform/index.esm.js +1 -0
  79. package/_dependencies/@hyperfrontend/project-scope/heuristics/dependencies/index.cjs.js +90 -0
  80. package/_dependencies/@hyperfrontend/project-scope/heuristics/dependencies/index.esm.js +90 -0
  81. package/_dependencies/@hyperfrontend/project-scope/heuristics/entry-points/index.cjs.js +174 -0
  82. package/_dependencies/@hyperfrontend/project-scope/heuristics/entry-points/index.esm.js +174 -0
  83. package/_dependencies/@hyperfrontend/project-scope/heuristics/framework/index.cjs.js +174 -0
  84. package/_dependencies/@hyperfrontend/project-scope/heuristics/framework/index.esm.js +172 -0
  85. package/_dependencies/@hyperfrontend/project-scope/heuristics/index.cjs.js +184 -0
  86. package/_dependencies/@hyperfrontend/project-scope/heuristics/index.esm.js +184 -0
  87. package/_dependencies/@hyperfrontend/project-scope/heuristics/project-type/index.cjs.js +172 -0
  88. package/_dependencies/@hyperfrontend/project-scope/heuristics/project-type/index.esm.js +172 -0
  89. package/_dependencies/@hyperfrontend/project-scope/index.cjs.js +222 -0
  90. package/_dependencies/@hyperfrontend/project-scope/index.esm.js +219 -0
  91. package/_dependencies/@hyperfrontend/project-scope/models/index.cjs.js +2 -0
  92. package/_dependencies/@hyperfrontend/project-scope/models/index.esm.js +1 -0
  93. package/_dependencies/@hyperfrontend/project-scope/nx/index.cjs.js +94 -0
  94. package/_dependencies/@hyperfrontend/project-scope/nx/index.esm.js +94 -0
  95. package/_dependencies/@hyperfrontend/project-scope/project/config/index.cjs.js +172 -0
  96. package/_dependencies/@hyperfrontend/project-scope/project/config/index.esm.js +172 -0
  97. package/_dependencies/@hyperfrontend/project-scope/project/index.cjs.js +176 -0
  98. package/_dependencies/@hyperfrontend/project-scope/project/index.esm.js +176 -0
  99. package/_dependencies/@hyperfrontend/project-scope/project/package/index.cjs.js +88 -0
  100. package/_dependencies/@hyperfrontend/project-scope/project/package/index.esm.js +88 -0
  101. package/_dependencies/@hyperfrontend/project-scope/project/root/index.cjs.js +154 -0
  102. package/_dependencies/@hyperfrontend/project-scope/project/root/index.esm.js +153 -0
  103. package/_dependencies/@hyperfrontend/project-scope/project/traversal/index.cjs.js +91 -0
  104. package/_dependencies/@hyperfrontend/project-scope/project/traversal/index.esm.js +89 -0
  105. package/_dependencies/@hyperfrontend/project-scope/tech/backend/index.cjs.js +88 -0
  106. package/_dependencies/@hyperfrontend/project-scope/tech/backend/index.esm.js +88 -0
  107. package/_dependencies/@hyperfrontend/project-scope/tech/build/index.cjs.js +88 -0
  108. package/_dependencies/@hyperfrontend/project-scope/tech/build/index.esm.js +88 -0
  109. package/_dependencies/@hyperfrontend/project-scope/tech/frontend/index.cjs.js +88 -0
  110. package/_dependencies/@hyperfrontend/project-scope/tech/frontend/index.esm.js +88 -0
  111. package/_dependencies/@hyperfrontend/project-scope/tech/index.cjs.js +171 -0
  112. package/_dependencies/@hyperfrontend/project-scope/tech/index.esm.js +169 -0
  113. package/_dependencies/@hyperfrontend/project-scope/tech/legacy/index.cjs.js +88 -0
  114. package/_dependencies/@hyperfrontend/project-scope/tech/legacy/index.esm.js +88 -0
  115. package/_dependencies/@hyperfrontend/project-scope/tech/linting/index.cjs.js +88 -0
  116. package/_dependencies/@hyperfrontend/project-scope/tech/linting/index.esm.js +88 -0
  117. package/_dependencies/@hyperfrontend/project-scope/tech/monorepo/index.cjs.js +88 -0
  118. package/_dependencies/@hyperfrontend/project-scope/tech/monorepo/index.esm.js +88 -0
  119. package/_dependencies/@hyperfrontend/project-scope/tech/testing/index.cjs.js +88 -0
  120. package/_dependencies/@hyperfrontend/project-scope/tech/testing/index.esm.js +88 -0
  121. package/_dependencies/@hyperfrontend/project-scope/tech/types/index.cjs.js +88 -0
  122. package/_dependencies/@hyperfrontend/project-scope/tech/types/index.esm.js +88 -0
  123. package/_dependencies/@hyperfrontend/project-scope/vfs/index.cjs.js +102 -0
  124. package/_dependencies/@hyperfrontend/project-scope/vfs/index.esm.js +102 -0
  125. package/_dependencies/@hyperfrontend/versioning/changelog/compare/index.cjs.js +1 -0
  126. package/_dependencies/@hyperfrontend/versioning/changelog/compare/index.esm.js +1 -0
  127. package/_dependencies/@hyperfrontend/versioning/changelog/index.cjs.js +1 -0
  128. package/_dependencies/@hyperfrontend/versioning/changelog/index.esm.js +1 -0
  129. package/_dependencies/@hyperfrontend/versioning/changelog/models/index.cjs.js +1 -0
  130. package/_dependencies/@hyperfrontend/versioning/changelog/models/index.esm.js +1 -0
  131. package/_dependencies/@hyperfrontend/versioning/changelog/operations/index.cjs.js +1 -0
  132. package/_dependencies/@hyperfrontend/versioning/changelog/operations/index.esm.js +1 -0
  133. package/_dependencies/@hyperfrontend/versioning/changelog/parse/index.cjs.js +1 -0
  134. package/_dependencies/@hyperfrontend/versioning/changelog/parse/index.esm.js +1 -0
  135. package/_dependencies/@hyperfrontend/versioning/changelog/serialize/index.cjs.js +1 -0
  136. package/_dependencies/@hyperfrontend/versioning/changelog/serialize/index.esm.js +1 -0
  137. package/_dependencies/@hyperfrontend/versioning/commits/author/index.cjs.js +2403 -0
  138. package/_dependencies/@hyperfrontend/versioning/commits/author/index.esm.js +2381 -0
  139. package/_dependencies/@hyperfrontend/versioning/commits/classify/index.cjs.js +38 -0
  140. package/_dependencies/@hyperfrontend/versioning/commits/classify/index.esm.js +30 -0
  141. package/_dependencies/@hyperfrontend/versioning/commits/format/index.cjs.js +1 -0
  142. package/_dependencies/@hyperfrontend/versioning/commits/format/index.esm.js +1 -0
  143. package/_dependencies/@hyperfrontend/versioning/commits/index.cjs.js +2457 -0
  144. package/_dependencies/@hyperfrontend/versioning/commits/index.esm.js +2407 -0
  145. package/_dependencies/@hyperfrontend/versioning/commits/models/index.cjs.js +1 -0
  146. package/_dependencies/@hyperfrontend/versioning/commits/models/index.esm.js +1 -0
  147. package/_dependencies/@hyperfrontend/versioning/commits/parse/index.cjs.js +1 -0
  148. package/_dependencies/@hyperfrontend/versioning/commits/parse/index.esm.js +1 -0
  149. package/_dependencies/@hyperfrontend/versioning/commits/validate/index.cjs.js +27 -0
  150. package/_dependencies/@hyperfrontend/versioning/commits/validate/index.esm.js +25 -0
  151. package/_dependencies/@hyperfrontend/versioning/flow/executor/index.cjs.js +36 -0
  152. package/_dependencies/@hyperfrontend/versioning/flow/executor/index.esm.js +36 -0
  153. package/_dependencies/@hyperfrontend/versioning/flow/index.cjs.js +51 -0
  154. package/_dependencies/@hyperfrontend/versioning/flow/index.esm.js +51 -0
  155. package/_dependencies/@hyperfrontend/versioning/flow/models/index.cjs.js +30 -0
  156. package/_dependencies/@hyperfrontend/versioning/flow/models/index.esm.js +28 -0
  157. package/_dependencies/@hyperfrontend/versioning/flow/presets/index.cjs.js +47 -0
  158. package/_dependencies/@hyperfrontend/versioning/flow/presets/index.esm.js +45 -0
  159. package/_dependencies/@hyperfrontend/versioning/flow/steps/index.cjs.js +47 -0
  160. package/_dependencies/@hyperfrontend/versioning/flow/steps/index.esm.js +45 -0
  161. package/_dependencies/@hyperfrontend/versioning/git/index.cjs.js +8 -0
  162. package/_dependencies/@hyperfrontend/versioning/git/index.esm.js +9 -0
  163. package/_dependencies/@hyperfrontend/versioning/git/models/index.cjs.js +1 -0
  164. package/_dependencies/@hyperfrontend/versioning/git/models/index.esm.js +1 -0
  165. package/_dependencies/@hyperfrontend/versioning/git/operations/index.cjs.js +3 -0
  166. package/_dependencies/@hyperfrontend/versioning/git/operations/index.esm.js +3 -0
  167. package/_dependencies/@hyperfrontend/versioning/index.cjs.js +2481 -0
  168. package/_dependencies/@hyperfrontend/versioning/index.esm.js +2423 -0
  169. package/_dependencies/@hyperfrontend/versioning/registry/index.cjs.js +1 -0
  170. package/_dependencies/@hyperfrontend/versioning/registry/index.esm.js +1 -0
  171. package/_dependencies/@hyperfrontend/versioning/registry/models/index.cjs.js +1 -0
  172. package/_dependencies/@hyperfrontend/versioning/registry/models/index.esm.js +1 -0
  173. package/_dependencies/@hyperfrontend/versioning/registry/npm/index.cjs.js +1 -0
  174. package/_dependencies/@hyperfrontend/versioning/registry/npm/index.esm.js +1 -0
  175. package/_dependencies/@hyperfrontend/versioning/repository/index.cjs.js +18 -0
  176. package/_dependencies/@hyperfrontend/versioning/repository/index.esm.js +17 -0
  177. package/_dependencies/@hyperfrontend/versioning/repository/models/index.cjs.js +11 -0
  178. package/_dependencies/@hyperfrontend/versioning/repository/models/index.esm.js +10 -0
  179. package/_dependencies/@hyperfrontend/versioning/repository/parse/index.cjs.js +184 -0
  180. package/_dependencies/@hyperfrontend/versioning/repository/parse/index.esm.js +185 -0
  181. package/_dependencies/@hyperfrontend/versioning/repository/url/index.cjs.js +10 -0
  182. package/_dependencies/@hyperfrontend/versioning/repository/url/index.esm.js +8 -0
  183. package/_dependencies/@hyperfrontend/versioning/semver/compare/index.cjs.js +1 -0
  184. package/_dependencies/@hyperfrontend/versioning/semver/compare/index.esm.js +1 -0
  185. package/_dependencies/@hyperfrontend/versioning/semver/format/index.cjs.js +1 -0
  186. package/_dependencies/@hyperfrontend/versioning/semver/format/index.esm.js +1 -0
  187. package/_dependencies/@hyperfrontend/versioning/semver/increment/index.cjs.js +1 -0
  188. package/_dependencies/@hyperfrontend/versioning/semver/increment/index.esm.js +1 -0
  189. package/_dependencies/@hyperfrontend/versioning/semver/index.cjs.js +1 -0
  190. package/_dependencies/@hyperfrontend/versioning/semver/index.esm.js +1 -0
  191. package/_dependencies/@hyperfrontend/versioning/semver/models/index.cjs.js +1 -0
  192. package/_dependencies/@hyperfrontend/versioning/semver/models/index.esm.js +1 -0
  193. package/_dependencies/@hyperfrontend/versioning/semver/parse/index.cjs.js +1 -0
  194. package/_dependencies/@hyperfrontend/versioning/semver/parse/index.esm.js +1 -0
  195. package/_dependencies/@hyperfrontend/versioning/workspace/discovery/index.cjs.js +29 -0
  196. package/_dependencies/@hyperfrontend/versioning/workspace/discovery/index.esm.js +29 -0
  197. package/_dependencies/@hyperfrontend/versioning/workspace/index.cjs.js +29 -0
  198. package/_dependencies/@hyperfrontend/versioning/workspace/index.esm.js +29 -0
  199. package/_dependencies/@hyperfrontend/versioning/workspace/models/index.cjs.js +1 -0
  200. package/_dependencies/@hyperfrontend/versioning/workspace/models/index.esm.js +1 -0
  201. package/_dependencies/@hyperfrontend/versioning/workspace/operations/index.cjs.js +2 -0
  202. package/_dependencies/@hyperfrontend/versioning/workspace/operations/index.esm.js +2 -0
  203. package/_dependencies/@rollup/plugin-commonjs/index.cjs.js +6629 -0
  204. package/_dependencies/@rollup/plugin-commonjs/index.esm.js +6608 -0
  205. package/_dependencies/@rollup/plugin-json/index.cjs.js +2324 -0
  206. package/_dependencies/@rollup/plugin-json/index.esm.js +2322 -0
  207. package/_dependencies/@rollup/plugin-node-resolve/index.cjs.js +5430 -0
  208. package/_dependencies/@rollup/plugin-node-resolve/index.esm.js +5424 -0
  209. package/_dependencies/@rollup/plugin-terser/index.cjs.js +33220 -0
  210. package/_dependencies/@rollup/plugin-terser/index.esm.js +33217 -0
  211. package/_dependencies/@rollup/plugin-typescript/index.cjs.js +4840 -0
  212. package/_dependencies/@rollup/plugin-typescript/index.esm.js +4819 -0
  213. package/_dependencies/postject/index.cjs.js +5140 -0
  214. package/_dependencies/postject/index.esm.js +5131 -0
  215. package/_dependencies/rollup/index.cjs.js +24668 -0
  216. package/_dependencies/rollup/index.d.ts +1921 -0
  217. package/_dependencies/rollup/index.esm.js +24652 -0
  218. package/_dependencies/rollup-plugin-dts/index.cjs.js +6547 -0
  219. package/_dependencies/rollup-plugin-dts/index.esm.js +6537 -0
  220. package/_shared/bin/format/index.cjs.js +7 -0
  221. package/_shared/bin/format/index.esm.js +5 -0
  222. package/_shared/bin/native/codesign/index.cjs.js +30 -0
  223. package/_shared/bin/native/codesign/index.esm.js +26 -0
  224. package/_shared/bin/native/host-binary/index.cjs.js +13 -0
  225. package/_shared/bin/native/host-binary/index.esm.js +11 -0
  226. package/_shared/bin/native/inject/index.cjs.js +25 -0
  227. package/_shared/bin/native/inject/index.esm.js +18 -0
  228. package/_shared/bin/native/platform-check/index.cjs.js +13 -0
  229. package/_shared/bin/native/platform-check/index.esm.js +10 -0
  230. package/_shared/bin/native/sea-blob/index.cjs.js +21 -0
  231. package/_shared/bin/native/sea-blob/index.esm.js +19 -0
  232. package/_shared/bin/native/sea-config/index.cjs.js +9 -0
  233. package/_shared/bin/native/sea-config/index.esm.js +7 -0
  234. package/_shared/bin/script/bootstrap-footer/index.cjs.js +22 -0
  235. package/_shared/bin/script/bootstrap-footer/index.esm.js +19 -0
  236. package/_shared/bundle/declarations/flatten-paths/index.cjs.js +34 -0
  237. package/_shared/bundle/declarations/flatten-paths/index.esm.js +29 -0
  238. package/_shared/bundle/dependencies/collect-workspace-deps/index.cjs.js +24 -0
  239. package/_shared/bundle/dependencies/collect-workspace-deps/index.esm.js +21 -0
  240. package/_shared/bundle/dependencies/externalize-plugin/index.cjs.js +93 -0
  241. package/_shared/bundle/dependencies/externalize-plugin/index.esm.js +86 -0
  242. package/_shared/bundle/dependencies/prune/ast-utils/index.esm.js +31 -0
  243. package/_shared/bundle/dependencies/prune/namespace-usage/index.esm.js +208 -0
  244. package/_shared/bundle/dependencies/prune/specifiers/index.cjs.js +62 -0
  245. package/_shared/bundle/dependencies/prune/specifiers/index.esm.js +53 -0
  246. package/_shared/bundle/entries/discover-entries/index.cjs.js +87 -0
  247. package/_shared/bundle/entries/discover-entries/index.esm.js +80 -0
  248. package/_shared/bundle/entries/resolve-entries/index.cjs.js +38 -0
  249. package/_shared/bundle/entries/resolve-entries/index.esm.js +34 -0
  250. package/_shared/bundle/externals/validate-globals/index.cjs.js +14 -0
  251. package/_shared/bundle/externals/validate-globals/index.esm.js +12 -0
  252. package/_shared/bundle/fs/deps-root/index.cjs.js +7 -0
  253. package/_shared/bundle/fs/deps-root/index.esm.js +5 -0
  254. package/_shared/bundle/fs/empty-dirs/index.cjs.js +23 -0
  255. package/_shared/bundle/fs/empty-dirs/index.esm.js +21 -0
  256. package/_shared/bundle/fs/entry-dir/index.cjs.js +7 -0
  257. package/_shared/bundle/fs/entry-dir/index.esm.js +5 -0
  258. package/_shared/bundle/fs/posix-path/index.cjs.js +9 -0
  259. package/_shared/bundle/fs/posix-path/index.esm.js +4 -0
  260. package/_shared/bundle/fs/under-dir/index.cjs.js +5 -0
  261. package/_shared/bundle/fs/under-dir/index.esm.js +3 -0
  262. package/_shared/memory/recover/index.cjs.js +15 -0
  263. package/_shared/memory/recover/index.esm.js +14 -0
  264. package/_shared/package/finalize-files/index.cjs.js +16 -0
  265. package/_shared/package/finalize-files/index.esm.js +15 -0
  266. package/_shared/package/json/cdn-paths/index.cjs.js +13 -0
  267. package/_shared/package/json/cdn-paths/index.esm.js +11 -0
  268. package/_shared/package/json/filter-deps/index.cjs.js +37 -0
  269. package/_shared/package/json/filter-deps/index.esm.js +34 -0
  270. package/_shared/package/json/generate-exports/index.cjs.js +56 -0
  271. package/_shared/package/json/generate-exports/index.esm.js +52 -0
  272. package/_shared/package/json/inherit-fields/index.cjs.js +19 -0
  273. package/_shared/package/json/inherit-fields/index.esm.js +17 -0
  274. package/_shared/package/json/read-package-json/index.cjs.js +7 -0
  275. package/_shared/package/json/read-package-json/index.esm.js +6 -0
  276. package/_shared/package/json/reflect-files-allowlist/index.cjs.js +39 -0
  277. package/_shared/package/json/reflect-files-allowlist/index.esm.js +33 -0
  278. package/_shared/package/json/synthesize/index.cjs.js +72 -0
  279. package/_shared/package/json/synthesize/index.esm.js +68 -0
  280. package/_shared/package/json/write/index.cjs.js +9 -0
  281. package/_shared/package/json/write/index.esm.js +8 -0
  282. package/_shared/package/licenses/generate-content/index.cjs.js +17 -0
  283. package/_shared/package/licenses/generate-content/index.esm.js +17 -0
  284. package/_shared/package/licenses/license-url/index.esm.js +29 -0
  285. package/_shared/package/licenses/write/index.cjs.js +9 -0
  286. package/_shared/package/licenses/write/index.esm.js +8 -0
  287. package/_shared/presets/by-names/index.cjs.js +10 -0
  288. package/_shared/presets/by-names/index.esm.js +8 -0
  289. package/_shared/presets/by-prefix/index.cjs.js +7 -0
  290. package/_shared/presets/by-prefix/index.esm.js +5 -0
  291. package/bin/format.d.ts +18 -0
  292. package/bin/format.d.ts.map +1 -0
  293. package/bin/hf-build.d.ts +81 -0
  294. package/bin/hf-build.d.ts.map +1 -0
  295. package/bin/hf-build.js +208533 -0
  296. package/bin/hf-build.linux-x64 +0 -0
  297. package/bin/index.cjs.js +548 -0
  298. package/bin/index.d.ts +26 -0
  299. package/bin/index.d.ts.map +1 -0
  300. package/bin/index.esm.js +546 -0
  301. package/bin/native/build-native.d.ts +44 -0
  302. package/bin/native/build-native.d.ts.map +1 -0
  303. package/bin/native/codesign.d.ts +65 -0
  304. package/bin/native/codesign.d.ts.map +1 -0
  305. package/bin/native/dispatch.d.ts +75 -0
  306. package/bin/native/dispatch.d.ts.map +1 -0
  307. package/bin/native/host-binary.d.ts +36 -0
  308. package/bin/native/host-binary.d.ts.map +1 -0
  309. package/bin/native/index.cjs.js +264 -0
  310. package/bin/native/index.d.ts +407 -0
  311. package/bin/native/index.d.ts.map +1 -0
  312. package/bin/native/index.esm.js +249 -0
  313. package/bin/native/inject.d.ts +61 -0
  314. package/bin/native/inject.d.ts.map +1 -0
  315. package/bin/native/platform-check.d.ts +39 -0
  316. package/bin/native/platform-check.d.ts.map +1 -0
  317. package/bin/native/sea-blob.d.ts +40 -0
  318. package/bin/native/sea-blob.d.ts.map +1 -0
  319. package/bin/native/sea-config.d.ts +45 -0
  320. package/bin/native/sea-config.d.ts.map +1 -0
  321. package/bin/native/worker/index.cjs.js +88 -0
  322. package/bin/native/worker/index.d.ts +68 -0
  323. package/bin/native/worker/index.d.ts.map +1 -0
  324. package/bin/native/worker/index.esm.js +86 -0
  325. package/bin/native/worker/job-runner.d.ts +29 -0
  326. package/bin/native/worker/job-runner.d.ts.map +1 -0
  327. package/bin/native/worker/types.d.ts +38 -0
  328. package/bin/native/worker/types.d.ts.map +1 -0
  329. package/bin/run-bin-phase.d.ts +24 -0
  330. package/bin/run-bin-phase.d.ts.map +1 -0
  331. package/bin/script/bootstrap-footer.d.ts +41 -0
  332. package/bin/script/bootstrap-footer.d.ts.map +1 -0
  333. package/bin/script/build-bin.d.ts +36 -0
  334. package/bin/script/build-bin.d.ts.map +1 -0
  335. package/bin/script/index.cjs.js +265 -0
  336. package/bin/script/index.d.ts +79 -0
  337. package/bin/script/index.d.ts.map +1 -0
  338. package/bin/script/index.esm.js +262 -0
  339. package/build.d.ts +56 -0
  340. package/build.d.ts.map +1 -0
  341. package/bundle/declarations/dts-per-entry.d.ts +27 -0
  342. package/bundle/declarations/dts-per-entry.d.ts.map +1 -0
  343. package/bundle/declarations/dts-pre-pass.d.ts +18 -0
  344. package/bundle/declarations/dts-pre-pass.d.ts.map +1 -0
  345. package/bundle/declarations/flatten-paths.d.ts +28 -0
  346. package/bundle/declarations/flatten-paths.d.ts.map +1 -0
  347. package/bundle/declarations/generate-declarations.d.ts +33 -0
  348. package/bundle/declarations/generate-declarations.d.ts.map +1 -0
  349. package/bundle/declarations/index.cjs.js +868 -0
  350. package/bundle/declarations/index.d.ts +262 -0
  351. package/bundle/declarations/index.d.ts.map +1 -0
  352. package/bundle/declarations/index.esm.js +857 -0
  353. package/bundle/declarations/prune-orphan-dts.d.ts +33 -0
  354. package/bundle/declarations/prune-orphan-dts.d.ts.map +1 -0
  355. package/bundle/declarations/sibling-resolver.d.ts +125 -0
  356. package/bundle/declarations/sibling-resolver.d.ts.map +1 -0
  357. package/bundle/dedupe/attribute-modules.d.ts +178 -0
  358. package/bundle/dedupe/attribute-modules.d.ts.map +1 -0
  359. package/bundle/dedupe/extract-chunk.d.ts +103 -0
  360. package/bundle/dedupe/extract-chunk.d.ts.map +1 -0
  361. package/bundle/dedupe/hoist-shared.d.ts +37 -0
  362. package/bundle/dedupe/hoist-shared.d.ts.map +1 -0
  363. package/bundle/dedupe/index.cjs.js +818 -0
  364. package/bundle/dedupe/index.d.ts +400 -0
  365. package/bundle/dedupe/index.d.ts.map +1 -0
  366. package/bundle/dedupe/index.esm.js +766 -0
  367. package/bundle/dedupe/plan-hoists.d.ts +46 -0
  368. package/bundle/dedupe/plan-hoists.d.ts.map +1 -0
  369. package/bundle/dedupe/rewrite-entry.d.ts +39 -0
  370. package/bundle/dedupe/rewrite-entry.d.ts.map +1 -0
  371. package/bundle/dependencies/collect-workspace-deps.d.ts +34 -0
  372. package/bundle/dependencies/collect-workspace-deps.d.ts.map +1 -0
  373. package/bundle/dependencies/externalize-plugin.d.ts +100 -0
  374. package/bundle/dependencies/externalize-plugin.d.ts.map +1 -0
  375. package/bundle/dependencies/index.cjs.js +964 -0
  376. package/bundle/dependencies/index.d.ts +388 -0
  377. package/bundle/dependencies/index.d.ts.map +1 -0
  378. package/bundle/dependencies/index.esm.js +947 -0
  379. package/bundle/dependencies/pre-pass.d.ts +154 -0
  380. package/bundle/dependencies/pre-pass.d.ts.map +1 -0
  381. package/bundle/dependencies/prune/ast-utils.d.ts +121 -0
  382. package/bundle/dependencies/prune/ast-utils.d.ts.map +1 -0
  383. package/bundle/dependencies/prune/chunk-graph.d.ts +175 -0
  384. package/bundle/dependencies/prune/chunk-graph.d.ts.map +1 -0
  385. package/bundle/dependencies/prune/dead-export-pass.d.ts +32 -0
  386. package/bundle/dependencies/prune/dead-export-pass.d.ts.map +1 -0
  387. package/bundle/dependencies/prune/dead-exports.d.ts +36 -0
  388. package/bundle/dependencies/prune/dead-exports.d.ts.map +1 -0
  389. package/bundle/dependencies/prune/destructure-requires-pass.d.ts +31 -0
  390. package/bundle/dependencies/prune/destructure-requires-pass.d.ts.map +1 -0
  391. package/bundle/dependencies/prune/destructure-requires.d.ts +42 -0
  392. package/bundle/dependencies/prune/destructure-requires.d.ts.map +1 -0
  393. package/bundle/dependencies/prune/edits.d.ts +30 -0
  394. package/bundle/dependencies/prune/edits.d.ts.map +1 -0
  395. package/bundle/dependencies/prune/namespace-usage.d.ts +104 -0
  396. package/bundle/dependencies/prune/namespace-usage.d.ts.map +1 -0
  397. package/bundle/dependencies/prune/orphan-chunks.d.ts +69 -0
  398. package/bundle/dependencies/prune/orphan-chunks.d.ts.map +1 -0
  399. package/bundle/dependencies/prune/property-strip-pass.d.ts +38 -0
  400. package/bundle/dependencies/prune/property-strip-pass.d.ts.map +1 -0
  401. package/bundle/dependencies/prune/property-strip.d.ts +69 -0
  402. package/bundle/dependencies/prune/property-strip.d.ts.map +1 -0
  403. package/bundle/dependencies/prune/prune-dependencies.d.ts +52 -0
  404. package/bundle/dependencies/prune/prune-dependencies.d.ts.map +1 -0
  405. package/bundle/dependencies/prune/reachability.d.ts +36 -0
  406. package/bundle/dependencies/prune/reachability.d.ts.map +1 -0
  407. package/bundle/dependencies/prune/specifiers.d.ts +39 -0
  408. package/bundle/dependencies/prune/specifiers.d.ts.map +1 -0
  409. package/bundle/dependencies/prune/strip-comments.d.ts +47 -0
  410. package/bundle/dependencies/prune/strip-comments.d.ts.map +1 -0
  411. package/bundle/dependencies/prune/used-exports.d.ts +32 -0
  412. package/bundle/dependencies/prune/used-exports.d.ts.map +1 -0
  413. package/bundle/dependencies/resolve-bundled-deps.d.ts +37 -0
  414. package/bundle/dependencies/resolve-bundled-deps.d.ts.map +1 -0
  415. package/bundle/dependencies/resolve-dep-entry.d.ts +38 -0
  416. package/bundle/dependencies/resolve-dep-entry.d.ts.map +1 -0
  417. package/bundle/dependencies/resolve-workspace-bundled-deps.d.ts +96 -0
  418. package/bundle/dependencies/resolve-workspace-bundled-deps.d.ts.map +1 -0
  419. package/bundle/dependencies/worker/index.cjs.js +524 -0
  420. package/bundle/dependencies/worker/index.d.ts +102 -0
  421. package/bundle/dependencies/worker/index.d.ts.map +1 -0
  422. package/bundle/dependencies/worker/index.esm.js +515 -0
  423. package/bundle/dependencies/worker/job-runner.d.ts +115 -0
  424. package/bundle/dependencies/worker/job-runner.d.ts.map +1 -0
  425. package/bundle/entries/by-platform.d.ts +27 -0
  426. package/bundle/entries/by-platform.d.ts.map +1 -0
  427. package/bundle/entries/discover-entries.d.ts +24 -0
  428. package/bundle/entries/discover-entries.d.ts.map +1 -0
  429. package/bundle/entries/index.cjs.js +38 -0
  430. package/bundle/entries/index.d.ts +70 -0
  431. package/bundle/entries/index.d.ts.map +1 -0
  432. package/bundle/entries/index.esm.js +33 -0
  433. package/bundle/entries/resolve-entries.d.ts +19 -0
  434. package/bundle/entries/resolve-entries.d.ts.map +1 -0
  435. package/bundle/externals/index.cjs.js +54 -0
  436. package/bundle/externals/index.d.ts +74 -0
  437. package/bundle/externals/index.d.ts.map +1 -0
  438. package/bundle/externals/index.esm.js +51 -0
  439. package/bundle/externals/resolve-externals.d.ts +52 -0
  440. package/bundle/externals/resolve-externals.d.ts.map +1 -0
  441. package/bundle/externals/validate-globals.d.ts +19 -0
  442. package/bundle/externals/validate-globals.d.ts.map +1 -0
  443. package/bundle/fs/deps-root.d.ts +17 -0
  444. package/bundle/fs/deps-root.d.ts.map +1 -0
  445. package/bundle/fs/empty-dirs.d.ts +18 -0
  446. package/bundle/fs/empty-dirs.d.ts.map +1 -0
  447. package/bundle/fs/entry-dir.d.ts +21 -0
  448. package/bundle/fs/entry-dir.d.ts.map +1 -0
  449. package/bundle/fs/posix-path.d.ts +30 -0
  450. package/bundle/fs/posix-path.d.ts.map +1 -0
  451. package/bundle/fs/under-dir.d.ts +19 -0
  452. package/bundle/fs/under-dir.d.ts.map +1 -0
  453. package/bundle/index.cjs.js +4046 -0
  454. package/bundle/index.d.ts +25 -0
  455. package/bundle/index.d.ts.map +1 -0
  456. package/bundle/index.esm.js +3689 -0
  457. package/bundle/rollup/descriptor.d.ts +99 -0
  458. package/bundle/rollup/descriptor.d.ts.map +1 -0
  459. package/bundle/rollup/dispatch.d.ts +72 -0
  460. package/bundle/rollup/dispatch.d.ts.map +1 -0
  461. package/bundle/rollup/index.cjs.js +715 -0
  462. package/bundle/rollup/index.d.ts +174 -0
  463. package/bundle/rollup/index.d.ts.map +1 -0
  464. package/bundle/rollup/index.esm.js +698 -0
  465. package/bundle/rollup/worker/index.cjs.js +290 -0
  466. package/bundle/rollup/worker/index.d.ts +131 -0
  467. package/bundle/rollup/worker/index.d.ts.map +1 -0
  468. package/bundle/rollup/worker/index.esm.js +280 -0
  469. package/bundle/rollup/worker/job-runner.d.ts +18 -0
  470. package/bundle/rollup/worker/job-runner.d.ts.map +1 -0
  471. package/bundle/rollup/worker/types.d.ts +111 -0
  472. package/bundle/rollup/worker/types.d.ts.map +1 -0
  473. package/bundle/run-bundle-phase.d.ts +23 -0
  474. package/bundle/run-bundle-phase.d.ts.map +1 -0
  475. package/clean-output.d.ts +26 -0
  476. package/clean-output.d.ts.map +1 -0
  477. package/index.cjs.js +5317 -0
  478. package/index.d.ts +64 -0
  479. package/index.d.ts.map +1 -0
  480. package/index.esm.js +4910 -0
  481. package/memory/index.cjs.js +101 -0
  482. package/memory/index.d.ts +81 -0
  483. package/memory/index.d.ts.map +1 -0
  484. package/memory/index.esm.js +98 -0
  485. package/memory/monitor.d.ts +59 -0
  486. package/memory/monitor.d.ts.map +1 -0
  487. package/memory/recover.d.ts +19 -0
  488. package/memory/recover.d.ts.map +1 -0
  489. package/models/build-config.d.ts +266 -0
  490. package/models/build-config.d.ts.map +1 -0
  491. package/models/build-context.d.ts +68 -0
  492. package/models/build-context.d.ts.map +1 -0
  493. package/models/build-result.d.ts +43 -0
  494. package/models/build-result.d.ts.map +1 -0
  495. package/models/entry-point.d.ts +45 -0
  496. package/models/entry-point.d.ts.map +1 -0
  497. package/models/format-output.d.ts +34 -0
  498. package/models/format-output.d.ts.map +1 -0
  499. package/models/index.cjs.js +2 -0
  500. package/models/index.d.ts +581 -0
  501. package/models/index.d.ts.map +1 -0
  502. package/models/index.esm.js +1 -0
  503. package/models/package-json.d.ts +130 -0
  504. package/models/package-json.d.ts.map +1 -0
  505. package/package/assets/copy-assets.d.ts +31 -0
  506. package/package/assets/copy-assets.d.ts.map +1 -0
  507. package/package/assets/index.cjs.js +84 -0
  508. package/package/assets/index.d.ts +33 -0
  509. package/package/assets/index.d.ts.map +1 -0
  510. package/package/assets/index.esm.js +82 -0
  511. package/package/finalize-files.d.ts +25 -0
  512. package/package/finalize-files.d.ts.map +1 -0
  513. package/package/index.cjs.js +276 -0
  514. package/package/index.d.ts +56 -0
  515. package/package/index.d.ts.map +1 -0
  516. package/package/index.esm.js +231 -0
  517. package/package/json/cdn-paths.d.ts +41 -0
  518. package/package/json/cdn-paths.d.ts.map +1 -0
  519. package/package/json/filter-deps.d.ts +39 -0
  520. package/package/json/filter-deps.d.ts.map +1 -0
  521. package/package/json/generate-exports.d.ts +29 -0
  522. package/package/json/generate-exports.d.ts.map +1 -0
  523. package/package/json/index.cjs.js +24 -0
  524. package/package/json/index.d.ts +252 -0
  525. package/package/json/index.d.ts.map +1 -0
  526. package/package/json/index.esm.js +14 -0
  527. package/package/json/inherit-fields.d.ts +25 -0
  528. package/package/json/inherit-fields.d.ts.map +1 -0
  529. package/package/json/read-package-json.d.ts +18 -0
  530. package/package/json/read-package-json.d.ts.map +1 -0
  531. package/package/json/reflect-files-allowlist.d.ts +32 -0
  532. package/package/json/reflect-files-allowlist.d.ts.map +1 -0
  533. package/package/json/synthesize.d.ts +53 -0
  534. package/package/json/synthesize.d.ts.map +1 -0
  535. package/package/json/write.d.ts +18 -0
  536. package/package/json/write.d.ts.map +1 -0
  537. package/package/licenses/collect.d.ts +25 -0
  538. package/package/licenses/collect.d.ts.map +1 -0
  539. package/package/licenses/generate-content.d.ts +20 -0
  540. package/package/licenses/generate-content.d.ts.map +1 -0
  541. package/package/licenses/index.cjs.js +135 -0
  542. package/package/licenses/index.d.ts +73 -0
  543. package/package/licenses/index.d.ts.map +1 -0
  544. package/package/licenses/index.esm.js +89 -0
  545. package/package/licenses/license-url.d.ts +20 -0
  546. package/package/licenses/license-url.d.ts.map +1 -0
  547. package/package/licenses/types.d.ts +12 -0
  548. package/package/licenses/types.d.ts.map +1 -0
  549. package/package/licenses/write.d.ts +16 -0
  550. package/package/licenses/write.d.ts.map +1 -0
  551. package/package/run-package-phase.d.ts +30 -0
  552. package/package/run-package-phase.d.ts.map +1 -0
  553. package/package.json +347 -0
  554. package/presets/by-names.d.ts +20 -0
  555. package/presets/by-names.d.ts.map +1 -0
  556. package/presets/by-prefix.d.ts +22 -0
  557. package/presets/by-prefix.d.ts.map +1 -0
  558. package/presets/index.cjs.js +8 -0
  559. package/presets/index.d.ts +43 -0
  560. package/presets/index.d.ts.map +1 -0
  561. package/presets/index.esm.js +5 -0
@@ -0,0 +1,3689 @@
1
+ import { from, isArray } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/array/index.esm.js';
2
+ import { createError } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/error/index.esm.js';
3
+ import { createSet } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/index.esm.js';
4
+ import { logger } from '../_dependencies/@hyperfrontend/logging/index.esm.js';
5
+ import { join as join$2, exists, relativePath, removeDirectory, readFileContent, getDirname, readDirectory, ensureDir, writeFileContent, isDirectory, matchGlobPattern } from '../_dependencies/@hyperfrontend/project-scope/core/index.esm.js';
6
+ import { createPromise } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/promise/index.esm.js';
7
+ import { setTimeout, clearInterval, setInterval } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/timers/index.esm.js';
8
+ import { createRequire } from 'node:module';
9
+ import { join as join$1, dirname, isAbsolute, resolve } from 'node:path';
10
+ import { spawn } from 'node:child_process';
11
+ import { rmSync, existsSync, mkdtempSync, readFileSync, cpSync, statSync, unlinkSync, rmdirSync } from 'node:fs';
12
+ import { tmpdir } from 'node:os';
13
+ import { stringify, parse } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/json/index.esm.js';
14
+ import { readJsonFileIfExists, exists as exists$1, readJsonFile } from '../_dependencies/@hyperfrontend/project-scope/core/fs/index.esm.js';
15
+ import { join as join$3, normalizeToForwardSlashes as normalizeToForwardSlashes$1 } from '../_dependencies/@hyperfrontend/project-scope/core/path/index.esm.js';
16
+ import { dateNow } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/date/index.esm.js';
17
+ import ts from 'typescript';
18
+ import { createMap } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/map/index.esm.js';
19
+ import { min } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/math/index.esm.js';
20
+ import { keys } from '../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/object/index.esm.js';
21
+ import { recover } from '../_shared/memory/recover/index.esm.js';
22
+ import { normalizeToForwardSlashes, join } from '../_shared/bundle/fs/posix-path/index.esm.js';
23
+ import { buildWorkspaceRoutes } from '../_shared/bundle/dependencies/externalize-plugin/index.esm.js';
24
+ import { validateExternalsConfig } from '../_shared/bundle/externals/validate-globals/index.esm.js';
25
+ import { depsRootOf } from '../_shared/bundle/fs/deps-root/index.esm.js';
26
+ import { collectWorkspacePrefixDeps, collectWorkspaceExactSpecifiers } from '../_shared/bundle/dependencies/collect-workspace-deps/index.esm.js';
27
+ import { flattenDeclarationPaths } from '../_shared/bundle/declarations/flatten-paths/index.esm.js';
28
+ import { collectChunkSpecifiers, hasDynamicSpecifier } from '../_shared/bundle/dependencies/prune/specifiers/index.esm.js';
29
+ import { entryDirOf } from '../_shared/bundle/fs/entry-dir/index.esm.js';
30
+ import { isUnderDir } from '../_shared/bundle/fs/under-dir/index.esm.js';
31
+ import { parseChunk, resolveRelativeTarget, getRequireSpecifier, classifyRequireBinding } from '../_shared/bundle/dependencies/prune/ast-utils/index.esm.js';
32
+ import { removeEmptyDirs } from '../_shared/bundle/fs/empty-dirs/index.esm.js';
33
+ import { mergeDemand, classifyNamespaceUse, collectNamespaceUsage } from '../_shared/bundle/dependencies/prune/namespace-usage/index.esm.js';
34
+ import { resolveEntries } from '../_shared/bundle/entries/resolve-entries/index.esm.js';
35
+
36
+ const log$b = logger.channel('builder:bundle:dependencies:pre-pass');
37
+ const REPORT_DIR_PREFIX$1 = 'hf-builder-prepass-';
38
+ const createReportDir$1 = () => mkdtempSync(join$2(tmpdir(), REPORT_DIR_PREFIX$1));
39
+ const reportPathFor$1 = (reportDir, job, index) => join$2(reportDir, `${index}-${job.dep.replace(/\//g, '__')}-${job.kind}-${job.format}.json`);
40
+ const runOne$1 = (job, reportPath, options) => createPromise((resolve, reject) => {
41
+ const execPath = options.execPath ?? process.execPath;
42
+ const argv = [...(options.execArgv ?? []), options.workerPath, stringify({ ...job, reportPath })];
43
+ const child = spawn(execPath, argv, { stdio: ['ignore', 'pipe', 'pipe'] });
44
+ let capturedStderr = '';
45
+ child.stdout?.on('data', (chunk) => {
46
+ process.stdout.write(chunk);
47
+ });
48
+ child.stderr?.on('data', (chunk) => {
49
+ const text = typeof chunk === 'string' ? chunk : chunk.toString();
50
+ capturedStderr += text;
51
+ process.stderr.write(text);
52
+ });
53
+ child.on('error', (error) => {
54
+ reject(createError(`pre-pass worker for ${job.dep} (${job.kind}/${job.format}) failed to spawn: ${error.message}`));
55
+ });
56
+ child.on('exit', (code) => {
57
+ if (code !== 0) {
58
+ const tail = capturedStderr.trim().split('\n').slice(-10).join('\n');
59
+ reject(createError(`pre-pass worker for ${job.dep} (${job.kind}/${job.format}) exited with code ${code}\n${tail}`));
60
+ return;
61
+ }
62
+ resolve();
63
+ });
64
+ });
65
+ const readReport$1 = (reportPath, job) => {
66
+ if (!existsSync(reportPath)) {
67
+ throw createError(`pre-pass worker for ${job.dep} (${job.kind}/${job.format}) did not write a report at ${reportPath}`);
68
+ }
69
+ const data = parse(readFileSync(reportPath, 'utf8'));
70
+ return { job, outputSize: data.outputSize, endHeapMB: data.endHeapMB, endRssMB: data.endRssMB, durationMs: data.durationMs };
71
+ };
72
+ const SWC_NODE_REGISTER$1 = '@swc-node/register';
73
+ const swcNodeAvailable$1 = (workspaceRoot) => existsSync(join$2(workspaceRoot, 'node_modules', '@swc-node', 'register', 'index.js'));
74
+ /**
75
+ * Default worker-path resolution: prefers the built-and-published artifact, falls
76
+ * back to the workspace dist path, and finally to the in-source TypeScript file
77
+ * via `@swc-node/register` (bootstrap case where builder is building itself for
78
+ * the first time and the dist worker doesn't exist yet).
79
+ *
80
+ * Looks at, in order:
81
+ * 1. `<workspaceRoot>/dist/libs/builder/bundle/dependencies/worker/index.cjs.js`
82
+ * 2. `<workspaceRoot>/node_modules/@hyperfrontend/builder/bundle/dependencies/worker/index.cjs.js`
83
+ * 3. `<workspaceRoot>/libs/builder/src/bundle/dependencies/worker/index.ts` (with `--require \@swc-node/register`)
84
+ *
85
+ * @param workspaceRoot - Absolute workspace root.
86
+ * @returns Worker invocation descriptor, or `undefined` if no candidate exists.
87
+ *
88
+ * @example Locating the worker for an in-workspace consumer
89
+ * ```typescript
90
+ * const invocation = resolveDefaultWorkerPath('/abs/repo')
91
+ * if (!invocation) throw new Error('builder worker artifact not found')
92
+ * ```
93
+ */
94
+ const resolveDefaultWorkerPath = (workspaceRoot) => {
95
+ const distCandidates = [
96
+ join$2(workspaceRoot, 'dist', 'libs', 'builder', 'bundle', 'dependencies', 'worker', 'index.cjs.js'),
97
+ join$2(workspaceRoot, 'node_modules', '@hyperfrontend', 'builder', 'bundle', 'dependencies', 'worker', 'index.cjs.js'),
98
+ ];
99
+ for (const path of distCandidates) {
100
+ if (existsSync(path))
101
+ return { path, execArgv: [] };
102
+ }
103
+ const sourcePath = join$2(workspaceRoot, 'libs', 'builder', 'src', 'bundle', 'dependencies', 'worker', 'index.ts');
104
+ if (existsSync(sourcePath) && swcNodeAvailable$1(workspaceRoot)) {
105
+ return { path: sourcePath, execArgv: ['--require', SWC_NODE_REGISTER$1] };
106
+ }
107
+ return undefined;
108
+ };
109
+ /**
110
+ * Sequentially runs the supplied pre-pass jobs by forking a fresh Node child
111
+ * per invocation. Strict sequential execution is mandatory — concurrent
112
+ * children would simultaneously pressure RAM and OOM the container.
113
+ *
114
+ * Each child writes a JSON report to a parent-supplied path; this function
115
+ * reads the report after the child exits and accumulates per-job statistics.
116
+ * If any worker exits non-zero or fails to produce a report, the function
117
+ * throws with the failed job's context.
118
+ *
119
+ * The report directory is created in the OS temp dir and removed before
120
+ * returning, regardless of success or failure.
121
+ *
122
+ * @param jobs - Pre-pass jobs to run.
123
+ * @param options - Worker path + optional memory monitor.
124
+ * @returns One result per supplied job, in the order the jobs were given.
125
+ *
126
+ * @example Pre-passing rollup and one of its plugins
127
+ * ```typescript
128
+ * const results = await runPrePass(jobs, { workerPath: '/abs/dist/libs/builder/bundle/dependencies/worker.cjs.js' })
129
+ * ```
130
+ */
131
+ const runPrePass = async (jobs, options) => {
132
+ if (jobs.length === 0)
133
+ return [];
134
+ const reportDir = createReportDir$1();
135
+ const results = [];
136
+ try {
137
+ for (const [index, job] of jobs.entries()) {
138
+ const reportPath = reportPathFor$1(reportDir, job, index);
139
+ log$b.info(`pre-pass ${index + 1}/${jobs.length}: ${job.dep} (${job.kind}/${job.format})`);
140
+ options.monitor?.check(`bundle:dependencies:prepass:${index + 1}/${jobs.length}:${job.dep}:${job.kind}:${job.format}:start`);
141
+ await runOne$1(job, reportPath, options);
142
+ const result = readReport$1(reportPath, job);
143
+ log$b.debug(`pre-pass ${index + 1}/${jobs.length} done: ${job.dep} size=${result.outputSize}B heap=${result.endHeapMB.toFixed(1)}MB rss=${result.endRssMB.toFixed(1)}MB t=${result.durationMs}ms`);
144
+ options.monitor?.check(`bundle:dependencies:prepass:${index + 1}/${jobs.length}:${job.dep}:${job.kind}:${job.format}:end`);
145
+ results.push(result);
146
+ }
147
+ return results;
148
+ }
149
+ finally {
150
+ rmSync(reportDir, { recursive: true, force: true });
151
+ }
152
+ };
153
+
154
+ /**
155
+ * Joins an output base directory with an entry's `srcPath` to produce the
156
+ * absolute path of the entry's bundled `index.d.ts`.
157
+ *
158
+ * @param outputPath - Absolute output directory.
159
+ * @param srcPath - Entry's `srcPath`. `''` for root.
160
+ * @returns Absolute path to `<outputPath>/<srcPath>/index.d.ts`.
161
+ *
162
+ * @example Computing the d.ts path for a sub-entry
163
+ * ```typescript
164
+ * dtsPathFor('/abs/dist/libs/foo', 'models') // => '/abs/dist/libs/foo/models/index.d.ts'
165
+ * ```
166
+ */
167
+ const dtsPathFor = (outputPath, srcPath) => srcPath ? join(outputPath, srcPath, 'index.d.ts') : join(outputPath, 'index.d.ts');
168
+
169
+ const log$a = logger.channel('builder:bundle:declarations:dts-per-entry');
170
+ const buildSiblingDescriptors = (entries, context, currentSrcPath) => {
171
+ const descriptors = [];
172
+ for (const entry of entries) {
173
+ if (entry.srcPath === currentSrcPath)
174
+ continue;
175
+ const indexDtsPath = dtsPathFor(context.outputPath, entry.srcPath);
176
+ if (!exists(indexDtsPath))
177
+ continue;
178
+ descriptors.push({ srcPath: entry.srcPath, indexDtsPath });
179
+ }
180
+ return descriptors;
181
+ };
182
+ const buildJobs$1 = (entries, context) => {
183
+ const jobs = [];
184
+ const workspacePrefixDeps = collectWorkspacePrefixDeps(context);
185
+ const workspaceExactSpecifiers = collectWorkspaceExactSpecifiers(context);
186
+ const workspaceRoutes = buildWorkspaceRoutes(context.workspaceBundledDeps);
187
+ const depsRoot = depsRootOf(context);
188
+ for (const entry of entries) {
189
+ const inputPath = dtsPathFor(context.outputPath, entry.srcPath);
190
+ if (!exists(inputPath))
191
+ continue;
192
+ const siblingEntries = buildSiblingDescriptors(entries, context, entry.srcPath);
193
+ jobs.push({
194
+ kind: 'dts',
195
+ dep: entry.exportPath,
196
+ inputPath,
197
+ format: 'esm',
198
+ outputPath: inputPath,
199
+ otherDeps: [...context.bundledDeps, ...workspacePrefixDeps],
200
+ otherWorkspaceSpecifiers: workspaceExactSpecifiers,
201
+ siblingEntries,
202
+ selfDtsPath: inputPath,
203
+ selfSrcPath: entry.srcPath,
204
+ npmDeps: context.bundledDeps,
205
+ workspaceRoutes,
206
+ depsRoot,
207
+ });
208
+ }
209
+ return jobs;
210
+ };
211
+ /**
212
+ * Runs the per-entry d.ts inlining pass: re-runs `rollup-plugin-dts` over every
213
+ * tsc-emitted entry `.d.ts` so (a) local per-source sibling re-exports
214
+ * (`export … from './create-logger'`) are flattened into the entry's
215
+ * `index.d.ts`, and (b) bundled-dep type imports are routed through
216
+ * `_dependencies/<dep>/index.d.ts` rather than left as bare specifiers. This
217
+ * self-containment is what lets `pruneOrphanDeclarations` delete the orphaned
218
+ * per-source `.d.ts` afterwards without orphaning a still-referenced sibling.
219
+ *
220
+ * Runs whenever the build bundles any dep — npm (`bundledDeps`) **or** workspace
221
+ * (`workspaceBundledDeps`); a package whose deps are all `@hyperfrontend/*` still
222
+ * needs the flatten. Entries whose tsc output is missing are skipped silently —
223
+ * the bundle phase may have skipped them deliberately (e.g., empty bundles).
224
+ *
225
+ * @param context - Resolved build context.
226
+ * @param monitor - Optional memory monitor invoked between jobs.
227
+ * @throws {Error} When the worker artifact cannot be located, or when any per-entry job fails.
228
+ *
229
+ * @example Inlining bundled-dep types into every entry's .d.ts after tsc emission
230
+ * ```typescript
231
+ * await runDtsPerEntry(context)
232
+ * ```
233
+ */
234
+ const runDtsPerEntry = async (context, monitor) => {
235
+ if (context.bundledDeps.length === 0 && context.workspaceBundledDeps.length === 0)
236
+ return;
237
+ const invocation = resolveDefaultWorkerPath(context.workspaceRoot);
238
+ if (!invocation) {
239
+ throw createError('bundleAllDeps is enabled but the pre-pass worker artifact was not found for the per-entry d.ts pass.');
240
+ }
241
+ const jobs = buildJobs$1(context.entryPointDiscovery.entryPoints, context);
242
+ if (jobs.length === 0) {
243
+ log$a.debug('per-entry d.ts pass: no entries with tsc-emitted .d.ts files');
244
+ return;
245
+ }
246
+ log$a.info(`per-entry d.ts pass: ${jobs.length} entries`);
247
+ monitor?.check('bundle:declarations:dts-perentry:start');
248
+ await runPrePass(jobs, { workerPath: invocation.path, execArgv: invocation.execArgv, monitor });
249
+ monitor?.check('bundle:declarations:dts-perentry:end');
250
+ };
251
+
252
+ const ROOTS = (projectRoot, workspaceRoot) => [projectRoot, workspaceRoot];
253
+ const findPackageJsonByWalkingUp = (entryPath, dep) => {
254
+ const segments = entryPath.split('/');
255
+ for (let i = segments.length - 1; i > 0; i--) {
256
+ const prefix = segments.slice(0, i).join('/');
257
+ const candidate = `${prefix}/package.json`;
258
+ if (!exists$1(candidate))
259
+ continue;
260
+ try {
261
+ const meta = readJsonFileIfExists(candidate);
262
+ if (meta?.name === dep)
263
+ return candidate;
264
+ }
265
+ catch {
266
+ // fall through
267
+ }
268
+ }
269
+ return undefined;
270
+ };
271
+ const findPackageJsonViaRequire = (dep, fromRoots) => {
272
+ for (const root of fromRoots) {
273
+ try {
274
+ const anchor = join$3(root, 'package.json');
275
+ if (!exists$1(anchor))
276
+ continue;
277
+ const req = createRequire(anchor);
278
+ const direct = `${dep}/package.json`;
279
+ try {
280
+ const path = req.resolve(direct);
281
+ if (exists$1(path))
282
+ return path;
283
+ }
284
+ catch {
285
+ // package may restrict ./package.json via exports — fall through to entry-anchored walk
286
+ }
287
+ try {
288
+ const entryPath = req.resolve(dep);
289
+ const found = findPackageJsonByWalkingUp(entryPath, dep);
290
+ if (found)
291
+ return found;
292
+ }
293
+ catch {
294
+ // entry resolution may also fail (e.g., type-only package); try the next root
295
+ }
296
+ }
297
+ catch {
298
+ // try next root
299
+ }
300
+ }
301
+ return undefined;
302
+ };
303
+ const ensureJsEntry = (pkg) => pkg.module ?? pkg.main;
304
+ const ensureDtsEntry = (pkg) => pkg.types ?? pkg.typings;
305
+ const absolutize = (relativeTo, rel) => {
306
+ if (isAbsolute(rel))
307
+ return normalizeToForwardSlashes$1(rel);
308
+ return normalizeToForwardSlashes$1(resolve(relativeTo, rel));
309
+ };
310
+ /**
311
+ * Resolves the absolute path to a bundled dep's entry file (JS or `.d.ts`) for a
312
+ * pre-pass invocation.
313
+ *
314
+ * For JS jobs the resolution prefers the dep's `module` field (ESM) over `main`
315
+ * (CJS). For dts jobs it prefers `types` over `typings`. Lookup walks the project
316
+ * root first, then the workspace root, using `createRequire` so node's standard
317
+ * resolution semantics apply (including support for hoisted `node_modules`).
318
+ *
319
+ * @param options - Dep name, root paths, and kind.
320
+ * @returns Absolute path to the dep's entry file.
321
+ * @throws {Error} When the dep's `package.json` cannot be located or it lacks the
322
+ * required entry field.
323
+ *
324
+ * @example Resolving the runtime entry for `rollup`
325
+ * ```typescript
326
+ * const entry = resolveDepEntry({ dep: 'rollup', projectRoot, workspaceRoot, kind: 'js' })
327
+ * ```
328
+ */
329
+ const resolveDepEntry = (options) => {
330
+ const { dep, projectRoot, workspaceRoot, kind } = options;
331
+ const pkgPath = findPackageJsonViaRequire(dep, ROOTS(projectRoot, workspaceRoot));
332
+ if (!pkgPath)
333
+ throw createError(`pre-pass: cannot locate package.json for dep "${dep}"`);
334
+ const pkg = readJsonFileIfExists(pkgPath);
335
+ if (!pkg)
336
+ throw createError(`pre-pass: package.json for dep "${dep}" could not be read at ${pkgPath}`);
337
+ const relative = kind === 'js' ? ensureJsEntry(pkg) : ensureDtsEntry(pkg);
338
+ if (!relative)
339
+ throw createError(`pre-pass: dep "${dep}" has no ${kind === 'js' ? 'main/module' : 'types/typings'} entry`);
340
+ return absolutize(dirname(pkgPath), relative);
341
+ };
342
+
343
+ const log$9 = logger.channel('builder:bundle:declarations:dts-pre-pass');
344
+ const workspaceDtsOutputFile = (entry) => entry.subPath ? `${entry.specifier}/index.d.ts` : `${entry.packageName}/index.d.ts`;
345
+ const filterRouteEntries$1 = (entry, all) => all.filter((other) => (entry.policy === 'sub-path' ? other.specifier !== entry.specifier : other.packageName !== entry.packageName));
346
+ const buildJobs = (deps, context) => {
347
+ const depsRoot = depsRootOf(context);
348
+ const jobs = [];
349
+ const workspacePrefixDeps = collectWorkspacePrefixDeps(context);
350
+ const workspaceExactSpecifiers = collectWorkspaceExactSpecifiers(context);
351
+ const workspaceRoutes = buildWorkspaceRoutes(context.workspaceBundledDeps);
352
+ for (const dep of deps) {
353
+ let inputPath;
354
+ try {
355
+ inputPath = resolveDepEntry({ dep, projectRoot: context.projectRoot, workspaceRoot: context.workspaceRoot, kind: 'dts' });
356
+ }
357
+ catch (error) {
358
+ log$9.warn(`skipping d.ts pre-pass for ${dep}: ${error instanceof Error ? error.message : String(error)}`);
359
+ continue;
360
+ }
361
+ const otherNpmDeps = deps.filter((d) => d !== dep);
362
+ jobs.push({
363
+ kind: 'dts',
364
+ dep,
365
+ inputPath,
366
+ format: 'esm',
367
+ outputPath: join$2(depsRoot, dep, 'index.d.ts'),
368
+ otherDeps: [...otherNpmDeps, ...workspacePrefixDeps],
369
+ otherWorkspaceSpecifiers: workspaceExactSpecifiers,
370
+ npmDeps: otherNpmDeps,
371
+ workspaceRoutes,
372
+ depsRoot,
373
+ });
374
+ }
375
+ return jobs;
376
+ };
377
+ const buildWorkspaceJobs = (context, npmDeps) => {
378
+ if (context.workspaceBundledDeps.length === 0)
379
+ return [];
380
+ const depsRoot = depsRootOf(context);
381
+ const wholeSurface = collectWorkspacePrefixDeps(context);
382
+ const subPathSpecifiers = collectWorkspaceExactSpecifiers(context);
383
+ const jobs = [];
384
+ for (const entry of context.workspaceBundledDeps) {
385
+ const otherWorkspacePackages = wholeSurface.filter((name) => name !== entry.packageName || entry.policy === 'sub-path');
386
+ const otherSubPathSpecifiers = subPathSpecifiers.filter((spec) => spec !== entry.specifier);
387
+ const workspaceRoutes = buildWorkspaceRoutes(filterRouteEntries$1(entry, context.workspaceBundledDeps));
388
+ jobs.push({
389
+ kind: 'workspace-dts',
390
+ dep: entry.specifier,
391
+ inputPath: entry.inputPath,
392
+ format: 'esm',
393
+ outputPath: join$2(depsRoot, workspaceDtsOutputFile(entry)),
394
+ otherDeps: [...npmDeps, ...otherWorkspacePackages],
395
+ otherWorkspaceSpecifiers: otherSubPathSpecifiers,
396
+ tsConfigPath: entry.tsConfigPath,
397
+ workspaceRoot: context.workspaceRoot,
398
+ npmDeps,
399
+ workspaceRoutes,
400
+ depsRoot,
401
+ });
402
+ }
403
+ return jobs;
404
+ };
405
+ /**
406
+ * Runs the d.ts pre-pass: for each bundled dep, produces `_dependencies/<dep>/index.d.ts`
407
+ * by running `rollup-plugin-dts` over the dep's types entry. Cross-dep type imports are
408
+ * marked external so the per-entry d.ts pass can route them through `_dependencies/`.
409
+ *
410
+ * @param context - Resolved build context.
411
+ * @param monitor - Optional memory monitor invoked between jobs.
412
+ * @throws {Error} When the worker artifact cannot be located, or when any d.ts job fails.
413
+ *
414
+ * @example Producing _dependencies/<dep>/index.d.ts for a self-contained build
415
+ * ```typescript
416
+ * await runDtsPrePass(context)
417
+ * ```
418
+ */
419
+ const runDtsPrePass = async (context, monitor) => {
420
+ if (context.bundledDeps.length === 0 && context.workspaceBundledDeps.length === 0)
421
+ return;
422
+ const invocation = resolveDefaultWorkerPath(context.workspaceRoot);
423
+ if (!invocation) {
424
+ throw createError('bundleAllDeps is enabled but the pre-pass worker artifact was not found for the d.ts pre-pass.');
425
+ }
426
+ const npmJobs = buildJobs(context.bundledDeps, context);
427
+ const workspaceJobs = buildWorkspaceJobs(context, context.bundledDeps);
428
+ const jobs = [...npmJobs, ...workspaceJobs];
429
+ if (jobs.length === 0) {
430
+ log$9.debug('d.ts pre-pass: no eligible deps (all skipped due to missing types)');
431
+ return;
432
+ }
433
+ log$9.info(`d.ts pre-pass: ${npmJobs.length} npm + ${workspaceJobs.length} workspace = ${jobs.length} job(s)`);
434
+ monitor?.check('bundle:declarations:dts-prepass:start');
435
+ await runPrePass(jobs, { workerPath: invocation.path, execArgv: invocation.execArgv, monitor });
436
+ monitor?.check('bundle:declarations:dts-prepass:end');
437
+ };
438
+
439
+ const log$8 = logger.channel('builder:bundle:declarations');
440
+ const HEARTBEAT_INTERVAL_MS = 5000;
441
+ const BYTES_PER_MB = 1024 * 1024;
442
+ const formatMB = (bytes) => (bytes / BYTES_PER_MB).toFixed(1);
443
+ const startHeartbeat = (label, startedAt) => setInterval(() => {
444
+ const usage = process.memoryUsage();
445
+ const elapsedSec = ((dateNow() - startedAt) / 1000).toFixed(1);
446
+ log$8.info(`${label} still running: elapsed=${elapsedSec}s parent heap=${formatMB(usage.heapUsed)}MB rss=${formatMB(usage.rss)}MB`);
447
+ }, HEARTBEAT_INTERVAL_MS);
448
+ const runTsc = (tscPath, args, cwd) => createPromise((resolve, reject) => {
449
+ const startedAt = dateNow();
450
+ const child = spawn(tscPath, args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
451
+ log$8.info(`tsc spawned: pid=${child.pid ?? 'unknown'}`);
452
+ log$8.debug(`tsc args: ${args.join(' ')}`);
453
+ const heartbeat = startHeartbeat('tsc', startedAt);
454
+ let stdout = '';
455
+ let stderr = '';
456
+ child.stdout.on('data', (chunk) => {
457
+ const text = chunk.toString();
458
+ stdout += text;
459
+ log$8.debug(text.trimEnd());
460
+ });
461
+ child.stderr.on('data', (chunk) => {
462
+ const text = chunk.toString();
463
+ stderr += text;
464
+ log$8.warn(text.trimEnd());
465
+ });
466
+ child.on('error', (error) => {
467
+ clearInterval(heartbeat);
468
+ log$8.error(`tsc spawn error: ${error.message}`);
469
+ reject(error);
470
+ });
471
+ child.on('close', (code) => {
472
+ clearInterval(heartbeat);
473
+ const durationMs = dateNow() - startedAt;
474
+ if (code !== 0) {
475
+ log$8.error(`tsc failed with exit code ${code} after ${durationMs}ms`);
476
+ reject(createError(`tsc failed with exit code ${code}`));
477
+ return;
478
+ }
479
+ log$8.info(`tsc exited 0 in ${durationMs}ms`);
480
+ resolve({ success: true, stdout, stderr });
481
+ });
482
+ });
483
+ /**
484
+ * Generates `.d.ts` and `.d.ts.map` files for every entry point in the project
485
+ * by spawning the workspace-local TypeScript compiler.
486
+ *
487
+ * After tsc finishes, calls `flattenDeclarationPaths` to relocate the nested
488
+ * `dist/<lib>/libs/<lib>/src/...` structure that tsc emits with `baseUrl=workspaceRoot`
489
+ * back into the flat per-library shape consumers expect.
490
+ *
491
+ * @param context - Resolved build context. Provides project root, output path, tsconfig path,
492
+ * workspace root, and entry point discovery for the flatten step.
493
+ * @returns Promise resolving with tsc's exit status, captured stdout, and captured stderr.
494
+ * @throws {Error} When tsc exits with a non-zero status or fails to spawn.
495
+ *
496
+ * @example Generating declarations as part of a custom build
497
+ * ```typescript
498
+ * const result = await generateDeclarations(context)
499
+ * console.log(result.stdout)
500
+ * ```
501
+ */
502
+ const generateDeclarations = async (context) => {
503
+ log$8.info('generating typescript declarations');
504
+ const usage = process.memoryUsage();
505
+ log$8.info(`pre-tsc memory: parent heap=${formatMB(usage.heapUsed)}MB rss=${formatMB(usage.rss)}MB`);
506
+ const tscPath = join$3(context.workspaceRoot, 'node_modules', '.bin', 'tsc');
507
+ const args = [
508
+ '--project',
509
+ context.tsConfigPath,
510
+ '--noEmit',
511
+ 'false',
512
+ '--emitDeclarationOnly',
513
+ '--declaration',
514
+ '--declarationMap',
515
+ '--outDir',
516
+ context.outputPath,
517
+ ];
518
+ const result = await runTsc(tscPath, args, context.projectRoot);
519
+ log$8.info('flattening declaration paths');
520
+ const flattenStart = dateNow();
521
+ flattenDeclarationPaths(context);
522
+ log$8.info(`flatten complete in ${dateNow() - flattenStart}ms`);
523
+ return result;
524
+ };
525
+
526
+ const log$7 = logger.channel('builder:bundle:declarations:prune-orphans');
527
+ const ORPHAN_DTS_RE = /\.d\.ts$|\.d\.ts\.map$/;
528
+ const INDEX_DTS_NAME = 'index.d.ts';
529
+ /**
530
+ * Resolves a relative specifier found in a `.d.ts` to the absolute `.d.ts` file
531
+ * it points at, or `null` when it resolves to nothing on disk or into
532
+ * `_dependencies/`.
533
+ *
534
+ * Declaration specifiers are extensionless (`./create-logger`, `./shared/consts`)
535
+ * or directory imports (`./shared` → `shared/index.d.ts`); the canonical
536
+ * `_dependencies` routing uses an explicit runtime extension (`.../index.js`),
537
+ * which is rewritten to its declaration sibling. Targets under `depsRoot` are
538
+ * never edges for this pass — bundled-dep declarations are managed by the
539
+ * dependency Type Prune, and this pass must never touch them.
540
+ *
541
+ * @param dir - Absolute directory of the referencing `.d.ts`.
542
+ * @param spec - Relative specifier text (already known to start with `.`).
543
+ * @param depsRoot - Absolute path to the `_dependencies/` directory.
544
+ * @returns Absolute `.d.ts` path of the referenced sibling, or `null`.
545
+ */
546
+ const toDtsTarget$1 = (dir, spec, depsRoot) => {
547
+ const abs = join$2(dir, spec);
548
+ // why: a `.js` specifier is the bundled-dep routing shape; map it onto its declaration sibling.
549
+ const candidates = spec.endsWith('.js') ? [`${abs.slice(0, -3)}.d.ts`] : [`${abs}.d.ts`, join$2(abs, INDEX_DTS_NAME)];
550
+ for (const candidate of candidates) {
551
+ if (isUnderDir(candidate, depsRoot))
552
+ return null;
553
+ if (exists(candidate))
554
+ return candidate;
555
+ }
556
+ return null;
557
+ };
558
+ /**
559
+ * Computes the set of `.d.ts` files reachable from the entry-point `index.d.ts`
560
+ * roots by transitively following their relative specifiers.
561
+ *
562
+ * Breadth-first: each visited file's text is read, scanned once, then released
563
+ * before the next, so only one declaration source is resident at a time and the
564
+ * memory profile stays flat. Edges into `_dependencies/` and to non-existent
565
+ * targets are dropped. The specifier scan over-approximates (a spurious match
566
+ * over-keeps harmless bytes) so it never under-keeps a referenced sibling.
567
+ *
568
+ * If any reached `.d.ts` contains a dynamic (non-literal) `import(`/`require(`,
569
+ * the graph cannot be fully resolved, so the function returns `null` — the
570
+ * safe sentinel that makes the caller keep every declaration.
571
+ *
572
+ * @param roots - Absolute paths to the entry-point `index.d.ts` roots.
573
+ * @param depsRoot - Absolute path to the `_dependencies/` directory.
574
+ * @returns The set of reachable absolute `.d.ts` paths, or `null` on a dynamic
575
+ * specifier bail.
576
+ */
577
+ const computeReachableDeclarations = (roots, depsRoot) => {
578
+ const reachable = createSet([]);
579
+ const queue = [];
580
+ for (const root of roots) {
581
+ if (exists(root) && !reachable.has(root)) {
582
+ reachable.add(root);
583
+ queue.push(root);
584
+ }
585
+ }
586
+ let head = 0;
587
+ while (head < queue.length) {
588
+ const file = queue[head];
589
+ head += 1;
590
+ // why: every queued path was `exists`-checked before enqueue (roots and `toDtsTarget` targets), so a direct read is safe.
591
+ const source = readFileContent(file);
592
+ if (hasDynamicSpecifier(source)) {
593
+ log$7.warn(`dynamic import/require in ${file}; keeping all orphan declarations for safety`);
594
+ return null;
595
+ }
596
+ const dir = getDirname(file);
597
+ for (const spec of collectChunkSpecifiers(source)) {
598
+ const target = toDtsTarget$1(dir, spec, depsRoot);
599
+ if (target !== null && !reachable.has(target)) {
600
+ reachable.add(target);
601
+ queue.push(target);
602
+ }
603
+ }
604
+ }
605
+ return reachable;
606
+ };
607
+ /**
608
+ * Collects every `.d.ts` / `.d.ts.map` file under `root`, recursing the whole
609
+ * package tree but skipping the `_dependencies/` subtree (managed by the
610
+ * dependency Type Prune, never touched here).
611
+ *
612
+ * @param root - Absolute path to the package output root.
613
+ * @param depsRoot - Absolute path to the `_dependencies/` directory.
614
+ * @returns Absolute paths of all declaration files outside `_dependencies/`.
615
+ */
616
+ const collectDeclarationFiles = (root, depsRoot) => {
617
+ const files = [];
618
+ if (!exists(root))
619
+ return files;
620
+ const visit = (dir) => {
621
+ for (const entry of readDirectory(dir)) {
622
+ if (entry.isDirectory) {
623
+ if (isUnderDir(entry.path, depsRoot))
624
+ continue;
625
+ visit(entry.path);
626
+ }
627
+ else if (entry.isFile && ORPHAN_DTS_RE.test(entry.name)) {
628
+ files.push(entry.path);
629
+ }
630
+ }
631
+ };
632
+ visit(root);
633
+ return files;
634
+ };
635
+ /**
636
+ * Removes redundant per-source `.d.ts` / `.d.ts.map` files left behind once the
637
+ * per-entry flatten has inlined each entry's declarations into a self-contained
638
+ * `index.d.ts`.
639
+ *
640
+ * Walks the whole package tree (excluding `_dependencies/`) and deletes every
641
+ * declaration file **not reachable** from an entry-point `index.d.ts` via its
642
+ * transitive relative specifiers. Reachability — rather than a per-directory
643
+ * sweep — guarantees the invariant that after this runs no surviving `.d.ts`
644
+ * references a removed one: when the flatten made `index.d.ts` self-contained
645
+ * the reachable set collapses to the roots and every per-source sibling is
646
+ * pruned; when the flatten was skipped the siblings the public entry still
647
+ * re-exports (and anything they transitively re-export) stay live so the shipped
648
+ * types resolve. This removes the redundancy at the source so `dist` == the
649
+ * shipped tarball, demoting `package.json#files` to a backstop.
650
+ *
651
+ * Safety rails:
652
+ * - Never touches anything inside `_dependencies/`.
653
+ * - A `.d.ts.map` is kept iff its sibling `.d.ts` is reachable.
654
+ * - A dynamic (non-literal) `import(`/`require(` in any reached declaration
655
+ * aborts the prune and keeps every declaration file.
656
+ *
657
+ * @param context - Resolved build context.
658
+ * @returns The total number of `.d.ts` / `.d.ts.map` files removed.
659
+ *
660
+ * @example Pruning orphans after generateDeclarations
661
+ * ```typescript
662
+ * const removed = pruneOrphanDeclarations(context)
663
+ * ```
664
+ */
665
+ const pruneOrphanDeclarations = (context) => {
666
+ const depsRoot = depsRootOf(context);
667
+ const roots = [];
668
+ for (const entry of context.entryPointDiscovery.entryPoints) {
669
+ const dir = entryDirOf(entry, context);
670
+ if (isUnderDir(dir, depsRoot))
671
+ continue;
672
+ roots.push(join$2(dir, INDEX_DTS_NAME));
673
+ }
674
+ const reachable = computeReachableDeclarations(roots, depsRoot);
675
+ if (reachable === null)
676
+ return 0;
677
+ let total = 0;
678
+ for (const file of collectDeclarationFiles(context.outputPath, depsRoot)) {
679
+ // why: a `.d.ts.map` shares the liveness of its `.d.ts` sibling, keyed by stripping the trailing `.map`.
680
+ const dtsKey = file.endsWith('.d.ts.map') ? file.slice(0, -4) : file;
681
+ if (reachable.has(dtsKey))
682
+ continue;
683
+ unlinkSync(file);
684
+ total += 1;
685
+ }
686
+ if (total > 0)
687
+ log$7.info(`pruned ${total} orphan declaration file(s)`);
688
+ return total;
689
+ };
690
+
691
+ /** Per-format output chunk file name, mirroring the bundler's entry naming. */
692
+ const CHUNK_FILE = { esm: 'index.esm.js', cjs: 'index.cjs.js' };
693
+ /**
694
+ * Strips rollup's `$N` collision-rename suffix from a local name, yielding the
695
+ * canonical source symbol name.
696
+ *
697
+ * @param name - A local identifier from an emitted bundle.
698
+ * @returns The base name with any trailing `$digits` removed.
699
+ *
700
+ * @example Undoing a collision rename
701
+ * ```typescript
702
+ * baseName('Store$1') // => 'Store'
703
+ * ```
704
+ */
705
+ const baseName = (name) => name.replace(/\$\d+$/, '');
706
+ /**
707
+ * Computes a rename-insensitive identity key for a top-level statement.
708
+ *
709
+ * Two copies of the same source that differ only in rollup's per-entry `$N`
710
+ * collision suffixes compare equal, while genuinely different code never
711
+ * collides: `$N` is stripped from identifier nodes only, so string literals,
712
+ * comments, numeric tokens, and discriminating member names stay intact.
713
+ *
714
+ * @param statement - The top-level statement to fingerprint.
715
+ * @param sourceFile - The source file the statement belongs to.
716
+ * @returns The statement's text with `$N` stripped from every identifier node.
717
+ *
718
+ * @example Stripping a dep-namespace local's collision suffix
719
+ * ```typescript
720
+ * fingerprintOf(statement, sourceFile) // 'const x = index_cjs_js.getType();' for both `$1` and `$2` copies
721
+ * ```
722
+ */
723
+ const fingerprintOf = (statement, sourceFile) => {
724
+ const start = statement.getStart(sourceFile);
725
+ const text = statement.getText(sourceFile);
726
+ const edits = [];
727
+ const visit = (node) => {
728
+ if (ts.isIdentifier(node)) {
729
+ const base = baseName(node.text);
730
+ if (base !== node.text)
731
+ edits.push([node.getStart(sourceFile) - start, node.getEnd() - start, base]);
732
+ }
733
+ ts.forEachChild(node, visit);
734
+ };
735
+ visit(statement);
736
+ let out = text;
737
+ for (const [s, e, replacement] of edits.sort((a, b) => b[0] - a[0]))
738
+ out = `${out.slice(0, s)}${replacement}${out.slice(e)}`;
739
+ return out;
740
+ };
741
+ /**
742
+ * Resolves a hoisted module's chunk file name for a format.
743
+ *
744
+ * @param format - Output module format.
745
+ * @returns The per-entry chunk file name (`index.esm.js` / `index.cjs.js`).
746
+ *
747
+ * @example Naming the CJS chunk
748
+ * ```typescript
749
+ * chunkFileName('cjs') // => 'index.cjs.js'
750
+ * ```
751
+ */
752
+ const chunkFileName = (format) => CHUNK_FILE[format];
753
+ /**
754
+ * Computes the `_shared/` directory (relative to the output root) that holds a
755
+ * module's hoisted chunk.
756
+ *
757
+ * @param moduleKey - The owning module's key.
758
+ * @returns The forward-slashed `_shared/<moduleKey>` directory.
759
+ *
760
+ * @example Locating a module's shared directory
761
+ * ```typescript
762
+ * sharedDirFor('events/events') // => '_shared/events/events'
763
+ * ```
764
+ */
765
+ const sharedDirFor = (moduleKey) => `_shared/${moduleKey}`;
766
+ const isExported = (statement) => ts.canHaveModifiers(statement) && (ts.getModifiers(statement) ?? []).some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword);
767
+ const declaredNames = (statement) => {
768
+ if ((ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement) || ts.isEnumDeclaration(statement)) && statement.name)
769
+ return [statement.name.text];
770
+ if (!ts.isVariableStatement(statement))
771
+ return [];
772
+ const names = [];
773
+ for (const decl of statement.declarationList.declarations)
774
+ if (ts.isIdentifier(decl.name))
775
+ names.push(decl.name.text);
776
+ return names;
777
+ };
778
+ const requireSpecifierOf = (initializer) => {
779
+ if (initializer === undefined)
780
+ return null;
781
+ if (ts.isPropertyAccessExpression(initializer))
782
+ return getRequireSpecifier(initializer.expression);
783
+ return getRequireSpecifier(initializer);
784
+ };
785
+ const isRequireVarStatement$1 = (statement) => ts.isVariableStatement(statement) &&
786
+ statement.declarationList.declarations.length > 0 &&
787
+ statement.declarationList.declarations.every((decl) => requireSpecifierOf(decl.initializer) !== null);
788
+ const collectCjsBindings = (statement, bindings) => {
789
+ for (const decl of statement.declarationList.declarations) {
790
+ const specifier = requireSpecifierOf(decl.initializer);
791
+ if (specifier === null)
792
+ continue;
793
+ if (ts.isIdentifier(decl.name)) {
794
+ // why: `var x = require('s').foo` binds a single named export; the bare `var ns = require('s')` binds the whole namespace.
795
+ const imported = decl.initializer && ts.isPropertyAccessExpression(decl.initializer) ? decl.initializer.name.text : undefined;
796
+ bindings.set(decl.name.text, imported ? { specifier, kind: 'cjs-named', imported } : { specifier, kind: 'cjs-namespace' });
797
+ }
798
+ else if (ts.isObjectBindingPattern(decl.name)) {
799
+ for (const element of decl.name.elements)
800
+ if (ts.isIdentifier(element.name))
801
+ bindings.set(element.name.text, { specifier, kind: 'cjs-named', imported: (element.propertyName ?? element.name).getText() });
802
+ }
803
+ }
804
+ };
805
+ const collectEsmBindings = (statement, bindings) => {
806
+ const specifier = statement.moduleSpecifier.text;
807
+ const clause = statement.importClause;
808
+ if (!clause)
809
+ return;
810
+ if (clause.name)
811
+ bindings.set(clause.name.text, { specifier, kind: 'default' });
812
+ if (!clause.namedBindings)
813
+ return;
814
+ if (ts.isNamespaceImport(clause.namedBindings)) {
815
+ bindings.set(clause.namedBindings.name.text, { specifier, kind: 'namespace' });
816
+ return;
817
+ }
818
+ for (const element of clause.namedBindings.elements)
819
+ bindings.set(element.name.text, { specifier, kind: 'named', imported: (element.propertyName ?? element.name).text });
820
+ };
821
+ const isUseStrict = (statement) => ts.isExpressionStatement(statement) && ts.isStringLiteral(statement.expression) && statement.expression.text === 'use strict';
822
+ const isHeaderStatement = (statement, format) => isUseStrict(statement) || (format === 'esm' ? ts.isImportDeclaration(statement) : isRequireVarStatement$1(statement));
823
+ const isExportSurface = (statement, format) => {
824
+ if (format === 'esm')
825
+ return ts.isExportDeclaration(statement) && !statement.moduleSpecifier;
826
+ // why: CJS export surface is a chain of `exports.x = y` assignment statements emitted at the bundle tail.
827
+ if (!ts.isExpressionStatement(statement) || !ts.isBinaryExpression(statement.expression))
828
+ return false;
829
+ const { left, operatorToken } = statement.expression;
830
+ return (operatorToken.kind === ts.SyntaxKind.EqualsToken &&
831
+ ts.isPropertyAccessExpression(left) &&
832
+ ts.isIdentifier(left.expression) &&
833
+ left.expression.text === 'exports');
834
+ };
835
+ /**
836
+ * Parses one entry bundle into the structural model the hoist pass consumes.
837
+ *
838
+ * Classifies every top-level statement as an import binding, a removable
839
+ * runtime declaration, the export surface, or an opaque bare statement. Inline
840
+ * `export`-modified declarations are treated as part of the export surface
841
+ * (never removable), so the bundle's published API is never disturbed.
842
+ *
843
+ * @param source - Raw entry bundle source text.
844
+ * @param format - Module format selecting ESM vs CJS import/export shapes.
845
+ * @returns The parsed entry model.
846
+ *
847
+ * @example Modeling an ESM entry bundle
848
+ * ```typescript
849
+ * const parsed = parseEntry("import { x } from './_dependencies/a/index.esm.js'\nclass C {}", 'esm')
850
+ * ```
851
+ */
852
+ const parseEntry = (source, format) => {
853
+ const sourceFile = parseChunk(source);
854
+ const decls = [];
855
+ const importBindings = createMap();
856
+ const bareStatements = [];
857
+ const declNames = createSet([]);
858
+ let headerEnd = 0;
859
+ let inHeader = true;
860
+ for (const statement of sourceFile.statements) {
861
+ if (inHeader && isHeaderStatement(statement, format))
862
+ headerEnd = statement.getEnd();
863
+ else
864
+ inHeader = false;
865
+ if (format === 'esm' && ts.isImportDeclaration(statement)) {
866
+ collectEsmBindings(statement, importBindings);
867
+ continue;
868
+ }
869
+ if (format === 'cjs' && isRequireVarStatement$1(statement)) {
870
+ collectCjsBindings(statement, importBindings);
871
+ continue;
872
+ }
873
+ if (isUseStrict(statement) || isExportSurface(statement, format))
874
+ continue;
875
+ const names = isExported(statement) ? [] : declaredNames(statement);
876
+ for (const name of names)
877
+ declNames.add(name);
878
+ // why: only a single-name, non-exported declaration can be cleanly lifted; multi-declarator and inline-exported statements stay put (and may entangle their module out of the plan).
879
+ if (names.length !== 1) {
880
+ bareStatements.push(statement);
881
+ continue;
882
+ }
883
+ decls.push({
884
+ base: baseName(names[0]),
885
+ localName: names[0],
886
+ statement,
887
+ text: statement.getText(sourceFile),
888
+ fingerprint: fingerprintOf(statement, sourceFile),
889
+ });
890
+ }
891
+ return { sourceFile, decls, importBindings, bareStatements, declNames, headerEnd };
892
+ };
893
+ /**
894
+ * Groups an entry's attributable declarations by their owning module.
895
+ *
896
+ * Declarations whose base name is unowned (a dependency or unexported helper
897
+ * inlined into the bundle) are skipped, leaving them in place.
898
+ *
899
+ * @param parsed - A parsed entry bundle.
900
+ * @param owners - The first-party ownership index.
901
+ * @returns Map from module key to that module's declarations in source order.
902
+ *
903
+ * @example Attributing an entry's declarations
904
+ * ```typescript
905
+ * const byModule = attribute(parseEntry(source, 'esm'), owners)
906
+ * ```
907
+ */
908
+ const attribute = (parsed, owners) => {
909
+ const byModule = createMap();
910
+ for (const decl of parsed.decls) {
911
+ const moduleKey = owners.ownerOf.get(decl.base);
912
+ if (moduleKey === undefined)
913
+ continue;
914
+ const group = byModule.get(moduleKey) ?? [];
915
+ group.push(decl);
916
+ byModule.set(moduleKey, group);
917
+ }
918
+ return byModule;
919
+ };
920
+ const toModuleKey = (srcRoot, file) => file
921
+ .slice(srcRoot.length + 1)
922
+ .replace(/\.ts$/, '')
923
+ .split(/[\\/]/)
924
+ .join('/');
925
+ // why: private top-level helpers (e.g. a reducer's `handlers` map) are inlined alongside the exported symbols that use them; attributing them too lets the whole module hoist instead of bailing on the "unresolved" private reference. Collisions across modules are dropped as ambiguous by indexOwners, preserving safety.
926
+ const ownersFromSource = (source) => {
927
+ const sourceFile = ts.createSourceFile('module.ts', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
928
+ const names = [];
929
+ for (const statement of sourceFile.statements)
930
+ names.push(...declaredNames(statement));
931
+ return names;
932
+ };
933
+ const walkTsFiles = (dir, acc) => {
934
+ for (const entry of readDirectory(dir)) {
935
+ if (entry.isDirectory)
936
+ walkTsFiles(entry.path, acc);
937
+ else if (entry.name.endsWith('.ts') && !entry.name.endsWith('.d.ts') && !entry.name.endsWith('.spec.ts'))
938
+ acc.push(entry.path);
939
+ }
940
+ };
941
+ /**
942
+ * Builds the first-party ownership index by scanning `<srcRoot>/**` for the
943
+ * runtime symbols each module exports.
944
+ *
945
+ * Both exported and private top-level runtime declarations are indexed, so a
946
+ * module's private helpers hoist alongside the exports that use them. Types-only
947
+ * modules declare no runtime symbols and contribute nothing. A name declared by
948
+ * two different modules is ambiguous and dropped from the index, so the pass can
949
+ * never misattribute it.
950
+ *
951
+ * @param srcRoot - Absolute path to the project's `src/` directory.
952
+ * @returns The ownership index.
953
+ *
954
+ * @example Indexing a library's source tree
955
+ * ```typescript
956
+ * const owners = indexOwners('/abs/libs/foo/src')
957
+ * ```
958
+ */
959
+ const indexOwners = (srcRoot) => {
960
+ const files = [];
961
+ walkTsFiles(srcRoot, files);
962
+ const firstOwner = createMap();
963
+ const ambiguous = createSet([]);
964
+ const ownerOf = createMap();
965
+ for (const file of files) {
966
+ const moduleKey = toModuleKey(srcRoot, file);
967
+ for (const name of ownersFromSource(readFileContent(file))) {
968
+ if (ambiguous.has(name))
969
+ continue;
970
+ const prior = firstOwner.get(name);
971
+ if (prior !== undefined && prior !== moduleKey) {
972
+ ambiguous.add(name);
973
+ ownerOf.delete(name);
974
+ continue;
975
+ }
976
+ firstOwner.set(name, moduleKey);
977
+ ownerOf.set(name, moduleKey);
978
+ }
979
+ }
980
+ return { ownerOf };
981
+ };
982
+
983
+ const EVAL_SIDE_EFFECT_KINDS = createSet([
984
+ ts.SyntaxKind.CallExpression,
985
+ ts.SyntaxKind.NewExpression,
986
+ ts.SyntaxKind.AwaitExpression,
987
+ ts.SyntaxKind.YieldExpression,
988
+ ts.SyntaxKind.TaggedTemplateExpression,
989
+ ]);
990
+ /**
991
+ * Globals whose call observably only mutates-then-returns its (fresh-literal)
992
+ * argument and is therefore side-effect-free — `freeze`/`seal`/`preventExtensions`
993
+ * all behave this way on a freshly-built object/array literal.
994
+ */
995
+ const PURE_GLOBAL_CALLEES = createSet(['Object.freeze', 'Object.seal', 'Object.preventExtensions']);
996
+ // context: dotted global-rooted name for a call target, with a leading `globalThis.` stripped and each top-level binding resolved through `resolution`. Null when the base is a local binding that does not resolve to a global (a shadow) or is not a plain identifier/property chain (a call, element access, …).
997
+ const canonicalCallee = (expr, resolution) => {
998
+ if (ts.isIdentifier(expr)) {
999
+ const mapped = resolution.canonical.get(expr.text);
1000
+ if (mapped !== undefined)
1001
+ return mapped;
1002
+ // why: a top-level binding that did not resolve to a global alias shadows that global; treat as opaque so e.g. `const Object = {}` disables bare `Object.freeze`.
1003
+ return resolution.bindings.has(expr.text) ? null : expr.text;
1004
+ }
1005
+ if (ts.isPropertyAccessExpression(expr)) {
1006
+ const base = canonicalCallee(expr.expression, resolution);
1007
+ if (base === null)
1008
+ return null;
1009
+ const dotted = `${base}.${expr.name.text}`;
1010
+ return dotted.startsWith('globalThis.') ? dotted.slice('globalThis.'.length) : dotted;
1011
+ }
1012
+ return null;
1013
+ };
1014
+ /**
1015
+ * Maps each top-level binding to its canonical global-rooted callee form, in
1016
+ * source order so a later alias resolves through an earlier one. Both `const`
1017
+ * and `var` are resolved; bundled dep chunks never reassign these interop
1018
+ * bindings. A call/literal initializer is opaque and only contributes a
1019
+ * shadowing entry in `bindings`.
1020
+ *
1021
+ * @param sourceFile - The parsed chunk whose top-level bindings are resolved.
1022
+ * @returns The binding resolution: every top-level name plus the global-rooted
1023
+ * canonical form of each identifier/property-chain alias.
1024
+ *
1025
+ * @example Resolving an alias-of-global freeze
1026
+ * ```typescript
1027
+ * const { canonical } = collectBindingCanonical(parseChunk('const _O = globalThis.Object;\nconst freeze = _O.freeze;'))
1028
+ * canonical.get('freeze') // => 'Object.freeze'
1029
+ * ```
1030
+ */
1031
+ const collectBindingCanonical = (sourceFile) => {
1032
+ const resolution = { bindings: createSet([]), canonical: createMap() };
1033
+ for (const statement of sourceFile.statements) {
1034
+ if ((ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && statement.name)
1035
+ resolution.bindings.add(statement.name.text);
1036
+ if (!ts.isVariableStatement(statement))
1037
+ continue;
1038
+ for (const decl of statement.declarationList.declarations) {
1039
+ if (!ts.isIdentifier(decl.name))
1040
+ continue;
1041
+ resolution.bindings.add(decl.name.text);
1042
+ // why: only an identifier/property-access initializer can alias a global; resolve it through the bindings collected so far (leftmost identifier only).
1043
+ if (decl.initializer && (ts.isIdentifier(decl.initializer) || ts.isPropertyAccessExpression(decl.initializer))) {
1044
+ const resolved = canonicalCallee(decl.initializer, resolution);
1045
+ if (resolved !== null)
1046
+ resolution.canonical.set(decl.name.text, resolved);
1047
+ }
1048
+ }
1049
+ }
1050
+ return resolution;
1051
+ };
1052
+ /**
1053
+ * Reports whether a call is a recognized pure callee
1054
+ * (`Object.freeze`/`seal`/`preventExtensions`, however aliased) over a fresh
1055
+ * object/array literal. The argument must be a same-expression literal —
1056
+ * freezing a shared binding mutates it observably, so an identifier argument is
1057
+ * rejected. This checks only the callee and argument shape, not the purity of
1058
+ * the argument's own subexpressions.
1059
+ *
1060
+ * @param call - The call expression to classify.
1061
+ * @param resolution - The chunk's binding resolution, used to canonicalize the callee.
1062
+ * @returns `true` when the call is an observably pure freeze of a fresh literal.
1063
+ *
1064
+ * @example Recognizing an aliased freeze of a fresh literal
1065
+ * ```typescript
1066
+ * const sourceFile = parseChunk('const _O = globalThis.Object;\nconst X = _O.freeze({ a: 1 });')
1067
+ * // for the `_O.freeze({ a: 1 })` call node
1068
+ * isPureFreezeCall(call, collectBindingCanonical(sourceFile)) // => true
1069
+ * ```
1070
+ */
1071
+ const isPureFreezeCall = (call, resolution) => {
1072
+ const callee = canonicalCallee(call.expression, resolution);
1073
+ if (callee === null || !PURE_GLOBAL_CALLEES.has(callee))
1074
+ return false;
1075
+ if (call.arguments.length < 1)
1076
+ return false;
1077
+ const first = call.arguments[0];
1078
+ return ts.isObjectLiteralExpression(first) || ts.isArrayLiteralExpression(first);
1079
+ };
1080
+ /**
1081
+ * Reports whether a call is `<global-rooted chain>.bind(…)`.
1082
+ * `Function.prototype.bind` only builds and returns a new bound function — no
1083
+ * observable side effect. The receiver must canonicalize to a global so an
1084
+ * arbitrary user object's `.bind` — potentially a redefined, side-effecting
1085
+ * method — is never assumed pure. As with {@link isPureFreezeCall}, this checks
1086
+ * only the call shape, not the purity of the argument's own subexpressions.
1087
+ *
1088
+ * @param call - The call expression to classify.
1089
+ * @param resolution - The chunk's binding resolution, used to canonicalize the receiver.
1090
+ * @returns `true` when the call binds a method off a global-rooted receiver chain.
1091
+ *
1092
+ * @example Recognizing a bind of a global-rooted receiver
1093
+ * ```typescript
1094
+ * const sourceFile = parseChunk('const _P = globalThis.Promise;\nconst X = _P.resolve.bind(_P);')
1095
+ * // for the `_P.resolve.bind(_P)` call node
1096
+ * isPureBindCall(call, collectBindingCanonical(sourceFile)) // => true
1097
+ * ```
1098
+ */
1099
+ const isPureBindCall = (call, resolution) => {
1100
+ const callee = call.expression;
1101
+ if (!ts.isPropertyAccessExpression(callee) || callee.name.text !== 'bind')
1102
+ return false;
1103
+ return canonicalCallee(callee.expression, resolution) !== null;
1104
+ };
1105
+
1106
+ const PURE_ANNOTATION = /[@#]__PURE__/;
1107
+
1108
+ const isAnnotatedPure = (node) => PURE_ANNOTATION.test(node.getSourceFile().text.slice(node.getFullStart(), node.getStart()));
1109
+
1110
+ const containsEvalSideEffect = (node, resolution) => {
1111
+ let found = false;
1112
+ const visit = (current) => {
1113
+ if (found || ts.isFunctionLike(current))
1114
+ return;
1115
+ if (ts.isCallExpression(current) || ts.isNewExpression(current)) {
1116
+ if ((ts.isCallExpression(current) && (isPureFreezeCall(current, resolution) || isPureBindCall(current, resolution))) ||
1117
+ isAnnotatedPure(current)) {
1118
+ ts.forEachChild(current, visit);
1119
+ return;
1120
+ }
1121
+ found = true;
1122
+ return;
1123
+ }
1124
+ if (EVAL_SIDE_EFFECT_KINDS.has(current.kind)) {
1125
+ found = true;
1126
+ return;
1127
+ }
1128
+ ts.forEachChild(current, visit);
1129
+ };
1130
+ visit(node);
1131
+ return found;
1132
+ };
1133
+ const isSideEffectFreeInitializer = (initializer, resolution) => initializer === undefined || !containsEvalSideEffect(initializer, resolution);
1134
+ /**
1135
+ * Collects the identifier names referenced within a node, excluding identifiers
1136
+ * that sit in a property-name position (`obj.name`, `{ name: … }`, `{ name: x }`
1137
+ * binding keys) since those never refer to a top-level declaration.
1138
+ *
1139
+ * Deliberately over-approximates: a name captured that is not actually a
1140
+ * top-level declaration is harmless, and capturing more only keeps more code.
1141
+ *
1142
+ * @param node - The subtree to scan.
1143
+ * @param sink - Set that receives every referenced identifier name.
1144
+ *
1145
+ * @example Collecting references inside a function body
1146
+ * ```typescript
1147
+ * const refs = createSet<string>([])
1148
+ * collectRefs(functionDeclaration, refs)
1149
+ * ```
1150
+ */
1151
+ const collectRefs = (node, sink) => {
1152
+ const visit = (current) => {
1153
+ if (ts.isIdentifier(current)) {
1154
+ const parent = current.parent;
1155
+ if (ts.isPropertyAccessExpression(parent) && parent.name === current)
1156
+ return;
1157
+ if (ts.isPropertyAssignment(parent) && parent.name === current)
1158
+ return;
1159
+ if (ts.isBindingElement(parent) && parent.propertyName === current)
1160
+ return;
1161
+ sink.add(current.text);
1162
+ return;
1163
+ }
1164
+ ts.forEachChild(current, visit);
1165
+ };
1166
+ visit(node);
1167
+ };
1168
+ const hasExportModifier = (node) => ts.canHaveModifiers(node) && (ts.getModifiers(node) ?? []).some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword);
1169
+ const isRequireInitializer = (init) => getRequireSpecifier(init) !== null || (ts.isPropertyAccessExpression(init) && getRequireSpecifier(init.expression) !== null);
1170
+ const isRequireVarStatement = (statement) => ts.isVariableStatement(statement) &&
1171
+ statement.declarationList.declarations.some((decl) => decl.initializer !== undefined && isRequireInitializer(decl.initializer));
1172
+ /**
1173
+ * Returns the local binding names introduced by a CJS `require` variable
1174
+ * statement, across identifier and object-destructure bindings.
1175
+ *
1176
+ * @param statement - A variable statement known to bind a `require` call.
1177
+ * @returns The local names it introduces.
1178
+ *
1179
+ * @example Bindings of a destructured require
1180
+ * ```typescript
1181
+ * // for `var { a, b } = require('./x.cjs.js')`
1182
+ * requireBindingLocals(statement) // => ['a', 'b']
1183
+ * ```
1184
+ */
1185
+ const requireBindingLocals = (statement) => {
1186
+ const locals = [];
1187
+ if (!ts.isVariableStatement(statement))
1188
+ return locals;
1189
+ for (const decl of statement.declarationList.declarations) {
1190
+ if (ts.isIdentifier(decl.name))
1191
+ locals.push(decl.name.text);
1192
+ else if (ts.isObjectBindingPattern(decl.name))
1193
+ for (const element of decl.name.elements)
1194
+ if (ts.isIdentifier(element.name))
1195
+ locals.push(element.name.text);
1196
+ }
1197
+ return locals;
1198
+ };
1199
+ const tryDecl = (statement, resolution) => {
1200
+ if ((ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && statement.name) {
1201
+ return { statement, names: [statement.name.text], sideEffectFree: true };
1202
+ }
1203
+ if (!ts.isVariableStatement(statement))
1204
+ return null;
1205
+ const names = [];
1206
+ let sideEffectFree = true;
1207
+ for (const decl of statement.declarationList.declarations) {
1208
+ // why: a destructured top-level binding is not a simple named export and its initializer is typically a call — never treat it as a removable declaration.
1209
+ if (!ts.isIdentifier(decl.name))
1210
+ return null;
1211
+ names.push(decl.name.text);
1212
+ if (!isSideEffectFreeInitializer(decl.initializer, resolution))
1213
+ sideEffectFree = false;
1214
+ }
1215
+ return { statement, names, sideEffectFree };
1216
+ };
1217
+ const collectEsmExports = (statement, entries, surface) => {
1218
+ if (ts.isExportDeclaration(statement) &&
1219
+ !statement.moduleSpecifier &&
1220
+ statement.exportClause &&
1221
+ ts.isNamedExports(statement.exportClause)) {
1222
+ surface.add(statement);
1223
+ for (const element of statement.exportClause.elements)
1224
+ entries.push({ exported: element.name.text, local: (element.propertyName ?? element.name).text, statement, kind: 'esm-list' });
1225
+ return;
1226
+ }
1227
+ if (!hasExportModifier(statement))
1228
+ return;
1229
+ if ((ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && statement.name) {
1230
+ entries.push({ exported: statement.name.text, local: statement.name.text, statement, kind: 'esm-inline' });
1231
+ }
1232
+ else if (ts.isVariableStatement(statement)) {
1233
+ for (const decl of statement.declarationList.declarations)
1234
+ if (ts.isIdentifier(decl.name))
1235
+ entries.push({ exported: decl.name.text, local: decl.name.text, statement, kind: 'esm-inline' });
1236
+ }
1237
+ };
1238
+ const collectCjsExports = (statement, entries, surface) => {
1239
+ if (!ts.isExpressionStatement(statement) || !ts.isBinaryExpression(statement.expression))
1240
+ return;
1241
+ const { left, operatorToken, right } = statement.expression;
1242
+ if (operatorToken.kind !== ts.SyntaxKind.EqualsToken)
1243
+ return;
1244
+ if (ts.isPropertyAccessExpression(left) &&
1245
+ ts.isIdentifier(left.expression) &&
1246
+ left.expression.text === 'exports' &&
1247
+ ts.isIdentifier(left.name) &&
1248
+ ts.isIdentifier(right)) {
1249
+ surface.add(statement);
1250
+ entries.push({ exported: left.name.text, local: right.text, statement, kind: 'cjs-assign' });
1251
+ }
1252
+ };
1253
+ /**
1254
+ * Builds the structural model of a chunk: its removable declarations, import
1255
+ * sites, and export surface.
1256
+ *
1257
+ * @param sourceFile - The parsed chunk.
1258
+ * @param format - Module format selecting ESM vs CJS export/import shapes.
1259
+ * @returns The chunk model consumed by {@link computeKeepClosure}.
1260
+ *
1261
+ * @example Modeling an ESM chunk
1262
+ * ```typescript
1263
+ * const model = analyzeChunk(parseChunk(source), 'esm')
1264
+ * ```
1265
+ */
1266
+ const analyzeChunk = (sourceFile, format) => {
1267
+ const nameToDecl = createMap();
1268
+ const decls = [];
1269
+ const importStatements = [];
1270
+ // why: not named `exports` — a local `exports` shadows the module object, breaking the transpiled `(0, exports.collectBindingCanonical)` reference under isolatedModules CJS.
1271
+ const exportEntries = [];
1272
+ const exportSurfaceStatements = createSet([]);
1273
+ const resolution = collectBindingCanonical(sourceFile);
1274
+ for (const statement of sourceFile.statements) {
1275
+ if (format === 'esm' ? ts.isImportDeclaration(statement) : isRequireVarStatement(statement)) {
1276
+ importStatements.push(statement);
1277
+ continue;
1278
+ }
1279
+ const decl = tryDecl(statement, resolution);
1280
+ if (decl) {
1281
+ decls.push(decl);
1282
+ for (const name of decl.names)
1283
+ nameToDecl.set(name, decl);
1284
+ }
1285
+ if (format === 'esm')
1286
+ collectEsmExports(statement, exportEntries, exportSurfaceStatements);
1287
+ else
1288
+ collectCjsExports(statement, exportEntries, exportSurfaceStatements);
1289
+ }
1290
+ return { nameToDecl, decls, importStatements, exports: exportEntries, exportSurfaceStatements };
1291
+ };
1292
+ const collectRoots = (sourceFile, model, keep, declStatements) => {
1293
+ const roots = createSet([]);
1294
+ for (const entry of model.exports)
1295
+ if (keep.has(entry.exported))
1296
+ roots.add(entry.local);
1297
+ for (const decl of model.decls)
1298
+ if (!decl.sideEffectFree)
1299
+ for (const name of decl.names)
1300
+ roots.add(name);
1301
+ for (const statement of sourceFile.statements) {
1302
+ if (declStatements.has(statement) || model.exportSurfaceStatements.has(statement) || model.importStatements.includes(statement))
1303
+ continue;
1304
+ collectRefs(statement, roots);
1305
+ }
1306
+ return roots;
1307
+ };
1308
+ /**
1309
+ * Computes the closure of local declaration names that must be retained: every
1310
+ * kept export, every side-effecting declaration, every name referenced by a
1311
+ * bare top-level statement, and everything those transitively reference.
1312
+ *
1313
+ * @param sourceFile - The parsed chunk.
1314
+ * @param model - The chunk model from {@link analyzeChunk}.
1315
+ * @param keep - Exported names demanded by importers.
1316
+ * @returns The set of local names that may not be removed.
1317
+ *
1318
+ * @example Names that survive given a one-export demand
1319
+ * ```typescript
1320
+ * const live = computeKeepClosure(sourceFile, model, createSet(['getType']))
1321
+ * ```
1322
+ */
1323
+ const computeKeepClosure = (sourceFile, model, keep) => {
1324
+ const declStatements = createSet(model.decls.map((decl) => decl.statement));
1325
+ const refsCache = createMap();
1326
+ const refsOf = (statement) => {
1327
+ const cached = refsCache.get(statement);
1328
+ if (cached)
1329
+ return cached;
1330
+ const refs = createSet([]);
1331
+ collectRefs(statement, refs);
1332
+ refsCache.set(statement, refs);
1333
+ return refs;
1334
+ };
1335
+ const keepClosure = createSet([]);
1336
+ const stack = from(collectRoots(sourceFile, model, keep, declStatements));
1337
+ while (stack.length > 0) {
1338
+ const name = stack.pop();
1339
+ if (keepClosure.has(name))
1340
+ continue;
1341
+ keepClosure.add(name);
1342
+ const decl = model.nameToDecl.get(name);
1343
+ if (!decl)
1344
+ continue;
1345
+ for (const ref of refsOf(decl.statement))
1346
+ if (!keepClosure.has(ref))
1347
+ stack.push(ref);
1348
+ }
1349
+ return keepClosure;
1350
+ };
1351
+
1352
+ /**
1353
+ * Classifies every free identifier referenced by a module's declarations,
1354
+ * partitioning them into cross-module edges, dependency edges, and hard
1355
+ * blockers.
1356
+ *
1357
+ * Identifiers the module declares itself are intra-chunk and ignored. A name
1358
+ * that is neither owned, nor a dependency binding, nor a top-level entry
1359
+ * declaration is a runtime global and needs no import. Cross-module references
1360
+ * are always safe to lift because {@link planHoists} only keeps an acyclic
1361
+ * subset, so every dependency chunk is fully evaluated before its dependent.
1362
+ *
1363
+ * @param decls - The module's canonical declarations.
1364
+ * @param owners - First-party ownership index.
1365
+ * @param importBindings - The consuming entry's import bindings.
1366
+ * @param entryDeclNames - Every top-level declaration name in the entry.
1367
+ * @param selfModuleKey - The module being resolved.
1368
+ * @returns The reference resolution.
1369
+ *
1370
+ * @example Resolving a module's references
1371
+ * ```typescript
1372
+ * const resolution = resolveModuleRefs(decls, owners, parsed.importBindings, parsed.declNames, 'events/events')
1373
+ * ```
1374
+ */
1375
+ const resolveModuleRefs = (decls, owners, importBindings, entryDeclNames, selfModuleKey) => {
1376
+ const selfLocals = createSet(decls.map((decl) => decl.localName));
1377
+ const allRefs = createSet([]);
1378
+ for (const decl of decls)
1379
+ collectRefs(decl.statement, allRefs);
1380
+ const crossModule = [];
1381
+ const depImports = [];
1382
+ const unresolved = [];
1383
+ for (const ref of allRefs) {
1384
+ if (selfLocals.has(ref))
1385
+ continue;
1386
+ const base = baseName(ref);
1387
+ const owner = owners.ownerOf.get(base);
1388
+ if (owner !== undefined) {
1389
+ if (owner !== selfModuleKey)
1390
+ crossModule.push({ ref, base, moduleKey: owner });
1391
+ continue;
1392
+ }
1393
+ const binding = importBindings.get(ref);
1394
+ if (binding !== undefined) {
1395
+ depImports.push({ ref, binding });
1396
+ continue;
1397
+ }
1398
+ if (entryDeclNames.has(ref))
1399
+ unresolved.push(ref);
1400
+ }
1401
+ return { crossModule, depImports, unresolved };
1402
+ };
1403
+ const namedBinding = (local, imported) => (imported === local ? local : `${imported} as ${local}`);
1404
+ const cjsBinding$1 = (local, imported) => (imported === local ? local : `${imported}: ${local}`);
1405
+ const groupBySpecifier = (items, specifierOf) => {
1406
+ const groups = createMap();
1407
+ for (const item of items) {
1408
+ const group = groups.get(specifierOf(item)) ?? [];
1409
+ group.push(item);
1410
+ groups.set(specifierOf(item), group);
1411
+ }
1412
+ return from(groups.entries()).sort(([a], [b]) => (a < b ? -1 : 1));
1413
+ };
1414
+ const renderEsmImports = (crossImports, depImports) => {
1415
+ const lines = [];
1416
+ for (const [specifier, group] of groupBySpecifier(crossImports, (c) => c.specifier))
1417
+ lines.push(`import { ${group.map((c) => namedBinding(c.ref, c.exported)).join(', ')} } from '${specifier}';`);
1418
+ for (const dep of depImports.filter((d) => d.kind === 'namespace'))
1419
+ lines.push(`import * as ${dep.ref} from '${dep.specifier}';`);
1420
+ for (const dep of depImports.filter((d) => d.kind === 'default'))
1421
+ lines.push(`import ${dep.ref} from '${dep.specifier}';`);
1422
+ for (const [specifier, group] of groupBySpecifier(depImports.filter((d) => d.kind === 'named'), (d) => d.specifier))
1423
+ lines.push(`import { ${group.map((d) => namedBinding(d.ref, d.imported ?? d.ref)).join(', ')} } from '${specifier}';`);
1424
+ return lines;
1425
+ };
1426
+ const renderCjsRequires = (crossImports, depImports) => {
1427
+ const lines = [];
1428
+ for (const [specifier, group] of groupBySpecifier(crossImports, (c) => c.specifier))
1429
+ lines.push(`const { ${group.map((c) => cjsBinding$1(c.ref, c.exported)).join(', ')} } = require('${specifier}');`);
1430
+ for (const dep of depImports.filter((d) => d.kind === 'cjs-namespace'))
1431
+ lines.push(`const ${dep.ref} = require('${dep.specifier}');`);
1432
+ for (const [specifier, group] of groupBySpecifier(depImports.filter((d) => d.kind === 'cjs-named'), (d) => d.specifier))
1433
+ lines.push(`const { ${group.map((d) => cjsBinding$1(d.ref, d.imported ?? d.ref)).join(', ')} } = require('${specifier}');`);
1434
+ return lines;
1435
+ };
1436
+ const renderEsmExports = (decls) => `export { ${decls.map((decl) => (decl.localName === decl.base ? decl.base : `${decl.localName} as ${decl.base}`)).join(', ')} };`;
1437
+ const renderCjsExports = (decls) => decls.map((decl) => `exports.${decl.base} = ${decl.localName};`).join('\n');
1438
+ /**
1439
+ * Renders a hoisted module chunk: its resolved imports, the union of its
1440
+ * declarations, and an export surface naming each declaration by its base name.
1441
+ *
1442
+ * @param plan - The module's declarations plus resolved import edges.
1443
+ * @param format - Output module format.
1444
+ * @returns The chunk source text.
1445
+ *
1446
+ * @example Rendering an ESM chunk
1447
+ * ```typescript
1448
+ * const source = renderChunk({ decls, crossImports: [], depImports: [] }, 'esm')
1449
+ * ```
1450
+ */
1451
+ const renderChunk = (plan, format) => {
1452
+ const body = plan.decls.map((decl) => decl.text).join('\n');
1453
+ if (format === 'esm') {
1454
+ const imports = renderEsmImports(plan.crossImports, plan.depImports);
1455
+ const blocks = imports.length > 0 ? [imports.join('\n'), body, renderEsmExports(plan.decls)] : [body, renderEsmExports(plan.decls)];
1456
+ return `${blocks.join('\n\n')}\n`;
1457
+ }
1458
+ const requires = renderCjsRequires(plan.crossImports, plan.depImports);
1459
+ const blocks = requires.length > 0
1460
+ ? ["'use strict';", requires.join('\n'), body, renderCjsExports(plan.decls)]
1461
+ : ["'use strict';", body, renderCjsExports(plan.decls)];
1462
+ return `${blocks.join('\n\n')}\n`;
1463
+ };
1464
+
1465
+ const invertOwners = (owners) => {
1466
+ const byModule = createMap();
1467
+ for (const [base, moduleKey] of owners.ownerOf) {
1468
+ const names = byModule.get(moduleKey) ?? createSet([]);
1469
+ names.add(base);
1470
+ byModule.set(moduleKey, names);
1471
+ }
1472
+ return byModule;
1473
+ };
1474
+ const collectAppearances = (entries) => {
1475
+ const appearances = createMap();
1476
+ for (const [index, entry] of entries.entries())
1477
+ for (const moduleKey of entry.byModule.keys()) {
1478
+ const list = appearances.get(moduleKey) ?? [];
1479
+ list.push(index);
1480
+ appearances.set(moduleKey, list);
1481
+ }
1482
+ return appearances;
1483
+ };
1484
+ // why: a bare statement (multi-declarator var, enum IIFE, side-effecting init) that names one of the module's symbols cannot be cleanly split out — its symbol would vanish from the chunk; leave the whole module inlined.
1485
+ const isEntangled = (entries, indexes, ownedNames) => indexes.some((index) => entries[index].parsed.bareStatements.some((statement) => {
1486
+ const refs = createSet([]);
1487
+ collectRefs(statement, refs);
1488
+ return from(refs).some((ref) => ownedNames.has(baseName(ref)));
1489
+ }));
1490
+ const pickCanonical = (entries, moduleKey, indexes) => indexes.reduce((best, index) => (entries[index].byModule.get(moduleKey) ?? []).length > (entries[best].byModule.get(moduleKey) ?? []).length ? index : best);
1491
+ const isConsistentCopy = (canonicalFingerprint, order, decls) => {
1492
+ let previous = -1;
1493
+ for (const decl of decls) {
1494
+ const index = order.get(decl.base);
1495
+ // why: a copy that names a declaration absent from the canonical superset, reorders it, or differs structurally (rename-insensitive fingerprint) is not provably the same code.
1496
+ if (index === undefined || index <= previous || canonicalFingerprint.get(decl.base) !== decl.fingerprint)
1497
+ return false;
1498
+ previous = index;
1499
+ }
1500
+ return true;
1501
+ };
1502
+ const planCandidate = (entries, owners, moduleKey, indexes, ownedNames) => {
1503
+ if (isEntangled(entries, indexes, ownedNames))
1504
+ return null;
1505
+ const canonicalEntryIndex = pickCanonical(entries, moduleKey, indexes);
1506
+ const canonicalDecls = entries[canonicalEntryIndex].byModule.get(moduleKey) ?? [];
1507
+ // why: identity gates on the rename-insensitive fingerprint, but chunk rendering still uses each decl's raw `text` via canonicalDecls.
1508
+ const canonicalFingerprint = createMap();
1509
+ const order = createMap();
1510
+ for (const [index, decl] of canonicalDecls.entries()) {
1511
+ canonicalFingerprint.set(decl.base, decl.fingerprint);
1512
+ order.set(decl.base, index);
1513
+ }
1514
+ for (const index of indexes)
1515
+ if (!isConsistentCopy(canonicalFingerprint, order, entries[index].byModule.get(moduleKey) ?? []))
1516
+ return null;
1517
+ const canonical = entries[canonicalEntryIndex].parsed;
1518
+ const resolution = resolveModuleRefs(canonicalDecls, owners, canonical.importBindings, canonical.declNames, moduleKey);
1519
+ if (resolution.unresolved.length > 0)
1520
+ return null;
1521
+ return { canonicalEntryIndex, decls: canonicalDecls, resolution, consumingEntryIndexes: indexes };
1522
+ };
1523
+ const closeOverDependencies = (candidates) => {
1524
+ let changed = true;
1525
+ while (changed) {
1526
+ changed = false;
1527
+ for (const [moduleKey, planned] of candidates)
1528
+ if (planned.resolution.crossModule.some((ref) => !candidates.has(ref.moduleKey))) {
1529
+ candidates.delete(moduleKey);
1530
+ changed = true;
1531
+ }
1532
+ }
1533
+ return candidates;
1534
+ };
1535
+ // why: shared chunks load topologically, so an acyclic dependency graph guarantees every chunk is fully evaluated before its dependents — no cross-chunk temporal-dead-zone. Modules in (or feeding) a cycle cannot be ordered safely, so they are peeled off and left inlined.
1536
+ const keepAcyclic = (candidates) => {
1537
+ const depsOf = createMap();
1538
+ for (const [moduleKey, planned] of candidates)
1539
+ depsOf.set(moduleKey, planned.resolution.crossModule.map((ref) => ref.moduleKey));
1540
+ const pending = createSet(candidates.keys());
1541
+ let changed = true;
1542
+ while (changed) {
1543
+ changed = false;
1544
+ for (const [moduleKey, deps] of depsOf)
1545
+ if (pending.has(moduleKey) && deps.every((dep) => !pending.has(dep))) {
1546
+ pending.delete(moduleKey);
1547
+ changed = true;
1548
+ }
1549
+ }
1550
+ for (const moduleKey of pending)
1551
+ candidates.delete(moduleKey);
1552
+ return candidates;
1553
+ };
1554
+ /**
1555
+ * Plans which first-party modules can be hoisted into shared chunks.
1556
+ *
1557
+ * A module qualifies only when it is inlined into at least two entries, is not
1558
+ * entangled with a bare statement, presents structurally identical declarations
1559
+ * (rename-insensitive) in a consistent order across every copy, references
1560
+ * nothing unresolvable, and —
1561
+ * after closure and acyclic peeling — depends only on other hoisted modules
1562
+ * through a cycle-free graph. Anything failing these is left inlined, so the
1563
+ * worst case equals the unmodified output.
1564
+ *
1565
+ * @param entries - Parsed entries with their per-module attribution.
1566
+ * @param owners - First-party ownership index.
1567
+ * @returns Map from module key to its hoist plan.
1568
+ *
1569
+ * @example Planning hoists for a set of entries
1570
+ * ```typescript
1571
+ * const plan = planHoists(entries, owners)
1572
+ * ```
1573
+ */
1574
+ const planHoists = (entries, owners) => {
1575
+ const ownedNames = invertOwners(owners);
1576
+ const candidates = createMap();
1577
+ for (const [moduleKey, indexes] of collectAppearances(entries)) {
1578
+ if (indexes.length < 2)
1579
+ continue;
1580
+ const planned = planCandidate(entries, owners, moduleKey, indexes, ownedNames.get(moduleKey) ?? createSet([]));
1581
+ if (planned)
1582
+ candidates.set(moduleKey, planned);
1583
+ }
1584
+ return keepAcyclic(closeOverDependencies(candidates));
1585
+ };
1586
+
1587
+ const esmBinding = (decl) => (decl.base === decl.localName ? decl.base : `${decl.base} as ${decl.localName}`);
1588
+ const cjsBinding = (decl) => (decl.base === decl.localName ? decl.base : `${decl.base}: ${decl.localName}`);
1589
+ const renderImport = (hoist, format) => format === 'esm'
1590
+ ? `import { ${hoist.decls.map(esmBinding).join(', ')} } from '${hoist.specifier}';`
1591
+ : `const { ${hoist.decls.map(cjsBinding).join(', ')} } = require('${hoist.specifier}');`;
1592
+ const applyEdits$1 = (source, edits) => {
1593
+ let code = source;
1594
+ for (const edit of from(edits).sort((a, b) => b.start - a.start))
1595
+ code = `${code.slice(0, edit.start)}${edit.text}${code.slice(edit.end)}`;
1596
+ // why: splicing whole statements leaves runs of blank lines; collapse them so the trimmed entry stays readable.
1597
+ return code.replace(/\n{3,}/g, '\n\n');
1598
+ };
1599
+ // why: liveness over-approximates — every identifier node (property names included) counts as a use, so trimming an import can only drop a name nothing references, never one that survives.
1600
+ const collectIdentifierNames = (source) => {
1601
+ const names = createSet([]);
1602
+ const visit = (node) => {
1603
+ if (ts.isIdentifier(node))
1604
+ names.add(node.text);
1605
+ ts.forEachChild(node, visit);
1606
+ };
1607
+ visit(parseChunk(source));
1608
+ return names;
1609
+ };
1610
+ /**
1611
+ * Rewrites an entry bundle to consume hoisted modules from `_shared/` chunks
1612
+ * instead of inlining them.
1613
+ *
1614
+ * Splices every hoisted declaration (and its leading comments) out of the entry
1615
+ * and prepends an import/`require` binding the chunk's base export to the
1616
+ * entry's local name — aliasing when rollup renamed the local (`foo as foo$1`).
1617
+ * Only the hoisted symbols the entry still references after splicing are
1618
+ * re-imported: a private helper used solely by another hoisted export (e.g. a
1619
+ * reducer's `handlers`, used only by the hoisted `rootReducer`) is seen as dead
1620
+ * against the spliced body and omitted from the import, while the chunk it lives
1621
+ * in keeps it. The bundle's export surface is left untouched: surviving spliced
1622
+ * names are now supplied by the inserted imports, so the published API is
1623
+ * byte-for-byte identical to before.
1624
+ *
1625
+ * @param parsed - The parsed entry bundle.
1626
+ * @param hoists - The modules hoisted out of this entry, each with its chunk specifier.
1627
+ * @param format - Output module format.
1628
+ * @returns The rewritten entry source, or the original source when `hoists` is empty.
1629
+ *
1630
+ * @example Rewriting an entry to import a shared module
1631
+ * ```typescript
1632
+ * const rewritten = rewriteEntry(parseEntry(source, 'esm'), [{ decls, specifier: './_shared/state/index.esm.js' }], 'esm')
1633
+ * ```
1634
+ */
1635
+ const rewriteEntry = (parsed, hoists, format) => {
1636
+ if (hoists.length === 0)
1637
+ return parsed.sourceFile.text;
1638
+ const deletions = [];
1639
+ for (const hoist of hoists)
1640
+ for (const decl of hoist.decls)
1641
+ deletions.push({ start: decl.statement.getFullStart(), end: decl.statement.getEnd(), text: '' });
1642
+ // why: liveness is measured on the body WITHOUT the hoisted decls (and before re-inserting imports), so a private symbol used only by another hoisted decl (e.g. `handlers`, used only by the hoisted `rootReducer`) is correctly seen as dead and never re-imported.
1643
+ const spliced = applyEdits$1(parsed.sourceFile.text, deletions);
1644
+ const live = collectIdentifierNames(spliced);
1645
+ const liveHoists = hoists
1646
+ .map((hoist) => ({ ...hoist, decls: hoist.decls.filter((decl) => live.has(decl.localName)) }))
1647
+ .filter((hoist) => hoist.decls.length > 0);
1648
+ if (liveHoists.length === 0)
1649
+ return spliced;
1650
+ const block = liveHoists.map((hoist) => renderImport(hoist, format)).join('\n');
1651
+ const insertion = parsed.headerEnd > 0 ? `\n${block}` : `${block}\n`;
1652
+ return applyEdits$1(parsed.sourceFile.text, [...deletions, { start: parsed.headerEnd, end: parsed.headerEnd, text: insertion }]);
1653
+ };
1654
+
1655
+ const log$6 = logger.channel('builder:bundle:dedupe');
1656
+ const FORMATS = ['esm', 'cjs'];
1657
+ const toSpecifier = (relative) => (relative.startsWith('.') ? relative : `./${relative}`);
1658
+ const recomputeSpecifier = (specifier, fromDir, baseDir) =>
1659
+ // why: relative `_dependencies`/`_shared` edges move with the chunk; bare and node-builtin specifiers resolve identically from anywhere, so they pass through verbatim.
1660
+ specifier.startsWith('.') ? toSpecifier(relativePath(fromDir, join$2(baseDir, specifier))) : specifier;
1661
+ const locateEntries = (context, format) => {
1662
+ const locations = [];
1663
+ for (const entry of context.entryPointDiscovery.entryPoints) {
1664
+ const dir = entryDirOf(entry, context);
1665
+ const file = join$2(dir, chunkFileName(format));
1666
+ if (exists(file))
1667
+ locations.push({ dir, file });
1668
+ }
1669
+ return locations;
1670
+ };
1671
+ const chunkFileFor = (context, moduleKey, format) => join$2(context.outputPath, sharedDirFor(moduleKey), chunkFileName(format));
1672
+ const buildChunkPlan = (planned, context, chunkDir, canonicalDir, format) => {
1673
+ const crossImports = planned.resolution.crossModule.map((ref) => ({
1674
+ ref: ref.ref,
1675
+ exported: ref.base,
1676
+ specifier: toSpecifier(relativePath(chunkDir, chunkFileFor(context, ref.moduleKey, format))),
1677
+ }));
1678
+ const depImports = planned.resolution.depImports.map((dep) => ({
1679
+ ref: dep.ref,
1680
+ kind: dep.binding.kind,
1681
+ imported: dep.binding.imported,
1682
+ specifier: recomputeSpecifier(dep.binding.specifier, chunkDir, canonicalDir),
1683
+ }));
1684
+ return { decls: planned.decls, crossImports, depImports };
1685
+ };
1686
+ const writeChunks = (context, plan, locations, format, report) => {
1687
+ for (const [moduleKey, planned] of plan) {
1688
+ const chunkDir = join$2(context.outputPath, sharedDirFor(moduleKey));
1689
+ const chunkPlan = buildChunkPlan(planned, context, chunkDir, locations[planned.canonicalEntryIndex].dir, format);
1690
+ const source = renderChunk(chunkPlan, format);
1691
+ ensureDir(chunkDir);
1692
+ writeFileContent(chunkFileFor(context, moduleKey, format), source);
1693
+ report.chunksWritten += 1;
1694
+ report.bytesReclaimed -= Buffer.byteLength(source);
1695
+ }
1696
+ };
1697
+ const rewriteEntries = (context, plan, entries, locations, format, report) => {
1698
+ for (const [index, entry] of entries.entries()) {
1699
+ const hoists = [];
1700
+ for (const [moduleKey] of plan) {
1701
+ const decls = entry.byModule.get(moduleKey);
1702
+ if (decls === undefined)
1703
+ continue;
1704
+ hoists.push({
1705
+ decls,
1706
+ specifier: toSpecifier(relativePath(locations[index].dir, chunkFileFor(context, moduleKey, format))),
1707
+ });
1708
+ for (const decl of decls)
1709
+ report.bytesReclaimed += Buffer.byteLength(decl.text);
1710
+ }
1711
+ if (hoists.length > 0)
1712
+ writeFileContent(locations[index].file, rewriteEntry(entry.parsed, hoists, format));
1713
+ }
1714
+ };
1715
+ const processFormat$2 = (context, owners, format, report) => {
1716
+ const locations = locateEntries(context, format);
1717
+ if (locations.length < 2)
1718
+ return;
1719
+ const entries = locations.map((location) => {
1720
+ const parsed = parseEntry(readFileContent(location.file), format);
1721
+ return { parsed, byModule: attribute(parsed, owners) };
1722
+ });
1723
+ const plan = planHoists(entries, owners);
1724
+ if (plan.size === 0)
1725
+ return;
1726
+ writeChunks(context, plan, locations, format, report);
1727
+ rewriteEntries(context, plan, entries, locations, format, report);
1728
+ };
1729
+ /**
1730
+ * Lifts first-party modules that are inlined into multiple entry bundles into
1731
+ * shared `_shared/<srcPath>/index.<fmt>.js` chunks and rewrites every consuming
1732
+ * entry to import them.
1733
+ *
1734
+ * Runs as an additive post-emit pass over the already-bundled `esm` and `cjs`
1735
+ * outputs, each processed independently; `iife`/`umd`/`bin` and `.d.ts` outputs
1736
+ * are never read. Per-entry isolated bundling is untouched. Every hoist is
1737
+ * proven safe by {@link planHoists} before it happens — structurally identical
1738
+ * copies, resolvable references, and cycle-free module-initialization — so any module
1739
+ * that cannot be proven safe is left inlined and the output is, worst case,
1740
+ * identical to the input.
1741
+ *
1742
+ * @param context - Resolved build context. `outputPath` locates the bundles and
1743
+ * `projectRoot/src` drives ownership attribution.
1744
+ * @param monitor - Optional memory monitor; a checkpoint is captured after each
1745
+ * format so the pass is observable.
1746
+ * @returns Counts of chunks written and net bytes reclaimed.
1747
+ *
1748
+ * @example Hoisting after the dependency prune
1749
+ * ```typescript
1750
+ * const report = hoistSharedFirstParty(context, monitor)
1751
+ * ```
1752
+ */
1753
+ const hoistSharedFirstParty = (context, monitor) => {
1754
+ const report = { chunksWritten: 0, bytesReclaimed: 0 };
1755
+ const srcRoot = join$2(context.projectRoot, 'src');
1756
+ if (!exists(srcRoot))
1757
+ return report;
1758
+ const owners = indexOwners(srcRoot);
1759
+ for (const format of FORMATS) {
1760
+ processFormat$2(context, owners, format, report);
1761
+ monitor?.check(`bundle:dedupe:shared-first-party:${format}:end`);
1762
+ }
1763
+ if (report.chunksWritten > 0)
1764
+ log$6.info(`hoisted ${report.chunksWritten} shared chunk(s), reclaimed ${report.bytesReclaimed} byte(s)`);
1765
+ return report;
1766
+ };
1767
+
1768
+ /**
1769
+ * Applies text-range edits to a chunk source by splicing each span in
1770
+ * descending start order, so every edit's offsets stay valid against the
1771
+ * original source regardless of the order they are passed in. All offsets must
1772
+ * refer to the original `source`, and spans must not overlap. The input `edits`
1773
+ * array is copied before sorting, so the caller's order is left untouched.
1774
+ *
1775
+ * @param source - Original chunk source text.
1776
+ * @param edits - Edits to apply; their relative order does not matter.
1777
+ * @param collapseBlankLines - When `true`, runs of three or more newlines left
1778
+ * behind by whole-statement splices are collapsed to a single blank line so the
1779
+ * trimmed chunk stays readable. Defaults to `false`.
1780
+ * @returns The rewritten source.
1781
+ *
1782
+ * @example Deleting a statement and collapsing the blank run it leaves
1783
+ * ```typescript
1784
+ * applyEdits(source, [{ start, end, text: '' }], true)
1785
+ * ```
1786
+ */
1787
+ const applyEdits = (source, edits, collapseBlankLines = false) => {
1788
+ let code = source;
1789
+ for (const edit of [...edits].sort((a, b) => b.start - a.start))
1790
+ code = `${code.slice(0, edit.start)}${edit.text}${code.slice(edit.end)}`;
1791
+ // why: splicing whole statements leaves runs of blank lines; collapse them so the trimmed chunk stays readable.
1792
+ return collapseBlankLines ? code.replace(/\n{3,}/g, '\n\n') : code;
1793
+ };
1794
+
1795
+ const renderEsmExportList = (entries) => `export { ${entries.map((entry) => (entry.exported === entry.local ? entry.local : `${entry.local} as ${entry.exported}`)).join(', ')} };`;
1796
+ const renderEsmImport = (elements, specifierText) => {
1797
+ const bindings = elements.map((element) => {
1798
+ const imported = (element.propertyName ?? element.name).text;
1799
+ return imported === element.name.text ? imported : `${imported} as ${element.name.text}`;
1800
+ });
1801
+ return `import { ${bindings.join(', ')} } from ${specifierText};`;
1802
+ };
1803
+ const narrowEsmImport = (statement, usedNames, sourceFile, edits) => {
1804
+ const clause = statement.importClause;
1805
+ // why: default and namespace imports bind the whole module object — never narrowed.
1806
+ if (!clause || clause.name || !clause.namedBindings || !ts.isNamedImports(clause.namedBindings))
1807
+ return;
1808
+ const surviving = clause.namedBindings.elements.filter((element) => usedNames.has(element.name.text));
1809
+ if (surviving.length === clause.namedBindings.elements.length)
1810
+ return;
1811
+ if (surviving.length === 0)
1812
+ edits.push({ start: statement.getFullStart(), end: statement.getEnd(), text: '' });
1813
+ else
1814
+ edits.push({
1815
+ start: statement.getStart(sourceFile),
1816
+ end: statement.getEnd(),
1817
+ text: renderEsmImport(surviving, statement.moduleSpecifier.getText(sourceFile)),
1818
+ });
1819
+ };
1820
+ const narrowCjsRequire = (statement, usedNames, edits) => {
1821
+ const locals = requireBindingLocals(statement);
1822
+ if (locals.length > 0 && locals.every((local) => !usedNames.has(local)))
1823
+ edits.push({ start: statement.getFullStart(), end: statement.getEnd(), text: '' });
1824
+ };
1825
+ const collectExportEdits = (exports$1, removedLocals, sourceFile, edits) => {
1826
+ const listGroups = createMap();
1827
+ for (const entry of exports$1) {
1828
+ if (entry.kind === 'cjs-assign' && removedLocals.has(entry.local))
1829
+ edits.push({ start: entry.statement.getFullStart(), end: entry.statement.getEnd(), text: '' });
1830
+ if (entry.kind !== 'esm-list')
1831
+ continue;
1832
+ const group = listGroups.get(entry.statement) ?? [];
1833
+ group.push(entry);
1834
+ listGroups.set(entry.statement, group);
1835
+ }
1836
+ for (const [statement, group] of listGroups) {
1837
+ const surviving = group.filter((entry) => !removedLocals.has(entry.local));
1838
+ if (surviving.length === group.length)
1839
+ continue;
1840
+ if (surviving.length === 0)
1841
+ edits.push({ start: statement.getFullStart(), end: statement.getEnd(), text: '' });
1842
+ else
1843
+ edits.push({ start: statement.getStart(sourceFile), end: statement.getEnd(), text: renderEsmExportList(surviving) });
1844
+ }
1845
+ };
1846
+ /**
1847
+ * Removes guaranteed-dead exported declarations (and the now-dead private code
1848
+ * and imports they pulled in) from a single chunk's source.
1849
+ *
1850
+ * Builds the chunk's declaration/export model, computes the keep-closure from
1851
+ * the importer-supplied `keep` demand, and splices out every side-effect-free
1852
+ * top-level declaration that no kept declaration, kept export, or bare
1853
+ * side-effecting statement references. The matching entries are dropped from the
1854
+ * export surface, and import bindings left unreferenced by the surviving code are
1855
+ * narrowed away (whole import statements when fully unused) — which is what
1856
+ * shrinks the cross-chunk dependency graph for the next fixpoint pass.
1857
+ * Side-effecting initializers and bare statements are always kept.
1858
+ *
1859
+ * @param source - Raw chunk source text.
1860
+ * @param format - Module format of the chunk.
1861
+ * @param keep - Exported names importers demand, or `'all'` to keep everything.
1862
+ * @returns The rewritten source and removed export names, or `null` when nothing
1863
+ * could be removed.
1864
+ *
1865
+ * @example Stripping all but one export from a chunk
1866
+ * ```typescript
1867
+ * stripDeadExports(source, 'esm', createSet(['getType']))
1868
+ * ```
1869
+ */
1870
+ const stripDeadExports = (source, format, keep) => {
1871
+ if (keep === 'all')
1872
+ return null;
1873
+ const sourceFile = parseChunk(source);
1874
+ const model = analyzeChunk(sourceFile, format);
1875
+ const keepClosure = computeKeepClosure(sourceFile, model, keep);
1876
+ const removableDecls = model.decls.filter((decl) => decl.sideEffectFree && decl.names.every((name) => !keepClosure.has(name)));
1877
+ if (removableDecls.length === 0)
1878
+ return null;
1879
+ const removedLocals = createSet([]);
1880
+ for (const decl of removableDecls)
1881
+ for (const name of decl.names)
1882
+ removedLocals.add(name);
1883
+ const removeSet = createSet(removableDecls.map((decl) => decl.statement));
1884
+ const removedNames = createSet([]);
1885
+ for (const entry of model.exports)
1886
+ if (removedLocals.has(entry.local))
1887
+ removedNames.add(entry.exported);
1888
+ const usedNames = createSet([]);
1889
+ for (const statement of sourceFile.statements) {
1890
+ if (model.importStatements.includes(statement) || removeSet.has(statement))
1891
+ continue;
1892
+ collectRefs(statement, usedNames);
1893
+ }
1894
+ const edits = removableDecls.map((decl) => ({ start: decl.statement.getFullStart(), end: decl.statement.getEnd(), text: '' }));
1895
+ collectExportEdits(model.exports, removedLocals, sourceFile, edits);
1896
+ for (const statement of model.importStatements) {
1897
+ if (format === 'esm')
1898
+ narrowEsmImport(statement, usedNames, sourceFile, edits);
1899
+ else
1900
+ narrowCjsRequire(statement, usedNames, edits);
1901
+ }
1902
+ return { code: applyEdits(source, edits, true), removedNames: from(removedNames) };
1903
+ };
1904
+
1905
+ const log$5 = logger.channel('builder:bundle:dependencies:prune');
1906
+ /**
1907
+ * Computes the set of files reachable from a set of root files by following
1908
+ * literal relative specifiers, restricted to targets under `depsRoot`.
1909
+ *
1910
+ * Targets that resolve outside `depsRoot` (the package's own non-dependency
1911
+ * code) are ignored; the roots themselves are always included so callers can use
1912
+ * the returned set as a single live-membership oracle.
1913
+ *
1914
+ * If a reached file **under `depsRoot`** contains a dynamic (non-literal)
1915
+ * `import(`/`require(`, the dependency chunk graph cannot be fully resolved, so
1916
+ * the function logs and returns `null` — the guaranteed-safe sentinel that
1917
+ * disables orphan deletion for the run. A dynamic specifier in a first-party
1918
+ * **root** (which is never under `depsRoot`) is ignored: its target is always an
1919
+ * external/user path, never a bundled dep chunk, so it cannot hide a
1920
+ * `_dependencies/` edge — bailing on it would needlessly strand emptied dep
1921
+ * chunks the sweep should reclaim.
1922
+ *
1923
+ * @param roots - Absolute paths to the root files reachability starts from.
1924
+ * @param depsRoot - Absolute path to the `_dependencies/` directory; traversal
1925
+ * never leaves it.
1926
+ * @param resolveTarget - Maps each resolved specifier target before it is
1927
+ * visited; defaults to identity. The d.ts pass passes a mapper that rewrites a
1928
+ * runtime specifier (`'.../index.js'`) to its declaration sibling
1929
+ * (`'.../index.d.ts'`) so traversal follows the type graph, never the runtime
1930
+ * graph.
1931
+ * @returns The set of reachable absolute file paths, or `null` when a dynamic
1932
+ * specifier forces a safety bail.
1933
+ *
1934
+ * @example Reachability from an ESM entry chunk
1935
+ * ```typescript
1936
+ * const live = computeReachable(['/dist/libs/foo/index.esm.js'], '/dist/libs/foo/_dependencies')
1937
+ * if (live && !live.has(orphanChunk)) unlinkSync(orphanChunk)
1938
+ * ```
1939
+ */
1940
+ const computeReachable = (roots, depsRoot, resolveTarget = (target) => target) => {
1941
+ const reachable = createSet([]);
1942
+ const queue = [];
1943
+ for (const root of roots) {
1944
+ if (exists(root) && !reachable.has(root)) {
1945
+ reachable.add(root);
1946
+ queue.push(root);
1947
+ }
1948
+ }
1949
+ let head = 0;
1950
+ while (head < queue.length) {
1951
+ const file = queue[head];
1952
+ head += 1;
1953
+ const source = readFileContent(file);
1954
+ // why: a dynamic specifier only threatens the sweep when it sits in a `_dependencies/` chunk, where it can hide an intra-deps edge to a sibling chunk we'd otherwise delete. First-party entry roots legitimately carry dynamic `import(<expr>)` (e.g. runtime config loading) whose targets are always external user paths — never bundled dep chunks — so bailing on those needlessly disables the entire sweep and strands emptied dep chunks. Roots are never under `depsRoot` (collectEntryFiles excludes them), so this scopes the bail to dep chunks only.
1955
+ if (isUnderDir(file, depsRoot) && hasDynamicSpecifier(source)) {
1956
+ log$5.warn(`dynamic import/require in ${file}; skipping dependency orphan prune for safety`);
1957
+ return null;
1958
+ }
1959
+ const dir = getDirname(file);
1960
+ for (const spec of collectChunkSpecifiers(source)) {
1961
+ const target = resolveTarget(join$2(dir, spec));
1962
+ if (isUnderDir(target, depsRoot) && exists(target) && !reachable.has(target)) {
1963
+ reachable.add(target);
1964
+ queue.push(target);
1965
+ }
1966
+ }
1967
+ }
1968
+ return reachable;
1969
+ };
1970
+
1971
+ /**
1972
+ * Resolves the package's own entry output files for the given file names,
1973
+ * skipping any entry directory that resolves at or under `_dependencies/`.
1974
+ *
1975
+ * These are the reachability/usage roots: the chunks a consumer's package entry
1976
+ * points actually load, from which dependency code is reached.
1977
+ *
1978
+ * @param context - Resolved build context supplying the entry points.
1979
+ * @param depsRoot - Absolute path to the `_dependencies/` directory.
1980
+ * @param fileNames - Output file names to look for in each entry directory
1981
+ * (e.g. `['index.esm.js']`).
1982
+ * @returns Absolute paths of every entry file that exists on disk.
1983
+ *
1984
+ * @example Collecting ESM entry roots
1985
+ * ```typescript
1986
+ * const roots = collectEntryFiles(context, depsRoot, ['index.esm.js'])
1987
+ * ```
1988
+ */
1989
+ const collectEntryFiles = (context, depsRoot, fileNames) => {
1990
+ const files = [];
1991
+ for (const entry of context.entryPointDiscovery.entryPoints) {
1992
+ const dir = entryDirOf(entry, context);
1993
+ if (isUnderDir(dir, depsRoot))
1994
+ continue;
1995
+ for (const name of fileNames) {
1996
+ const candidate = join$2(dir, name);
1997
+ if (exists(candidate))
1998
+ files.push(candidate);
1999
+ }
2000
+ }
2001
+ return files;
2002
+ };
2003
+ /**
2004
+ * Recursively collects file paths under `dir` whose base name satisfies
2005
+ * `matches`, appending them to `acc`.
2006
+ *
2007
+ * @param dir - Directory to walk; assumed to exist (the `_dependencies/` root or
2008
+ * a directory yielded by `readDirectory`).
2009
+ * @param matches - Predicate over a file's base name.
2010
+ * @param acc - Accumulator that receives every matching absolute path.
2011
+ *
2012
+ * @example Gathering every ESM chunk
2013
+ * ```typescript
2014
+ * const chunks: string[] = []
2015
+ * walkFiles(depsRoot, (name) => name === 'index.esm.js', chunks)
2016
+ * ```
2017
+ */
2018
+ const walkFiles = (dir, matches, acc) => {
2019
+ // why: only ever called on the validated `_dependencies/` root or a directory from `readDirectory`, so the target always exists — no existence guard needed.
2020
+ for (const entry of readDirectory(dir)) {
2021
+ if (entry.isDirectory)
2022
+ walkFiles(entry.path, matches, acc);
2023
+ else if (matches(entry.name))
2024
+ acc.push(entry.path);
2025
+ }
2026
+ };
2027
+ const unlinkWithMap = (path) => {
2028
+ // why: the caller only passes paths it just enumerated from disk, so statSync never misses.
2029
+ let bytesRemoved = statSync(path).size;
2030
+ let orphanFilesRemoved = 1;
2031
+ unlinkSync(path);
2032
+ const mapPath = `${path}.map`;
2033
+ if (exists(mapPath)) {
2034
+ bytesRemoved += statSync(mapPath).size;
2035
+ unlinkSync(mapPath);
2036
+ orphanFilesRemoved += 1;
2037
+ }
2038
+ return { orphanFilesRemoved, bytesRemoved };
2039
+ };
2040
+ const pruneJsOrphans = (context, depsRoot) => {
2041
+ const roots = collectEntryFiles(context, depsRoot, ['index.esm.js', 'index.cjs.js']);
2042
+ const reachable = computeReachable(roots, depsRoot);
2043
+ const chunks = [];
2044
+ walkFiles(depsRoot, (name) => name === 'index.esm.js' || name === 'index.cjs.js', chunks);
2045
+ // why: a dynamic-specifier bail keeps every chunk.
2046
+ if (reachable === null)
2047
+ return { orphanFilesRemoved: 0, bytesRemoved: 0 };
2048
+ let orphanFilesRemoved = 0;
2049
+ let bytesRemoved = 0;
2050
+ for (const chunk of chunks) {
2051
+ if (reachable.has(chunk))
2052
+ continue;
2053
+ const removed = unlinkWithMap(chunk);
2054
+ orphanFilesRemoved += removed.orphanFilesRemoved;
2055
+ bytesRemoved += removed.bytesRemoved;
2056
+ }
2057
+ return { orphanFilesRemoved, bytesRemoved };
2058
+ };
2059
+ // why: declaration specifiers carry the runtime extension (`'.../index.js'`, also `.esm.js`/`.cjs.js`); a d.ts type-reference resolves to the sibling `index.d.ts`, so the type-graph walk must rewrite the target before visiting it.
2060
+ const toDtsTarget = (target) => target.replace(/(?:\.esm|\.cjs)?\.[mc]?js$/, '.d.ts');
2061
+ const pruneDtsOrphans = (context, depsRoot) => {
2062
+ const roots = collectEntryFiles(context, depsRoot, ['index.d.ts']);
2063
+ const reachable = computeReachable(roots, depsRoot, toDtsTarget);
2064
+ const chunks = [];
2065
+ walkFiles(depsRoot, (name) => name === 'index.d.ts', chunks);
2066
+ // why: a dynamic specifier in the type graph cannot be resolved — keep every dep d.ts (guaranteed-safe fallback), mirroring the JS sweep.
2067
+ if (reachable === null)
2068
+ return { orphanFilesRemoved: 0, bytesRemoved: 0 };
2069
+ let orphanFilesRemoved = 0;
2070
+ let bytesRemoved = 0;
2071
+ for (const chunk of chunks) {
2072
+ // why: keep a dep's types only when an entry's own d.ts type-graph reaches them — the dts-per-entry pass makes each entry `index.d.ts` self-contained, so any dep d.ts no entry type-graph references is dead.
2073
+ if (reachable.has(chunk))
2074
+ continue;
2075
+ const removed = unlinkWithMap(chunk);
2076
+ orphanFilesRemoved += removed.orphanFilesRemoved;
2077
+ bytesRemoved += removed.bytesRemoved;
2078
+ }
2079
+ return { orphanFilesRemoved, bytesRemoved };
2080
+ };
2081
+ /**
2082
+ * Orphan Sweep: deletes `_dependencies/**` chunk files that no package entry
2083
+ * reaches.
2084
+ *
2085
+ * Runs reachability from the package's own entry output chunks over the
2086
+ * `_dependencies/` JS graph, unlinks every `index.{esm,cjs}.js` (and `.map`
2087
+ * sibling) that is unreachable, then applies the d.ts retention rule — a dep's
2088
+ * `index.d.ts` is kept only when it is reachable from an entry's `.d.ts` graph.
2089
+ * Entry `index.d.ts` are self-contained (dts-per-entry), so dep types no entry
2090
+ * type-graph references are dead and removed. Empty directories left behind are
2091
+ * removed. A dynamic, non-literal `import(`/`require(` anywhere in the reachable
2092
+ * graph disables deletion entirely (guaranteed-safe fallback).
2093
+ *
2094
+ * @param context - Resolved build context.
2095
+ * @param depsRoot - Absolute path to the `_dependencies/` directory.
2096
+ * @returns Aggregate count of files removed and bytes reclaimed.
2097
+ *
2098
+ * @example Sweeping orphans after the per-entry d.ts pass
2099
+ * ```typescript
2100
+ * const { orphanFilesRemoved } = pruneOrphanChunks(context, depsRootOf(context))
2101
+ * ```
2102
+ */
2103
+ const pruneOrphanChunks = (context, depsRoot) => {
2104
+ if (!exists(depsRoot) || !isDirectory(depsRoot))
2105
+ return { orphanFilesRemoved: 0, bytesRemoved: 0 };
2106
+ const js = pruneJsOrphans(context, depsRoot);
2107
+ const dts = pruneDtsOrphans(context, depsRoot);
2108
+ // why: shares the package-wide empty-dir helper; `depsRoot` itself is left intact, matching the prior `cleanupEmptyDirs` behavior.
2109
+ removeEmptyDirs(depsRoot);
2110
+ return {
2111
+ orphanFilesRemoved: js.orphanFilesRemoved + dts.orphanFilesRemoved,
2112
+ bytesRemoved: js.bytesRemoved + dts.bytesRemoved,
2113
+ };
2114
+ };
2115
+
2116
+ const mergeName = (edges, target, name) => {
2117
+ const current = edges.get(target);
2118
+ if (current === 'all')
2119
+ return;
2120
+ if (current)
2121
+ current.add(name);
2122
+ else
2123
+ edges.set(target, createSet([name]));
2124
+ };
2125
+ const mergeAll = (edges, target) => void edges.set(target, 'all');
2126
+ // why: a side-effect-only import (`import './x'`) reaches a chunk without naming any export; record it with an empty demand so the orphan re-sweep, not the export stripper, decides its fate.
2127
+ const markReached = (edges, target) => void (edges.has(target) || edges.set(target, createSet([])));
2128
+ const collectEsmEdges = (sourceFile, importerDir, edges) => {
2129
+ for (const statement of sourceFile.statements) {
2130
+ if (ts.isImportDeclaration(statement)) {
2131
+ // why: an `ImportDeclaration`'s module specifier is always a string literal in parseable source.
2132
+ const target = resolveRelativeTarget(importerDir, statement.moduleSpecifier.text);
2133
+ if (target === null)
2134
+ continue;
2135
+ const clause = statement.importClause;
2136
+ if (!clause) {
2137
+ markReached(edges, target);
2138
+ continue;
2139
+ }
2140
+ // why: `import def from 'F'` pulls the default export — consume the whole surface to stay safe.
2141
+ if (clause.name) {
2142
+ mergeAll(edges, target);
2143
+ continue;
2144
+ }
2145
+ // why: with no default binding, a parseable import always carries named bindings — either `* as ns` or `{ … }`.
2146
+ const bindings = clause.namedBindings;
2147
+ if (ts.isNamespaceImport(bindings)) {
2148
+ mergeAll(edges, target);
2149
+ continue;
2150
+ }
2151
+ for (const element of bindings.elements)
2152
+ mergeName(edges, target, (element.propertyName ?? element.name).text);
2153
+ continue;
2154
+ }
2155
+ if (ts.isExportDeclaration(statement) && statement.moduleSpecifier) {
2156
+ // why: a re-export's module specifier, when present, is always a string literal in parseable source.
2157
+ const target = resolveRelativeTarget(importerDir, statement.moduleSpecifier.text);
2158
+ if (target === null)
2159
+ continue;
2160
+ // why: `export * from 'F'` re-exports the entire surface — treat as wholesale demand.
2161
+ if (!statement.exportClause || !ts.isNamedExports(statement.exportClause)) {
2162
+ mergeAll(edges, target);
2163
+ continue;
2164
+ }
2165
+ for (const element of statement.exportClause.elements)
2166
+ mergeName(edges, target, (element.propertyName ?? element.name).text);
2167
+ }
2168
+ }
2169
+ };
2170
+ const collectCjsBindingEdges = (node, target, edges, namespaceBindings, declNames) => {
2171
+ const shape = classifyRequireBinding(node);
2172
+ switch (shape.kind) {
2173
+ case 'prop':
2174
+ mergeName(edges, target, shape.name);
2175
+ return;
2176
+ // why: inline element access (`require('./x')['foo']`, static or computed) keeps the whole chunk — this pass never narrowed it, and preserving that is safe (the namespace-usage pass narrows the static case). Narrowing here would be a separate enhancement.
2177
+ case 'elem-static':
2178
+ case 'elem-dynamic':
2179
+ mergeAll(edges, target);
2180
+ return;
2181
+ // why: a bare `require('./x')` statement pulls the chunk only for its side effects, naming no export; record it reached with empty demand — mirroring an ESM side-effect import — so the orphan re-sweep, not the export stripper, decides its fate.
2182
+ case 'side-effect':
2183
+ markReached(edges, target);
2184
+ return;
2185
+ case 'ns-binding':
2186
+ namespaceBindings.set(shape.name.text, target);
2187
+ declNames.add(shape.name);
2188
+ return;
2189
+ case 'destructure':
2190
+ for (const element of shape.pattern.elements) {
2191
+ // why: a rest element (`...rest`) captures every remaining export, so the surface must be kept whole.
2192
+ if (element.dotDotDotToken) {
2193
+ mergeAll(edges, target);
2194
+ continue;
2195
+ }
2196
+ const key = element.propertyName ?? element.name;
2197
+ if (ts.isIdentifier(key) || ts.isStringLiteralLike(key))
2198
+ mergeName(edges, target, key.text);
2199
+ else
2200
+ mergeAll(edges, target);
2201
+ }
2202
+ return;
2203
+ // why: a `require` used as a call argument, spread, or any non-binding position escapes member tracking — keep the whole chunk.
2204
+ case 'escape':
2205
+ mergeAll(edges, target);
2206
+ return;
2207
+ }
2208
+ };
2209
+ const scanNamespaceUse = (identifier, namespaceBindings, edges, declNames) => {
2210
+ const target = namespaceBindings.get(identifier.text);
2211
+ if (target === undefined || declNames.has(identifier))
2212
+ return;
2213
+ const parent = identifier.parent;
2214
+ if (ts.isPropertyAccessExpression(parent) && parent.expression === identifier && ts.isIdentifier(parent.name)) {
2215
+ mergeName(edges, target, parent.name.text);
2216
+ return;
2217
+ }
2218
+ if (ts.isElementAccessExpression(parent) && parent.expression === identifier) {
2219
+ if (ts.isStringLiteralLike(parent.argumentExpression))
2220
+ mergeName(edges, target, parent.argumentExpression.text);
2221
+ else
2222
+ mergeAll(edges, target);
2223
+ return;
2224
+ }
2225
+ // why: the binding name appearing as another object's property key is unrelated; every other position is a wholesale escape.
2226
+ if (!(ts.isPropertyAccessExpression(parent) && parent.name === identifier))
2227
+ mergeAll(edges, target);
2228
+ };
2229
+ const collectCjsEdges = (sourceFile, importerDir, edges) => {
2230
+ const namespaceBindings = createMap();
2231
+ const declNames = createSet([]);
2232
+ const findRequires = (node) => {
2233
+ const specifier = getRequireSpecifier(node);
2234
+ if (specifier !== null) {
2235
+ const target = resolveRelativeTarget(importerDir, specifier);
2236
+ if (target !== null)
2237
+ collectCjsBindingEdges(node, target, edges, namespaceBindings, declNames);
2238
+ }
2239
+ ts.forEachChild(node, findRequires);
2240
+ };
2241
+ findRequires(sourceFile);
2242
+ if (namespaceBindings.size === 0)
2243
+ return;
2244
+ const scanUses = (node) => {
2245
+ if (ts.isIdentifier(node))
2246
+ scanNamespaceUse(node, namespaceBindings, edges, declNames);
2247
+ ts.forEachChild(node, scanUses);
2248
+ };
2249
+ scanUses(sourceFile);
2250
+ };
2251
+ /**
2252
+ * Builds the map of chunk → exported-name demand for every relative module edge
2253
+ * a single importer declares.
2254
+ *
2255
+ * Each key is the absolute path the importer references; each value is the set
2256
+ * of exported names it pulls from that chunk, or `'all'` when the reference is
2257
+ * wholesale (namespace/default import, `export *`, or a `require` binding that
2258
+ * escapes member access). A side-effect-only `import './x'` records the target
2259
+ * with an empty set.
2260
+ *
2261
+ * @param source - Raw importer source text.
2262
+ * @param importerDir - Absolute directory of the importer file.
2263
+ * @param format - Module format that determines ESM vs CJS edge extraction.
2264
+ * @returns Map from resolved chunk path to its usage demand.
2265
+ *
2266
+ * @example Edges of an ESM entry
2267
+ * ```typescript
2268
+ * collectImportEdges("import { getType } from './_dependencies/x/index.esm.js'", '/dist/libs/foo', 'esm')
2269
+ * // => Map { '/dist/libs/foo/_dependencies/x/index.esm.js' => Set { 'getType' } }
2270
+ * ```
2271
+ */
2272
+ const collectImportEdges = (source, importerDir, format) => {
2273
+ const sourceFile = parseChunk(source);
2274
+ const edges = createMap();
2275
+ if (format === 'esm')
2276
+ collectEsmEdges(sourceFile, importerDir, edges);
2277
+ else
2278
+ collectCjsEdges(sourceFile, importerDir, edges);
2279
+ return edges;
2280
+ };
2281
+
2282
+ const log$4 = logger.channel('builder:bundle:dependencies:prune');
2283
+ // why: the strip → re-derive → strip cycle converges in passes bounded by the chunk-import depth; this cap is a runaway guard, logged if ever reached.
2284
+ const MAX_ITERATIONS = 50;
2285
+ const FORMAT_FILES$1 = [
2286
+ { format: 'esm', fileName: 'index.esm.js' },
2287
+ { format: 'cjs', fileName: 'index.cjs.js' },
2288
+ ];
2289
+ const mergeUsage = (usageMap, target, usage) => {
2290
+ const current = usageMap.get(target);
2291
+ // why: targets outside the surviving-chunk set are the package's own code — not strippable, so ignore their demand.
2292
+ if (current === undefined || current === 'all')
2293
+ return;
2294
+ if (usage === 'all') {
2295
+ usageMap.set(target, 'all');
2296
+ return;
2297
+ }
2298
+ for (const name of usage)
2299
+ current.add(name);
2300
+ };
2301
+ const buildUsageMap = (importers, chunks, format) => {
2302
+ const usageMap = createMap();
2303
+ for (const chunk of chunks)
2304
+ usageMap.set(chunk, createSet([]));
2305
+ // why: every importer is either a validated entry file or a chunk just walked off disk, so all are present — no existence guard needed.
2306
+ for (const importer of importers) {
2307
+ for (const [target, usage] of collectImportEdges(readFileContent(importer), getDirname(importer), format))
2308
+ mergeUsage(usageMap, target, usage);
2309
+ }
2310
+ return usageMap;
2311
+ };
2312
+ const stripChunks = (usageMap, format, result) => {
2313
+ let changed = false;
2314
+ for (const [chunk, keep] of usageMap) {
2315
+ const source = readFileContent(chunk);
2316
+ const stripped = stripDeadExports(source, format, keep);
2317
+ if (!stripped)
2318
+ continue;
2319
+ writeFileContent(chunk, stripped.code);
2320
+ result.deadExportsRemoved += stripped.removedNames.length;
2321
+ result.bytesRemoved += Buffer.byteLength(source) - Buffer.byteLength(stripped.code);
2322
+ changed = true;
2323
+ }
2324
+ return changed;
2325
+ };
2326
+ const processFormat$1 = (context, depsRoot, format, fileName, result) => {
2327
+ const entries = collectEntryFiles(context, depsRoot, [fileName]);
2328
+ for (let iteration = 0; iteration < MAX_ITERATIONS; iteration += 1) {
2329
+ const chunks = [];
2330
+ walkFiles(depsRoot, (name) => name === fileName, chunks);
2331
+ if (chunks.length === 0)
2332
+ return;
2333
+ const usageMap = buildUsageMap([...entries, ...chunks], chunks, format);
2334
+ if (!stripChunks(usageMap, format, result))
2335
+ return;
2336
+ // istanbul ignore next -- why: convergence exits via the early return above; a >50-deep chunk import chain that would exhaust the cap cannot occur in bundled dependency output, so the guard log is unreachable in practice.
2337
+ if (iteration === MAX_ITERATIONS - 1)
2338
+ log$4.warn(`dead-export strip for ${format} hit the ${MAX_ITERATIONS}-iteration cap before converging`);
2339
+ }
2340
+ };
2341
+ /**
2342
+ * Shrinks surviving `_dependencies/` chunks by stripping dead exported
2343
+ * declarations, iterating to a fixpoint per format.
2344
+ *
2345
+ * Each iteration re-derives the importer demand for every surviving chunk from
2346
+ * the current on-disk sources (entries plus sibling chunks), strips each chunk
2347
+ * to that demand, and repeats until no chunk changes — because removing one
2348
+ * chunk's import can make another chunk's export dead in turn. ESM and CJS are
2349
+ * processed independently. The orphan sweep is expected to run afterwards to
2350
+ * reclaim any chunk whose last import was removed here.
2351
+ *
2352
+ * @param context - Resolved build context supplying the entry points.
2353
+ * @param depsRoot - Absolute path to the `_dependencies/` directory.
2354
+ * @returns Counts of exports removed and bytes reclaimed.
2355
+ *
2356
+ * @example Running the strip pass after the orphan sweep
2357
+ * ```typescript
2358
+ * const { deadExportsRemoved } = stripDeadExportsPass(context, depsRootOf(context))
2359
+ * ```
2360
+ */
2361
+ const stripDeadExportsPass = (context, depsRoot) => {
2362
+ const result = { deadExportsRemoved: 0, bytesRemoved: 0 };
2363
+ if (!exists(depsRoot))
2364
+ return result;
2365
+ for (const { format, fileName } of FORMAT_FILES$1)
2366
+ processFormat$1(context, depsRoot, format, fileName, result);
2367
+ return result;
2368
+ };
2369
+
2370
+ // why: an identifier is a free reference or a binding name unless it sits in a member-name / object-key position, where it never introduces or reads a top-level-visible name. The reserved set is what new destructured locals must avoid colliding with.
2371
+ const isNameOnlyPosition = (id) => {
2372
+ const parent = id.parent;
2373
+ if (ts.isPropertyAccessExpression(parent) && parent.name === id)
2374
+ return true;
2375
+ if (ts.isPropertyAssignment(parent) && parent.name === id)
2376
+ return true;
2377
+ if (ts.isBindingElement(parent) && parent.propertyName === id)
2378
+ return true;
2379
+ return false;
2380
+ };
2381
+ const collectReserved = (sourceFile, bindingNodes) => {
2382
+ const reserved = createSet([]);
2383
+ const visit = (node) => {
2384
+ // why: a candidate's own binding name is being removed, so it never blocks a chosen local.
2385
+ if (ts.isIdentifier(node) && !bindingNodes.has(node) && !isNameOnlyPosition(node))
2386
+ reserved.add(node.text);
2387
+ ts.forEachChild(node, visit);
2388
+ };
2389
+ visit(sourceFile);
2390
+ return reserved;
2391
+ };
2392
+ const collectCandidates = (sourceFile, chunkDir, isSafeTarget) => {
2393
+ const candidates = createMap();
2394
+ const seen = createSet([]);
2395
+ const visit = (node) => {
2396
+ const specifier = getRequireSpecifier(node);
2397
+ if (specifier !== null) {
2398
+ const target = resolveRelativeTarget(chunkDir, specifier);
2399
+ const parent = node.parent;
2400
+ // why: when a `require` call's direct parent is a `VariableDeclaration`, the call is necessarily its initializer (a declaration's only expression child), so no separate initializer check is needed.
2401
+ if (target !== null && isSafeTarget(target) && ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)) {
2402
+ const local = parent.name.text;
2403
+ // why: a local bound twice cannot be tracked unambiguously by text scan — drop it from consideration entirely.
2404
+ if (seen.has(local))
2405
+ candidates.delete(local);
2406
+ else {
2407
+ seen.add(local);
2408
+ candidates.set(local, { local, nameNode: parent.name, members: createMap(), bail: false });
2409
+ }
2410
+ }
2411
+ }
2412
+ ts.forEachChild(node, visit);
2413
+ };
2414
+ visit(sourceFile);
2415
+ return candidates;
2416
+ };
2417
+ // why: a destructure shorthand `const { name } = require(...)` is legal only when `name` is a real BindingIdentifier — so lex `name` whole. A single `Identifier` followed by end-of-input proves it: a keyword (`default`, and strict-reserved `let`/`yield`/`static`/`await`, illegal in rollup's strict CJS) lexes to its own keyword token, not `Identifier`; a non-identifier key (`foo-bar` from `NS["foo-bar"]`) lexes to `Identifier` + more tokens, so the EOF check fails. Over-bailing a rare contextual export name (`as`/`type`) is safe: it keeps the namespace form, which is valid.
2418
+ const isValidBindingName = (name) => {
2419
+ const scanner = ts.createScanner(ts.ScriptTarget.ESNext, /*skipTrivia*/ true, ts.LanguageVariant.Standard, name);
2420
+ return scanner.scan() === ts.SyntaxKind.Identifier && scanner.scan() === ts.SyntaxKind.EndOfFileToken;
2421
+ };
2422
+ const scanUses = (sourceFile, candidates, bindingNodes) => {
2423
+ const visit = (node) => {
2424
+ if (ts.isIdentifier(node) && !bindingNodes.has(node)) {
2425
+ const candidate = candidates.get(node.text);
2426
+ if (candidate && !candidate.bail) {
2427
+ const classification = classifyNamespaceUse(node);
2428
+ // why: a member named by a non-identifier (`m['foo-bar']`) or a keyword (`m.default`) cannot be destructured to a legal `const { … }` binding — bail the whole candidate to its namespace form rather than emit invalid JS.
2429
+ if (classification.kind === 'bail' || (classification.kind === 'read' && !isValidBindingName(classification.prop)))
2430
+ candidate.bail = true;
2431
+ else if (classification.kind === 'read') {
2432
+ const nodes = candidate.members.get(classification.prop) ?? [];
2433
+ nodes.push(node.parent);
2434
+ candidate.members.set(classification.prop, nodes);
2435
+ }
2436
+ }
2437
+ }
2438
+ ts.forEachChild(node, visit);
2439
+ };
2440
+ visit(sourceFile);
2441
+ };
2442
+ const renderBindingPattern = (assignments) => `{ ${assignments.map(({ exported, local }) => (exported === local ? exported : `${exported}: ${local}`)).join(', ')} }`;
2443
+ const allocateLocal = (exported, taken) => {
2444
+ if (!taken.has(exported))
2445
+ return exported;
2446
+ let suffix = 1;
2447
+ while (taken.has(`${exported}$${suffix}`))
2448
+ suffix += 1;
2449
+ return `${exported}$${suffix}`;
2450
+ };
2451
+ /**
2452
+ * Rewrites whole-module CJS require bindings to destructuring binds when the
2453
+ * binding is consumed only as static member reads.
2454
+ *
2455
+ * For every top-level `const NS = require('./rel')` whose target `isSafeTarget`
2456
+ * accepts (a relative sibling chunk that is provably not in a `require` cycle
2457
+ * with this chunk), and where `NS` is used exclusively as `NS.member` /
2458
+ * `NS['member']` reads, the binding is collapsed to `const { member, … } =
2459
+ * require('./rel')` and each `NS.member` access is replaced by the bound local.
2460
+ * Locals that would collide with an existing free identifier or another bound
2461
+ * local are aliased (`member: member$1`) — so the rewrite never shadows the
2462
+ * chunk's own names. Any wholesale, dynamic, or reassigning use of `NS` leaves
2463
+ * its binding untouched, matching rollup's namespace-access codegen.
2464
+ *
2465
+ * The cycle guard is the caller's responsibility: rollup keeps the namespace
2466
+ * form precisely so an eager destructure cannot capture an export before a
2467
+ * circular dependency has initialized it. Passing only acyclic targets to
2468
+ * `isSafeTarget` preserves that guarantee.
2469
+ *
2470
+ * @param source - Raw CJS chunk source text.
2471
+ * @param chunkDir - Absolute directory of the chunk, for resolving relative requires.
2472
+ * @param isSafeTarget - Predicate selecting which resolved require targets may be destructured.
2473
+ * @returns The rewritten source and the count of bindings destructured, or `null`
2474
+ * when no binding qualified.
2475
+ *
2476
+ * @example Destructuring a single-member require
2477
+ * ```typescript
2478
+ * destructureRequires("const m = require('./math/index.cjs.js');\nm.abs(x);", '/d/p', () => true)
2479
+ * // => { code: "const { abs } = require('./math/index.cjs.js');\nabs(x);", rewrittenBindings: 1 }
2480
+ * ```
2481
+ */
2482
+ const destructureRequires = (source, chunkDir, isSafeTarget) => {
2483
+ const sourceFile = parseChunk(source);
2484
+ const candidates = collectCandidates(sourceFile, chunkDir, isSafeTarget);
2485
+ if (candidates.size === 0)
2486
+ return null;
2487
+ const bindingNodes = createSet([...candidates.values()].map((candidate) => candidate.nameNode));
2488
+ scanUses(sourceFile, candidates, bindingNodes);
2489
+ const qualified = [...candidates.values()].filter((candidate) => !candidate.bail && candidate.members.size > 0);
2490
+ if (qualified.length === 0)
2491
+ return null;
2492
+ // why: every binding being collapsed frees its own name, so exclude binding nodes; new locals must dodge all other free identifiers.
2493
+ const taken = collectReserved(sourceFile, bindingNodes);
2494
+ const edits = [];
2495
+ for (const candidate of qualified) {
2496
+ const assignments = [];
2497
+ for (const exported of [...candidate.members.keys()].sort()) {
2498
+ const local = allocateLocal(exported, taken);
2499
+ taken.add(local);
2500
+ assignments.push({ exported, local });
2501
+ // why: the member-access node (`NS.member` or `NS['member']`) collapses to the bound local; the key came from this same map, so the lookup always resolves.
2502
+ for (const accessNode of candidate.members.get(exported))
2503
+ edits.push({ start: accessNode.getStart(sourceFile), end: accessNode.getEnd(), text: local });
2504
+ }
2505
+ edits.push({
2506
+ start: candidate.nameNode.getStart(sourceFile),
2507
+ end: candidate.nameNode.getEnd(),
2508
+ text: renderBindingPattern(assignments),
2509
+ });
2510
+ }
2511
+ return { code: applyEdits(source, edits), rewrittenBindings: qualified.length };
2512
+ };
2513
+
2514
+ const log$3 = logger.channel('builder:bundle:dependencies:prune');
2515
+ const CJS_CHUNK = 'index.cjs.js';
2516
+ const collectRequireTargets = (source, chunkDir, chunkSet) => {
2517
+ const sourceFile = parseChunk(source);
2518
+ const targets = createSet([]);
2519
+ const visit = (node) => {
2520
+ const specifier = getRequireSpecifier(node);
2521
+ if (specifier !== null) {
2522
+ const target = resolveRelativeTarget(chunkDir, specifier);
2523
+ if (target !== null && chunkSet.has(target))
2524
+ targets.add(target);
2525
+ }
2526
+ ts.forEachChild(node, visit);
2527
+ };
2528
+ visit(sourceFile);
2529
+ return targets;
2530
+ };
2531
+ const buildRequireGraph = (chunks, chunkSet) => {
2532
+ const graph = createMap();
2533
+ for (const chunk of chunks)
2534
+ graph.set(chunk, collectRequireTargets(readFileContent(chunk), getDirname(chunk), chunkSet));
2535
+ return graph;
2536
+ };
2537
+ /**
2538
+ * Assigns every chunk a strongly-connected-component id via iterative Tarjan, so
2539
+ * a require edge `importer → target` is a cycle exactly when both share an id.
2540
+ *
2541
+ * Iterative (explicit work stack) to stay safe on deep require chains; the graph
2542
+ * is the relative-require graph restricted to chunks under `_dependencies/`.
2543
+ *
2544
+ * @param nodes - All chunk paths, in a stable order.
2545
+ * @param graph - Adjacency from each chunk to the chunks it requires.
2546
+ * @returns Map from chunk path to its SCC id.
2547
+ */
2548
+ const computeSccIds = (nodes, graph) => {
2549
+ const index = createMap();
2550
+ const low = createMap();
2551
+ const onStack = createSet([]);
2552
+ const componentOf = createMap();
2553
+ const tarjanStack = [];
2554
+ // why: invariants guarantee every node read below was opened (written) first, so the cast is total.
2555
+ const idxOf = (node) => index.get(node);
2556
+ const lowOf = (node) => low.get(node);
2557
+ // why: the graph holds an entry for every node, so the lookup always resolves.
2558
+ const neighborsOf = (node) => [...graph.get(node)];
2559
+ let counter = 0;
2560
+ let component = 0;
2561
+ const open = (node) => {
2562
+ index.set(node, counter);
2563
+ low.set(node, counter);
2564
+ counter += 1;
2565
+ tarjanStack.push(node);
2566
+ onStack.add(node);
2567
+ };
2568
+ for (const start of nodes) {
2569
+ if (index.has(start))
2570
+ continue;
2571
+ open(start);
2572
+ const work = [{ node: start, neighbors: neighborsOf(start), cursor: 0 }];
2573
+ while (work.length > 0) {
2574
+ const frame = work[work.length - 1];
2575
+ if (frame.cursor < frame.neighbors.length) {
2576
+ const next = frame.neighbors[frame.cursor];
2577
+ frame.cursor += 1;
2578
+ if (!index.has(next)) {
2579
+ open(next);
2580
+ work.push({ node: next, neighbors: neighborsOf(next), cursor: 0 });
2581
+ }
2582
+ else if (onStack.has(next))
2583
+ low.set(frame.node, min(lowOf(frame.node), idxOf(next)));
2584
+ continue;
2585
+ }
2586
+ if (lowOf(frame.node) === idxOf(frame.node)) {
2587
+ for (;;) {
2588
+ const popped = tarjanStack.pop();
2589
+ onStack.delete(popped);
2590
+ componentOf.set(popped, component);
2591
+ if (popped === frame.node)
2592
+ break;
2593
+ }
2594
+ component += 1;
2595
+ }
2596
+ work.pop();
2597
+ const parent = work[work.length - 1];
2598
+ if (parent)
2599
+ low.set(parent.node, min(lowOf(parent.node), lowOf(frame.node)));
2600
+ }
2601
+ }
2602
+ return componentOf;
2603
+ };
2604
+ /**
2605
+ * Collapses whole-module CJS require bindings (`const NS = require('./rel')`) to
2606
+ * destructuring binds across the surviving `_dependencies/` chunks, guarded so it
2607
+ * never destructures across a `require` cycle.
2608
+ *
2609
+ * Builds the relative-require graph over the CJS chunks, finds its
2610
+ * strongly-connected components, and lets each chunk destructure a target only
2611
+ * when the two sit in different components — i.e. the edge is acyclic, so an
2612
+ * eager destructure cannot capture an export before a circular dependency
2613
+ * finished initializing (the exact hazard rollup's namespace-access codegen
2614
+ * avoids). ESM chunks need nothing: their named imports already destructure. A
2615
+ * dynamic `import(`/`require(` anywhere disables the pass for safety, since it
2616
+ * could hide a cycle the static graph cannot see.
2617
+ *
2618
+ * @param depsRoot - Absolute path to the `_dependencies/` directory.
2619
+ * @returns Count of require bindings destructured.
2620
+ *
2621
+ * @example Running the pass after the strip/orphan passes
2622
+ * ```typescript
2623
+ * const { requireBindingsDestructured } = destructureRequiresPass(depsRootOf(context))
2624
+ * ```
2625
+ */
2626
+ const destructureRequiresPass = (depsRoot) => {
2627
+ const result = { requireBindingsDestructured: 0 };
2628
+ if (!exists(depsRoot))
2629
+ return result;
2630
+ const chunks = [];
2631
+ walkFiles(depsRoot, (name) => name === CJS_CHUNK, chunks);
2632
+ if (chunks.length === 0)
2633
+ return result;
2634
+ const sources = createMap();
2635
+ for (const chunk of chunks) {
2636
+ const source = readFileContent(chunk);
2637
+ // why: a dynamic specifier could hide a require cycle the static graph misses; bail the whole pass, mirroring the orphan sweep's safety posture.
2638
+ if (hasDynamicSpecifier(source)) {
2639
+ log$3.warn(`dynamic import/require in ${chunk}; skipping require-destructure pass for safety`);
2640
+ return result;
2641
+ }
2642
+ sources.set(chunk, source);
2643
+ }
2644
+ const chunkSet = createSet(chunks);
2645
+ const graph = buildRequireGraph(chunks, chunkSet);
2646
+ const componentOf = computeSccIds(chunks, graph);
2647
+ for (const chunk of chunks) {
2648
+ // why: every chunk was just read into `sources` above, so the lookup always resolves.
2649
+ const source = sources.get(chunk);
2650
+ const myComponent = componentOf.get(chunk);
2651
+ const isSafeTarget = (target) => chunkSet.has(target) && componentOf.get(target) !== myComponent;
2652
+ const rewritten = destructureRequires(source, getDirname(chunk), isSafeTarget);
2653
+ if (!rewritten)
2654
+ continue;
2655
+ writeFileContent(chunk, rewritten.code);
2656
+ result.requireBindingsDestructured += rewritten.rewrittenBindings;
2657
+ }
2658
+ return result;
2659
+ };
2660
+
2661
+ const propertyName = (element) => {
2662
+ if (ts.isShorthandPropertyAssignment(element))
2663
+ return element.name.text;
2664
+ if (ts.isPropertyAssignment(element) && (ts.isIdentifier(element.name) || ts.isStringLiteralLike(element.name)))
2665
+ return element.name.text;
2666
+ return null;
2667
+ };
2668
+ // why: only a literal of plain `key: value` / shorthand slots can be safely partitioned; a spread, computed key, method, or accessor makes per-slot removal unsound, so such a literal is left whole (no NamespaceObject yielded).
2669
+ const readProperties = (literal) => {
2670
+ const properties = [];
2671
+ for (const element of literal.properties) {
2672
+ const name = propertyName(element);
2673
+ if (name === null)
2674
+ return null;
2675
+ properties.push({ name, element });
2676
+ }
2677
+ return properties;
2678
+ };
2679
+ const exportedLocalNames = (sourceFile, format) => {
2680
+ const single = createMap();
2681
+ const seen = createSet([]);
2682
+ for (const entry of analyzeChunk(sourceFile, format).exports) {
2683
+ // why: a local published under two names cannot be keyed to one demand set — drop it from the strippable set.
2684
+ if (seen.has(entry.local))
2685
+ single.delete(entry.local);
2686
+ else {
2687
+ seen.add(entry.local);
2688
+ single.set(entry.local, entry.exported);
2689
+ }
2690
+ }
2691
+ return single;
2692
+ };
2693
+ // context: visits each exported, frozen, plain-slot namespace object in source order. A namespace is a single-declarator top-level `const`/`var` whose initializer is a recognized pure freeze (`Object.freeze`/`seal`/`preventExtensions`, however aliased) of a fresh object literal, and whose local is exported under exactly one name.
2694
+ const forEachNamespaceObject = (sourceFile, format, visit) => {
2695
+ const exported = exportedLocalNames(sourceFile, format);
2696
+ const resolution = collectBindingCanonical(sourceFile);
2697
+ for (const statement of sourceFile.statements) {
2698
+ if (!ts.isVariableStatement(statement) || statement.declarationList.declarations.length !== 1)
2699
+ continue;
2700
+ const decl = statement.declarationList.declarations[0];
2701
+ if (!decl || !ts.isIdentifier(decl.name))
2702
+ continue;
2703
+ const name = decl.name.text;
2704
+ const exportName = exported.get(name);
2705
+ if (exportName === undefined || !decl.initializer || !ts.isCallExpression(decl.initializer))
2706
+ continue;
2707
+ if (!isPureFreezeCall(decl.initializer, resolution))
2708
+ continue;
2709
+ const argument = decl.initializer.arguments[0];
2710
+ if (!argument || !ts.isObjectLiteralExpression(argument))
2711
+ continue;
2712
+ const properties = readProperties(argument);
2713
+ if (properties === null)
2714
+ continue;
2715
+ visit({ exported: exportName, local: name, statement, literal: argument, properties });
2716
+ }
2717
+ };
2718
+ /**
2719
+ * Analyzes a single chunk for frozen namespace exports and the demand its own
2720
+ * body places on them.
2721
+ *
2722
+ * Returns the namespace exports as node-free data (so the parsed source can be
2723
+ * released) and a self-demand map folding every reference to a namespace's local
2724
+ * binding outside its own declaration and export surface: a static `NS.prop`
2725
+ * read contributes that property, any other use marks the namespace `'all'`.
2726
+ *
2727
+ * @param source - Raw chunk source text.
2728
+ * @param format - Module format selecting the export shape.
2729
+ * @returns The chunk's namespace exports and the demand it self-imposes.
2730
+ *
2731
+ * @example A chunk that exports a frozen namespace it never self-references
2732
+ * ```typescript
2733
+ * analyzeChunkNamespaces('const a = 1;\nconst NS = Object.freeze({ a });\nexport { a, NS };', 'esm')
2734
+ * // => { namespaces: [{ exported: 'NS', properties: ['a'] }], selfDemand: Map {} }
2735
+ * ```
2736
+ */
2737
+ const analyzeChunkNamespaces = (source, format) => {
2738
+ const sourceFile = parseChunk(source);
2739
+ const namespaces = [];
2740
+ const localToExport = createMap();
2741
+ const skip = createSet([]);
2742
+ forEachNamespaceObject(sourceFile, format, (object) => {
2743
+ namespaces.push({ exported: object.exported, properties: object.properties.map((property) => property.name) });
2744
+ localToExport.set(object.local, object.exported);
2745
+ skip.add(object.statement);
2746
+ });
2747
+ const selfDemand = createMap();
2748
+ if (namespaces.length === 0)
2749
+ return { namespaces, selfDemand };
2750
+ // why: a namespace's own declaration and its `export { … }` site are not consumer reads — skip them so only genuine internal uses count.
2751
+ for (const entry of analyzeChunk(sourceFile, format).exportSurfaceStatements)
2752
+ skip.add(entry);
2753
+ const visit = (node) => {
2754
+ if (ts.isIdentifier(node)) {
2755
+ const exportName = localToExport.get(node.text);
2756
+ if (exportName !== undefined) {
2757
+ const classification = classifyNamespaceUse(node);
2758
+ if (classification.kind === 'read')
2759
+ mergeDemand(selfDemand, exportName, createSet([classification.prop]));
2760
+ else if (classification.kind === 'bail')
2761
+ mergeDemand(selfDemand, exportName, 'all');
2762
+ }
2763
+ }
2764
+ ts.forEachChild(node, visit);
2765
+ };
2766
+ for (const statement of sourceFile.statements)
2767
+ if (!skip.has(statement))
2768
+ visit(statement);
2769
+ return { namespaces, selfDemand };
2770
+ };
2771
+ /**
2772
+ * Rewrites a chunk's frozen namespace literals to keep only the slots the
2773
+ * consumer graph reads, dropping the rest.
2774
+ *
2775
+ * For every exported frozen namespace, `keepByExport` supplies the property names
2776
+ * to retain (the read set already intersected with the literal's own slots). A
2777
+ * namespace absent from the map, or whose kept set is empty or covers every
2778
+ * slot, is left untouched. Dropping a slot removes the only reference its factory
2779
+ * binding had, so the subsequent dead-export pass collapses the now-dead
2780
+ * factories — this pass only edits the literal.
2781
+ *
2782
+ * @param source - Raw chunk source text.
2783
+ * @param format - Module format selecting the export shape.
2784
+ * @param keepByExport - Per-export set of property names to retain.
2785
+ * @returns The rewritten source and slot-removal count, or `null` when nothing changed.
2786
+ *
2787
+ * @example Keeping a single slot of a two-slot namespace
2788
+ * ```typescript
2789
+ * stripDeadProperties('const a=1;\nconst b=2;\nconst NS=Object.freeze({a,b});\nexport{NS};', 'esm', new Map([['NS', new Set(['a'])]]))
2790
+ * // => literal rewritten to `{ a }`, removedProperties: 1
2791
+ * ```
2792
+ */
2793
+ const stripDeadProperties = (source, format, keepByExport) => {
2794
+ const sourceFile = parseChunk(source);
2795
+ const edits = [];
2796
+ let removedProperties = 0;
2797
+ forEachNamespaceObject(sourceFile, format, (object) => {
2798
+ const keep = keepByExport.get(object.exported);
2799
+ if (!keep)
2800
+ return;
2801
+ const survivors = object.properties.filter((property) => keep.has(property.name));
2802
+ // why: never produce an empty `freeze({})` and never rewrite when nothing is dropped.
2803
+ if (survivors.length === 0 || survivors.length === object.properties.length)
2804
+ return;
2805
+ removedProperties += object.properties.length - survivors.length;
2806
+ const rendered = survivors.map((property) => source.slice(property.element.getStart(sourceFile), property.element.getEnd()));
2807
+ edits.push({ start: object.literal.getStart(sourceFile), end: object.literal.getEnd(), text: `{ ${rendered.join(', ')} }` });
2808
+ });
2809
+ if (edits.length === 0)
2810
+ return null;
2811
+ return { code: applyEdits(source, edits), removedProperties };
2812
+ };
2813
+
2814
+ const FORMAT_FILES = [
2815
+ { format: 'esm', fileName: 'index.esm.js' },
2816
+ { format: 'cjs', fileName: 'index.cjs.js' },
2817
+ ];
2818
+ // why: a dynamic, non-literal `import(`/`require(` anywhere in the consumer graph means a consumer we cannot resolve might read a namespace wholesale — disable property-strip for the format (guaranteed-safe fallback, mirroring the orphan sweep).
2819
+ const graphHasDynamicSpecifier = (importers) => importers.some((importer) => hasDynamicSpecifier(readFileContent(importer)));
2820
+ const collectChunkNamespaces = (chunks, format) => {
2821
+ const byChunk = createMap();
2822
+ for (const chunk of chunks) {
2823
+ const { namespaces } = analyzeChunkNamespaces(readFileContent(chunk), format);
2824
+ if (namespaces.length > 0)
2825
+ byChunk.set(chunk, namespaces);
2826
+ }
2827
+ return byChunk;
2828
+ };
2829
+ // why: seed each namespace-bearing chunk's demand with the demand its own body imposes, so an internal read or escape is counted before importers are scanned.
2830
+ const seedSelfDemand = (chunks, namespacesByChunk, format) => {
2831
+ const demand = createMap();
2832
+ for (const chunk of chunks) {
2833
+ if (!namespacesByChunk.has(chunk))
2834
+ continue;
2835
+ const { selfDemand } = analyzeChunkNamespaces(readFileContent(chunk), format);
2836
+ demand.set(chunk, selfDemand);
2837
+ }
2838
+ return demand;
2839
+ };
2840
+ const accumulateImporterDemand = (importers, namespacesByChunk, demand, format) => {
2841
+ for (const importer of importers) {
2842
+ const edges = collectNamespaceUsage(readFileContent(importer), getDirname(importer), format);
2843
+ for (const [target, usage] of edges) {
2844
+ const chunkDemand = demand.get(target);
2845
+ const namespaces = namespacesByChunk.get(target);
2846
+ // why: edges to chunks with no strippable namespace are irrelevant here.
2847
+ if (!chunkDemand || !namespaces)
2848
+ continue;
2849
+ if (usage.bailAll) {
2850
+ for (const namespace of namespaces)
2851
+ mergeDemand(chunkDemand, namespace.exported, 'all');
2852
+ continue;
2853
+ }
2854
+ for (const [name, propDemand] of usage.perName)
2855
+ mergeDemand(chunkDemand, name, propDemand);
2856
+ }
2857
+ }
2858
+ };
2859
+ // context: the set of property names to retain for each namespace export of one chunk — only namespaces read at a strict, non-empty subset of their slots, so leaving a fully-unread namespace (dead) to the export pass and a wholesale-consumed one untouched.
2860
+ const keepSetsForChunk = (namespaces, chunkDemand) => {
2861
+ const keepByExport = createMap();
2862
+ for (const namespace of namespaces) {
2863
+ const propDemand = chunkDemand.get(namespace.exported);
2864
+ if (propDemand === undefined || propDemand === 'all')
2865
+ continue;
2866
+ const keep = createSet(namespace.properties.filter((property) => propDemand.has(property)));
2867
+ if (keep.size > 0 && keep.size < namespace.properties.length)
2868
+ keepByExport.set(namespace.exported, keep);
2869
+ }
2870
+ return keepByExport;
2871
+ };
2872
+ const rewriteChunks = (namespacesByChunk, demand, format, result) => {
2873
+ for (const [chunk, namespaces] of namespacesByChunk) {
2874
+ const chunkDemand = demand.get(chunk);
2875
+ if (!chunkDemand)
2876
+ continue;
2877
+ const keepByExport = keepSetsForChunk(namespaces, chunkDemand);
2878
+ if (keepByExport.size === 0)
2879
+ continue;
2880
+ const source = readFileContent(chunk);
2881
+ const stripped = stripDeadProperties(source, format, keepByExport);
2882
+ if (!stripped)
2883
+ continue;
2884
+ writeFileContent(chunk, stripped.code);
2885
+ result.deadPropertiesRemoved += stripped.removedProperties;
2886
+ result.bytesRemoved += Buffer.byteLength(source) - Buffer.byteLength(stripped.code);
2887
+ }
2888
+ };
2889
+ const processFormat = (context, depsRoot, format, fileName, result) => {
2890
+ const chunks = [];
2891
+ walkFiles(depsRoot, (name) => name === fileName, chunks);
2892
+ if (chunks.length === 0)
2893
+ return;
2894
+ const importers = [...collectEntryFiles(context, depsRoot, [fileName]), ...chunks];
2895
+ if (graphHasDynamicSpecifier(importers))
2896
+ return;
2897
+ const namespacesByChunk = collectChunkNamespaces(chunks, format);
2898
+ if (namespacesByChunk.size === 0)
2899
+ return;
2900
+ const demand = seedSelfDemand(chunks, namespacesByChunk, format);
2901
+ accumulateImporterDemand(importers, namespacesByChunk, demand, format);
2902
+ rewriteChunks(namespacesByChunk, demand, format, result);
2903
+ };
2904
+ /**
2905
+ * Property-level tree-shaking of kept, live frozen namespace objects: drops the
2906
+ * slots of an exported `freeze({ … })` namespace that no consumer in the whole
2907
+ * graph ever reads, letting the dead-export pass then collapse the now-dead
2908
+ * factory bindings.
2909
+ *
2910
+ * Runs per format (ESM and CJS) over `_dependencies/` chunks. The consumer graph
2911
+ * is the package's entry chunks plus every sibling dependency chunk — a complete
2912
+ * importer set, since per-entry bundling inlines all other first-party code.
2913
+ * Each namespace's demand is the union of its `NS.prop` reads across that graph
2914
+ * (in CJS, a two-level `require(...).NS.prop`); a wholesale consumption (spread,
2915
+ * pass-through, enumeration, dynamic index, re-export, namespace/default import)
2916
+ * or any dynamic specifier in the graph keeps the namespace whole. Only a
2917
+ * namespace read at a strict, non-empty subset of its slots is rewritten. The
2918
+ * caller is expected to re-run the dead-export pass afterwards to reclaim the
2919
+ * orphaned factories.
2920
+ *
2921
+ * @param context - Resolved build context supplying the entry points.
2922
+ * @param depsRoot - Absolute path to the `_dependencies/` directory.
2923
+ * @returns Counts of slots removed and bytes reclaimed.
2924
+ *
2925
+ * @example Running the property strip before the dead-export re-pass
2926
+ * ```typescript
2927
+ * const { deadPropertiesRemoved } = stripDeadPropertiesPass(context, depsRootOf(context))
2928
+ * ```
2929
+ */
2930
+ const stripDeadPropertiesPass = (context, depsRoot) => {
2931
+ const result = { deadPropertiesRemoved: 0, bytesRemoved: 0 };
2932
+ if (!exists(depsRoot))
2933
+ return result;
2934
+ for (const { format, fileName } of FORMAT_FILES)
2935
+ processFormat(context, depsRoot, format, fileName, result);
2936
+ return result;
2937
+ };
2938
+
2939
+ const PRESERVE = /@(?:__PURE__|__NO_SIDE_EFFECTS__|license|preserve|cc_on)|^\s*\/[*/]!|#__PURE__/;
2940
+ // why: tokens after which a `/` is the division operator, not a regex opener. After every other token (operators, `(`, `,`, `=`, keywords like `return`/`typeof`, or start of input) a `/` begins a regex, so the scanner must re-lex it as a whole regex literal — otherwise a `//` or `/*` *inside the regex body* (e.g. `/https?:\/\//`, `str.split(/\//g)`) is mis-scanned as comment trivia and the splice corrupts the regex.
2941
+ const VALUE_END_TOKENS = createSet([
2942
+ ts.SyntaxKind.Identifier,
2943
+ ts.SyntaxKind.NumericLiteral,
2944
+ ts.SyntaxKind.BigIntLiteral,
2945
+ ts.SyntaxKind.StringLiteral,
2946
+ ts.SyntaxKind.NoSubstitutionTemplateLiteral,
2947
+ ts.SyntaxKind.TemplateTail,
2948
+ ts.SyntaxKind.RegularExpressionLiteral,
2949
+ ts.SyntaxKind.CloseParenToken,
2950
+ ts.SyntaxKind.CloseBracketToken,
2951
+ ts.SyntaxKind.CloseBraceToken,
2952
+ ts.SyntaxKind.PlusPlusToken,
2953
+ ts.SyntaxKind.MinusMinusToken,
2954
+ ts.SyntaxKind.ThisKeyword,
2955
+ ts.SyntaxKind.SuperKeyword,
2956
+ ts.SyntaxKind.TrueKeyword,
2957
+ ts.SyntaxKind.FalseKeyword,
2958
+ ts.SyntaxKind.NullKeyword,
2959
+ ]);
2960
+ /**
2961
+ * Enumerates every comment trivia range in `text` via a `ts.Scanner` over the raw
2962
+ * source. The scanner keeps comment-looking text inside strings, templates, and
2963
+ * (with regex re-lexing) regex literals bound to those tokens, so the ranges it
2964
+ * returns are always genuine comments — never a `//` buried in a string or regex.
2965
+ *
2966
+ * @param text - Raw chunk source to scan.
2967
+ * @returns Every comment trivia range, in ascending source order.
2968
+ */
2969
+ const collectComments = (text) => {
2970
+ const scanner = ts.createScanner(ts.ScriptTarget.Latest, /*skipTrivia*/ false, ts.LanguageVariant.Standard, text);
2971
+ const ranges = [];
2972
+ // why: start-of-input is an expression position, so a leading `/` opens a regex.
2973
+ let prevSignificant = ts.SyntaxKind.Unknown;
2974
+ // why: ts.Scanner.scan() does not resume a template literal across its `${...}` substitution on its own — it returns the substitution's closing `}` as a bare CloseBraceToken, so the next backtick is mis-lexed as *opening* a string instead of closing the template. That flips backtick polarity for the rest of the file and exposes `//`/`/*` inside later templates as phantom comments. Track each open substitution's brace depth so the `}` that closes one is re-lexed as the template's continuation (TemplateMiddle when another `${` follows, TemplateTail when the backtick closes); a depth>0 brace is an ordinary block/object brace inside the expression and is left alone.
2975
+ const templateBraceDepths = [];
2976
+ let token = scanner.scan();
2977
+ while (token !== ts.SyntaxKind.EndOfFileToken) {
2978
+ const inSubstitution = templateBraceDepths.length > 0;
2979
+ if ((token === ts.SyntaxKind.SlashToken || token === ts.SyntaxKind.SlashEqualsToken) && !VALUE_END_TOKENS.has(prevSignificant)) {
2980
+ // why: a `/` in expression position is a regex; re-lex the whole literal so its body is never tokenized into stray comments. reScanSlashToken returns the original SlashToken when no valid regex closes on the line, which leaves a true division untouched.
2981
+ token = scanner.reScanSlashToken();
2982
+ }
2983
+ else if (token === ts.SyntaxKind.CloseBraceToken && inSubstitution && templateBraceDepths[templateBraceDepths.length - 1] === 0) {
2984
+ // why: this `}` closes the innermost `${...}`; re-lex it as the template's continuation so the trailing backtick is scanned as template text, not a fresh string opener.
2985
+ token = scanner.reScanTemplateToken(/*isTaggedTemplate*/ false);
2986
+ }
2987
+ if (token === ts.SyntaxKind.SingleLineCommentTrivia || token === ts.SyntaxKind.MultiLineCommentTrivia) {
2988
+ ranges.push({ start: scanner.getTokenStart(), end: scanner.getTextPos() });
2989
+ }
2990
+ else if (token !== ts.SyntaxKind.WhitespaceTrivia && token !== ts.SyntaxKind.NewLineTrivia) {
2991
+ // why: comments and whitespace don't change whether the next `/` is division or regex; only real tokens do.
2992
+ prevSignificant = token;
2993
+ }
2994
+ // why: maintain the substitution-depth stack after re-lexing so each token's effect (open a substitution, descend/ascend a nested brace, or close the template) is counted once.
2995
+ if (token === ts.SyntaxKind.TemplateHead)
2996
+ templateBraceDepths.push(0);
2997
+ else if (token === ts.SyntaxKind.TemplateTail)
2998
+ templateBraceDepths.pop();
2999
+ else if (inSubstitution && token === ts.SyntaxKind.OpenBraceToken)
3000
+ templateBraceDepths[templateBraceDepths.length - 1]++;
3001
+ else if (inSubstitution && token === ts.SyntaxKind.CloseBraceToken)
3002
+ templateBraceDepths[templateBraceDepths.length - 1]--;
3003
+ token = scanner.scan();
3004
+ }
3005
+ return ranges;
3006
+ };
3007
+ // why: include `\r` so a CRLF whole-line comment (trailing `\r` before the `\n`) still takes the line-collapse path. Rollup emits LF today, but a CRLF chunk would otherwise leave the `\r\n` residue behind.
3008
+ const isBlankSlice = (text, from, to) => /^[ \t\r]*$/.test(text.slice(from, to));
3009
+ const lineStartOf = (text, pos) => text.lastIndexOf('\n', pos - 1) + 1;
3010
+ const nextNewline = (text, pos) => {
3011
+ const nl = text.indexOf('\n', pos);
3012
+ return nl === -1 ? text.length : nl;
3013
+ };
3014
+ /**
3015
+ * Expands a bare comment range to the removal range actually spliced out.
3016
+ *
3017
+ * A comment that occupies a whole line (only whitespace before it on the line and
3018
+ * only whitespace after it up to the newline) is removed line-and-all, then any
3019
+ * immediately following blank lines are swallowed so contiguous JSDoc/banner
3020
+ * removals collapse without leaving blank-line residue. An inline comment is
3021
+ * removed verbatim. Blank-line swallowing is template-safe by construction:
3022
+ * comments only exist in code context, so the lines adjacent to a removed comment
3023
+ * are never inside a string or template literal.
3024
+ *
3025
+ * @param text - Raw chunk source the comment was found in.
3026
+ * @param comment - The bare comment range to expand.
3027
+ * @returns The offset range to splice out for this comment.
3028
+ */
3029
+ const removalRange = (text, comment) => {
3030
+ const lineStart = lineStartOf(text, comment.start);
3031
+ const eol = nextNewline(text, comment.end);
3032
+ const wholeLine = isBlankSlice(text, lineStart, comment.start) && isBlankSlice(text, comment.end, eol);
3033
+ if (!wholeLine)
3034
+ return comment;
3035
+ let to = eol < text.length ? eol + 1 : eol;
3036
+ while (to < text.length) {
3037
+ const nl = nextNewline(text, to);
3038
+ if (!isBlankSlice(text, to, nl))
3039
+ break;
3040
+ to = nl < text.length ? nl + 1 : nl;
3041
+ }
3042
+ return { start: lineStart, end: to };
3043
+ };
3044
+
3045
+ const stripComments = (source) => {
3046
+ const removable = collectComments(source).filter((range) => !PRESERVE.test(source.slice(range.start, range.end)));
3047
+ if (removable.length === 0)
3048
+ return null;
3049
+ const ranges = removable.map((comment) => removalRange(source, comment));
3050
+ // why: splice from the back so each earlier (smaller) offset stays valid; the ranges are disjoint and ascending, so descending removal never disturbs a not-yet-applied offset.
3051
+ let out = source;
3052
+ for (let i = ranges.length - 1; i >= 0; i--)
3053
+ out = out.slice(0, ranges[i].start) + out.slice(ranges[i].end);
3054
+ return out;
3055
+ };
3056
+
3057
+ const stripCommentsPass = (depsRoot) => {
3058
+ const result = { commentBytesRemoved: 0 };
3059
+ if (!exists(depsRoot))
3060
+ return result;
3061
+ const chunks = [];
3062
+ walkFiles(depsRoot, (name) => name === 'index.esm.js' || name === 'index.cjs.js', chunks);
3063
+ for (const chunk of chunks) {
3064
+ const source = readFileContent(chunk);
3065
+ const stripped = stripComments(source);
3066
+ if (stripped === null)
3067
+ continue;
3068
+ writeFileContent(chunk, stripped);
3069
+ result.commentBytesRemoved += Buffer.byteLength(source) - Buffer.byteLength(stripped);
3070
+ }
3071
+ return result;
3072
+ };
3073
+
3074
+ const log$2 = logger.channel('builder:bundle:dependencies:prune');
3075
+
3076
+ const pruneDependencies = (context, monitor) => {
3077
+ const depsRoot = depsRootOf(context);
3078
+ const orphans = pruneOrphanChunks(context, depsRoot);
3079
+ monitor?.check('bundle:dependencies:prune:orphans:end');
3080
+ const deadExports = stripDeadExportsPass(context, depsRoot);
3081
+ monitor?.check('bundle:dependencies:prune:dead-exports:end');
3082
+ const properties = stripDeadPropertiesPass(context, depsRoot);
3083
+ monitor?.check('bundle:dependencies:prune:property-strip:end');
3084
+ // why: dropping a namespace slot orphans the factory binding it held alive; a second export strip collapses those (and re-narrows the imports they pulled).
3085
+ const cascade = properties.deadPropertiesRemoved > 0 ? stripDeadExportsPass(context, depsRoot) : { deadExportsRemoved: 0, bytesRemoved: 0 };
3086
+ // why: a chunk whose last importing symbol was just stripped is now an orphan; reclaim it (and any d.ts left behind).
3087
+ const resweep = pruneOrphanChunks(context, depsRoot);
3088
+ // why: collapse whole-module CJS require bindings to destructures once the chunk surfaces are final; runs among the AST passes (before the comment strip) since it rewrites member-access spans.
3089
+ const destructured = destructureRequiresPass(depsRoot);
3090
+ monitor?.check('bundle:dependencies:prune:destructure-requires:end');
3091
+
3092
+ const comments = stripCommentsPass(depsRoot);
3093
+ monitor?.check('bundle:dependencies:prune:comment-strip:end');
3094
+ const report = {
3095
+ orphanFilesRemoved: orphans.orphanFilesRemoved + resweep.orphanFilesRemoved,
3096
+ deadExportsRemoved: deadExports.deadExportsRemoved + cascade.deadExportsRemoved,
3097
+ deadPropertiesRemoved: properties.deadPropertiesRemoved,
3098
+ requireBindingsDestructured: destructured.requireBindingsDestructured,
3099
+ commentBytesRemoved: comments.commentBytesRemoved,
3100
+ bytesRemoved: orphans.bytesRemoved +
3101
+ deadExports.bytesRemoved +
3102
+ properties.bytesRemoved +
3103
+ cascade.bytesRemoved +
3104
+ resweep.bytesRemoved +
3105
+ comments.commentBytesRemoved,
3106
+ };
3107
+ if (report.orphanFilesRemoved > 0 ||
3108
+ report.deadExportsRemoved > 0 ||
3109
+ report.deadPropertiesRemoved > 0 ||
3110
+ report.requireBindingsDestructured > 0 ||
3111
+ report.commentBytesRemoved > 0) {
3112
+ log$2.info(`pruned ${report.orphanFilesRemoved} orphan dependency file(s), ${report.deadExportsRemoved} dead export(s), and ${report.deadPropertiesRemoved} dead namespace slot(s), destructured ${report.requireBindingsDestructured} require binding(s), stripped ${report.commentBytesRemoved} comment byte(s), reclaimed ${report.bytesRemoved} byte(s)`);
3113
+ }
3114
+ return report;
3115
+ };
3116
+
3117
+ const readPkg = (packageJsonPath) => (exists$1(packageJsonPath) ? readJsonFile(packageJsonPath) : {});
3118
+ /**
3119
+ * Resolves the external package list for a single bundle.
3120
+ *
3121
+ * The output combines:
3122
+ * - top-level `dependencies` from the project's `package.json`
3123
+ * - `peerDependencies` (always external regardless of `bundleWorkspaceDeps`)
3124
+ * - the caller-supplied `additional` list
3125
+ *
3126
+ * When `bundleWorkspaceDeps` is `true` and a workspace predicate is supplied, packages
3127
+ * matching the predicate are stripped from `dependencies` and `additional` so they get
3128
+ * inlined by the bundler. Peer dependencies are always preserved.
3129
+ *
3130
+ * @param options - Inputs controlling the resolution.
3131
+ * @returns Sorted, de-duplicated list of external package names.
3132
+ *
3133
+ * @example Resolving externals while inlining workspace deps
3134
+ * ```typescript
3135
+ * const external = resolveExternals({
3136
+ * packageJsonPath: '/abs/libs/foo/package.json',
3137
+ * isWorkspacePackage: (n) => n.startsWith('@hyperfrontend/'),
3138
+ * bundleWorkspaceDeps: true,
3139
+ * })
3140
+ * ```
3141
+ */
3142
+ const resolveExternals = (options) => {
3143
+ const pkg = readPkg(options.packageJsonPath);
3144
+ const deps = keys(pkg.dependencies ?? {});
3145
+ const peerDeps = keys(pkg.peerDependencies ?? {});
3146
+ const additional = options.additional ?? [];
3147
+ const bundledSet = createSet(options.bundledDeps ?? []);
3148
+ const workspaceBundledSet = createSet(options.workspaceBundledDepNames ?? []);
3149
+ const inlineWorkspace = options.bundleWorkspaceDeps === true && options.isWorkspacePackage !== undefined;
3150
+ const filterWorkspace = (names) => inlineWorkspace ? names.filter((n) => !options.isWorkspacePackage(n)) : names;
3151
+ const filterBundled = (names) => (bundledSet.size === 0 ? names : names.filter((n) => !bundledSet.has(n)));
3152
+ const filterWorkspaceBundled = (names) => workspaceBundledSet.size === 0 ? names : names.filter((n) => !workspaceBundledSet.has(n));
3153
+ return from(createSet([
3154
+ ...filterWorkspaceBundled(filterBundled(filterWorkspace(deps))),
3155
+ ...filterWorkspaceBundled(filterBundled(peerDeps)),
3156
+ ...filterWorkspaceBundled(filterBundled(filterWorkspace(additional))),
3157
+ ]));
3158
+ };
3159
+
3160
+ const computeEntryOutputDir = (entry, context) => entry.srcPath ? join$3(context.outputPath, entry.srcPath) : context.outputPath;
3161
+ const computeBundleOutputDir = (bundleSubDir, context) => join$3(context.outputPath, bundleSubDir ?? 'bundle');
3162
+ /**
3163
+ * Builds the worker descriptor for the ESM output of a single entry point.
3164
+ *
3165
+ * The returned descriptor is fully serializable (no functions), ready to be
3166
+ * passed to {@link dispatchRollupWorker}.
3167
+ *
3168
+ * @param entry - Entry point to compile.
3169
+ * @param config - ESM-format configuration.
3170
+ * @param context - Resolved build context.
3171
+ * @param reportPath - Absolute path the worker will write its JSON report to.
3172
+ * @returns Descriptor ready to be JSON-serialized for the worker.
3173
+ *
3174
+ * @example Producing the descriptor for the root entry
3175
+ * ```typescript
3176
+ * const descriptor = toEsmBuildDescriptor(entry, esmConfig, context, '/tmp/report.json')
3177
+ * ```
3178
+ */
3179
+ const toEsmBuildDescriptor = (entry, config, context, reportPath) => {
3180
+ const outputDir = computeEntryOutputDir(entry, context);
3181
+ const sourcemap = config.sourcemap ?? false;
3182
+ const bundleWorkspaceDeps = config.bundleWorkspaceDeps ?? true;
3183
+ const bundleAllRequested = Boolean(config.bundleAllDeps);
3184
+ const bundledDeps = bundleAllRequested ? context.bundledDeps : [];
3185
+ const workspaceRoutes = bundleAllRequested ? buildWorkspaceRoutes(context.workspaceBundledDeps) : [];
3186
+ const useExternalizePlugin = bundledDeps.length > 0 || workspaceRoutes.length > 0;
3187
+ const external = resolveExternals({
3188
+ packageJsonPath: join$3(context.projectRoot, 'package.json'),
3189
+ additional: [...context.external, ...(config.external ?? [])],
3190
+ isWorkspacePackage: context.isWorkspacePackage,
3191
+ bundleWorkspaceDeps,
3192
+ bundledDeps,
3193
+ workspaceBundledDepNames: workspaceRoutes.map((r) => r.packageName),
3194
+ });
3195
+ return {
3196
+ format: 'esm',
3197
+ inputFile: entry.inputFile,
3198
+ outputDir,
3199
+ external,
3200
+ sourcemap,
3201
+ bundledDepsPlugin: useExternalizePlugin ? { deps: bundledDeps, depsRoot: depsRootOf(context) } : null,
3202
+ workspaceRoutes,
3203
+ tsConfigPath: context.tsConfigPath,
3204
+ projectRoot: context.projectRoot,
3205
+ workspaceRoot: context.workspaceRoot,
3206
+ bundleWorkspaceDeps,
3207
+ bundle: null,
3208
+ bin: null,
3209
+ reportPath,
3210
+ };
3211
+ };
3212
+ /**
3213
+ * Builds the worker descriptor for the CommonJS output of a single entry point.
3214
+ *
3215
+ * @param entry - Entry point to compile.
3216
+ * @param config - CJS-format configuration.
3217
+ * @param context - Resolved build context.
3218
+ * @param reportPath - Absolute path the worker will write its JSON report to.
3219
+ * @returns Descriptor ready to be JSON-serialized for the worker.
3220
+ *
3221
+ * @example Producing the descriptor for the root entry
3222
+ * ```typescript
3223
+ * const descriptor = toCjsBuildDescriptor(entry, cjsConfig, context, '/tmp/report.json')
3224
+ * ```
3225
+ */
3226
+ const toCjsBuildDescriptor = (entry, config, context, reportPath) => {
3227
+ const outputDir = computeEntryOutputDir(entry, context);
3228
+ const sourcemap = config.sourcemap ?? false;
3229
+ const bundleWorkspaceDeps = config.bundleWorkspaceDeps ?? true;
3230
+ const bundleAllRequested = Boolean(config.bundleAllDeps);
3231
+ const bundledDeps = bundleAllRequested ? context.bundledDeps : [];
3232
+ const workspaceRoutes = bundleAllRequested ? buildWorkspaceRoutes(context.workspaceBundledDeps) : [];
3233
+ const useExternalizePlugin = bundledDeps.length > 0 || workspaceRoutes.length > 0;
3234
+ const external = resolveExternals({
3235
+ packageJsonPath: join$3(context.projectRoot, 'package.json'),
3236
+ additional: [...context.external, ...(config.external ?? [])],
3237
+ isWorkspacePackage: context.isWorkspacePackage,
3238
+ bundleWorkspaceDeps,
3239
+ bundledDeps,
3240
+ workspaceBundledDepNames: workspaceRoutes.map((r) => r.packageName),
3241
+ });
3242
+ return {
3243
+ format: 'cjs',
3244
+ inputFile: entry.inputFile,
3245
+ outputDir,
3246
+ external,
3247
+ sourcemap,
3248
+ bundledDepsPlugin: useExternalizePlugin ? { deps: bundledDeps, depsRoot: depsRootOf(context) } : null,
3249
+ workspaceRoutes,
3250
+ tsConfigPath: context.tsConfigPath,
3251
+ projectRoot: context.projectRoot,
3252
+ workspaceRoot: context.workspaceRoot,
3253
+ bundleWorkspaceDeps,
3254
+ bundle: null,
3255
+ bin: null,
3256
+ reportPath,
3257
+ };
3258
+ };
3259
+ /**
3260
+ * Builds the worker descriptor for an IIFE bundle of a single entry point.
3261
+ *
3262
+ * Validates the externals/globals pairing eagerly, throwing before the
3263
+ * descriptor is returned.
3264
+ *
3265
+ * @param entry - Entry point to bundle.
3266
+ * @param config - IIFE-format configuration.
3267
+ * @param context - Resolved build context.
3268
+ * @param reportPath - Absolute path the worker will write its JSON report to.
3269
+ * @returns Descriptor ready to be JSON-serialized for the worker.
3270
+ * @throws {Error} When `config.external` is non-empty but `config.globals` is missing entries.
3271
+ *
3272
+ * @example Producing the descriptor for an IIFE bundle
3273
+ * ```typescript
3274
+ * const descriptor = toIifeBuildDescriptor(entry, iifeConfig, context, '/tmp/report.json')
3275
+ * ```
3276
+ */
3277
+ const toIifeBuildDescriptor = (entry, config, context, reportPath) => {
3278
+ validateExternalsConfig(config.external, config.globals);
3279
+ const outputDir = computeBundleOutputDir(config.output, context);
3280
+ const sourcemap = config.sourcemap ?? false;
3281
+ const minify = config.minify ?? true;
3282
+ return {
3283
+ format: 'iife',
3284
+ inputFile: entry.inputFile,
3285
+ outputDir,
3286
+ external: config.external ?? [],
3287
+ sourcemap,
3288
+ bundledDepsPlugin: null,
3289
+ workspaceRoutes: [],
3290
+ tsConfigPath: context.tsConfigPath,
3291
+ projectRoot: context.projectRoot,
3292
+ workspaceRoot: context.workspaceRoot,
3293
+ bundleWorkspaceDeps: false,
3294
+ bundle: { globalName: config.globalName, minify, globals: config.globals },
3295
+ bin: null,
3296
+ reportPath,
3297
+ };
3298
+ };
3299
+ /**
3300
+ * Builds the worker descriptor for a UMD bundle of a single entry point.
3301
+ *
3302
+ * Validates the externals/globals pairing eagerly, throwing before the
3303
+ * descriptor is returned.
3304
+ *
3305
+ * @param entry - Entry point to bundle.
3306
+ * @param config - UMD-format configuration.
3307
+ * @param context - Resolved build context.
3308
+ * @param reportPath - Absolute path the worker will write its JSON report to.
3309
+ * @returns Descriptor ready to be JSON-serialized for the worker.
3310
+ * @throws {Error} When `config.external` is non-empty but `config.globals` is missing entries.
3311
+ *
3312
+ * @example Producing the descriptor for a UMD bundle
3313
+ * ```typescript
3314
+ * const descriptor = toUmdBuildDescriptor(entry, umdConfig, context, '/tmp/report.json')
3315
+ * ```
3316
+ */
3317
+ const toUmdBuildDescriptor = (entry, config, context, reportPath) => {
3318
+ validateExternalsConfig(config.external, config.globals);
3319
+ const outputDir = computeBundleOutputDir(config.output, context);
3320
+ const sourcemap = config.sourcemap ?? false;
3321
+ const minify = config.minify ?? true;
3322
+ return {
3323
+ format: 'umd',
3324
+ inputFile: entry.inputFile,
3325
+ outputDir,
3326
+ external: config.external ?? [],
3327
+ sourcemap,
3328
+ bundledDepsPlugin: null,
3329
+ workspaceRoutes: [],
3330
+ tsConfigPath: context.tsConfigPath,
3331
+ projectRoot: context.projectRoot,
3332
+ workspaceRoot: context.workspaceRoot,
3333
+ bundleWorkspaceDeps: false,
3334
+ bundle: { globalName: config.globalName, minify, globals: config.globals, amdId: config.amdId },
3335
+ bin: null,
3336
+ reportPath,
3337
+ };
3338
+ };
3339
+
3340
+ const log$1 = logger.channel('builder:bundle:rollup:dispatch');
3341
+ const REPORT_DIR_PREFIX = 'hf-builder-rollup-';
3342
+ const SWC_NODE_REGISTER = '@swc-node/register';
3343
+ const swcNodeAvailable = (workspaceRoot) => existsSync(join$2(workspaceRoot, 'node_modules', '@swc-node', 'register', 'index.js'));
3344
+ /**
3345
+ * Default worker-path resolution: prefers the built-and-published artifact, falls
3346
+ * back to the workspace dist path, and finally to the in-source TypeScript file
3347
+ * via `@swc-node/register` (bootstrap case where builder is building itself for
3348
+ * the first time and the dist worker doesn't exist yet).
3349
+ *
3350
+ * Looks at, in order:
3351
+ * 1. `<workspaceRoot>/dist/libs/builder/bundle/rollup/worker/index.cjs.js`
3352
+ * 2. `<workspaceRoot>/node_modules/@hyperfrontend/builder/bundle/rollup/worker/index.cjs.js`
3353
+ * 3. `<workspaceRoot>/libs/builder/src/bundle/rollup/worker/index.ts` (with `--require \@swc-node/register`)
3354
+ *
3355
+ * @param workspaceRoot - Absolute workspace root.
3356
+ * @returns Worker invocation descriptor, or `undefined` if no candidate exists.
3357
+ *
3358
+ * @example Locating the worker for an in-workspace consumer
3359
+ * ```typescript
3360
+ * const invocation = resolveDefaultRollupWorkerPath('/abs/repo')
3361
+ * if (!invocation) throw new Error('builder rollup worker artifact not found')
3362
+ * ```
3363
+ */
3364
+ const resolveDefaultRollupWorkerPath = (workspaceRoot) => {
3365
+ const distCandidates = [
3366
+ join$2(workspaceRoot, 'dist', 'libs', 'builder', 'bundle', 'rollup', 'worker', 'index.cjs.js'),
3367
+ join$2(workspaceRoot, 'node_modules', '@hyperfrontend', 'builder', 'bundle', 'rollup', 'worker', 'index.cjs.js'),
3368
+ ];
3369
+ for (const path of distCandidates) {
3370
+ if (existsSync(path))
3371
+ return { path, execArgv: [] };
3372
+ }
3373
+ const sourcePath = join$2(workspaceRoot, 'libs', 'builder', 'src', 'bundle', 'rollup', 'worker', 'index.ts');
3374
+ if (existsSync(sourcePath) && swcNodeAvailable(workspaceRoot)) {
3375
+ return { path: sourcePath, execArgv: ['--require', SWC_NODE_REGISTER] };
3376
+ }
3377
+ return undefined;
3378
+ };
3379
+ const createReportDir = () => mkdtempSync(join$2(tmpdir(), REPORT_DIR_PREFIX));
3380
+ const reportPathFor = (reportDir, descriptor) => {
3381
+ const safeLabel = descriptor.inputFile.replace(/[^a-zA-Z0-9_-]+/g, '_');
3382
+ return join$2(reportDir, `${descriptor.format}-${safeLabel}.json`);
3383
+ };
3384
+ const runOne = (descriptor, options, label) => createPromise((resolve, reject) => {
3385
+ const execPath = options.execPath ?? process.execPath;
3386
+ const argv = [...(options.execArgv ?? []), options.workerPath, stringify(descriptor)];
3387
+ const child = spawn(execPath, argv, { stdio: ['ignore', 'pipe', 'pipe'] });
3388
+ let capturedStderr = '';
3389
+ child.stdout?.on('data', (chunk) => {
3390
+ process.stdout.write(chunk);
3391
+ });
3392
+ child.stderr?.on('data', (chunk) => {
3393
+ const text = typeof chunk === 'string' ? chunk : chunk.toString();
3394
+ capturedStderr += text;
3395
+ process.stderr.write(text);
3396
+ });
3397
+ child.on('error', (error) => {
3398
+ reject(createError(`rollup worker for ${label} failed to spawn: ${error.message}`));
3399
+ });
3400
+ child.on('exit', (code) => {
3401
+ if (code !== 0) {
3402
+ const tail = capturedStderr.trim().split('\n').slice(-10).join('\n');
3403
+ reject(createError(`rollup worker for ${label} exited with code ${code}\n${tail}`));
3404
+ return;
3405
+ }
3406
+ resolve();
3407
+ });
3408
+ });
3409
+ const readReport = (reportPath, label) => {
3410
+ if (!existsSync(reportPath)) {
3411
+ throw createError(`rollup worker for ${label} did not write a report at ${reportPath}`);
3412
+ }
3413
+ const data = parse(readFileSync(reportPath, 'utf8'));
3414
+ return data;
3415
+ };
3416
+ /**
3417
+ * Forks a single rollup worker for the supplied descriptor and waits for it
3418
+ * to exit. The caller-provided descriptor's `reportPath` is overwritten with
3419
+ * a temp-dir path created by this function.
3420
+ *
3421
+ * Each worker writes a JSON report at the temp path; this function reads it
3422
+ * after the child exits and returns the per-job statistics. If the worker
3423
+ * exits non-zero or fails to produce a report, the function throws with a
3424
+ * label-rich message.
3425
+ *
3426
+ * The temp report directory is cleaned up before returning, regardless of
3427
+ * success or failure.
3428
+ *
3429
+ * @param descriptor - Build descriptor to dispatch.
3430
+ * @param options - Worker path + optional memory monitor.
3431
+ * @returns Worker report (output size + memory + duration) for the dispatched job.
3432
+ *
3433
+ * @example Dispatching a single ESM build
3434
+ * ```typescript
3435
+ * const report = await dispatchRollupWorker(descriptor, { workerPath: '/abs/dist/.../worker.cjs.js' })
3436
+ * ```
3437
+ */
3438
+ const dispatchRollupWorker = async (descriptor, options) => {
3439
+ const reportDir = createReportDir();
3440
+ const label = options.label ?? `${descriptor.format}:${descriptor.inputFile}`;
3441
+ const reportPath = reportPathFor(reportDir, descriptor);
3442
+ const job = { ...descriptor, reportPath };
3443
+ try {
3444
+ options.monitor?.check(`bundle:rollup:dispatch:${label}:start`);
3445
+ log$1.info(`rollup dispatch: ${label}`);
3446
+ await runOne(job, options, label);
3447
+ const report = readReport(reportPath, label);
3448
+ log$1.debug(`rollup dispatch done: ${label} size=${report.outputSize}B heap=${report.endHeapMB.toFixed(1)}MB rss=${report.endRssMB.toFixed(1)}MB t=${report.durationMs}ms`);
3449
+ options.monitor?.check(`bundle:rollup:dispatch:${label}:end`);
3450
+ return report;
3451
+ }
3452
+ finally {
3453
+ rmSync(reportDir, { recursive: true, force: true });
3454
+ }
3455
+ };
3456
+
3457
+ const log = logger.channel('builder:bundle');
3458
+ const toArray = (value) => (value === undefined ? [] : isArray(value) ? value : [value]);
3459
+ const collectFormatsRequestingPrePass = (config) => {
3460
+ const formats = createSet([]);
3461
+ for (const c of toArray(config.esm))
3462
+ if (c.bundleAllDeps)
3463
+ formats.add('esm');
3464
+ for (const c of toArray(config.cjs))
3465
+ if (c.bundleAllDeps)
3466
+ formats.add('cjs');
3467
+ return from(formats);
3468
+ };
3469
+ const buildJsPrePassJobs = (deps, formats, context) => {
3470
+ const jobs = [];
3471
+ const depsRoot = depsRootOf(context);
3472
+ const workspacePrefixDeps = collectWorkspacePrefixDeps(context);
3473
+ const workspaceExactSpecifiers = collectWorkspaceExactSpecifiers(context);
3474
+ const workspaceRoutes = buildWorkspaceRoutes(context.workspaceBundledDeps);
3475
+ for (const dep of deps) {
3476
+ const entry = resolveDepEntry({ dep, projectRoot: context.projectRoot, workspaceRoot: context.workspaceRoot, kind: 'js' });
3477
+ const otherNpmDeps = deps.filter((d) => d !== dep);
3478
+ for (const format of formats) {
3479
+ jobs.push({
3480
+ kind: 'js',
3481
+ dep,
3482
+ inputPath: entry,
3483
+ format,
3484
+ outputPath: join$2(depsRoot, dep, chunkFileName(format)),
3485
+ otherDeps: [...otherNpmDeps, ...workspacePrefixDeps],
3486
+ otherWorkspaceSpecifiers: workspaceExactSpecifiers,
3487
+ npmDeps: otherNpmDeps,
3488
+ workspaceRoutes,
3489
+ depsRoot,
3490
+ });
3491
+ }
3492
+ }
3493
+ return jobs;
3494
+ };
3495
+ const workspaceOutputFile = (entry, format) => {
3496
+ const fileName = chunkFileName(format);
3497
+ return entry.subPath ? `${entry.specifier}/${fileName}` : `${entry.packageName}/${fileName}`;
3498
+ };
3499
+ const filterRouteEntries = (entry, all) => all.filter((other) => (entry.policy === 'sub-path' ? other.specifier !== entry.specifier : other.packageName !== entry.packageName));
3500
+ const buildWorkspaceJsPrePassJobs = (npmDeps, formats, context) => {
3501
+ if (context.workspaceBundledDeps.length === 0)
3502
+ return [];
3503
+ const jobs = [];
3504
+ const depsRoot = depsRootOf(context);
3505
+ const wholeSurface = collectWorkspacePrefixDeps(context);
3506
+ const subPathSpecifiers = collectWorkspaceExactSpecifiers(context);
3507
+ for (const entry of context.workspaceBundledDeps) {
3508
+ const otherWorkspacePackages = wholeSurface.filter((name) => name !== entry.packageName || entry.policy === 'sub-path');
3509
+ const otherSubPathSpecifiers = subPathSpecifiers.filter((spec) => spec !== entry.specifier);
3510
+ const workspaceRoutes = buildWorkspaceRoutes(filterRouteEntries(entry, context.workspaceBundledDeps));
3511
+ for (const format of formats) {
3512
+ jobs.push({
3513
+ kind: 'workspace-js',
3514
+ dep: entry.specifier,
3515
+ inputPath: entry.inputPath,
3516
+ format,
3517
+ outputPath: join$2(depsRoot, workspaceOutputFile(entry, format)),
3518
+ otherDeps: [...npmDeps, ...otherWorkspacePackages],
3519
+ otherWorkspaceSpecifiers: otherSubPathSpecifiers,
3520
+ tsConfigPath: entry.tsConfigPath,
3521
+ workspaceRoot: context.workspaceRoot,
3522
+ npmDeps,
3523
+ workspaceRoutes,
3524
+ depsRoot,
3525
+ });
3526
+ }
3527
+ }
3528
+ return jobs;
3529
+ };
3530
+ const resolvePrePassWorkerOrThrow = (workspaceRoot) => {
3531
+ const invocation = resolveDefaultWorkerPath(workspaceRoot);
3532
+ if (!invocation) {
3533
+ throw createError('bundleAllDeps is enabled but the pre-pass worker could not be resolved. Build @hyperfrontend/builder once with bundleAllDeps disabled, or ensure @swc-node/register is installed for source-mode bootstrap.');
3534
+ }
3535
+ return invocation;
3536
+ };
3537
+ const resolveRollupWorkerOrThrow = (workspaceRoot) => {
3538
+ const invocation = resolveDefaultRollupWorkerPath(workspaceRoot);
3539
+ if (!invocation) {
3540
+ throw createError('rollup worker could not be resolved. Build @hyperfrontend/builder at least once before invoking the bundle phase, or ensure @swc-node/register is installed for source-mode bootstrap.');
3541
+ }
3542
+ return invocation;
3543
+ };
3544
+ const createLazyDispatchResolver = (workspaceRoot) => {
3545
+ let cached = null;
3546
+ return () => {
3547
+ if (!cached) {
3548
+ const invocation = resolveRollupWorkerOrThrow(workspaceRoot);
3549
+ cached = { workerPath: invocation.path, execArgv: invocation.execArgv };
3550
+ }
3551
+ return cached;
3552
+ };
3553
+ };
3554
+ const dispatch = async (descriptor, label, options) => {
3555
+ await dispatchRollupWorker(descriptor, {
3556
+ workerPath: options.workerPath,
3557
+ execArgv: options.execArgv,
3558
+ label,
3559
+ });
3560
+ };
3561
+ const runEsmFormats = async (config, context, outputs, resolveDispatch, monitor) => {
3562
+ for (const esmConfig of toArray(config.esm)) {
3563
+ const entries = resolveEntries(esmConfig, context.entryPointDiscovery.entryPoints);
3564
+ for (const [i, entry] of entries.entries()) {
3565
+ const label = `esm:${i}/${entries.length}:${entry.exportPath}`;
3566
+ monitor?.check(`bundle:${label}:start`);
3567
+ const descriptor = toEsmBuildDescriptor(entry, esmConfig, context, '');
3568
+ await dispatch(descriptor, label, resolveDispatch());
3569
+ monitor?.check(`bundle:${label}:end`);
3570
+ }
3571
+ outputs.esm.push(...entries);
3572
+ }
3573
+ };
3574
+ const runCjsFormats = async (config, context, outputs, resolveDispatch, monitor) => {
3575
+ for (const cjsConfig of toArray(config.cjs)) {
3576
+ const entries = resolveEntries(cjsConfig, context.entryPointDiscovery.entryPoints);
3577
+ for (const [i, entry] of entries.entries()) {
3578
+ const label = `cjs:${i}/${entries.length}:${entry.exportPath}`;
3579
+ monitor?.check(`bundle:${label}:start`);
3580
+ const descriptor = toCjsBuildDescriptor(entry, cjsConfig, context, '');
3581
+ await dispatch(descriptor, label, resolveDispatch());
3582
+ monitor?.check(`bundle:${label}:end`);
3583
+ }
3584
+ outputs.cjs.push(...entries);
3585
+ }
3586
+ };
3587
+ const runIifeFormats = async (config, context, outputs, resolveDispatch, monitor) => {
3588
+ for (const iifeConfig of toArray(config.iife)) {
3589
+ const entries = resolveEntries(iifeConfig, context.entryPointDiscovery.entryPoints);
3590
+ if (entries.length === 0)
3591
+ continue;
3592
+ ensureDir(join$2(context.outputPath, iifeConfig.output ?? 'bundle'));
3593
+ for (const [i, entry] of entries.entries()) {
3594
+ const label = `iife:${i}/${entries.length}:${entry.exportPath}`;
3595
+ monitor?.check(`bundle:${label}:start`);
3596
+ const descriptor = toIifeBuildDescriptor(entry, iifeConfig, context, '');
3597
+ await dispatch(descriptor, label, resolveDispatch());
3598
+ monitor?.check(`bundle:${label}:end`);
3599
+ }
3600
+ outputs.iife.push({ config: iifeConfig, entries });
3601
+ }
3602
+ };
3603
+ const runUmdFormats = async (config, context, outputs, resolveDispatch, monitor) => {
3604
+ for (const umdConfig of toArray(config.umd)) {
3605
+ const entries = resolveEntries(umdConfig, context.entryPointDiscovery.entryPoints);
3606
+ if (entries.length === 0)
3607
+ continue;
3608
+ ensureDir(join$2(context.outputPath, umdConfig.output ?? 'bundle'));
3609
+ for (const [i, entry] of entries.entries()) {
3610
+ const label = `umd:${i}/${entries.length}:${entry.exportPath}`;
3611
+ monitor?.check(`bundle:${label}:start`);
3612
+ const descriptor = toUmdBuildDescriptor(entry, umdConfig, context, '');
3613
+ await dispatch(descriptor, label, resolveDispatch());
3614
+ monitor?.check(`bundle:${label}:end`);
3615
+ }
3616
+ outputs.umd.push({ config: umdConfig, entries });
3617
+ }
3618
+ };
3619
+ /**
3620
+ * Runs the entire bundle phase: ESM, CJS, IIFE, UMD outputs followed by declaration emission.
3621
+ *
3622
+ * Iterates the format-specific configurations in `config`, resolves the matching
3623
+ * entry points for each format, and bundles every one. After all bundles are
3624
+ * written, emits `.d.ts` declarations for the project exactly once.
3625
+ *
3626
+ * @param context - Resolved build context.
3627
+ * @param config - Top-level builder configuration. Only the format and `tsConfig`
3628
+ * fields are consulted by this phase.
3629
+ * @param monitor - Optional memory monitor; when provided, peak heap inside the
3630
+ * bundle phase is sampled at each format and declaration step.
3631
+ * @returns Aggregated outputs grouped by format.
3632
+ *
3633
+ * @example Driving the bundle phase from a custom orchestrator
3634
+ * ```typescript
3635
+ * const formatOutputs = await runBundlePhase(context, config)
3636
+ * ```
3637
+ */
3638
+ const runBundlePhase = async (context, config, monitor) => {
3639
+ const outputs = { esm: [], cjs: [], iife: [], umd: [] };
3640
+ const requestedPrePassFormats = collectFormatsRequestingPrePass(config);
3641
+ if (requestedPrePassFormats.length > 0 && (context.bundledDeps.length > 0 || context.workspaceBundledDeps.length > 0)) {
3642
+ const invocation = resolvePrePassWorkerOrThrow(context.workspaceRoot);
3643
+ const npmJobs = buildJsPrePassJobs(context.bundledDeps, requestedPrePassFormats, context);
3644
+ const workspaceJobs = buildWorkspaceJsPrePassJobs(context.bundledDeps, requestedPrePassFormats, context);
3645
+ const jobs = [...npmJobs, ...workspaceJobs];
3646
+ log.info(`bundle dependencies pre-pass: ${context.bundledDeps.length} npm + ${context.workspaceBundledDeps.length} workspace × ${requestedPrePassFormats.length} formats = ${jobs.length} jobs`);
3647
+ monitor?.check('bundle:dependencies:prepass:start');
3648
+ await runPrePass(jobs, { workerPath: invocation.path, execArgv: invocation.execArgv, monitor });
3649
+ monitor?.check('bundle:dependencies:prepass:end');
3650
+ }
3651
+ const resolveDispatch = createLazyDispatchResolver(context.workspaceRoot);
3652
+ await runEsmFormats(config, context, outputs, resolveDispatch, monitor);
3653
+ await recover();
3654
+ monitor?.check('bundle:esm:end:post-recover');
3655
+ await runCjsFormats(config, context, outputs, resolveDispatch, monitor);
3656
+ await recover();
3657
+ monitor?.check('bundle:cjs:end:post-recover');
3658
+ await runIifeFormats(config, context, outputs, resolveDispatch, monitor);
3659
+ await runUmdFormats(config, context, outputs, resolveDispatch, monitor);
3660
+ await recover();
3661
+ monitor?.check('bundle:declarations:start');
3662
+ await generateDeclarations(context);
3663
+ monitor?.check('bundle:declarations:end');
3664
+ if (context.bundledDeps.length > 0 || context.workspaceBundledDeps.length > 0) {
3665
+ await runDtsPrePass(context, monitor);
3666
+ await runDtsPerEntry(context, monitor);
3667
+ }
3668
+ pruneOrphanDeclarations(context);
3669
+ monitor?.check('bundle:declarations:prune-orphans:end');
3670
+ if (context.bundledDeps.length > 0 || context.workspaceBundledDeps.length > 0) {
3671
+ pruneDependencies(context, monitor);
3672
+ monitor?.check('bundle:dependencies:prune:end');
3673
+ }
3674
+ // why: dedup runs after prune so the lifted `_shared/` files are still present when `finalizeFilesAllowlist` reflects the published output tree.
3675
+ if (config.dedupeSharedInternals !== false) {
3676
+ hoistSharedFirstParty(context, monitor);
3677
+ monitor?.check('bundle:dedupe:shared-first-party:end');
3678
+ }
3679
+ // why: runs last (after the final file-producing pass) so no later pass re-creates a file under a removed directory; sweeps the per-source dirs left empty by the orphan-d.ts prune across the whole package, not just `_dependencies/`. Guarded for the degenerate case where no format produced an output tree.
3680
+ if (exists(context.outputPath)) {
3681
+ const emptyDirsRemoved = removeEmptyDirs(context.outputPath);
3682
+ if (emptyDirsRemoved > 0)
3683
+ log.info(`removed ${emptyDirsRemoved} empty director${emptyDirsRemoved === 1 ? 'y' : 'ies'}`);
3684
+ }
3685
+ monitor?.check('bundle:empty-dirs:end');
3686
+ return outputs;
3687
+ };
3688
+
3689
+ export { runBundlePhase };