@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,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
+ }
@@ -0,0 +1,138 @@
1
+ import type * as TS from 'typescript';
2
+ import type { VirtualFileSystem } from '../vfs.js';
3
+ import type { PathAlias } from '../projectConfig.js';
4
+ import { dirname, extname, join, normalizePath } from '../paths.js';
5
+ import { isBareSpecifier } from '../resolve.js';
6
+ import { AMBIENT_SHIM_PATH, EMPTY_TYPES_PATH, SHIMMED_TYPE_REFERENCES, SHIM_DIR } from './shims.js';
7
+ import { dtsCandidates, LIB_DIR, packageRequestUrl, TYPES_DIR, type TypeStore } from './typeStore.js';
8
+
9
+ /**
10
+ * A synchronous TypeScript CompilerHost over the project's VFS and a filled
11
+ * {@link TypeStore}. Module resolution is done here rather than by TypeScript's
12
+ * node resolver: project imports follow the runtime's own rules (resolve.ts
13
+ * probing, tsconfig aliases), bare imports go to the types the CDN named, and
14
+ * references inside fetched declaration files resolve as URLs.
15
+ */
16
+ export interface VirtualHostOptions {
17
+ fs: VirtualFileSystem;
18
+ store: TypeStore;
19
+ typesOrigin: string;
20
+ dependencies: Readonly<Record<string, string>>;
21
+ aliases: readonly PathAlias[];
22
+ /** The ambient shim's text (see shims.ts). */
23
+ shim: string;
24
+ }
25
+
26
+ const TS_PROBE = ['.ts', '.tsx', '.d.ts', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs', '.json'];
27
+
28
+ function extensionOf(ts: typeof TS, path: string): TS.Extension {
29
+ if (path.endsWith('.d.ts')) return ts.Extension.Dts;
30
+ if (path.endsWith('.d.mts')) return ts.Extension.Dmts;
31
+ if (path.endsWith('.d.cts')) return ts.Extension.Dcts;
32
+ const map: Record<string, TS.Extension> = {
33
+ '.ts': ts.Extension.Ts, '.tsx': ts.Extension.Tsx, '.mts': ts.Extension.Mts, '.cts': ts.Extension.Cts,
34
+ '.js': ts.Extension.Js, '.jsx': ts.Extension.Jsx, '.mjs': ts.Extension.Mjs, '.cjs': ts.Extension.Cjs, '.json': ts.Extension.Json,
35
+ };
36
+ return map[extname(path)] ?? ts.Extension.Ts;
37
+ }
38
+
39
+ /** TypeScript's probing for a project-relative path: extensions, `.js` → `.ts`, `index`. */
40
+ function probeProject(fs: VirtualFileSystem, base: string): string | undefined {
41
+ const ext = extname(base);
42
+ if (fs.isFile(base) && TS_PROBE.includes(ext)) return base;
43
+ for (const candidate of TS_PROBE) if (fs.isFile(base + candidate)) return base + candidate;
44
+ if (ext === '.js' || ext === '.jsx' || ext === '.mjs' || ext === '.cjs') {
45
+ const stem = base.slice(0, -ext.length);
46
+ for (const alt of ['.ts', '.tsx', '.d.ts', '.mts', '.cts']) if (fs.isFile(stem + alt)) return stem + alt;
47
+ }
48
+ for (const candidate of TS_PROBE) if (fs.isFile(join(base, `index${candidate}`))) return join(base, `index${candidate}`);
49
+ return undefined;
50
+ }
51
+
52
+ export function createVirtualHost(ts: typeof TS, options: VirtualHostOptions): TS.CompilerHost {
53
+ const { fs, store } = options;
54
+
55
+ const readFile = (path: string): string | undefined => {
56
+ if (path === AMBIENT_SHIM_PATH) return options.shim;
57
+ if (path === EMPTY_TYPES_PATH) return 'export {};\n';
58
+ return fs.readText(path) ?? store.read(path);
59
+ };
60
+
61
+ function typesFor(url: string | undefined | null): string | undefined {
62
+ return url ? store.virtualPath(url) : undefined;
63
+ }
64
+
65
+ function resolveInTypes(specifier: string, containingUrl: string): string | undefined {
66
+ if (isBareSpecifier(specifier)) return typesFor(store.packages.get(packageRequestUrl(options.typesOrigin, specifier, {})));
67
+ for (const candidate of dtsCandidates(specifier, containingUrl)) {
68
+ const final = store.finalUrl(candidate);
69
+ if (final) return typesFor(final);
70
+ }
71
+ return undefined;
72
+ }
73
+
74
+ function resolveInProject(specifier: string, containingFile: string): string | undefined {
75
+ if (specifier.includes('?')) return undefined; // `?raw`/`?url`: the ambient shim declares them
76
+ if (!isBareSpecifier(specifier)) {
77
+ const base = specifier.startsWith('/') ? normalizePath(specifier) : join(dirname(containingFile), specifier);
78
+ return probeProject(fs, base);
79
+ }
80
+ for (const alias of options.aliases) {
81
+ const matches = alias.wildcard ? specifier.startsWith(alias.prefix) : specifier === alias.prefix;
82
+ if (!matches) continue;
83
+ const rest = alias.wildcard ? specifier.slice(alias.prefix.length) : '';
84
+ for (const target of alias.targets) {
85
+ const hit = probeProject(fs, normalizePath(target + rest));
86
+ if (hit) return hit;
87
+ }
88
+ }
89
+ return typesFor(store.packages.get(packageRequestUrl(options.typesOrigin, specifier, options.dependencies)));
90
+ }
91
+
92
+ function resolveModule(specifier: string, containingFile: string): TS.ResolvedModuleFull | undefined {
93
+ const containingUrl = store.urlOf(containingFile);
94
+ const resolved = containingUrl ? resolveInTypes(specifier, containingUrl) : resolveInProject(specifier, containingFile);
95
+ if (!resolved) return undefined;
96
+ return { resolvedFileName: resolved, extension: extensionOf(ts, resolved), isExternalLibraryImport: resolved.startsWith(`${TYPES_DIR}/`) };
97
+ }
98
+
99
+ /** `/// <reference types>` resolves the same from anywhere: acquisition keyed it by name. */
100
+ function resolveTypeReference(name: string): string | undefined {
101
+ if (SHIMMED_TYPE_REFERENCES.has(name)) return EMPTY_TYPES_PATH;
102
+ return typesFor(store.packages.get(`types:${name}`));
103
+ }
104
+
105
+ return {
106
+ getSourceFile(fileName, languageVersion) {
107
+ const shared = !fs.isFile(fileName);
108
+ const cached = shared ? store.sourceFiles.get(fileName) : undefined;
109
+ if (cached) return cached;
110
+ const text = readFile(fileName);
111
+ if (text === undefined) return undefined;
112
+ const file = ts.createSourceFile(fileName, text, languageVersion, true);
113
+ // Lib and package files never change for a URL: parse once per store.
114
+ if (shared && fileName !== AMBIENT_SHIM_PATH) store.sourceFiles.set(fileName, file);
115
+ return file;
116
+ },
117
+ getDefaultLibFileName: (compilerOptions) => `${LIB_DIR}/${ts.getDefaultLibFileName(compilerOptions)}`,
118
+ getDefaultLibLocation: () => LIB_DIR,
119
+ writeFile: () => undefined,
120
+ getCurrentDirectory: () => '/',
121
+ getCanonicalFileName: (fileName) => fileName,
122
+ useCaseSensitiveFileNames: () => true,
123
+ getNewLine: () => '\n',
124
+ fileExists: (fileName) => readFile(fileName) !== undefined,
125
+ readFile,
126
+ directoryExists: (dir) => fs.isDirectory(dir) || dir.startsWith(TYPES_DIR) || dir === LIB_DIR || dir === SHIM_DIR,
127
+ getDirectories: () => [],
128
+ resolveModuleNameLiterals: (literals, containingFile) =>
129
+ literals.map((literal) => ({ resolvedModule: resolveModule(literal.text, containingFile) })),
130
+ resolveTypeReferenceDirectiveReferences: (references) =>
131
+ references.map((reference) => {
132
+ const resolved = resolveTypeReference(typeof reference === 'string' ? reference : reference.fileName);
133
+ return {
134
+ resolvedTypeReferenceDirective: resolved ? { primary: true, resolvedFileName: resolved, isExternalLibraryImport: true } : undefined,
135
+ };
136
+ }),
137
+ };
138
+ }
@@ -0,0 +1,48 @@
1
+ import type * as TS from 'typescript';
2
+
3
+ export type DiagnosticCategory = 'error' | 'warning' | 'suggestion' | 'message';
4
+
5
+ /**
6
+ * One problem, in a shape an editor (or an agent) can act on without the
7
+ * TypeScript API: positions are 1-based like an editor's gutter, and `file` is
8
+ * the project-relative path (`src/App.tsx`), the same key `FlatFiles` uses.
9
+ */
10
+ export interface CheckDiagnostic {
11
+ /** Project-relative path; absent for global problems (compiler options, a missing lib). */
12
+ file?: string;
13
+ line: number;
14
+ column: number;
15
+ message: string;
16
+ /** TypeScript's code (2322 for TS2322). */
17
+ code: number;
18
+ category: DiagnosticCategory;
19
+ }
20
+
21
+ const CATEGORIES: Record<number, DiagnosticCategory> = { 0: 'warning', 1: 'error', 2: 'suggestion', 3: 'message' };
22
+
23
+ export function toCheckDiagnostic(ts: typeof TS, diagnostic: TS.Diagnostic): CheckDiagnostic {
24
+ const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
25
+ const category = CATEGORIES[diagnostic.category] ?? 'error';
26
+ if (!diagnostic.file || diagnostic.start === undefined) return { line: 1, column: 1, message, code: diagnostic.code, category };
27
+ const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
28
+ return { file: diagnostic.file.fileName.replace(/^\//, ''), line: line + 1, column: character + 1, message, code: diagnostic.code, category };
29
+ }
30
+
31
+ /** `src/App.tsx(3,7): error TS2322: Type 'number' is not assignable to type 'string'.` — tsc's own format. */
32
+ export function formatDiagnostic(diagnostic: CheckDiagnostic): string {
33
+ const where = diagnostic.file ? `${diagnostic.file}(${diagnostic.line},${diagnostic.column}): ` : '';
34
+ return `${where}${diagnostic.category} TS${diagnostic.code}: ${diagnostic.message}`;
35
+ }
36
+
37
+ /** Stable order (file, then position) and no duplicates — a file in two tsconfig projects reports once. */
38
+ export function sortDiagnostics(diagnostics: CheckDiagnostic[]): CheckDiagnostic[] {
39
+ const seen = new Set<string>();
40
+ return diagnostics
41
+ .filter((d) => {
42
+ const key = `${d.file ?? ''}:${d.line}:${d.column}:${d.code}:${d.message}`;
43
+ if (seen.has(key)) return false;
44
+ seen.add(key);
45
+ return true;
46
+ })
47
+ .sort((a, b) => (a.file ?? '').localeCompare(b.file ?? '') || a.line - b.line || a.column - b.column);
48
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * `@seanhogg/builderforce-webcontainers-core/check` — type-checking a project in
3
+ * memory. A separate entry point because it is typed against the `typescript`
4
+ * package (an optional peer dependency), which the rest of the core never needs.
5
+ */
6
+ export { typecheckProject } from './typecheck.js';
7
+ export type { TypecheckOptions, TypecheckResult } from './typecheck.js';
8
+ export { toCheckDiagnostic, formatDiagnostic, sortDiagnostics } from './diagnostics.js';
9
+ export type { CheckDiagnostic, DiagnosticCategory } from './diagnostics.js';
10
+ export { acquireTypes, acquireExtendedConfigs } from './acquire.js';
11
+ export type { FetchLike, FetchResponseLike, AcquireRequest, AcquireOptions } from './acquire.js';
12
+ export { resolveCheckProjects, defaultCompilerOptions, createParseConfigHost } from './projects.js';
13
+ export type { CheckProject } from './projects.js';
14
+ export { createVirtualHost } from './compilerHost.js';
15
+ export type { VirtualHostOptions } from './compilerHost.js';
16
+ export { ambientShim, declaresModule, AMBIENT_SHIM_PATH, SHIMMED_TYPE_REFERENCES } from './shims.js';
17
+ export {
18
+ TypeStore,
19
+ libBaseUrlFor,
20
+ typesPackageName,
21
+ dtsCandidates,
22
+ packageRequestUrl,
23
+ DEFAULT_TYPES_ORIGIN,
24
+ DEFAULT_NPM_BASE_URL,
25
+ TYPES_DIR,
26
+ LIB_DIR,
27
+ } from './typeStore.js';
28
+ export type { TypeSources } from './typeStore.js';
@@ -0,0 +1,149 @@
1
+ import type * as TS from 'typescript';
2
+ import type { VirtualFileSystem } from '../vfs.js';
3
+ import { dirname, extname, join } from '../paths.js';
4
+ import type { TypeStore } from './typeStore.js';
5
+
6
+ /**
7
+ * Which programs to build, with which options, over which files — what `tsc -b`
8
+ * would derive from the project's tsconfig files.
9
+ *
10
+ * Vite's templates keep a root `tsconfig.json` holding only `references` (to
11
+ * `tsconfig.app.json` and `tsconfig.node.json`); each reference is its own
12
+ * program. With no tsconfig at all, the checker synthesises Vite's defaults for
13
+ * a React + TS app, so a generated project with no config still gets checked.
14
+ */
15
+ export interface CheckProject {
16
+ /** The tsconfig this came from; undefined when synthesised. */
17
+ configPath?: string;
18
+ options: TS.CompilerOptions;
19
+ rootNames: string[];
20
+ /** Problems parsing the config itself. */
21
+ errors: readonly TS.Diagnostic[];
22
+ }
23
+
24
+ /** Tool configs (`vite.config.ts`…) describe the build, which runs elsewhere: not checked. */
25
+ const TOOL_CONFIG = /(^|\/)(vite|vitest|svelte|tailwind|postcss|eslint|prettier|playwright)\.config\.[cm]?[jt]s$/;
26
+ const SOURCE_EXTENSIONS = ['.ts', '.tsx', '.mts', '.cts'];
27
+ /** "No inputs were found in config file" — a reference covering only tool configs. */
28
+ const NO_INPUTS = 18003;
29
+
30
+ /** Vite's React + TS template, made strict-ish; what a project with no tsconfig gets. */
31
+ export function defaultCompilerOptions(ts: typeof TS, jsxImportSource?: string): TS.CompilerOptions {
32
+ return {
33
+ target: ts.ScriptTarget.ES2020,
34
+ lib: ['lib.es2020.d.ts', 'lib.dom.d.ts', 'lib.dom.iterable.d.ts'],
35
+ module: ts.ModuleKind.ESNext,
36
+ moduleResolution: ts.ModuleResolutionKind.Bundler,
37
+ jsx: ts.JsxEmit.ReactJSX,
38
+ ...(jsxImportSource ? { jsxImportSource } : {}),
39
+ strict: true,
40
+ noFallthroughCasesInSwitch: true,
41
+ isolatedModules: true,
42
+ resolveJsonModule: true,
43
+ allowImportingTsExtensions: true,
44
+ esModuleInterop: true,
45
+ skipLibCheck: true,
46
+ noEmit: true,
47
+ };
48
+ }
49
+
50
+ /** Options no in-browser check wants, whatever the config says: nothing is emitted. */
51
+ function forCheck(options: TS.CompilerOptions): TS.CompilerOptions {
52
+ return {
53
+ ...options,
54
+ noEmit: true,
55
+ skipLibCheck: true,
56
+ composite: false,
57
+ incremental: false,
58
+ declaration: false,
59
+ declarationMap: false,
60
+ emitDeclarationOnly: false,
61
+ tsBuildInfoFile: undefined,
62
+ };
63
+ }
64
+
65
+ function globToRegExp(pattern: string): RegExp {
66
+ let source = '';
67
+ for (let i = 0; i < pattern.length; i++) {
68
+ const ch = pattern[i]!;
69
+ if (ch === '*' && pattern[i + 1] === '*' && pattern[i + 2] === '/') {
70
+ source += '(?:[^/]+/)*';
71
+ i += 2;
72
+ } else if (ch === '*') source += '[^/]*';
73
+ else if (ch === '?') source += '[^/]';
74
+ else source += ch.replace(/[.+^${}()|[\]\\]/g, '\\$&');
75
+ }
76
+ return new RegExp(`^${source}$`);
77
+ }
78
+
79
+ /** A tsconfig `include`/`exclude` spec as a matcher; a bare directory means everything under it. */
80
+ function specMatcher(root: string, spec: string): RegExp {
81
+ let abs = join(root, spec);
82
+ const last = abs.slice(abs.lastIndexOf('/') + 1);
83
+ if (!/[*?]/.test(last) && !extname(last)) abs = `${abs === '/' ? '' : abs}/**/*`;
84
+ return globToRegExp(abs);
85
+ }
86
+
87
+ /** The ParseConfigHost the config parser reads through: the VFS plus fetched `extends` packages. */
88
+ export function createParseConfigHost(fs: VirtualFileSystem, store: TypeStore): TS.ParseConfigHost {
89
+ return {
90
+ useCaseSensitiveFileNames: true,
91
+ fileExists: (path) => fs.isFile(path) || store.read(path) !== undefined,
92
+ readFile: (path) => fs.readText(path) ?? store.read(path),
93
+ readDirectory(rootDir, extensions, excludes, includes) {
94
+ const include = (includes ?? ['**/*']).map((spec) => specMatcher(rootDir, spec));
95
+ const exclude = (excludes ?? []).map((spec) => specMatcher(rootDir, spec));
96
+ return fs.list().filter((path) =>
97
+ extensions.some((ext) => path.endsWith(ext)) &&
98
+ !path.includes('/node_modules/') &&
99
+ include.some((re) => re.test(path)) &&
100
+ !exclude.some((re) => re.test(path)),
101
+ );
102
+ },
103
+ };
104
+ }
105
+
106
+ function parseConfig(ts: typeof TS, host: TS.ParseConfigHost, configPath: string): TS.ParsedCommandLine | { errors: TS.Diagnostic[] } {
107
+ const text = host.readFile(configPath) ?? '';
108
+ const json = ts.parseConfigFileTextToJson(configPath, text);
109
+ if (json.error) return { errors: [json.error] };
110
+ return ts.parseJsonConfigFileContent(json.config, host, dirname(configPath), undefined, configPath);
111
+ }
112
+
113
+ function referencedConfigs(ts: typeof TS, host: TS.ParseConfigHost, configPath: string): string[] {
114
+ const json = ts.parseConfigFileTextToJson(configPath, host.readFile(configPath) ?? '').config as { references?: Array<{ path?: unknown }>; files?: unknown[]; include?: unknown[] } | undefined;
115
+ const references = json?.references ?? [];
116
+ // A "solution" config — references and nothing of its own — is checked through its references.
117
+ const ownsFiles = (json?.files?.length ?? 0) > 0 || json?.include !== undefined;
118
+ if (!references.length || ownsFiles) return [];
119
+ return references
120
+ .map((ref) => (typeof ref.path === 'string' ? join(dirname(configPath), ref.path) : undefined))
121
+ .filter((path): path is string => !!path)
122
+ .map((path) => (path.endsWith('.json') ? path : join(path, 'tsconfig.json')))
123
+ .filter((path) => host.fileExists(path));
124
+ }
125
+
126
+ export function resolveCheckProjects(ts: typeof TS, fs: VirtualFileSystem, store: TypeStore, jsxImportSource?: string): CheckProject[] {
127
+ const host = createParseConfigHost(fs, store);
128
+ const root = ['/tsconfig.json', '/jsconfig.json'].find((path) => fs.isFile(path));
129
+
130
+ if (!root) {
131
+ const rootNames = fs.list().filter((path) => SOURCE_EXTENSIONS.some((ext) => path.endsWith(ext)) && !path.includes('/node_modules/') && !TOOL_CONFIG.test(path));
132
+ return rootNames.length ? [{ options: defaultCompilerOptions(ts, jsxImportSource), rootNames, errors: [] }] : [];
133
+ }
134
+
135
+ const configs = referencedConfigs(ts, host, root);
136
+ const projects: CheckProject[] = [];
137
+ for (const configPath of configs.length ? configs : [root]) {
138
+ const parsed = parseConfig(ts, host, configPath);
139
+ const errors = parsed.errors.filter((d) => d.code !== NO_INPUTS);
140
+ if (!('options' in parsed)) {
141
+ projects.push({ configPath, options: {}, rootNames: [], errors });
142
+ continue;
143
+ }
144
+ const rootNames = parsed.fileNames.filter((path) => !TOOL_CONFIG.test(path));
145
+ if (!rootNames.length && !errors.length) continue;
146
+ projects.push({ configPath, options: forCheck(parsed.options), rootNames, errors });
147
+ }
148
+ return projects;
149
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Ambient declarations the checker adds, standing in for what a local install
3
+ * would provide:
4
+ * • Vite's `vite/client` (`import.meta.env`, CSS/asset/`?raw` imports) and CRA's
5
+ * `react-scripts` types. Shimmed rather than fetched: they are what every
6
+ * generated app references, and a small local copy never fails to load;
7
+ * • `.vue` / `.svelte` imports. Component internals are not type-checked yet;
8
+ * importing one must not be an error;
9
+ * • packages whose types could not be found, declared as `any` — a CDN miss is
10
+ * not the user's type error.
11
+ *
12
+ * A pattern the project (or a fetched package) already declares is skipped: two
13
+ * declarations of `*.vue` with a default export each would be an error of ours.
14
+ */
15
+
16
+ export const SHIM_DIR = '/__bfwc_shims__';
17
+ export const AMBIENT_SHIM_PATH = `${SHIM_DIR}/ambient.d.ts`;
18
+ /** What a shimmed type reference (`/// <reference types="vite/client" />`) resolves to. */
19
+ export const EMPTY_TYPES_PATH = `${SHIM_DIR}/empty.d.ts`;
20
+ export const SHIMMED_TYPE_REFERENCES: ReadonlySet<string> = new Set(['vite/client', 'react-scripts']);
21
+
22
+ const STRING_DEFAULT = '{ const src: string; export default src; }';
23
+ const ANY_DEFAULT = '{ const value: any; export default value; }';
24
+
25
+ const MODULE_SHIMS: ReadonlyArray<[pattern: string, body: string]> = [
26
+ ['*.module.css', '{ const classes: { readonly [key: string]: string }; export default classes; }'],
27
+ ['*.module.scss', '{ const classes: { readonly [key: string]: string }; export default classes; }'],
28
+ ['*.css', '{}'],
29
+ ['*.scss', '{}'],
30
+ ['*.sass', '{}'],
31
+ ['*.less', '{}'],
32
+ ...['svg', 'png', 'jpg', 'jpeg', 'gif', 'webp', 'avif', 'ico', 'bmp', 'woff', 'woff2', 'ttf', 'otf', 'eot', 'mp4', 'webm', 'mp3', 'wav', 'ogg', 'pdf', 'txt', 'md', 'wasm'].map(
33
+ (ext): [string, string] => [`*.${ext}`, STRING_DEFAULT],
34
+ ),
35
+ ['*?raw', STRING_DEFAULT],
36
+ ['*?url', STRING_DEFAULT],
37
+ ['*?inline', STRING_DEFAULT],
38
+ ['*.vue', ANY_DEFAULT],
39
+ ['*.svelte', ANY_DEFAULT],
40
+ ];
41
+
42
+ const IMPORT_META = `interface ImportMetaEnv {
43
+ readonly [key: string]: any;
44
+ readonly MODE: string;
45
+ readonly BASE_URL: string;
46
+ readonly PROD: boolean;
47
+ readonly DEV: boolean;
48
+ readonly SSR: boolean;
49
+ }
50
+ interface ImportMeta {
51
+ readonly env: ImportMetaEnv;
52
+ readonly hot?: any;
53
+ readonly glob: any;
54
+ }`;
55
+
56
+ function escapeRegExp(text: string): string {
57
+ return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
58
+ }
59
+
60
+ /** True when any of `texts` declares `declare module '<pattern>'`. */
61
+ export function declaresModule(texts: Iterable<string>, pattern: string): boolean {
62
+ const re = new RegExp(`declare\\s+module\\s+['"]${escapeRegExp(pattern)}['"]`);
63
+ for (const text of texts) if (re.test(text)) return true;
64
+ return false;
65
+ }
66
+
67
+ export interface AmbientShimOptions {
68
+ /** Declarations already loaded: the project's own `.d.ts` files and fetched package types. */
69
+ existing: string[];
70
+ /** Packages with no types found — declared as `any`. */
71
+ untyped: string[];
72
+ }
73
+
74
+ export function ambientShim(options: AmbientShimOptions): string {
75
+ const lines = [IMPORT_META];
76
+ // CRA reads `process.env.REACT_APP_*`; @types/node, when loaded, declares it properly.
77
+ if (!options.existing.some((text) => /declare\s+var\s+process\b/.test(text))) {
78
+ lines.push('declare var process: { env: { readonly [key: string]: string | undefined; readonly NODE_ENV: string } };');
79
+ }
80
+ for (const [pattern, body] of MODULE_SHIMS) {
81
+ if (!declaresModule(options.existing, pattern)) lines.push(`declare module ${JSON.stringify(pattern)} ${body}`);
82
+ }
83
+ for (const name of options.untyped) {
84
+ lines.push(`declare module ${JSON.stringify(name)};`);
85
+ lines.push(`declare module ${JSON.stringify(`${name}/*`)};`);
86
+ }
87
+ return lines.join('\n') + '\n';
88
+ }