@seanhogg/builderforce-webcontainers-core 2026.10.2 → 2026.10.4

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 +12 -8
  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 +40 -0
  242. package/dist/packageCdn.d.ts.map +1 -1
  243. package/dist/packageCdn.js +54 -7
  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 +16 -11
  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 +91 -7
  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,103 @@
1
+ import type * as TS from 'typescript';
2
+ import { isRegistryRange } from '../packageCdn.js';
3
+ import { splitPackageSpecifier } from '../resolve.js';
4
+
5
+ /**
6
+ * Where the checker's non-project files live, and the cache that holds them.
7
+ *
8
+ * A TypeScript program is synchronous, but type definitions come from the
9
+ * network. So checking is two phases: acquisition fetches everything the project
10
+ * can reach into a {@link TypeStore}; the program then reads only the store. The
11
+ * store outlives one check (a worker keeps it), so a second check of the same
12
+ * project makes no requests and reuses parsed lib files.
13
+ *
14
+ * Fetched files are addressed by URL and exposed to TypeScript under virtual
15
+ * paths; libs and `extends`-ed tsconfig packages likewise.
16
+ */
17
+
18
+ export const TYPES_DIR = '/__bfwc_types__';
19
+ export const LIB_DIR = '/__bfwc_lib__';
20
+ /** tsconfig `extends: "@vue/tsconfig/..."` resolves through node_modules, so fetched configs live there. */
21
+ export const CONFIG_MODULES_DIR = '/node_modules';
22
+
23
+ export interface TypeSources {
24
+ /** An esm.sh-compatible CDN: answers `X-TypeScript-Types` for a package URL. */
25
+ typesOrigin: string;
26
+ /** Directory holding `lib.*.d.ts` for the TypeScript version in use. */
27
+ libBaseUrl: string;
28
+ /** Raw npm files (for tsconfig `extends` packages), jsDelivr's `/npm` layout. */
29
+ npmBaseUrl: string;
30
+ }
31
+
32
+ export const DEFAULT_TYPES_ORIGIN = 'https://esm.sh';
33
+ export const DEFAULT_NPM_BASE_URL = 'https://cdn.jsdelivr.net/npm';
34
+
35
+ export function libBaseUrlFor(typescriptVersion: string): string {
36
+ return `${DEFAULT_NPM_BASE_URL}/typescript@${typescriptVersion}/lib`;
37
+ }
38
+
39
+ /** `@scope/name` → `@types/scope__name`, DefinitelyTyped's naming. */
40
+ export function typesPackageName(name: string): string {
41
+ return `@types/${name.startsWith('@') ? name.slice(1).replace('/', '__') : name}`;
42
+ }
43
+
44
+ /** `name@range` when the project declares a registry range for it, else `name`. */
45
+ export function versioned(name: string, dependencies: Readonly<Record<string, string>>): string {
46
+ const range = dependencies[name];
47
+ return range && isRegistryRange(range) ? `${name}@${range}` : name;
48
+ }
49
+
50
+ /** The CDN module URL whose `X-TypeScript-Types` names a specifier's types. */
51
+ export function packageRequestUrl(origin: string, specifier: string, dependencies: Readonly<Record<string, string>>): string {
52
+ const { name, subpath } = splitPackageSpecifier(specifier);
53
+ return `${origin}/${versioned(name, dependencies)}${subpath}`;
54
+ }
55
+
56
+ /** URLs to try, in order, for a relative or absolute reference inside a fetched `.d.ts`. */
57
+ export function dtsCandidates(specifier: string, fromUrl: string): string[] {
58
+ const url = new URL(specifier, fromUrl).href.replace(/[?#].*$/, '');
59
+ if (/\.d\.[mc]?ts$/.test(url)) return [url];
60
+ if (/\.[mc]?js$/.test(url)) return [url.replace(/\.([mc]?)js$/, '.d.$1ts')];
61
+ if (/\.[mc]?ts$/.test(url)) return [url];
62
+ return [`${url}.d.ts`, `${url}/index.d.ts`];
63
+ }
64
+
65
+ export class TypeStore {
66
+ /** Final (post-redirect) URL → text. */
67
+ readonly files = new Map<string, string>();
68
+ /** Requested URL → final URL; `''` records a failure so it is not retried. */
69
+ readonly redirects = new Map<string, string>();
70
+ /** Package request URL (or `types:<name>`) → final types URL, or null when it has none. */
71
+ readonly packages = new Map<string, string | null>();
72
+ /** `lib.dom.d.ts` → text, or null when missing. */
73
+ readonly libs = new Map<string, string | null>();
74
+ /** `/node_modules/@vue/tsconfig/tsconfig.json` → text, or null when missing. */
75
+ readonly configs = new Map<string, string | null>();
76
+ /** Parsed lib and package files, reused by every program built over this store. */
77
+ readonly sourceFiles = new Map<string, TS.SourceFile>();
78
+
79
+ /** The final URL for a requested one, when it was fetched. */
80
+ finalUrl(url: string): string | undefined {
81
+ const final = this.redirects.get(url) ?? (this.files.has(url) ? url : undefined);
82
+ return final || undefined;
83
+ }
84
+
85
+ virtualPath(url: string): string {
86
+ return `${TYPES_DIR}/${url.replace(/^[a-z]+:\/\//i, '')}`;
87
+ }
88
+
89
+ urlOf(virtualPath: string): string | undefined {
90
+ if (!virtualPath.startsWith(`${TYPES_DIR}/`)) return undefined;
91
+ const rest = virtualPath.slice(TYPES_DIR.length + 1);
92
+ for (const scheme of ['https://', 'http://']) if (this.files.has(scheme + rest)) return scheme + rest;
93
+ return undefined;
94
+ }
95
+
96
+ /** Text for any virtual non-project path, or undefined. */
97
+ read(path: string): string | undefined {
98
+ if (path.startsWith(`${LIB_DIR}/`)) return this.libs.get(path.slice(LIB_DIR.length + 1)) ?? undefined;
99
+ if (path.startsWith(`${CONFIG_MODULES_DIR}/`)) return this.configs.get(path) ?? undefined;
100
+ const url = this.urlOf(path);
101
+ return url ? this.files.get(url) : undefined;
102
+ }
103
+ }
@@ -0,0 +1,134 @@
1
+ import type * as TS from 'typescript';
2
+ import { VirtualFileSystem, type FileSystemTree, type FlatFiles } from '../vfs.js';
3
+ import { readProjectConfig } from '../projectConfig.js';
4
+ import { isBareSpecifier, resolveAlias, splitPackageSpecifier } from '../resolve.js';
5
+ import { acquireExtendedConfigs, acquireTypes, type FetchLike } from './acquire.js';
6
+ import { createVirtualHost } from './compilerHost.js';
7
+ import { sortDiagnostics, toCheckDiagnostic, type CheckDiagnostic } from './diagnostics.js';
8
+ import { resolveCheckProjects, type CheckProject } from './projects.js';
9
+ import { AMBIENT_SHIM_PATH, ambientShim } from './shims.js';
10
+ import {
11
+ DEFAULT_NPM_BASE_URL,
12
+ DEFAULT_TYPES_ORIGIN,
13
+ libBaseUrlFor,
14
+ packageRequestUrl,
15
+ TypeStore,
16
+ type TypeSources,
17
+ } from './typeStore.js';
18
+
19
+ /**
20
+ * `tsc --noEmit` over a project held in memory. Runtime-agnostic: the caller
21
+ * passes the TypeScript module (the npm package in Node, the CDN build in a
22
+ * worker) and a `fetch` for type definitions, so the same code is tested in Node
23
+ * and run in the browser.
24
+ */
25
+ export interface TypecheckOptions {
26
+ fetch: FetchLike;
27
+ /** Where types, libs and tsconfig packages come from. Libs default to jsDelivr at `ts.version`. */
28
+ sources?: Partial<TypeSources>;
29
+ /** Reuse fetched and parsed declarations across checks (a long-lived worker keeps one). */
30
+ store?: TypeStore;
31
+ /** Cap on fetched declaration files. Default 2000. */
32
+ maxTypeFiles?: number;
33
+ }
34
+
35
+ export interface TypecheckResult {
36
+ diagnostics: CheckDiagnostic[];
37
+ /** Imported packages with no types on the CDN — checked as `any` rather than reported. */
38
+ untypedPackages: string[];
39
+ /** Project files that were checked, project-relative. */
40
+ files: string[];
41
+ }
42
+
43
+ interface Reach {
44
+ specifiers: Set<string>;
45
+ typeReferences: Set<string>;
46
+ libFiles: Set<string>;
47
+ }
48
+
49
+ function toFileSystem(files: VirtualFileSystem | FlatFiles | FileSystemTree): VirtualFileSystem {
50
+ if (files instanceof VirtualFileSystem) return files;
51
+ const fs = new VirtualFileSystem();
52
+ fs.mount(files);
53
+ return fs;
54
+ }
55
+
56
+ /** Everything a set of programs can reach outside the project: packages, type references, libs. */
57
+ function collectReach(ts: typeof TS, fs: VirtualFileSystem, projects: CheckProject[], isAliased: (spec: string) => boolean): Reach {
58
+ const reach: Reach = { specifiers: new Set(), typeReferences: new Set(), libFiles: new Set() };
59
+ for (const project of projects) {
60
+ const { options } = project;
61
+ for (const path of project.rootNames) {
62
+ const info = ts.preProcessFile(fs.readText(path) ?? '', true, true);
63
+ for (const ref of info.importedFiles) {
64
+ if (isBareSpecifier(ref.fileName) && !ref.fileName.includes('?') && !isAliased(ref.fileName)) reach.specifiers.add(ref.fileName);
65
+ }
66
+ for (const ref of info.typeReferenceDirectives) reach.typeReferences.add(ref.fileName);
67
+ for (const ref of info.libReferenceDirectives) reach.libFiles.add(`lib.${ref.fileName.toLowerCase()}.d.ts`);
68
+ }
69
+ for (const name of options.types ?? []) reach.typeReferences.add(name);
70
+ if (options.jsx === ts.JsxEmit.ReactJSX || options.jsx === ts.JsxEmit.ReactJSXDev) {
71
+ const runtime = options.jsx === ts.JsxEmit.ReactJSXDev ? 'jsx-dev-runtime' : 'jsx-runtime';
72
+ reach.specifiers.add(`${options.jsxImportSource ?? 'react'}/${runtime}`);
73
+ }
74
+ if (!options.noLib) for (const lib of options.lib ?? [ts.getDefaultLibFileName(options)]) reach.libFiles.add(lib);
75
+ }
76
+ return reach;
77
+ }
78
+
79
+ export async function typecheckProject(
80
+ ts: typeof TS,
81
+ files: VirtualFileSystem | FlatFiles | FileSystemTree,
82
+ options: TypecheckOptions,
83
+ ): Promise<TypecheckResult> {
84
+ const fs = toFileSystem(files);
85
+ const store = options.store ?? new TypeStore();
86
+ const sources: TypeSources = {
87
+ typesOrigin: DEFAULT_TYPES_ORIGIN,
88
+ npmBaseUrl: DEFAULT_NPM_BASE_URL,
89
+ libBaseUrl: libBaseUrlFor(ts.version),
90
+ ...options.sources,
91
+ };
92
+ const config = readProjectConfig(fs);
93
+ const { dependencies } = config;
94
+
95
+ await acquireExtendedConfigs(fs, store, dependencies, { fetch: options.fetch, sources });
96
+ const projects = resolveCheckProjects(ts, fs, store, config.jsx.importSource === 'react' ? undefined : config.jsx.importSource);
97
+ const reach = collectReach(ts, fs, projects, (spec) => resolveAlias(fs, config.aliases, spec) !== undefined);
98
+ await acquireTypes(
99
+ ts,
100
+ store,
101
+ { specifiers: [...reach.specifiers], typeReferences: [...reach.typeReferences], libFiles: [...reach.libFiles], dependencies },
102
+ { fetch: options.fetch, sources, maxFiles: options.maxTypeFiles ?? 2000 },
103
+ );
104
+
105
+ const untypedPackages = [
106
+ ...new Set(
107
+ [...reach.specifiers]
108
+ .filter((spec) => !store.packages.get(packageRequestUrl(sources.typesOrigin, spec, dependencies)))
109
+ .map((spec) => splitPackageSpecifier(spec).name),
110
+ ),
111
+ ].sort();
112
+ const projectDeclarations = fs.list().filter((path) => path.endsWith('.d.ts')).map((path) => fs.readText(path) ?? '');
113
+ const shim = ambientShim({ existing: [...projectDeclarations, ...store.files.values()], untyped: untypedPackages });
114
+
115
+ const diagnostics: CheckDiagnostic[] = [];
116
+ const checked = new Set<string>();
117
+ for (const project of projects) {
118
+ for (const error of project.errors) diagnostics.push(toCheckDiagnostic(ts, error));
119
+ if (!project.rootNames.length) continue;
120
+ const host = createVirtualHost(ts, { fs, store, typesOrigin: sources.typesOrigin, dependencies, aliases: config.aliases, shim });
121
+ const program = ts.createProgram({ rootNames: [...project.rootNames, AMBIENT_SHIM_PATH], options: project.options, host });
122
+ const found = [...program.getOptionsDiagnostics(), ...program.getGlobalDiagnostics()];
123
+ for (const file of program.getSourceFiles()) {
124
+ if (!fs.isFile(file.fileName)) continue; // libs, package types, shims
125
+ checked.add(file.fileName.slice(1));
126
+ found.push(...program.getSyntacticDiagnostics(file), ...program.getSemanticDiagnostics(file));
127
+ }
128
+ for (const diagnostic of found) {
129
+ if (diagnostic.file && !fs.isFile(diagnostic.file.fileName)) continue;
130
+ diagnostics.push(toCheckDiagnostic(ts, diagnostic));
131
+ }
132
+ }
133
+ return { diagnostics: sortDiagnostics(diagnostics), untypedPackages, files: [...checked].sort() };
134
+ }
@@ -0,0 +1,21 @@
1
+ import type { CompileContext } from './compileScript.js';
2
+ import { compileModule } from './compileScript.js';
3
+ import { componentExtension } from './components.js';
4
+ import { extname } from './paths.js';
5
+ import { injectStyleStatement, rewriteCssUrls } from './styleModules.js';
6
+
7
+ /**
8
+ * A `.vue` / `.svelte` file → one ES module for the dev server: the compiled
9
+ * component, its imports mapped like any script's, and its scoped CSS injected
10
+ * as a <style> tag keyed by the component's path (an edit replaces it in place).
11
+ */
12
+ export async function compileComponent(ctx: CompileContext, path: string): Promise<string> {
13
+ const extension = componentExtension(extname(path));
14
+ if (!extension) throw new Error(`Not a component: ${path}`);
15
+ const compiler = await ctx.components(extension, ctx.config.dependencies);
16
+ const compiled = await compiler.compile(ctx.fs.readText(path) ?? '', { path, dev: true });
17
+ const js = await compileModule(ctx, path, compiled.code, compiled.loader);
18
+ if (!compiled.css) return js;
19
+ const css = rewriteCssUrls(ctx.fs, path, compiled.css, ctx.base);
20
+ return `${js}\n${injectStyleStatement(path, JSON.stringify(css))}\n`;
21
+ }
@@ -1,7 +1,9 @@
1
1
  import type { VirtualFileSystem } from './vfs.js';
2
- import type { ProjectConfig } from './projectConfig.js';
2
+ import type { BuildMode, ProjectConfig } from './projectConfig.js';
3
3
  import type { PackageCdn } from './packageCdn.js';
4
- import type { Transformer } from './transformer.js';
4
+ import type { Loader, Transformer } from './transformer.js';
5
+ import type { ComponentCompilers } from './components.js';
6
+ import { componentExtension } from './components.js';
5
7
  import { loaderFor } from './transformer.js';
6
8
  import { dirname, extname } from './paths.js';
7
9
  import { isBareSpecifier, resolveAlias, resolveLocal, splitPackageSpecifier } from './resolve.js';
@@ -14,11 +16,19 @@ export interface CompileContext {
14
16
  transformer: Transformer;
15
17
  /** Preview base URL, ending in `/`. */
16
18
  base: string;
19
+ /** `.vue` / `.svelte` compilers. */
20
+ components: ComponentCompilers;
17
21
  }
18
22
 
19
23
  /** Vite-style import queries this runtime honours. */
20
24
  export type ImportQuery = 'import' | 'raw' | 'url';
21
25
 
26
+ /** A file served as a script module: TS/JS, or a component compiled to one. */
27
+ export function isScriptPath(path: string): boolean {
28
+ const ext = extname(path);
29
+ return loaderFor(ext) !== undefined || componentExtension(ext) !== undefined;
30
+ }
31
+
22
32
  /**
23
33
  * The URL a resolved VFS file is imported by. Scripts are served as-is; CSS and
24
34
  * JSON need the `?import` JS wrapper; anything else imported from JS (images,
@@ -28,12 +38,13 @@ export function moduleUrl(base: string, path: string, query?: ImportQuery): stri
28
38
  const url = base + path.slice(1);
29
39
  if (query === 'raw' || query === 'url') return `${url}?${query}`;
30
40
  const ext = extname(path);
31
- if (loaderFor(ext)) return url;
41
+ if (isScriptPath(path)) return url;
32
42
  if (ext === '.css' || ext === '.json') return `${url}?import`;
33
43
  return `${url}?url`;
34
44
  }
35
45
 
36
- function splitQuery(specifier: string): { path: string; query?: ImportQuery } {
46
+ /** Split `./notes.md?raw` into the path and the query this runtime honours (if any). */
47
+ export function splitQuery(specifier: string): { path: string; query?: ImportQuery } {
37
48
  const at = specifier.indexOf('?');
38
49
  if (at < 0) return { path: specifier };
39
50
  const query = specifier.slice(at + 1);
@@ -59,23 +70,34 @@ export function mapSpecifier(ctx: CompileContext, fromDir: string, specifier: st
59
70
  return resolved ? moduleUrl(ctx.base, resolved, query) : undefined;
60
71
  }
61
72
 
62
- /** Compile-time constants: Vite's `import.meta.env` and CRA's `process.env.REACT_APP_*`. */
63
- export function buildDefine(config: ProjectConfig, base: string): Record<string, string> {
64
- const env: Record<string, unknown> = { MODE: 'development', DEV: true, PROD: false, SSR: false, BASE_URL: base };
65
- const define: Record<string, string> = { 'process.env.NODE_ENV': '"development"' };
73
+ /**
74
+ * Compile-time constants: Vite's `import.meta.env`, CRA's `process.env.REACT_APP_*`
75
+ * and `PUBLIC_URL`. `base` is the URL the app is served under.
76
+ */
77
+ export function buildDefine(config: ProjectConfig, base: string, mode: BuildMode = 'development'): Record<string, string> {
78
+ const production = mode === 'production';
79
+ const env: Record<string, unknown> = { MODE: mode, DEV: !production, PROD: production, SSR: false, BASE_URL: base };
80
+ const define: Record<string, string> = {
81
+ 'process.env.NODE_ENV': JSON.stringify(mode),
82
+ // CRA's convention: the base without its trailing slash ('' at the root).
83
+ 'process.env.PUBLIC_URL': JSON.stringify(base.replace(/\/$/, '')),
84
+ };
66
85
  for (const [key, value] of Object.entries(config.env)) {
67
86
  if (key.startsWith('VITE_')) env[key] = value;
68
87
  if (key.startsWith('VITE_') || key.startsWith('REACT_APP_')) define[`process.env.${key}`] = JSON.stringify(value);
69
88
  }
89
+ // Each key on its own, so `import.meta.env.VITE_X` becomes a literal in place; the
90
+ // whole object only where code reads `import.meta.env` itself. (Defining just the
91
+ // object makes a bundler hoist it into a shared variable.)
92
+ for (const [key, value] of Object.entries(env)) {
93
+ if (/^[A-Za-z_$][\w$]*$/.test(key)) define[`import.meta.env.${key}`] = JSON.stringify(value);
94
+ }
70
95
  define['import.meta.env'] = JSON.stringify(env);
71
96
  return define;
72
97
  }
73
98
 
74
- /** TS/JSX → an ES module whose imports point at preview and CDN URLs. */
75
- export async function compileScript(ctx: CompileContext, path: string): Promise<string> {
76
- const loader = loaderFor(extname(path));
77
- if (!loader) throw new Error(`Not a script: ${path}`);
78
- const source = ctx.fs.readText(path) ?? '';
99
+ /** Compile module source (TS/JSX or plain JS) and point its imports at preview and CDN URLs. */
100
+ export async function compileModule(ctx: CompileContext, path: string, source: string, loader: Loader): Promise<string> {
79
101
  const { code } = await ctx.transformer.transform(source, {
80
102
  loader,
81
103
  sourcefile: path,
@@ -85,3 +107,10 @@ export async function compileScript(ctx: CompileContext, path: string): Promise<
85
107
  const fromDir = dirname(path);
86
108
  return rewriteImports(code, (specifier) => mapSpecifier(ctx, fromDir, specifier));
87
109
  }
110
+
111
+ /** TS/JSX → an ES module whose imports point at preview and CDN URLs. */
112
+ export async function compileScript(ctx: CompileContext, path: string): Promise<string> {
113
+ const loader = loaderFor(extname(path));
114
+ if (!loader) throw new Error(`Not a script: ${path}`);
115
+ return compileModule(ctx, path, ctx.fs.readText(path) ?? '', loader);
116
+ }
@@ -0,0 +1,59 @@
1
+ import type { Loader } from './transformer.js';
2
+
3
+ /**
4
+ * Single-file components (`.vue`, `.svelte`) as a PORT, like the Transformer. A
5
+ * component compiler turns one file into a script module plus the CSS it owns;
6
+ * the dev server injects that CSS with a <style> tag and the build extracts it
7
+ * into the CSS bundle, so the compilers themselves never touch the DOM.
8
+ *
9
+ * The core never imports a framework compiler. The browser runtime loads the
10
+ * official ones from a CDN on first use, pinned to the project's own framework
11
+ * version (a Svelte compiler must match its runtime exactly); Node tests pass the
12
+ * npm packages in.
13
+ */
14
+ export type ComponentExtension = '.vue' | '.svelte';
15
+
16
+ export const COMPONENT_EXTENSIONS: readonly ComponentExtension[] = ['.vue', '.svelte'];
17
+
18
+ export function componentExtension(ext: string): ComponentExtension | undefined {
19
+ return (COMPONENT_EXTENSIONS as readonly string[]).includes(ext) ? (ext as ComponentExtension) : undefined;
20
+ }
21
+
22
+ export interface ComponentRequest {
23
+ /** The VFS path — names the component in errors and seeds its style scope id. */
24
+ path: string;
25
+ /** Development output (dev warnings, readable names) vs production. */
26
+ dev: boolean;
27
+ }
28
+
29
+ export interface CompiledComponent {
30
+ /** An ES module (still TS when `loader` says so) whose default export is the component. */
31
+ code: string;
32
+ loader: Loader;
33
+ /** The component's styles, already scoped. Empty when it has none. */
34
+ css: string;
35
+ }
36
+
37
+ export interface ComponentCompiler {
38
+ compile(source: string, request: ComponentRequest): Promise<CompiledComponent> | CompiledComponent;
39
+ }
40
+
41
+ /**
42
+ * Supplies the compiler for an extension. Given the project's dependency ranges
43
+ * so a loader can fetch the compiler version that matches the project's runtime.
44
+ */
45
+ export type ComponentCompilers = (
46
+ extension: ComponentExtension,
47
+ dependencies: Readonly<Record<string, string>>,
48
+ ) => Promise<ComponentCompiler>;
49
+
50
+ /** Compilers already in hand (tests, a host that bundles them), keyed by extension. */
51
+ export function staticComponentCompilers(compilers: Partial<Record<ComponentExtension, ComponentCompiler>>): ComponentCompilers {
52
+ return (extension) => {
53
+ const compiler = compilers[extension];
54
+ return compiler ? Promise.resolve(compiler) : Promise.reject(new Error(`No compiler for ${extension} files is configured.`));
55
+ };
56
+ }
57
+
58
+ /** The default when a host configures none: a clear error instead of serving source. */
59
+ export const noComponentCompilers: ComponentCompilers = staticComponentCompilers({});
@@ -3,9 +3,13 @@ import { RESOLVE_EXTENSIONS } from './resolve.js';
3
3
 
4
4
  export type ProjectKind = 'vite' | 'cra' | 'static';
5
5
 
6
+ /** The UI framework, when the project uses one this runtime compiles. */
7
+ export type ProjectFramework = 'react' | 'vue' | 'svelte';
8
+
6
9
  export interface ProjectProfile {
7
10
  supported: boolean;
8
11
  kind?: ProjectKind;
12
+ framework?: ProjectFramework;
9
13
  /** The HTML document served at `/`. */
10
14
  htmlPath?: string;
11
15
  /** Script injected when the HTML has no module entry of its own (CRA). */
@@ -17,8 +21,10 @@ export interface ProjectProfile {
17
21
  }
18
22
 
19
23
  /**
20
- * Frameworks that need a server or a compiler this runtime does not have yet.
21
- * Data, not branches: supporting one later means deleting its row.
24
+ * Frameworks that need a server or a build pipeline this runtime does not have.
25
+ * Data, not branches: supporting one later means deleting its row. Checked before
26
+ * the plain-framework rules below, so SvelteKit and Nuxt (which depend on svelte
27
+ * and vue) are declined rather than mistaken for a Vite + Svelte/Vue app.
22
28
  */
23
29
  const NEEDS_NODE: ReadonlyArray<{ dependency: string; reason: string }> = [
24
30
  { dependency: 'next', reason: 'Next.js needs its Node server.' },
@@ -26,8 +32,6 @@ const NEEDS_NODE: ReadonlyArray<{ dependency: string; reason: string }> = [
26
32
  { dependency: '@remix-run/dev', reason: 'Remix needs its Node server.' },
27
33
  { dependency: '@sveltejs/kit', reason: 'SvelteKit needs its Node server.' },
28
34
  { dependency: 'astro', reason: 'Astro needs its build pipeline.' },
29
- { dependency: 'svelte', reason: 'Svelte components need the Svelte compiler.' },
30
- { dependency: 'vue', reason: 'Vue single-file components need the Vue compiler.' },
31
35
  ];
32
36
 
33
37
  const SERVER_ONLY = ['express', 'fastify', 'koa', '@nestjs/core', '@hapi/hapi'];
@@ -41,6 +45,13 @@ function readDependencyNames(fs: VirtualFileSystem): Set<string> {
41
45
  }
42
46
  }
43
47
 
48
+ function detectFramework(deps: Set<string>): ProjectFramework | undefined {
49
+ if (deps.has('vue')) return 'vue';
50
+ if (deps.has('svelte')) return 'svelte';
51
+ if (deps.has('react')) return 'react';
52
+ return undefined;
53
+ }
54
+
44
55
  function findEntry(fs: VirtualFileSystem): string | undefined {
45
56
  for (const stem of ['/src/index', '/src/main']) {
46
57
  for (const ext of RESOLVE_EXTENSIONS) if (fs.isFile(stem + ext)) return stem + ext;
@@ -53,11 +64,12 @@ export function detectProject(fs: VirtualFileSystem): ProjectProfile {
53
64
  const blocker = NEEDS_NODE.find((row) => deps.has(row.dependency));
54
65
  if (blocker) return { supported: false, publicDir: '/public', reason: blocker.reason };
55
66
 
67
+ const framework = detectFramework(deps);
56
68
  if (fs.isFile('/index.html')) {
57
- return { supported: true, kind: deps.has('vite') ? 'vite' : 'static', htmlPath: '/index.html', publicDir: '/public' };
69
+ return { supported: true, kind: deps.has('vite') ? 'vite' : 'static', framework, htmlPath: '/index.html', publicDir: '/public' };
58
70
  }
59
71
  if (fs.isFile('/public/index.html')) {
60
- return { supported: true, kind: 'cra', htmlPath: '/public/index.html', entry: findEntry(fs), publicDir: '/public' };
72
+ return { supported: true, kind: 'cra', framework, htmlPath: '/public/index.html', entry: findEntry(fs), publicDir: '/public' };
61
73
  }
62
74
  if (SERVER_ONLY.some((name) => deps.has(name))) {
63
75
  return { supported: false, publicDir: '/public', reason: 'This is a Node server app with no browser entry page.' };
package/src/devServer.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  import type { FsChange, VirtualFileSystem } from './vfs.js';
2
2
  import type { Transformer } from './transformer.js';
3
- import type { PackageCdn } from './packageCdn.js';
4
- import { createEsmShCdn } from './packageCdn.js';
3
+ import type { PackageCdn, PackageCdnFactory } from './packageCdn.js';
4
+ import { esmShCdnFactory } from './packageCdn.js';
5
+ import { noComponentCompilers, type ComponentCompilers } from './components.js';
5
6
  import { isConfigFile, readProjectConfig, type ProjectConfig } from './projectConfig.js';
6
7
  import { detectProject, type ProjectProfile } from './detectProject.js';
7
- import { compileScript, type CompileContext, type ImportQuery } from './compileScript.js';
8
+ import { compileScript, isScriptPath, type CompileContext, type ImportQuery } from './compileScript.js';
9
+ import { compileComponent } from './compileComponent.js';
8
10
  import { transformHtml } from './html.js';
9
11
  import { cssToModule, jsonToModule, rawToModule, rewriteCssUrls, urlToModule } from './styleModules.js';
10
12
  import { loaderFor } from './transformer.js';
@@ -23,7 +25,9 @@ export interface DevServerOptions {
23
25
  /** The URL the preview is served under, ending in `/` (`/__bfwc/<id>/`). */
24
26
  base: string;
25
27
  /** Package CDN factory, given the project's dependency ranges. Default: esm.sh. */
26
- cdn?: (dependencies: Record<string, string>) => PackageCdn;
28
+ cdn?: PackageCdnFactory;
29
+ /** `.vue` / `.svelte` compilers. Without them, requesting a component is an error. */
30
+ components?: ComponentCompilers;
27
31
  /** The "Built with Builderforce.ai" badge in served pages. Default true. */
28
32
  attribution?: boolean;
29
33
  }
@@ -73,7 +77,7 @@ function parseQuery(search: string): ImportQuery | undefined {
73
77
  */
74
78
  export class DevServer {
75
79
  private config?: ProjectConfig;
76
- private cdn?: PackageCdn;
80
+ private cdn?: Promise<PackageCdn>;
77
81
  private profileCache?: ProjectProfile;
78
82
  private readonly cache = new Map<string, { version: number; file: ServedFile }>();
79
83
  private readonly unwatch: () => void;
@@ -105,7 +109,7 @@ export class DevServer {
105
109
  if (!file) {
106
110
  // An extension-less path is a client-side route: serve the app (SPA fallback).
107
111
  if (!extname(path) && !query) return this.serveDocument(profile);
108
- return query || loaderFor(extname(path)) ? errorModule(`Cannot find module ${path}`) : reply(404, 'text/plain; charset=utf-8', `Not found: ${path}`);
112
+ return query || isScriptPath(path) ? errorModule(`Cannot find module ${path}`) : reply(404, 'text/plain; charset=utf-8', `Not found: ${path}`);
109
113
  }
110
114
 
111
115
  const key = `${file}?${query ?? ''}`;
@@ -129,14 +133,15 @@ export class DevServer {
129
133
  return query === 'import' ? reply(200, JS_MIME, cssToModule(file, css)) : reply(200, mimeFor(ext), css);
130
134
  }
131
135
  if (ext === '.json' && query === 'import') return reply(200, JS_MIME, jsonToModule(fs.readText(file) ?? ''));
132
- if (loaderFor(ext)) return reply(200, JS_MIME, await compileScript(this.context(), file));
136
+ if (loaderFor(ext)) return reply(200, JS_MIME, await compileScript(await this.context(), file));
137
+ if (isScriptPath(file)) return reply(200, JS_MIME, await compileComponent(await this.context(), file));
133
138
  if (ext === '.html' || ext === '.htm') {
134
139
  return reply(200, mimeFor(ext), transformHtml(fs.readText(file) ?? '', { base, attribution: this.options.attribution }));
135
140
  }
136
141
  return reply(200, mimeFor(ext), fs.readFile(file) ?? '');
137
142
  } catch (error) {
138
143
  const message = error instanceof Error ? error.message : String(error);
139
- return query || loaderFor(ext) ? errorModule(`${file}: ${message}`) : reply(500, 'text/plain; charset=utf-8', message);
144
+ return query || isScriptPath(file) ? errorModule(`${file}: ${message}`) : reply(500, 'text/plain; charset=utf-8', message);
140
145
  }
141
146
  }
142
147
 
@@ -149,11 +154,11 @@ export class DevServer {
149
154
  return reply(200, 'text/html; charset=utf-8', transformHtml(html, { base, entry: profile.entry, attribution }));
150
155
  }
151
156
 
152
- private context(): CompileContext {
157
+ private async context(): Promise<CompileContext> {
153
158
  const { fs, transformer, base } = this.options;
154
159
  this.config ??= readProjectConfig(fs);
155
- this.cdn ??= (this.options.cdn ?? ((dependencies) => createEsmShCdn({ dependencies })))(this.config.dependencies);
156
- return { fs, config: this.config, cdn: this.cdn, transformer, base };
160
+ this.cdn ??= Promise.resolve((this.options.cdn ?? esmShCdnFactory)(this.config.dependencies, { dev: true }));
161
+ return { fs, config: this.config, cdn: await this.cdn, transformer, base, components: this.options.components ?? noComponentCompilers };
157
162
  }
158
163
 
159
164
  private onChange(change: FsChange): void {
package/src/hash.ts ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * A short, deterministic content hash: cache-busting file names in a build and
3
+ * stable scope ids for component styles. Not cryptographic, and does not need to
4
+ * be — it only has to change when the bytes change. Synchronous (two FNV-1a
5
+ * variants mixed), so it works inside a bundler's resolve hook without
6
+ * `crypto.subtle`, which is async and missing outside secure contexts.
7
+ */
8
+ const encoder = new TextEncoder();
9
+
10
+ export function contentHash(data: string | Uint8Array, length = 8): string {
11
+ const bytes = typeof data === 'string' ? encoder.encode(data) : data;
12
+ let h1 = 0x811c9dc5;
13
+ let h2 = 0x5bd1e995;
14
+ for (let i = 0; i < bytes.length; i++) {
15
+ const byte = bytes[i]!;
16
+ h1 = Math.imul(h1 ^ byte, 0x01000193);
17
+ h2 = Math.imul(h2 ^ byte, 0x5bd1e995);
18
+ h2 ^= h2 >>> 15;
19
+ }
20
+ const hex = (h1 >>> 0).toString(16).padStart(8, '0') + (h2 >>> 0).toString(16).padStart(8, '0');
21
+ return hex.slice(0, length);
22
+ }
package/src/index.ts CHANGED
@@ -4,17 +4,46 @@ export { normalizePath, dirname, basename, join, extname } from './paths.js';
4
4
  export { DevServer } from './devServer.js';
5
5
  export type { DevServerOptions, ServedFile } from './devServer.js';
6
6
  export { detectProject } from './detectProject.js';
7
- export type { ProjectKind, ProjectProfile } from './detectProject.js';
8
- export { readProjectConfig, parseLooseJson, parseDotenv } from './projectConfig.js';
9
- export type { ProjectConfig, PathAlias } from './projectConfig.js';
10
- export { createEsmShCdn } from './packageCdn.js';
11
- export type { PackageCdn, EsmShOptions } from './packageCdn.js';
7
+ export type { ProjectKind, ProjectFramework, ProjectProfile } from './detectProject.js';
8
+ export { readProjectConfig, parseLooseJson, parseDotenv, envFiles } from './projectConfig.js';
9
+ export type { ProjectConfig, PathAlias, BuildMode } from './projectConfig.js';
10
+ export { createEsmShCdn, esmShCdnFactory, isRegistryRange, loadPackageManifests } from './packageCdn.js';
11
+ export type { PackageCdn, PackageCdnFactory, EsmShOptions, PackageDependencyFields, ManifestLoadOptions } from './packageCdn.js';
12
12
  export { createEsbuildTransformer, loaderFor } from './transformer.js';
13
13
  export type { Transformer, TransformRequest, Loader, EsbuildLike } from './transformer.js';
14
+ export { createEsbuildBundler } from './bundler.js';
15
+ export type {
16
+ Bundler,
17
+ BundleRequest,
18
+ BundleOutput,
19
+ BundleOutputFile,
20
+ BundleHost,
21
+ BundleLoad,
22
+ BundleLoader,
23
+ BundleResolution,
24
+ ResolveKind,
25
+ EsbuildBuildLike,
26
+ } from './bundler.js';
27
+ export { buildProject, normalizeBase } from './build.js';
28
+ export type { BuildOptions, BuildResult, BuiltFile } from './build.js';
29
+ export { createBuildHost } from './buildHost.js';
30
+ export type { BuildHost, BuildHostOptions } from './buildHost.js';
31
+ export { findHtmlEntries, rewriteBuiltHtml } from './buildHtml.js';
32
+ export type { HtmlEntry, BuiltHtmlOptions } from './buildHtml.js';
33
+ export { COMPONENT_EXTENSIONS, componentExtension, staticComponentCompilers, noComponentCompilers } from './components.js';
34
+ export type { ComponentCompiler, ComponentCompilers, ComponentExtension, ComponentRequest, CompiledComponent } from './components.js';
35
+ export { createVueCompiler } from './vueCompiler.js';
36
+ export type { VueCompilerSfcLike, VueDescriptor } from './vueCompiler.js';
37
+ export { createSvelteCompiler } from './svelteCompiler.js';
38
+ export type { SvelteCompilerLike } from './svelteCompiler.js';
39
+ export { contentHash } from './hash.js';
14
40
  export { rewriteImports } from './rewriteImports.js';
15
41
  export { resolveLocal, resolveAlias, isBareSpecifier, splitPackageSpecifier, RESOLVE_EXTENSIONS } from './resolve.js';
16
- export { compileScript, mapSpecifier, moduleUrl, buildDefine } from './compileScript.js';
42
+ export { compileScript, compileModule, isScriptPath, mapSpecifier, moduleUrl, buildDefine } from './compileScript.js';
43
+ export { compileComponent } from './compileComponent.js';
17
44
  export { transformHtml, errorBridgeScript, liveReloadScript, reloadChannelName, ERROR_MESSAGE_TYPE } from './html.js';
18
45
  export { mimeFor } from './mime.js';
19
46
  export { attributionScript, injectAttribution, ATTRIBUTION_URL, ATTRIBUTION_LABEL } from './attribution.js';
20
47
  export type { AttributionOptions } from './attribution.js';
48
+ export * from './installer/index.js';
49
+ export * from './system/index.js';