@seanhogg/builderforce-webcontainers-core 2026.10.2 → 2026.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (426) hide show
  1. package/dist/build.d.ts +42 -0
  2. package/dist/build.d.ts.map +1 -0
  3. package/dist/build.js +65 -0
  4. package/dist/build.js.map +1 -0
  5. package/dist/buildHost.d.ts +31 -0
  6. package/dist/buildHost.d.ts.map +1 -0
  7. package/dist/buildHost.js +125 -0
  8. package/dist/buildHost.js.map +1 -0
  9. package/dist/buildHtml.d.ts +28 -0
  10. package/dist/buildHtml.d.ts.map +1 -0
  11. package/dist/buildHtml.js +74 -0
  12. package/dist/buildHtml.js.map +1 -0
  13. package/dist/bundler.d.ts +129 -0
  14. package/dist/bundler.d.ts.map +1 -0
  15. package/dist/bundler.js +79 -0
  16. package/dist/bundler.js.map +1 -0
  17. package/dist/check/acquire.d.ts +46 -0
  18. package/dist/check/acquire.d.ts.map +1 -0
  19. package/dist/check/acquire.js +179 -0
  20. package/dist/check/acquire.js.map +1 -0
  21. package/dist/check/compilerHost.d.ts +22 -0
  22. package/dist/check/compilerHost.d.ts.map +1 -0
  23. package/dist/check/compilerHost.js +128 -0
  24. package/dist/check/compilerHost.js.map +1 -0
  25. package/dist/check/diagnostics.d.ts +23 -0
  26. package/dist/check/diagnostics.d.ts.map +1 -0
  27. package/dist/check/diagnostics.js +28 -0
  28. package/dist/check/diagnostics.js.map +1 -0
  29. package/dist/check/index.d.ts +19 -0
  30. package/dist/check/index.d.ts.map +1 -0
  31. package/dist/check/index.js +13 -0
  32. package/dist/check/index.js.map +1 -0
  33. package/dist/check/projects.d.ts +26 -0
  34. package/dist/check/projects.d.ts.map +1 -0
  35. package/dist/check/projects.js +124 -0
  36. package/dist/check/projects.js.map +1 -0
  37. package/dist/check/shims.d.ts +29 -0
  38. package/dist/check/shims.d.ts.map +1 -0
  39. package/dist/check/shims.js +76 -0
  40. package/dist/check/shims.js.map +1 -0
  41. package/dist/check/typeStore.d.ts +57 -0
  42. package/dist/check/typeStore.d.ts.map +1 -0
  43. package/dist/check/typeStore.js +89 -0
  44. package/dist/check/typeStore.js.map +1 -0
  45. package/dist/check/typecheck.d.ts +29 -0
  46. package/dist/check/typecheck.d.ts.map +1 -0
  47. package/dist/check/typecheck.js +91 -0
  48. package/dist/check/typecheck.js.map +1 -0
  49. package/dist/compileComponent.d.ts +8 -0
  50. package/dist/compileComponent.d.ts.map +1 -0
  51. package/dist/compileComponent.js +22 -0
  52. package/dist/compileComponent.js.map +1 -0
  53. package/dist/compileScript.d.ts +19 -4
  54. package/dist/compileScript.d.ts.map +1 -1
  55. package/dist/compileScript.js +37 -12
  56. package/dist/compileScript.js.map +1 -1
  57. package/dist/components.d.ts +41 -0
  58. package/dist/components.d.ts.map +1 -0
  59. package/dist/components.js +14 -0
  60. package/dist/components.js.map +1 -0
  61. package/dist/detectProject.d.ts +3 -0
  62. package/dist/detectProject.d.ts.map +1 -1
  63. package/dist/detectProject.js +16 -6
  64. package/dist/detectProject.js.map +1 -1
  65. package/dist/devServer.d.ts +5 -2
  66. package/dist/devServer.d.ts.map +1 -1
  67. package/dist/devServer.js +10 -6
  68. package/dist/devServer.js.map +1 -1
  69. package/dist/hash.d.ts +2 -0
  70. package/dist/hash.d.ts.map +1 -0
  71. package/dist/hash.js +22 -0
  72. package/dist/hash.js.map +1 -0
  73. package/dist/index.d.ts +24 -6
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +14 -3
  76. package/dist/index.js.map +1 -1
  77. package/dist/installer/bins.d.ts +24 -0
  78. package/dist/installer/bins.d.ts.map +1 -0
  79. package/dist/installer/bins.js +56 -0
  80. package/dist/installer/bins.js.map +1 -0
  81. package/dist/installer/index.d.ts +14 -0
  82. package/dist/installer/index.d.ts.map +1 -0
  83. package/dist/installer/index.js +9 -0
  84. package/dist/installer/index.js.map +1 -0
  85. package/dist/installer/install.d.ts +46 -0
  86. package/dist/installer/install.d.ts.map +1 -0
  87. package/dist/installer/install.js +245 -0
  88. package/dist/installer/install.js.map +1 -0
  89. package/dist/installer/lockfile.d.ts +49 -0
  90. package/dist/installer/lockfile.d.ts.map +1 -0
  91. package/dist/installer/lockfile.js +110 -0
  92. package/dist/installer/lockfile.js.map +1 -0
  93. package/dist/installer/registry.d.ts +84 -0
  94. package/dist/installer/registry.d.ts.map +1 -0
  95. package/dist/installer/registry.js +130 -0
  96. package/dist/installer/registry.js.map +1 -0
  97. package/dist/installer/semver.d.ts +38 -0
  98. package/dist/installer/semver.d.ts.map +1 -0
  99. package/dist/installer/semver.js +187 -0
  100. package/dist/installer/semver.js.map +1 -0
  101. package/dist/installer/spec.d.ts +30 -0
  102. package/dist/installer/spec.d.ts.map +1 -0
  103. package/dist/installer/spec.js +30 -0
  104. package/dist/installer/spec.js.map +1 -0
  105. package/dist/installer/tar.d.ts +17 -0
  106. package/dist/installer/tar.d.ts.map +1 -0
  107. package/dist/installer/tar.js +150 -0
  108. package/dist/installer/tar.js.map +1 -0
  109. package/dist/installer/tree.d.ts +48 -0
  110. package/dist/installer/tree.d.ts.map +1 -0
  111. package/dist/installer/tree.js +179 -0
  112. package/dist/installer/tree.js.map +1 -0
  113. package/dist/node/assert.d.ts +15 -0
  114. package/dist/node/assert.d.ts.map +1 -0
  115. package/dist/node/assert.js +137 -0
  116. package/dist/node/assert.js.map +1 -0
  117. package/dist/node/buffer.d.ts +84 -0
  118. package/dist/node/buffer.d.ts.map +1 -0
  119. package/dist/node/buffer.js +304 -0
  120. package/dist/node/buffer.js.map +1 -0
  121. package/dist/node/builtins.d.ts +25 -0
  122. package/dist/node/builtins.d.ts.map +1 -0
  123. package/dist/node/builtins.js +101 -0
  124. package/dist/node/builtins.js.map +1 -0
  125. package/dist/node/callable.d.ts +13 -0
  126. package/dist/node/callable.d.ts.map +1 -0
  127. package/dist/node/callable.js +26 -0
  128. package/dist/node/callable.js.map +1 -0
  129. package/dist/node/childProcess.d.ts +13 -0
  130. package/dist/node/childProcess.d.ts.map +1 -0
  131. package/dist/node/childProcess.js +143 -0
  132. package/dist/node/childProcess.js.map +1 -0
  133. package/dist/node/crypto.d.ts +3 -0
  134. package/dist/node/crypto.d.ts.map +1 -0
  135. package/dist/node/crypto.js +180 -0
  136. package/dist/node/crypto.js.map +1 -0
  137. package/dist/node/esm.d.ts +9 -0
  138. package/dist/node/esm.d.ts.map +1 -0
  139. package/dist/node/esm.js +202 -0
  140. package/dist/node/esm.js.map +1 -0
  141. package/dist/node/events.d.ts +40 -0
  142. package/dist/node/events.d.ts.map +1 -0
  143. package/dist/node/events.js +160 -0
  144. package/dist/node/events.js.map +1 -0
  145. package/dist/node/fs/index.d.ts +7 -0
  146. package/dist/node/fs/index.d.ts.map +1 -0
  147. package/dist/node/fs/index.js +270 -0
  148. package/dist/node/fs/index.js.map +1 -0
  149. package/dist/node/fs/stats.d.ts +93 -0
  150. package/dist/node/fs/stats.d.ts.map +1 -0
  151. package/dist/node/fs/stats.js +104 -0
  152. package/dist/node/fs/stats.js.map +1 -0
  153. package/dist/node/fs/sync.d.ts +98 -0
  154. package/dist/node/fs/sync.d.ts.map +1 -0
  155. package/dist/node/fs/sync.js +348 -0
  156. package/dist/node/fs/sync.js.map +1 -0
  157. package/dist/node/hashes.d.ts +15 -0
  158. package/dist/node/hashes.d.ts.map +1 -0
  159. package/dist/node/hashes.js +195 -0
  160. package/dist/node/hashes.js.map +1 -0
  161. package/dist/node/http/client.d.ts +35 -0
  162. package/dist/node/http/client.d.ts.map +1 -0
  163. package/dist/node/http/client.js +161 -0
  164. package/dist/node/http/client.js.map +1 -0
  165. package/dist/node/http/index.d.ts +5 -0
  166. package/dist/node/http/index.d.ts.map +1 -0
  167. package/dist/node/http/index.js +125 -0
  168. package/dist/node/http/index.js.map +1 -0
  169. package/dist/node/http/server.d.ts +135 -0
  170. package/dist/node/http/server.d.ts.map +1 -0
  171. package/dist/node/http/server.js +308 -0
  172. package/dist/node/http/server.js.map +1 -0
  173. package/dist/node/http/status.d.ts +3 -0
  174. package/dist/node/http/status.d.ts.map +1 -0
  175. package/dist/node/http/status.js +13 -0
  176. package/dist/node/http/status.js.map +1 -0
  177. package/dist/node/inspect.d.ts +22 -0
  178. package/dist/node/inspect.d.ts.map +1 -0
  179. package/dist/node/inspect.js +172 -0
  180. package/dist/node/inspect.js.map +1 -0
  181. package/dist/node/loader.d.ts +91 -0
  182. package/dist/node/loader.d.ts.map +1 -0
  183. package/dist/node/loader.js +265 -0
  184. package/dist/node/loader.js.map +1 -0
  185. package/dist/node/loop.d.ts +71 -0
  186. package/dist/node/loop.d.ts.map +1 -0
  187. package/dist/node/loop.js +189 -0
  188. package/dist/node/loop.js.map +1 -0
  189. package/dist/node/misc.d.ts +10 -0
  190. package/dist/node/misc.d.ts.map +1 -0
  191. package/dist/node/misc.js +256 -0
  192. package/dist/node/misc.js.map +1 -0
  193. package/dist/node/path.d.ts +14 -0
  194. package/dist/node/path.d.ts.map +1 -0
  195. package/dist/node/path.js +128 -0
  196. package/dist/node/path.js.map +1 -0
  197. package/dist/node/process.d.ts +31 -0
  198. package/dist/node/process.d.ts.map +1 -0
  199. package/dist/node/process.js +309 -0
  200. package/dist/node/process.js.map +1 -0
  201. package/dist/node/program.d.ts +19 -0
  202. package/dist/node/program.d.ts.map +1 -0
  203. package/dist/node/program.js +165 -0
  204. package/dist/node/program.js.map +1 -0
  205. package/dist/node/readline.d.ts +2 -0
  206. package/dist/node/readline.d.ts.map +1 -0
  207. package/dist/node/readline.js +155 -0
  208. package/dist/node/readline.js.map +1 -0
  209. package/dist/node/resolve.d.ts +45 -0
  210. package/dist/node/resolve.d.ts.map +1 -0
  211. package/dist/node/resolve.js +206 -0
  212. package/dist/node/resolve.js.map +1 -0
  213. package/dist/node/runtime.d.ts +40 -0
  214. package/dist/node/runtime.d.ts.map +1 -0
  215. package/dist/node/runtime.js +149 -0
  216. package/dist/node/runtime.js.map +1 -0
  217. package/dist/node/stream/index.d.ts +52 -0
  218. package/dist/node/stream/index.d.ts.map +1 -0
  219. package/dist/node/stream/index.js +184 -0
  220. package/dist/node/stream/index.js.map +1 -0
  221. package/dist/node/stream/readable.d.ts +83 -0
  222. package/dist/node/stream/readable.d.ts.map +1 -0
  223. package/dist/node/stream/readable.js +325 -0
  224. package/dist/node/stream/readable.js.map +1 -0
  225. package/dist/node/stream/writable.d.ts +80 -0
  226. package/dist/node/stream/writable.d.ts.map +1 -0
  227. package/dist/node/stream/writable.js +224 -0
  228. package/dist/node/stream/writable.js.map +1 -0
  229. package/dist/node/urlqs.d.ts +22 -0
  230. package/dist/node/urlqs.d.ts.map +1 -0
  231. package/dist/node/urlqs.js +165 -0
  232. package/dist/node/urlqs.js.map +1 -0
  233. package/dist/node/util.d.ts +37 -0
  234. package/dist/node/util.d.ts.map +1 -0
  235. package/dist/node/util.js +160 -0
  236. package/dist/node/util.js.map +1 -0
  237. package/dist/node/zlib.d.ts +2 -0
  238. package/dist/node/zlib.d.ts.map +1 -0
  239. package/dist/node/zlib.js +133 -0
  240. package/dist/node/zlib.js.map +1 -0
  241. package/dist/packageCdn.d.ts +12 -0
  242. package/dist/packageCdn.d.ts.map +1 -1
  243. package/dist/packageCdn.js +3 -1
  244. package/dist/packageCdn.js.map +1 -1
  245. package/dist/projectConfig.d.ts +6 -2
  246. package/dist/projectConfig.d.ts.map +1 -1
  247. package/dist/projectConfig.js +32 -8
  248. package/dist/projectConfig.js.map +1 -1
  249. package/dist/shell/builtins.d.ts +23 -0
  250. package/dist/shell/builtins.d.ts.map +1 -0
  251. package/dist/shell/builtins.js +131 -0
  252. package/dist/shell/builtins.js.map +1 -0
  253. package/dist/shell/context.d.ts +41 -0
  254. package/dist/shell/context.d.ts.map +1 -0
  255. package/dist/shell/context.js +65 -0
  256. package/dist/shell/context.js.map +1 -0
  257. package/dist/shell/devHandoff.d.ts +18 -0
  258. package/dist/shell/devHandoff.d.ts.map +1 -0
  259. package/dist/shell/devHandoff.js +36 -0
  260. package/dist/shell/devHandoff.js.map +1 -0
  261. package/dist/shell/exec.d.ts +67 -0
  262. package/dist/shell/exec.d.ts.map +1 -0
  263. package/dist/shell/exec.js +247 -0
  264. package/dist/shell/exec.js.map +1 -0
  265. package/dist/shell/expand.d.ts +28 -0
  266. package/dist/shell/expand.d.ts.map +1 -0
  267. package/dist/shell/expand.js +149 -0
  268. package/dist/shell/expand.js.map +1 -0
  269. package/dist/shell/fileCommands.d.ts +10 -0
  270. package/dist/shell/fileCommands.d.ts.map +1 -0
  271. package/dist/shell/fileCommands.js +208 -0
  272. package/dist/shell/fileCommands.js.map +1 -0
  273. package/dist/shell/lineEditor.d.ts +43 -0
  274. package/dist/shell/lineEditor.d.ts.map +1 -0
  275. package/dist/shell/lineEditor.js +234 -0
  276. package/dist/shell/lineEditor.js.map +1 -0
  277. package/dist/shell/npm.d.ts +6 -0
  278. package/dist/shell/npm.d.ts.map +1 -0
  279. package/dist/shell/npm.js +234 -0
  280. package/dist/shell/npm.js.map +1 -0
  281. package/dist/shell/parse.d.ts +73 -0
  282. package/dist/shell/parse.d.ts.map +1 -0
  283. package/dist/shell/parse.js +300 -0
  284. package/dist/shell/parse.js.map +1 -0
  285. package/dist/shell/program.d.ts +12 -0
  286. package/dist/shell/program.d.ts.map +1 -0
  287. package/dist/shell/program.js +219 -0
  288. package/dist/shell/program.js.map +1 -0
  289. package/dist/shell/textCommands.d.ts +15 -0
  290. package/dist/shell/textCommands.d.ts.map +1 -0
  291. package/dist/shell/textCommands.js +185 -0
  292. package/dist/shell/textCommands.js.map +1 -0
  293. package/dist/styleModules.d.ts +6 -0
  294. package/dist/styleModules.d.ts.map +1 -1
  295. package/dist/styleModules.js +14 -4
  296. package/dist/styleModules.js.map +1 -1
  297. package/dist/svelteCompiler.d.ts +28 -0
  298. package/dist/svelteCompiler.d.ts.map +1 -0
  299. package/dist/svelteCompiler.js +13 -0
  300. package/dist/svelteCompiler.js.map +1 -0
  301. package/dist/system/commands.d.ts +26 -0
  302. package/dist/system/commands.d.ts.map +1 -0
  303. package/dist/system/commands.js +53 -0
  304. package/dist/system/commands.js.map +1 -0
  305. package/dist/system/index.d.ts +23 -0
  306. package/dist/system/index.d.ts.map +1 -0
  307. package/dist/system/index.js +16 -0
  308. package/dist/system/index.js.map +1 -0
  309. package/dist/system/kernel.d.ts +54 -0
  310. package/dist/system/kernel.d.ts.map +1 -0
  311. package/dist/system/kernel.js +81 -0
  312. package/dist/system/kernel.js.map +1 -0
  313. package/dist/system/ports.d.ts +32 -0
  314. package/dist/system/ports.d.ts.map +1 -0
  315. package/dist/system/ports.js +57 -0
  316. package/dist/system/ports.js.map +1 -0
  317. package/dist/system/process.d.ts +32 -0
  318. package/dist/system/process.d.ts.map +1 -0
  319. package/dist/system/process.js +130 -0
  320. package/dist/system/process.js.map +1 -0
  321. package/dist/system/programs.d.ts +10 -0
  322. package/dist/system/programs.d.ts.map +1 -0
  323. package/dist/system/programs.js +22 -0
  324. package/dist/system/programs.js.map +1 -0
  325. package/dist/system/terminal.d.ts +45 -0
  326. package/dist/system/terminal.d.ts.map +1 -0
  327. package/dist/system/terminal.js +127 -0
  328. package/dist/system/terminal.js.map +1 -0
  329. package/dist/system/types.d.ts +100 -0
  330. package/dist/system/types.d.ts.map +1 -0
  331. package/dist/system/types.js +2 -0
  332. package/dist/system/types.js.map +1 -0
  333. package/dist/vfs.d.ts +28 -4
  334. package/dist/vfs.d.ts.map +1 -1
  335. package/dist/vfs.js +95 -32
  336. package/dist/vfs.js.map +1 -1
  337. package/dist/vueCompiler.d.ts +75 -0
  338. package/dist/vueCompiler.d.ts.map +1 -0
  339. package/dist/vueCompiler.js +67 -0
  340. package/dist/vueCompiler.js.map +1 -0
  341. package/package.json +18 -2
  342. package/src/build.ts +105 -0
  343. package/src/buildHost.ts +154 -0
  344. package/src/buildHtml.ts +101 -0
  345. package/src/bundler.ts +190 -0
  346. package/src/check/acquire.ts +212 -0
  347. package/src/check/compilerHost.ts +138 -0
  348. package/src/check/diagnostics.ts +48 -0
  349. package/src/check/index.ts +28 -0
  350. package/src/check/projects.ts +149 -0
  351. package/src/check/shims.ts +88 -0
  352. package/src/check/typeStore.ts +103 -0
  353. package/src/check/typecheck.ts +134 -0
  354. package/src/compileComponent.ts +21 -0
  355. package/src/compileScript.ts +42 -13
  356. package/src/components.ts +59 -0
  357. package/src/detectProject.ts +18 -6
  358. package/src/devServer.ts +13 -8
  359. package/src/hash.ts +22 -0
  360. package/src/index.ts +35 -6
  361. package/src/installer/bins.ts +64 -0
  362. package/src/installer/index.ts +13 -0
  363. package/src/installer/install.ts +275 -0
  364. package/src/installer/lockfile.ts +146 -0
  365. package/src/installer/registry.ts +175 -0
  366. package/src/installer/semver.ts +190 -0
  367. package/src/installer/spec.ts +53 -0
  368. package/src/installer/tar.ts +155 -0
  369. package/src/installer/tree.ts +236 -0
  370. package/src/node/assert.ts +127 -0
  371. package/src/node/buffer.ts +304 -0
  372. package/src/node/builtins.ts +123 -0
  373. package/src/node/callable.ts +25 -0
  374. package/src/node/childProcess.ts +164 -0
  375. package/src/node/crypto.ts +187 -0
  376. package/src/node/esm.ts +196 -0
  377. package/src/node/events.ts +176 -0
  378. package/src/node/fs/index.ts +277 -0
  379. package/src/node/fs/stats.ts +110 -0
  380. package/src/node/fs/sync.ts +335 -0
  381. package/src/node/hashes.ts +171 -0
  382. package/src/node/http/client.ts +173 -0
  383. package/src/node/http/index.ts +122 -0
  384. package/src/node/http/server.ts +308 -0
  385. package/src/node/http/status.ts +13 -0
  386. package/src/node/inspect.ts +166 -0
  387. package/src/node/loader.ts +293 -0
  388. package/src/node/loop.ts +193 -0
  389. package/src/node/misc.ts +250 -0
  390. package/src/node/path.ts +135 -0
  391. package/src/node/process.ts +324 -0
  392. package/src/node/program.ts +170 -0
  393. package/src/node/readline.ts +157 -0
  394. package/src/node/resolve.ts +216 -0
  395. package/src/node/runtime.ts +184 -0
  396. package/src/node/stream/index.ts +196 -0
  397. package/src/node/stream/readable.ts +345 -0
  398. package/src/node/stream/writable.ts +244 -0
  399. package/src/node/urlqs.ts +162 -0
  400. package/src/node/util.ts +145 -0
  401. package/src/node/zlib.ts +145 -0
  402. package/src/packageCdn.ts +11 -1
  403. package/src/projectConfig.ts +34 -7
  404. package/src/shell/builtins.ts +141 -0
  405. package/src/shell/context.ts +89 -0
  406. package/src/shell/devHandoff.ts +49 -0
  407. package/src/shell/exec.ts +268 -0
  408. package/src/shell/expand.ts +145 -0
  409. package/src/shell/fileCommands.ts +206 -0
  410. package/src/shell/lineEditor.ts +233 -0
  411. package/src/shell/npm.ts +229 -0
  412. package/src/shell/parse.ts +295 -0
  413. package/src/shell/program.ts +223 -0
  414. package/src/shell/textCommands.ts +177 -0
  415. package/src/styleModules.ts +15 -4
  416. package/src/svelteCompiler.ts +31 -0
  417. package/src/system/commands.ts +72 -0
  418. package/src/system/index.ts +22 -0
  419. package/src/system/kernel.ts +106 -0
  420. package/src/system/ports.ts +73 -0
  421. package/src/system/process.ts +158 -0
  422. package/src/system/programs.ts +31 -0
  423. package/src/system/terminal.ts +135 -0
  424. package/src/system/types.ts +103 -0
  425. package/src/vfs.ts +92 -28
  426. package/src/vueCompiler.ts +121 -0
@@ -0,0 +1,154 @@
1
+ import type { VirtualFileSystem } from './vfs.js';
2
+ import type { ProjectConfig } from './projectConfig.js';
3
+ import type { PackageCdn } from './packageCdn.js';
4
+ import type { BundleHost, BundleLoad, ResolveKind } from './bundler.js';
5
+ import type { ComponentCompilers } from './components.js';
6
+ import { componentExtension } from './components.js';
7
+ import { loaderFor } from './transformer.js';
8
+ import { basename, dirname, extname, join } from './paths.js';
9
+ import { isBareSpecifier, resolveAlias, resolveLocal, splitPackageSpecifier } from './resolve.js';
10
+ import { contentHash } from './hash.js';
11
+
12
+ /**
13
+ * The project side of a production build: the same resolution rules the dev
14
+ * server uses (resolve.ts, tsconfig aliases, the package CDN), expressed as a
15
+ * {@link BundleHost} so any bundler can walk the graph.
16
+ *
17
+ * Packages stay on the CDN — a bare import becomes an absolute, version-pinned
18
+ * URL with the same `?deps=` dedupe as the dev server — so the output runs
19
+ * without node_modules. Assets (images, fonts, `?url`) are emitted by the host
20
+ * itself with content-hashed names, so one asset referenced from JS and CSS is
21
+ * written once.
22
+ */
23
+ export interface BuildHostOptions {
24
+ fs: VirtualFileSystem;
25
+ config: ProjectConfig;
26
+ cdn: PackageCdn;
27
+ components: ComponentCompilers;
28
+ publicDir: string;
29
+ /** The URL the site is served under: `./` (relative) or absolute, ending in `/`. */
30
+ base: string;
31
+ }
32
+
33
+ export interface BuildHost extends BundleHost {
34
+ /** Emitted assets, output path (`assets/logo-1a2b3c4d.svg`) → bytes. */
35
+ readonly assets: Map<string, Uint8Array>;
36
+ }
37
+
38
+ /** The query a compiled component's own CSS is imported under. */
39
+ const COMPONENT_CSS = 'bfwc-component-css';
40
+ /** The query (and virtual directory) of a package stylesheet imported from JS. */
41
+ const PACKAGE_CSS = 'bfwc-package-css';
42
+ const encoder = new TextEncoder();
43
+
44
+ function splitAnyQuery(specifier: string): { path: string; query?: string } {
45
+ const at = specifier.indexOf('?');
46
+ return at < 0 ? { path: specifier } : { path: specifier.slice(0, at), query: specifier.slice(at + 1) || undefined };
47
+ }
48
+
49
+ /** Relative base: every chunk and asset lives in `assets/`, so siblings are `./x`. */
50
+ function isRelativeBase(base: string): boolean {
51
+ return base.startsWith('.');
52
+ }
53
+
54
+ export function createBuildHost(options: BuildHostOptions): BuildHost {
55
+ const { fs, config, cdn, publicDir, base } = options;
56
+ const assets = new Map<string, Uint8Array>();
57
+ const componentCss = new Map<string, string>();
58
+
59
+ function emitAsset(path: string): string {
60
+ const raw = fs.readFile(path) ?? new Uint8Array();
61
+ const bytes = typeof raw === 'string' ? encoder.encode(raw) : raw;
62
+ const ext = extname(path);
63
+ const stem = basename(path).slice(0, basename(path).length - ext.length) || 'asset';
64
+ const name = `${stem}-${contentHash(bytes)}${ext}`;
65
+ assets.set(`assets/${name}`, bytes);
66
+ return name;
67
+ }
68
+
69
+ /** An asset's URL from a stylesheet. CSS lives in `assets/` beside it. */
70
+ function cssAssetUrl(path: string): string {
71
+ const name = emitAsset(path);
72
+ return isRelativeBase(base) ? `./${name}` : `${base}assets/${name}`;
73
+ }
74
+
75
+ /**
76
+ * An asset imported from JS. With a relative base the URL is resolved against
77
+ * the chunk (`import.meta.url`), not the page — the same app must work when
78
+ * served from any directory, and from client-side routes deeper than `/`.
79
+ */
80
+ function assetModule(path: string): string {
81
+ const name = emitAsset(path);
82
+ return isRelativeBase(base)
83
+ ? `export default new URL(${JSON.stringify(`./${name}`)}, import.meta.url).href;`
84
+ : `export default ${JSON.stringify(`${base}assets/${name}`)};`;
85
+ }
86
+
87
+ function resolveFile(fromDir: string, path: string, kind: ResolveKind): string | undefined {
88
+ const local = resolveLocal(fs, fromDir, path);
89
+ if (local) return local;
90
+ // `/vite.svg` in source names `public/vite.svg`, served from the site root.
91
+ if (path.startsWith('/')) return resolveLocal(fs, '/', join(publicDir, path));
92
+ // CSS `url(bg.png)` is relative even without `./`.
93
+ if (kind === 'css-url' || kind === 'css-import') return resolveLocal(fs, fromDir, `./${path}`);
94
+ return undefined;
95
+ }
96
+
97
+ return {
98
+ assets,
99
+
100
+ resolve(specifier, importer, kind) {
101
+ if (/^(https?:|data:|blob:|node:|\/\/)/i.test(specifier)) return { external: specifier };
102
+ const css = kind === 'css-import' || kind === 'css-url';
103
+ // `~pkg/x.css` is the webpack/Vite spelling of a package path inside CSS.
104
+ const unhashed = (css && specifier.startsWith('~') ? specifier.slice(1) : specifier).split('#');
105
+ const fragment = unhashed.length > 1 ? `#${unhashed.slice(1).join('#')}` : ''; // `icons.svg#close`
106
+ const { path, query } = splitAnyQuery(unhashed[0]!);
107
+ const fromDir = importer ? dirname(importer) : '/';
108
+
109
+ let file: string | undefined;
110
+ if (isBareSpecifier(path)) {
111
+ file = (css ? resolveLocal(fs, fromDir, `./${path}`) : undefined) ?? resolveAlias(fs, config.aliases, path);
112
+ if (!file) {
113
+ const { name, subpath } = splitPackageSpecifier(path);
114
+ // A package stylesheet imported from JS (`import 'bootstrap/dist/css/bootstrap.css'`)
115
+ // can't stay a JS import of a CSS URL; it joins the CSS bundle as an @import.
116
+ if (!css && extname(subpath) === '.css') return { path: `/${PACKAGE_CSS}/${path}`, query: PACKAGE_CSS };
117
+ return { external: cdn.urlFor(name, subpath) };
118
+ }
119
+ } else {
120
+ file = resolveFile(fromDir, path, kind);
121
+ }
122
+ if (!file) return undefined;
123
+ if (kind === 'css-url' && extname(file) !== '.css') return { external: cssAssetUrl(file) + fragment };
124
+ return { path: file, ...(query ? { query } : {}) };
125
+ },
126
+
127
+ async load(path, query): Promise<BundleLoad> {
128
+ if (query === 'raw') return { contents: fs.readText(path) ?? '', loader: 'text' };
129
+ if (query === COMPONENT_CSS) return { contents: componentCss.get(path) ?? '', loader: 'css' };
130
+ if (query === PACKAGE_CSS) {
131
+ const { name, subpath } = splitPackageSpecifier(path.slice(PACKAGE_CSS.length + 2));
132
+ return { contents: `@import ${JSON.stringify(cdn.urlFor(name, subpath))};`, loader: 'css' };
133
+ }
134
+
135
+ const ext = extname(path);
136
+ if (query === 'url') return { contents: assetModule(path), loader: 'js' };
137
+ const loader = loaderFor(ext);
138
+ if (loader) return { contents: fs.readFile(path) ?? '', loader };
139
+ if (ext === '.css') return { contents: fs.readFile(path) ?? '', loader: /\.module\.css$/i.test(path) ? 'local-css' : 'css' };
140
+ if (ext === '.json') return { contents: fs.readFile(path) ?? '', loader: 'json' };
141
+
142
+ const extension = componentExtension(ext);
143
+ if (extension) {
144
+ const compiler = await options.components(extension, config.dependencies);
145
+ const compiled = await compiler.compile(fs.readText(path) ?? '', { path, dev: false });
146
+ if (!compiled.css) return { contents: compiled.code, loader: compiled.loader };
147
+ componentCss.set(path, compiled.css);
148
+ // Importing its own CSS puts the component's styles in the entry's CSS bundle.
149
+ return { contents: `${compiled.code}\nimport ${JSON.stringify(`${path}?${COMPONENT_CSS}`)};`, loader: compiled.loader };
150
+ }
151
+ return { contents: assetModule(path), loader: 'js' };
152
+ },
153
+ };
154
+ }
@@ -0,0 +1,101 @@
1
+ import type { VirtualFileSystem } from './vfs.js';
2
+ import { dirname } from './paths.js';
3
+ import { resolveLocal } from './resolve.js';
4
+
5
+ /**
6
+ * The HTML side of a production build: find the page's local entry points
7
+ * (module scripts and stylesheets), then rewrite the page to load their bundles
8
+ * instead — the job Vite's build does to `index.html`.
9
+ */
10
+
11
+ export interface HtmlEntry {
12
+ tag: 'script' | 'style';
13
+ /** The attribute value as written (`/src/main.tsx`). */
14
+ url: string;
15
+ /** The VFS file it names. */
16
+ path: string;
17
+ }
18
+
19
+ const TAG = /<([a-zA-Z][\w-]*)\b[^>]*>/g;
20
+ const URL_ATTR = /(\s(src|href)\s*=\s*)(["'])([^"']*)\3/gi;
21
+
22
+ function attribute(tag: string, name: string): string | undefined {
23
+ const match = new RegExp(`\\s${name}\\s*=\\s*(["'])([^"']*)\\1`, 'i').exec(tag);
24
+ return match?.[2];
25
+ }
26
+
27
+ function isEntryTag(name: string, tag: string): HtmlEntry['tag'] | undefined {
28
+ const lower = name.toLowerCase();
29
+ if (lower === 'script' && attribute(tag, 'type')?.toLowerCase() === 'module' && attribute(tag, 'src')) return 'script';
30
+ if (lower === 'link' && /(^|\s)stylesheet(\s|$)/i.test(attribute(tag, 'rel') ?? '') && attribute(tag, 'href')) return 'style';
31
+ return undefined;
32
+ }
33
+
34
+ /** `%PUBLIC_URL%` (CRA) becomes root-absolute, then is rebased like any other root path. */
35
+ function fillPublicUrl(html: string): string {
36
+ return html.replace(/%PUBLIC_URL%/g, '');
37
+ }
38
+
39
+ /** The local file an entry URL names, or undefined for URLs and files that do not exist. */
40
+ function resolveEntry(fs: VirtualFileSystem, htmlPath: string, url: string): string | undefined {
41
+ if (/^([a-z][a-z0-9+.-]*:|\/\/)/i.test(url)) return undefined;
42
+ const [path] = url.split(/[?#]/);
43
+ if (!path) return undefined;
44
+ // Root-absolute means the project root (Vite's convention), wherever the page lives.
45
+ return path.startsWith('/') ? resolveLocal(fs, '/', path) : resolveLocal(fs, dirname(htmlPath), path);
46
+ }
47
+
48
+ export function findHtmlEntries(fs: VirtualFileSystem, html: string, htmlPath: string): HtmlEntry[] {
49
+ const entries: HtmlEntry[] = [];
50
+ for (const match of fillPublicUrl(html).matchAll(TAG)) {
51
+ const kind = isEntryTag(match[1]!, match[0]);
52
+ if (!kind) continue;
53
+ const url = attribute(match[0], kind === 'script' ? 'src' : 'href')!;
54
+ const path = resolveEntry(fs, htmlPath, url);
55
+ if (path) entries.push({ tag: kind, url, path });
56
+ }
57
+ return entries;
58
+ }
59
+
60
+ export interface BuiltHtmlOptions {
61
+ /** Where the site is served from, ending in `/` (`./` for relative). */
62
+ base: string;
63
+ entries: HtmlEntry[];
64
+ /** Per entry path, the bundle files (relative to the site root). */
65
+ outputs: Record<string, { js?: string; css?: string }>;
66
+ /** Entry script to add when the page has none of its own (CRA). */
67
+ inject?: string;
68
+ }
69
+
70
+ function insertBefore(html: string, closing: RegExp, markup: string): string {
71
+ return closing.test(html) ? html.replace(closing, (tag) => `${markup}\n${tag}`) : html + markup;
72
+ }
73
+
74
+ export function rewriteBuiltHtml(html: string, options: BuiltHtmlOptions): string {
75
+ const { base, entries, outputs } = options;
76
+ const byUrl = new Map(entries.map((entry) => [`${entry.tag}:${entry.url}`, entry]));
77
+ const stylesheets: string[] = [];
78
+
79
+ let out = fillPublicUrl(html).replace(TAG, (tag, name: string) => {
80
+ const kind = isEntryTag(name, tag);
81
+ const entry = kind && byUrl.get(`${kind}:${attribute(tag, kind === 'script' ? 'src' : 'href')}`);
82
+ if (entry) {
83
+ const output = outputs[entry.path];
84
+ const file = entry.tag === 'script' ? output?.js : output?.css;
85
+ if (entry.tag === 'script' && output?.css) stylesheets.push(output.css);
86
+ return file ? tag.replace(URL_ATTR, (m, attr: string, _n, quote: string) => `${attr}${quote}${base}${file}${quote}`) : tag;
87
+ }
88
+ // Any other root-absolute URL (`/favicon.svg` from public/) moves under the base.
89
+ return tag.replace(URL_ATTR, (m, attr: string, _n, quote: string, value: string) =>
90
+ value.startsWith('/') && !value.startsWith('//') ? `${attr}${quote}${base}${value.slice(1)}${quote}` : m,
91
+ );
92
+ });
93
+
94
+ if (options.inject) {
95
+ const output = outputs[options.inject];
96
+ if (output?.css) stylesheets.push(output.css);
97
+ if (output?.js) out = insertBefore(out, /<\/body>/i, `<script type="module" src="${base}${output.js}"></script>`);
98
+ }
99
+ const links = [...new Set(stylesheets)].map((css) => `<link rel="stylesheet" href="${base}${css}">`).join('\n');
100
+ return links ? insertBefore(out, /<\/head>/i, links) : out;
101
+ }
package/src/bundler.ts ADDED
@@ -0,0 +1,190 @@
1
+ /**
2
+ * The production bundler, as a PORT — the build-time sibling of {@link Transformer}.
3
+ *
4
+ * The split of responsibilities is deliberate: everything that knows about the
5
+ * project (how a specifier resolves, what a file compiles to, where assets go)
6
+ * lives behind {@link BundleHost}, written once in the core; a bundler only walks
7
+ * the graph through the host's two callbacks and writes chunks. So the esbuild
8
+ * adapter below is the only esbuild-specific code, and a fork could put Rollup
9
+ * behind the same port without re-implementing resolution.
10
+ */
11
+ import type { Loader } from './transformer.js';
12
+
13
+ export type BundleLoader = Loader | 'css' | 'local-css' | 'json' | 'text';
14
+
15
+ /** Where an import appears: an entry point, JS, a CSS `@import`, or a CSS `url()`. */
16
+ export type ResolveKind = 'entry' | 'import' | 'css-import' | 'css-url';
17
+
18
+ /** A module inside the graph (with an optional `?query`), or a URL left as-is in the output. */
19
+ export type BundleResolution = { path: string; query?: string } | { external: string };
20
+
21
+ export interface BundleLoad {
22
+ contents: string | Uint8Array;
23
+ loader: BundleLoader;
24
+ }
25
+
26
+ export interface BundleHost {
27
+ /** Undefined means "cannot resolve", reported as a build error. */
28
+ resolve(specifier: string, importer: string | undefined, kind: ResolveKind): BundleResolution | undefined;
29
+ load(path: string, query: string | undefined): Promise<BundleLoad> | BundleLoad;
30
+ }
31
+
32
+ export interface BundleRequest {
33
+ /** VFS paths of the entry modules (scripts or stylesheets). */
34
+ entryPoints: string[];
35
+ host: BundleHost;
36
+ /** esbuild `define` semantics (values are JS source). */
37
+ define: Record<string, string>;
38
+ jsx: { runtime: 'automatic' | 'classic'; importSource: string };
39
+ minify: boolean;
40
+ }
41
+
42
+ export interface BundleOutputFile {
43
+ /** Relative to the site root, e.g. `assets/main-1a2b3c4d.js`. */
44
+ path: string;
45
+ contents: Uint8Array;
46
+ }
47
+
48
+ export interface BundleOutput {
49
+ files: BundleOutputFile[];
50
+ /** Per entry point (VFS path): its JS chunk and the CSS extracted from it. */
51
+ entries: Record<string, { js?: string; css?: string }>;
52
+ }
53
+
54
+ export interface Bundler {
55
+ bundle(request: BundleRequest): Promise<BundleOutput>;
56
+ }
57
+
58
+ // ---- esbuild adapter ------------------------------------------------------
59
+
60
+ interface EsbuildResolveArgs {
61
+ path: string;
62
+ importer: string;
63
+ kind: string;
64
+ }
65
+
66
+ interface EsbuildLoadArgs {
67
+ path: string;
68
+ suffix?: string;
69
+ }
70
+
71
+ interface EsbuildResolveResult {
72
+ path?: string;
73
+ namespace?: string;
74
+ suffix?: string;
75
+ external?: boolean;
76
+ errors?: Array<{ text: string }>;
77
+ }
78
+
79
+ interface EsbuildPluginBuild {
80
+ onResolve(options: { filter: RegExp }, callback: (args: EsbuildResolveArgs) => EsbuildResolveResult): void;
81
+ onLoad(
82
+ options: { filter: RegExp; namespace: string },
83
+ callback: (args: EsbuildLoadArgs) => Promise<{ contents: string | Uint8Array; loader: BundleLoader }>,
84
+ ): void;
85
+ }
86
+
87
+ /** The subset of esbuild's (and esbuild-wasm's) `build` API the adapter uses. */
88
+ export interface EsbuildBuildLike {
89
+ build(options: {
90
+ entryPoints: string[];
91
+ bundle: true;
92
+ write: false;
93
+ metafile: true;
94
+ format: 'esm';
95
+ splitting: true;
96
+ target: string;
97
+ outdir: string;
98
+ entryNames: string;
99
+ chunkNames: string;
100
+ assetNames: string;
101
+ minify: boolean;
102
+ define: Record<string, string>;
103
+ jsx: 'automatic' | 'transform';
104
+ jsxImportSource?: string;
105
+ charset: 'utf8';
106
+ logLevel: 'silent';
107
+ plugins: Array<{ name: string; setup(build: EsbuildPluginBuild): void }>;
108
+ }): Promise<{
109
+ outputFiles?: Array<{ path: string; contents: Uint8Array }>;
110
+ metafile?: { outputs: Record<string, { entryPoint?: string; cssBundle?: string }> };
111
+ }>;
112
+ }
113
+
114
+ const NAMESPACE = 'bfwc';
115
+ /** A marker directory: nothing is written; output paths are made relative to it. */
116
+ const OUT_DIR = '__bfwc_dist__';
117
+
118
+ const KINDS: Record<string, ResolveKind> = {
119
+ 'entry-point': 'entry',
120
+ 'import-rule': 'css-import',
121
+ 'composes-from': 'css-import',
122
+ 'url-token': 'css-url',
123
+ };
124
+
125
+ /** An output path (absolute, OS-specific, or metafile-relative) → `assets/x.js`. */
126
+ function relativeOutput(path: string): string {
127
+ const normalized = path.replace(/\\/g, '/');
128
+ const at = normalized.lastIndexOf(`${OUT_DIR}/`);
129
+ return at < 0 ? normalized : normalized.slice(at + OUT_DIR.length + 1);
130
+ }
131
+
132
+ /** Adapt esbuild or esbuild-wasm's `build` to {@link Bundler}. */
133
+ export function createEsbuildBundler(esbuild: EsbuildBuildLike): Bundler {
134
+ return {
135
+ async bundle(request) {
136
+ const { host } = request;
137
+ const result = await esbuild.build({
138
+ entryPoints: request.entryPoints,
139
+ bundle: true,
140
+ write: false,
141
+ metafile: true,
142
+ format: 'esm',
143
+ splitting: true,
144
+ target: 'es2022',
145
+ outdir: OUT_DIR,
146
+ entryNames: 'assets/[name]-[hash]',
147
+ chunkNames: 'assets/[name]-[hash]',
148
+ assetNames: 'assets/[name]-[hash]',
149
+ minify: request.minify,
150
+ define: request.define,
151
+ jsx: request.jsx.runtime === 'automatic' ? 'automatic' : 'transform',
152
+ ...(request.jsx.runtime === 'automatic' ? { jsxImportSource: request.jsx.importSource } : {}),
153
+ charset: 'utf8',
154
+ logLevel: 'silent',
155
+ plugins: [
156
+ {
157
+ name: 'bfwc-vfs',
158
+ setup(build) {
159
+ build.onResolve({ filter: /.*/ }, (args) => {
160
+ const importer = args.importer || undefined;
161
+ const resolved = host.resolve(args.path, importer, KINDS[args.kind] ?? 'import');
162
+ if (!resolved) return { errors: [{ text: `Cannot resolve "${args.path}"${importer ? ` from ${importer}` : ''}` }] };
163
+ if ('external' in resolved) return { path: resolved.external, external: true };
164
+ return { path: resolved.path, namespace: NAMESPACE, ...(resolved.query ? { suffix: `?${resolved.query}` } : {}) };
165
+ });
166
+ build.onLoad({ filter: /.*/, namespace: NAMESPACE }, async (args) => {
167
+ const query = args.suffix?.startsWith('?') ? args.suffix.slice(1) : undefined;
168
+ return host.load(args.path, query);
169
+ });
170
+ },
171
+ },
172
+ ],
173
+ });
174
+
175
+ const files = (result.outputFiles ?? []).map((file) => ({ path: relativeOutput(file.path), contents: file.contents }));
176
+ const entries: BundleOutput['entries'] = {};
177
+ for (const [output, meta] of Object.entries(result.metafile?.outputs ?? {})) {
178
+ if (!meta.entryPoint) continue;
179
+ const entry = meta.entryPoint.replace(`${NAMESPACE}:`, '').replace(/\?.*$/, '');
180
+ const slot = (entries[entry] ??= {});
181
+ if (output.endsWith('.css')) slot.css = relativeOutput(output);
182
+ else {
183
+ slot.js = relativeOutput(output);
184
+ if (meta.cssBundle) slot.css = relativeOutput(meta.cssBundle);
185
+ }
186
+ }
187
+ return { files, entries };
188
+ },
189
+ };
190
+ }
@@ -0,0 +1,212 @@
1
+ import type * as TS from 'typescript';
2
+ import { isBareSpecifier, splitPackageSpecifier } from '../resolve.js';
3
+ import { dirname, join } from '../paths.js';
4
+ import { parseLooseJson } from '../projectConfig.js';
5
+ import type { VirtualFileSystem } from '../vfs.js';
6
+ import { SHIMMED_TYPE_REFERENCES } from './shims.js';
7
+ import {
8
+ CONFIG_MODULES_DIR,
9
+ dtsCandidates,
10
+ packageRequestUrl,
11
+ typesPackageName,
12
+ versioned,
13
+ type TypeSources,
14
+ type TypeStore,
15
+ } from './typeStore.js';
16
+
17
+ /** The part of a fetch `Response` acquisition reads; the real `fetch` satisfies it. */
18
+ export interface FetchResponseLike {
19
+ ok: boolean;
20
+ /** The final URL after redirects. Relative references resolve against it. */
21
+ url: string;
22
+ headers: { get(name: string): string | null };
23
+ text(): Promise<string>;
24
+ }
25
+
26
+ export type FetchLike = (url: string) => Promise<FetchResponseLike>;
27
+
28
+ export interface AcquireRequest {
29
+ /** Bare module specifiers imported by project files (`react`, `react/jsx-runtime`). */
30
+ specifiers: string[];
31
+ /** `types` entries and `/// <reference types>` names. */
32
+ typeReferences: string[];
33
+ /** Lib file names (`lib.es2020.full.d.ts`). */
34
+ libFiles: string[];
35
+ dependencies: Readonly<Record<string, string>>;
36
+ }
37
+
38
+ export interface AcquireOptions {
39
+ fetch: FetchLike;
40
+ sources: TypeSources;
41
+ /** Upper bound on fetched `.d.ts` files — one run-away graph must not stall a check. */
42
+ maxFiles: number;
43
+ }
44
+
45
+ const TYPES_HEADER = 'X-TypeScript-Types';
46
+
47
+ /**
48
+ * Fetch every declaration file the request can reach into the store: package
49
+ * entry types (via the CDN's `X-TypeScript-Types` header), then everything those
50
+ * import or reference, transitively; lib files and their `/// <reference lib>`s.
51
+ *
52
+ * Fetches run concurrently. Each URL is fetched once and its references are
53
+ * scheduled rather than awaited inside the fetch, so reference cycles between
54
+ * declaration files cannot deadlock.
55
+ */
56
+ export async function acquireTypes(ts: typeof TS, store: TypeStore, request: AcquireRequest, options: AcquireOptions): Promise<void> {
57
+ const { sources } = options;
58
+ const inflight = new Map<string, Promise<unknown>>();
59
+ const tasks: Promise<unknown>[] = [];
60
+ const schedule = (task: () => Promise<unknown>) => tasks.push(task().catch(() => undefined));
61
+ const once = <T>(key: string, task: () => Promise<T>): Promise<T> => {
62
+ if (!inflight.has(key)) inflight.set(key, task());
63
+ return inflight.get(key) as Promise<T>;
64
+ };
65
+ const get = (url: string) => options.fetch(url).then((res) => (res.ok ? res : undefined), () => undefined);
66
+
67
+ function walk(fromUrl: string, text: string): void {
68
+ const info = ts.preProcessFile(text, true, true);
69
+ for (const ref of info.referencedFiles) schedule(() => fetchFirst(dtsCandidates(ref.fileName, fromUrl)));
70
+ for (const ref of info.typeReferenceDirectives) schedule(() => ensureTypeReference(ref.fileName));
71
+ for (const ref of info.libReferenceDirectives) schedule(() => ensureLib(`lib.${ref.fileName.toLowerCase()}.d.ts`));
72
+ for (const ref of info.importedFiles) {
73
+ const spec = ref.fileName;
74
+ schedule(() => (isBareSpecifier(spec) ? ensurePackage(spec) : fetchFirst(dtsCandidates(spec, fromUrl))));
75
+ }
76
+ }
77
+
78
+ /** Fetch one declaration file; resolves to its final URL. */
79
+ function fetchDts(url: string): Promise<string | undefined> {
80
+ const known = store.redirects.get(url);
81
+ if (known !== undefined) return Promise.resolve(known || undefined);
82
+ if (store.files.has(url)) return Promise.resolve(url);
83
+ return once(`dts:${url}`, async () => {
84
+ if (store.files.size >= options.maxFiles) return undefined;
85
+ const res = await get(url);
86
+ if (!res) {
87
+ store.redirects.set(url, '');
88
+ return undefined;
89
+ }
90
+ const final = res.url || url;
91
+ store.redirects.set(url, final);
92
+ if (!store.files.has(final)) {
93
+ const text = await res.text();
94
+ store.files.set(final, text);
95
+ walk(final, text);
96
+ }
97
+ return final;
98
+ });
99
+ }
100
+
101
+ async function fetchFirst(candidates: string[]): Promise<string | undefined> {
102
+ for (const url of candidates) {
103
+ const final = await fetchDts(url);
104
+ if (final) return final;
105
+ }
106
+ return undefined;
107
+ }
108
+
109
+ /** A bare specifier's entry types, located by the CDN's header. */
110
+ function ensurePackage(specifier: string, dependencies: Readonly<Record<string, string>> = {}): Promise<string | undefined> {
111
+ const key = packageRequestUrl(sources.typesOrigin, specifier, dependencies);
112
+ if (store.packages.has(key)) return Promise.resolve(store.packages.get(key) ?? undefined);
113
+ return once(`pkg:${key}`, async () => {
114
+ const res = await get(key);
115
+ const header = res?.headers.get(TYPES_HEADER);
116
+ const final = header ? await fetchDts(new URL(header, res!.url || key).href) : undefined;
117
+ store.packages.set(key, final ?? null);
118
+ return final;
119
+ });
120
+ }
121
+
122
+ /** `/// <reference types="x" />` and `types: ["x"]`: the package's own types, else DefinitelyTyped. */
123
+ function ensureTypeReference(name: string, dependencies: Readonly<Record<string, string>> = {}): Promise<unknown> {
124
+ if (SHIMMED_TYPE_REFERENCES.has(name)) return Promise.resolve();
125
+ const key = `types:${name}`;
126
+ if (store.packages.has(key)) return Promise.resolve();
127
+ return once(key, async () => {
128
+ // `node` is DefinitelyTyped's, not the npm package called "node".
129
+ const own = name === 'node' ? undefined : await ensurePackage(name, dependencies);
130
+ const { name: pkg, subpath } = splitPackageSpecifier(name);
131
+ const typesPkg = typesPackageName(pkg);
132
+ const definitelyTyped = own
133
+ ? undefined
134
+ : await fetchDts(`${sources.typesOrigin}/${versioned(typesPkg, dependencies)}${subpath || '/index'}.d.ts`);
135
+ store.packages.set(key, own ?? definitelyTyped ?? null);
136
+ });
137
+ }
138
+
139
+ function ensureLib(file: string): Promise<unknown> {
140
+ if (store.libs.has(file)) return Promise.resolve();
141
+ return once(`lib:${file}`, async () => {
142
+ const res = await get(`${sources.libBaseUrl}/${file}`);
143
+ const text = res ? await res.text() : null;
144
+ store.libs.set(file, text);
145
+ if (text) {
146
+ for (const ref of ts.preProcessFile(text, true, false).libReferenceDirectives) {
147
+ schedule(() => ensureLib(`lib.${ref.fileName.toLowerCase()}.d.ts`));
148
+ }
149
+ }
150
+ });
151
+ }
152
+
153
+ for (const spec of request.specifiers) schedule(() => ensurePackage(spec, request.dependencies));
154
+ for (const name of request.typeReferences) schedule(() => ensureTypeReference(name, request.dependencies));
155
+ for (const file of request.libFiles) schedule(() => ensureLib(file));
156
+ while (tasks.length) await Promise.all(tasks.splice(0));
157
+ }
158
+
159
+ /**
160
+ * Fetch tsconfig files the project `extends` from packages (`@vue/tsconfig`,
161
+ * `@tsconfig/svelte`) into the store's virtual node_modules, following their own
162
+ * `extends` chains, so the config parser sees what a local install would hold.
163
+ */
164
+ export async function acquireExtendedConfigs(
165
+ fs: VirtualFileSystem,
166
+ store: TypeStore,
167
+ dependencies: Readonly<Record<string, string>>,
168
+ options: Pick<AcquireOptions, 'fetch' | 'sources'>,
169
+ ): Promise<void> {
170
+ const tasks: Promise<void>[] = [];
171
+
172
+ function extendsOf(text: string): string[] {
173
+ try {
174
+ const value = (parseLooseJson(text) as { extends?: unknown }).extends;
175
+ return (Array.isArray(value) ? value : [value]).filter((v): v is string => typeof v === 'string');
176
+ } catch {
177
+ return [];
178
+ }
179
+ }
180
+
181
+ function follow(fromPath: string, text: string): void {
182
+ for (const spec of extendsOf(text)) {
183
+ let path: string;
184
+ if (isBareSpecifier(spec)) {
185
+ const { name, subpath } = splitPackageSpecifier(spec);
186
+ path = `${CONFIG_MODULES_DIR}/${name}${subpath ? (subpath.endsWith('.json') ? subpath : `${subpath}.json`) : '/tsconfig.json'}`;
187
+ } else if (fromPath.startsWith(`${CONFIG_MODULES_DIR}/`)) {
188
+ path = join(dirname(fromPath), spec.endsWith('.json') ? spec : `${spec}.json`);
189
+ } else {
190
+ continue; // a project-local config: already in the VFS
191
+ }
192
+ if (store.configs.has(path)) continue;
193
+ store.configs.set(path, null);
194
+ tasks.push(fetchConfig(path));
195
+ }
196
+ }
197
+
198
+ async function fetchConfig(path: string): Promise<void> {
199
+ const rest = path.slice(CONFIG_MODULES_DIR.length + 1);
200
+ const { name, subpath } = splitPackageSpecifier(rest);
201
+ const res = await options.fetch(`${options.sources.npmBaseUrl}/${versioned(name, dependencies)}${subpath}`).catch(() => undefined);
202
+ if (!res?.ok) return;
203
+ const text = await res.text();
204
+ store.configs.set(path, text);
205
+ follow(path, text);
206
+ }
207
+
208
+ for (const path of fs.list()) {
209
+ if (/^\/tsconfig[^/]*\.json$/.test(path)) follow(path, fs.readText(path) ?? '');
210
+ }
211
+ while (tasks.length) await Promise.all(tasks.splice(0));
212
+ }