toiljs 0.0.4 → 0.0.5

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 (359) hide show
  1. package/.idea/prettier.xml +1 -0
  2. package/as-pect.config.js +1 -1
  3. package/build/backend/.tsbuildinfo +1 -1
  4. package/build/backend/index.js +1 -2
  5. package/build/cli/.tsbuildinfo +1 -1
  6. package/build/cli/configure.d.ts +15 -0
  7. package/build/cli/configure.js +201 -0
  8. package/build/cli/create.d.ts +4 -0
  9. package/build/cli/create.js +168 -57
  10. package/build/cli/features.d.ts +23 -0
  11. package/build/cli/features.js +85 -0
  12. package/build/cli/index.js +42 -2
  13. package/build/cli/proc.d.ts +1 -0
  14. package/build/cli/proc.js +11 -0
  15. package/build/cli/ui.js +1 -2
  16. package/build/cli/validate.d.ts +4 -0
  17. package/build/cli/validate.js +19 -0
  18. package/build/client/.tsbuildinfo +1 -1
  19. package/build/client/Link.d.ts +8 -0
  20. package/build/client/Link.js +44 -0
  21. package/build/client/NavLink.d.ts +14 -0
  22. package/build/client/NavLink.js +37 -0
  23. package/build/client/Router.d.ts +7 -0
  24. package/build/client/Router.js +55 -0
  25. package/build/client/error-boundary.d.ts +16 -0
  26. package/build/client/error-boundary.js +19 -0
  27. package/build/client/head.d.ts +26 -0
  28. package/build/client/head.js +87 -0
  29. package/build/client/hooks.d.ts +17 -0
  30. package/build/client/hooks.js +48 -0
  31. package/build/client/index.d.ts +14 -2
  32. package/build/client/index.js +8 -1
  33. package/build/client/lazy.d.ts +16 -0
  34. package/build/client/lazy.js +53 -0
  35. package/build/client/match.js +7 -0
  36. package/build/client/mount.d.ts +2 -0
  37. package/build/client/mount.js +13 -0
  38. package/build/client/navigation.d.ts +13 -0
  39. package/build/client/navigation.js +97 -0
  40. package/build/client/params-context.d.ts +2 -0
  41. package/build/client/params-context.js +2 -0
  42. package/build/client/prefetch.d.ts +11 -0
  43. package/build/client/prefetch.js +100 -0
  44. package/build/client/scroll.d.ts +8 -0
  45. package/build/client/scroll.js +36 -0
  46. package/build/client/types.d.ts +27 -0
  47. package/build/client/types.js +1 -0
  48. package/build/compiler/.tsbuildinfo +1 -1
  49. package/build/compiler/config.d.ts +2 -0
  50. package/build/compiler/config.js +4 -1
  51. package/build/compiler/docs.d.ts +10 -0
  52. package/build/compiler/docs.js +59 -0
  53. package/build/compiler/generate.js +134 -16
  54. package/build/compiler/index.d.ts +4 -2
  55. package/build/compiler/index.js +4 -3
  56. package/build/compiler/plugin.js +2 -1
  57. package/build/compiler/routes.js +5 -1
  58. package/build/compiler/vite.d.ts +1 -1
  59. package/build/compiler/vite.js +17 -1
  60. package/build/io/.tsbuildinfo +1 -1
  61. package/build/io/BinaryWriter.js +2 -2
  62. package/eslint.config.js +1 -1
  63. package/examples/basic/.toil/docs/cli.md +3 -0
  64. package/examples/basic/.toil/docs/client.md +3 -0
  65. package/examples/basic/.toil/docs/index.md +3 -0
  66. package/examples/basic/.toil/docs/routing.md +3 -0
  67. package/examples/basic/.toil/docs/server.md +3 -0
  68. package/examples/basic/.toil/docs/styling.md +3 -0
  69. package/examples/basic/.toil/entry.tsx +3 -8
  70. package/examples/basic/.toil/globals.ts +6 -0
  71. package/examples/basic/.toil/index.html +16 -12
  72. package/examples/basic/.toil/public/images/.gitkeep +1 -0
  73. package/examples/basic/.toil/public/images/logo.svg +37 -0
  74. package/examples/basic/.toil/public/robots.txt +2 -0
  75. package/examples/basic/.toil/routes.ts +9 -7
  76. package/examples/basic/build/client/assets/404-Bq0jNTUo.js +1 -0
  77. package/examples/basic/build/client/assets/_...slug_-CXKf6qnB.js +1 -0
  78. package/examples/basic/build/client/assets/_id_-BadAyQnb.js +1 -0
  79. package/examples/basic/build/client/assets/about-BOhoEcEO.js +1 -0
  80. package/examples/basic/build/client/assets/get-started-BIXpcjkT.js +9 -0
  81. package/examples/basic/build/client/assets/index-BmqcTaBB.js +1 -0
  82. package/examples/basic/build/client/assets/io-DEVjjaJj.js +1 -0
  83. package/examples/basic/build/client/assets/layout-DJegirdz.js +1 -0
  84. package/examples/basic/build/client/assets/react-DEQrz1q7.js +9 -0
  85. package/examples/basic/build/client/assets/rolldown-runtime-KL5VtC6j.js +1 -0
  86. package/examples/basic/build/client/assets/routes-BYWn6TxK.js +1 -0
  87. package/examples/basic/build/client/css/style.css +2 -0
  88. package/examples/basic/build/client/images/.gitkeep +1 -0
  89. package/examples/basic/build/client/images/logo.svg +37 -0
  90. package/examples/basic/build/client/index.html +17 -0
  91. package/examples/basic/build/client/robots.txt +2 -0
  92. package/examples/basic/client/404.tsx +2 -5
  93. package/examples/basic/client/components/.gitkeep +1 -0
  94. package/examples/basic/client/components/Footer.tsx +8 -0
  95. package/examples/basic/client/layout.tsx +39 -26
  96. package/examples/basic/client/public/images/.gitkeep +1 -0
  97. package/examples/basic/client/public/images/logo.svg +37 -0
  98. package/examples/basic/client/public/index.html +15 -0
  99. package/examples/basic/client/public/robots.txt +2 -0
  100. package/examples/basic/client/routes/about.tsx +1 -3
  101. package/examples/basic/client/routes/blog/[id].tsx +2 -4
  102. package/examples/basic/client/routes/docs/[...slug].tsx +3 -6
  103. package/examples/basic/client/routes/get-started.tsx +84 -0
  104. package/examples/basic/client/routes/index.tsx +74 -7
  105. package/examples/basic/client/routes/io.tsx +3 -7
  106. package/examples/basic/client/styles/main.css +461 -0
  107. package/examples/basic/client/toil.tsx +7 -0
  108. package/examples/basic/node_modules/.bin/toilinit +16 -0
  109. package/examples/basic/node_modules/.bin/toilinit.cmd +17 -0
  110. package/examples/basic/node_modules/.bin/toilinit.ps1 +28 -0
  111. package/examples/basic/node_modules/.bin/toilscript +16 -0
  112. package/examples/basic/node_modules/.bin/toilscript.cmd +17 -0
  113. package/examples/basic/node_modules/.bin/toilscript.ps1 +28 -0
  114. package/examples/basic/node_modules/.bin/wasm-as +16 -0
  115. package/examples/basic/node_modules/.bin/wasm-as.cmd +17 -0
  116. package/examples/basic/node_modules/.bin/wasm-as.ps1 +28 -0
  117. package/examples/basic/node_modules/.bin/wasm-ctor-eval +16 -0
  118. package/examples/basic/node_modules/.bin/wasm-ctor-eval.cmd +17 -0
  119. package/examples/basic/node_modules/.bin/wasm-ctor-eval.ps1 +28 -0
  120. package/examples/basic/node_modules/.bin/wasm-dis +16 -0
  121. package/examples/basic/node_modules/.bin/wasm-dis.cmd +17 -0
  122. package/examples/basic/node_modules/.bin/wasm-dis.ps1 +28 -0
  123. package/examples/basic/node_modules/.bin/wasm-merge +16 -0
  124. package/examples/basic/node_modules/.bin/wasm-merge.cmd +17 -0
  125. package/examples/basic/node_modules/.bin/wasm-merge.ps1 +28 -0
  126. package/examples/basic/node_modules/.bin/wasm-metadce +16 -0
  127. package/examples/basic/node_modules/.bin/wasm-metadce.cmd +17 -0
  128. package/examples/basic/node_modules/.bin/wasm-metadce.ps1 +28 -0
  129. package/examples/basic/node_modules/.bin/wasm-opt +16 -0
  130. package/examples/basic/node_modules/.bin/wasm-opt.cmd +17 -0
  131. package/examples/basic/node_modules/.bin/wasm-opt.ps1 +28 -0
  132. package/examples/basic/node_modules/.bin/wasm-reduce +16 -0
  133. package/examples/basic/node_modules/.bin/wasm-reduce.cmd +17 -0
  134. package/examples/basic/node_modules/.bin/wasm-reduce.ps1 +28 -0
  135. package/examples/basic/node_modules/.bin/wasm-shell +16 -0
  136. package/examples/basic/node_modules/.bin/wasm-shell.cmd +17 -0
  137. package/examples/basic/node_modules/.bin/wasm-shell.ps1 +28 -0
  138. package/examples/basic/node_modules/.bin/wasm2js +16 -0
  139. package/examples/basic/node_modules/.bin/wasm2js.cmd +17 -0
  140. package/examples/basic/node_modules/.bin/wasm2js.ps1 +28 -0
  141. package/examples/basic/node_modules/.package-lock.json +49 -1
  142. package/examples/basic/node_modules/.vite/deps/_metadata.json +9 -9
  143. package/examples/basic/node_modules/binaryen/LICENSE +201 -0
  144. package/examples/basic/node_modules/binaryen/README.md +1362 -0
  145. package/examples/basic/node_modules/binaryen/bin/package.json +3 -0
  146. package/examples/basic/node_modules/binaryen/bin/wasm-as +0 -0
  147. package/examples/basic/node_modules/binaryen/bin/wasm-ctor-eval +0 -0
  148. package/examples/basic/node_modules/binaryen/bin/wasm-dis +0 -0
  149. package/examples/basic/node_modules/binaryen/bin/wasm-merge +0 -0
  150. package/examples/basic/node_modules/binaryen/bin/wasm-metadce +0 -0
  151. package/examples/basic/node_modules/binaryen/bin/wasm-opt +0 -0
  152. package/examples/basic/node_modules/binaryen/bin/wasm-reduce +0 -0
  153. package/examples/basic/node_modules/binaryen/bin/wasm-shell +0 -0
  154. package/examples/basic/node_modules/binaryen/bin/wasm2js +0 -0
  155. package/examples/basic/node_modules/binaryen/index.d.ts +2371 -0
  156. package/examples/basic/node_modules/binaryen/index.js +30552 -0
  157. package/examples/basic/node_modules/binaryen/package.json +50 -0
  158. package/examples/basic/node_modules/long/LICENSE +202 -0
  159. package/examples/basic/node_modules/long/README.md +286 -0
  160. package/examples/basic/node_modules/long/index.d.ts +2 -0
  161. package/examples/basic/node_modules/long/index.js +1581 -0
  162. package/examples/basic/node_modules/long/package.json +58 -0
  163. package/examples/basic/node_modules/long/types.d.ts +474 -0
  164. package/examples/basic/node_modules/long/umd/index.d.ts +3 -0
  165. package/examples/basic/node_modules/long/umd/index.js +1622 -0
  166. package/examples/basic/node_modules/long/umd/package.json +3 -0
  167. package/examples/basic/node_modules/long/umd/types.d.ts +474 -0
  168. package/examples/basic/node_modules/toilscript/LICENSE +201 -0
  169. package/examples/basic/node_modules/toilscript/NOTICE +94 -0
  170. package/examples/basic/node_modules/toilscript/README.md +66 -0
  171. package/examples/basic/node_modules/toilscript/bin/toilinit.js +468 -0
  172. package/examples/basic/node_modules/toilscript/bin/toilscript.js +35 -0
  173. package/examples/basic/node_modules/toilscript/dist/cli.d.ts +4 -0
  174. package/examples/basic/node_modules/toilscript/dist/cli.generated.d.ts +10027 -0
  175. package/examples/basic/node_modules/toilscript/dist/cli.js +24474 -0
  176. package/examples/basic/node_modules/toilscript/dist/cli.js.map +7 -0
  177. package/examples/basic/node_modules/toilscript/dist/importmap.json +9 -0
  178. package/examples/basic/node_modules/toilscript/dist/toilscript.d.ts +4 -0
  179. package/examples/basic/node_modules/toilscript/dist/toilscript.generated.d.ts +11242 -0
  180. package/examples/basic/node_modules/toilscript/dist/toilscript.js +337 -0
  181. package/examples/basic/node_modules/toilscript/dist/toilscript.js.map +7 -0
  182. package/examples/basic/node_modules/toilscript/dist/transform.cjs +1 -0
  183. package/examples/basic/node_modules/toilscript/dist/transform.d.ts +1 -0
  184. package/examples/basic/node_modules/toilscript/dist/transform.js +1 -0
  185. package/examples/basic/node_modules/toilscript/dist/web.js +22 -0
  186. package/examples/basic/node_modules/toilscript/lib/binaryen.d.ts +2 -0
  187. package/examples/basic/node_modules/toilscript/lib/binaryen.js +2 -0
  188. package/examples/basic/node_modules/toilscript/package.json +115 -0
  189. package/examples/basic/node_modules/toilscript/std/README.md +6 -0
  190. package/examples/basic/node_modules/toilscript/std/assembly/array.ts +550 -0
  191. package/examples/basic/node_modules/toilscript/std/assembly/arraybuffer.ts +77 -0
  192. package/examples/basic/node_modules/toilscript/std/assembly/atomics.ts +127 -0
  193. package/examples/basic/node_modules/toilscript/std/assembly/bindings/asyncify.ts +16 -0
  194. package/examples/basic/node_modules/toilscript/std/assembly/bindings/dom.ts +291 -0
  195. package/examples/basic/node_modules/toilscript/std/assembly/bindings/node.ts +6 -0
  196. package/examples/basic/node_modules/toilscript/std/assembly/bitflags.ts +53 -0
  197. package/examples/basic/node_modules/toilscript/std/assembly/builtins.ts +2650 -0
  198. package/examples/basic/node_modules/toilscript/std/assembly/byteslice.ts +177 -0
  199. package/examples/basic/node_modules/toilscript/std/assembly/compat.ts +2 -0
  200. package/examples/basic/node_modules/toilscript/std/assembly/console.ts +42 -0
  201. package/examples/basic/node_modules/toilscript/std/assembly/crypto.ts +9 -0
  202. package/examples/basic/node_modules/toilscript/std/assembly/dataview.ts +181 -0
  203. package/examples/basic/node_modules/toilscript/std/assembly/date.ts +375 -0
  204. package/examples/basic/node_modules/toilscript/std/assembly/diagnostics.ts +11 -0
  205. package/examples/basic/node_modules/toilscript/std/assembly/encoding.ts +151 -0
  206. package/examples/basic/node_modules/toilscript/std/assembly/endian.ts +45 -0
  207. package/examples/basic/node_modules/toilscript/std/assembly/error.ts +44 -0
  208. package/examples/basic/node_modules/toilscript/std/assembly/fixedarray.ts +173 -0
  209. package/examples/basic/node_modules/toilscript/std/assembly/fixedmap.ts +326 -0
  210. package/examples/basic/node_modules/toilscript/std/assembly/fixedset.ts +275 -0
  211. package/examples/basic/node_modules/toilscript/std/assembly/function.ts +42 -0
  212. package/examples/basic/node_modules/toilscript/std/assembly/index.d.ts +2892 -0
  213. package/examples/basic/node_modules/toilscript/std/assembly/iterator.ts +35 -0
  214. package/examples/basic/node_modules/toilscript/std/assembly/map.ts +269 -0
  215. package/examples/basic/node_modules/toilscript/std/assembly/math.ts +3289 -0
  216. package/examples/basic/node_modules/toilscript/std/assembly/memory.ts +123 -0
  217. package/examples/basic/node_modules/toilscript/std/assembly/number.ts +388 -0
  218. package/examples/basic/node_modules/toilscript/std/assembly/object.ts +36 -0
  219. package/examples/basic/node_modules/toilscript/std/assembly/performance.ts +9 -0
  220. package/examples/basic/node_modules/toilscript/std/assembly/pointer.ts +80 -0
  221. package/examples/basic/node_modules/toilscript/std/assembly/polyfills.ts +27 -0
  222. package/examples/basic/node_modules/toilscript/std/assembly/process.ts +50 -0
  223. package/examples/basic/node_modules/toilscript/std/assembly/reference.ts +48 -0
  224. package/examples/basic/node_modules/toilscript/std/assembly/regexp.ts +12 -0
  225. package/examples/basic/node_modules/toilscript/std/assembly/rt/README.md +83 -0
  226. package/examples/basic/node_modules/toilscript/std/assembly/rt/common.ts +81 -0
  227. package/examples/basic/node_modules/toilscript/std/assembly/rt/index-incremental.ts +2 -0
  228. package/examples/basic/node_modules/toilscript/std/assembly/rt/index-memory.ts +1 -0
  229. package/examples/basic/node_modules/toilscript/std/assembly/rt/index-minimal.ts +2 -0
  230. package/examples/basic/node_modules/toilscript/std/assembly/rt/index-stub.ts +1 -0
  231. package/examples/basic/node_modules/toilscript/std/assembly/rt/index.d.ts +37 -0
  232. package/examples/basic/node_modules/toilscript/std/assembly/rt/itcms.ts +419 -0
  233. package/examples/basic/node_modules/toilscript/std/assembly/rt/memory-runtime.ts +94 -0
  234. package/examples/basic/node_modules/toilscript/std/assembly/rt/rtrace.ts +15 -0
  235. package/examples/basic/node_modules/toilscript/std/assembly/rt/stub.ts +133 -0
  236. package/examples/basic/node_modules/toilscript/std/assembly/rt/tcms.ts +254 -0
  237. package/examples/basic/node_modules/toilscript/std/assembly/rt/tlsf.ts +592 -0
  238. package/examples/basic/node_modules/toilscript/std/assembly/rt.ts +90 -0
  239. package/examples/basic/node_modules/toilscript/std/assembly/set.ts +225 -0
  240. package/examples/basic/node_modules/toilscript/std/assembly/shared/feature.ts +68 -0
  241. package/examples/basic/node_modules/toilscript/std/assembly/shared/runtime.ts +13 -0
  242. package/examples/basic/node_modules/toilscript/std/assembly/shared/target.ts +11 -0
  243. package/examples/basic/node_modules/toilscript/std/assembly/shared/tsconfig.json +11 -0
  244. package/examples/basic/node_modules/toilscript/std/assembly/shared/typeinfo.ts +72 -0
  245. package/examples/basic/node_modules/toilscript/std/assembly/staticarray.ts +423 -0
  246. package/examples/basic/node_modules/toilscript/std/assembly/string.ts +850 -0
  247. package/examples/basic/node_modules/toilscript/std/assembly/symbol.ts +114 -0
  248. package/examples/basic/node_modules/toilscript/std/assembly/table.ts +16 -0
  249. package/examples/basic/node_modules/toilscript/std/assembly/toilscript.ts +16 -0
  250. package/examples/basic/node_modules/toilscript/std/assembly/tsconfig.json +6 -0
  251. package/examples/basic/node_modules/toilscript/std/assembly/typedarray.ts +1954 -0
  252. package/examples/basic/node_modules/toilscript/std/assembly/uri.ts +17 -0
  253. package/examples/basic/node_modules/toilscript/std/assembly/util/bytes.ts +107 -0
  254. package/examples/basic/node_modules/toilscript/std/assembly/util/casemap.ts +497 -0
  255. package/examples/basic/node_modules/toilscript/std/assembly/util/error.ts +58 -0
  256. package/examples/basic/node_modules/toilscript/std/assembly/util/hash.ts +117 -0
  257. package/examples/basic/node_modules/toilscript/std/assembly/util/math.ts +1922 -0
  258. package/examples/basic/node_modules/toilscript/std/assembly/util/memory.ts +290 -0
  259. package/examples/basic/node_modules/toilscript/std/assembly/util/number.ts +873 -0
  260. package/examples/basic/node_modules/toilscript/std/assembly/util/sort.ts +313 -0
  261. package/examples/basic/node_modules/toilscript/std/assembly/util/string.ts +1202 -0
  262. package/examples/basic/node_modules/toilscript/std/assembly/util/uri.ts +275 -0
  263. package/examples/basic/node_modules/toilscript/std/assembly/vector.ts +4 -0
  264. package/examples/basic/node_modules/toilscript/std/assembly.json +16 -0
  265. package/examples/basic/node_modules/toilscript/std/portable/index.d.ts +461 -0
  266. package/examples/basic/node_modules/toilscript/std/portable/index.js +416 -0
  267. package/examples/basic/node_modules/toilscript/std/portable.json +11 -0
  268. package/examples/basic/node_modules/toilscript/std/types/assembly/index.d.ts +1 -0
  269. package/examples/basic/node_modules/toilscript/std/types/assembly/package.json +3 -0
  270. package/examples/basic/node_modules/toilscript/std/types/portable/index.d.ts +1 -0
  271. package/examples/basic/node_modules/toilscript/std/types/portable/package.json +3 -0
  272. package/examples/basic/node_modules/toilscript/tsconfig-base.json +13 -0
  273. package/examples/basic/node_modules/toilscript/util/README.md +23 -0
  274. package/examples/basic/node_modules/toilscript/util/browser/fs.js +1 -0
  275. package/examples/basic/node_modules/toilscript/util/browser/module.js +5 -0
  276. package/examples/basic/node_modules/toilscript/util/browser/path.js +520 -0
  277. package/examples/basic/node_modules/toilscript/util/browser/process.js +59 -0
  278. package/examples/basic/node_modules/toilscript/util/browser/url.js +23 -0
  279. package/examples/basic/node_modules/toilscript/util/cpu.d.ts +9 -0
  280. package/examples/basic/node_modules/toilscript/util/cpu.js +42 -0
  281. package/examples/basic/node_modules/toilscript/util/find.d.ts +6 -0
  282. package/examples/basic/node_modules/toilscript/util/find.js +20 -0
  283. package/examples/basic/node_modules/toilscript/util/node.d.ts +21 -0
  284. package/examples/basic/node_modules/toilscript/util/node.js +34 -0
  285. package/examples/basic/node_modules/toilscript/util/options.d.ts +70 -0
  286. package/examples/basic/node_modules/toilscript/util/options.js +262 -0
  287. package/examples/basic/node_modules/toilscript/util/terminal.d.ts +52 -0
  288. package/examples/basic/node_modules/toilscript/util/terminal.js +35 -0
  289. package/examples/basic/node_modules/toilscript/util/text.d.ts +26 -0
  290. package/examples/basic/node_modules/toilscript/util/text.js +114 -0
  291. package/examples/basic/node_modules/toilscript/util/tsconfig.json +9 -0
  292. package/examples/basic/node_modules/toilscript/util/web.d.ts +11 -0
  293. package/examples/basic/node_modules/toilscript/util/web.js +33 -0
  294. package/examples/basic/package-lock.json +50 -1
  295. package/examples/basic/package.json +5 -2
  296. package/examples/basic/server/index.ts +3 -0
  297. package/examples/basic/server/main.ts +6 -0
  298. package/examples/basic/server/tsconfig.json +7 -0
  299. package/examples/basic/toil-env.d.ts +20 -1
  300. package/examples/basic/toil.config.ts +2 -5
  301. package/examples/basic/toilconfig.json +30 -0
  302. package/package.json +1 -1
  303. package/presets/eslint.js +2 -7
  304. package/presets/no-uint8array-tostring.js +4 -5
  305. package/presets/prettier.json +8 -1
  306. package/src/backend/index.ts +11 -18
  307. package/src/cli/configure.ts +272 -0
  308. package/src/cli/create.ts +227 -69
  309. package/src/cli/features.ts +128 -0
  310. package/src/cli/index.ts +44 -3
  311. package/src/cli/proc.ts +20 -0
  312. package/src/cli/ui.ts +4 -6
  313. package/src/cli/validate.ts +31 -0
  314. package/src/client/Link.tsx +99 -0
  315. package/src/client/NavLink.tsx +86 -0
  316. package/src/client/Router.tsx +95 -0
  317. package/src/client/error-boundary.tsx +43 -0
  318. package/src/client/head.ts +140 -0
  319. package/src/client/hooks.ts +115 -0
  320. package/src/client/index.ts +35 -5
  321. package/src/client/lazy.ts +93 -0
  322. package/src/client/match.ts +11 -3
  323. package/src/client/mount.tsx +28 -0
  324. package/src/client/navigation.ts +142 -0
  325. package/src/client/params-context.ts +10 -0
  326. package/src/client/prefetch.ts +130 -0
  327. package/src/client/scroll.ts +53 -0
  328. package/src/client/types.ts +36 -0
  329. package/src/compiler/config.ts +15 -8
  330. package/src/compiler/docs.ts +87 -0
  331. package/src/compiler/generate.ts +164 -23
  332. package/src/compiler/index.ts +6 -4
  333. package/src/compiler/plugin.ts +3 -1
  334. package/src/compiler/routes.ts +13 -7
  335. package/src/compiler/vite.ts +28 -5
  336. package/src/io/BinaryReader.ts +1 -5
  337. package/src/io/BinaryWriter.ts +3 -3
  338. package/src/server/index.ts +3 -4
  339. package/src/server/tsconfig.json +4 -0
  340. package/test/configure.test.ts +90 -0
  341. package/test/features.test.ts +111 -0
  342. package/test/head.test.ts +35 -0
  343. package/test/io.test.ts +8 -0
  344. package/test/navlink.test.ts +28 -0
  345. package/test/routes.test.ts +15 -0
  346. package/test/validate.test.ts +42 -0
  347. package/vitest.config.ts +1 -1
  348. package/examples/basic/dist/assets/404-D1bS2aH_.js +0 -1
  349. package/examples/basic/dist/assets/_...slug_-wR3shlWn.js +0 -1
  350. package/examples/basic/dist/assets/_id_-EWYvHfi2.js +0 -1
  351. package/examples/basic/dist/assets/about-Ddvj1tjF.js +0 -1
  352. package/examples/basic/dist/assets/index-CdG0me90.js +0 -1
  353. package/examples/basic/dist/assets/io-CODNJU57.js +0 -1
  354. package/examples/basic/dist/assets/layout-C15ZTPYI.js +0 -1
  355. package/examples/basic/dist/assets/react-JbAfoxYe.js +0 -9
  356. package/examples/basic/dist/assets/rolldown-runtime-1VNLd2iN.js +0 -1
  357. package/examples/basic/dist/assets/routes-GoydenoY.js +0 -1
  358. package/examples/basic/dist/index.html +0 -12
  359. package/src/client/runtime.tsx +0 -190
package/src/cli/create.ts CHANGED
@@ -3,18 +3,61 @@
3
3
  * app to the enforced toiljs presets (tsconfig / eslint / prettier) and file-based routing.
4
4
  * Supports a non-interactive path via flags (`--yes`, `--template`, …) for scripting/CI.
5
5
  */
6
- import { spawn } from 'node:child_process';
7
6
  import fs from 'node:fs/promises';
8
7
  import path from 'node:path';
9
8
 
10
- import { intro, outro, text, select, confirm, isCancel, cancel, spinner, note } from '@clack/prompts';
11
- import { TOIL_ENV_DTS } from 'toiljs/compiler';
9
+ import {
10
+ intro,
11
+ outro,
12
+ text,
13
+ select,
14
+ multiselect,
15
+ confirm,
16
+ isCancel,
17
+ cancel,
18
+ spinner,
19
+ note,
20
+ } from '@clack/prompts';
21
+ import { AI_HELPERS, AI_HELPER_IDS, aiHelperFiles, TOIL_DOCS, TOIL_ENV_DTS } from 'toiljs/compiler';
12
22
  import pc from 'picocolors';
13
23
 
24
+ import {
25
+ PKG_VERSION,
26
+ PREPROCESSORS,
27
+ requiredPackages,
28
+ styleEntry,
29
+ styleImportLines,
30
+ TAILWIND_CSS,
31
+ TAILWIND_ENTRY,
32
+ type Preprocessor,
33
+ type StyleFeatures,
34
+ } from './features.js';
35
+ import { run } from './proc.js';
14
36
  import { accent, dim, version } from './ui.js';
37
+ import { isPackageManager, isValidName, resolveProjectDir } from './validate.js';
15
38
 
16
39
  export type Template = 'app' | 'minimal';
17
40
 
41
+ /** Human label for each preprocessor in the styling picker. */
42
+ const PREPROCESSOR_LABEL: Record<Preprocessor, string> = {
43
+ css: 'Plain CSS',
44
+ sass: 'Sass (SCSS)',
45
+ less: 'Less',
46
+ stylus: 'Stylus',
47
+ };
48
+
49
+ /** Default global stylesheet contents (palette base styles), shared by every preprocessor. */
50
+ const DEFAULT_STYLE_CONTENT =
51
+ ':root {\n color-scheme: dark;\n}\n\n' +
52
+ 'body {\n margin: 0;\n background: #080d11;\n color: #f5f6fa;\n' +
53
+ ' font-family: system-ui, -apple-system, sans-serif;\n line-height: 1.6;\n}\n\n' +
54
+ 'a {\n color: #2563ff;\n text-decoration: none;\n}\n\n' +
55
+ 'a:hover {\n color: #22e3ab;\n}\n\n' +
56
+ 'code {\n background: #11161f;\n color: #22e3ab;\n padding: 0.1rem 0.4rem;\n' +
57
+ ' border-radius: 4px;\n font-size: 0.9em;\n}\n\n' +
58
+ 'h1 {\n background: linear-gradient(90deg, #2563ff, #7c3aed, #22e3ab);\n' +
59
+ ' -webkit-background-clip: text;\n background-clip: text;\n color: transparent;\n}\n';
60
+
18
61
  /** A selectable template in the `create` wizard. */
19
62
  interface TemplateOption {
20
63
  readonly value: Template;
@@ -25,6 +68,10 @@ interface TemplateOption {
25
68
  export interface CreateOptions {
26
69
  readonly name?: string;
27
70
  readonly template?: Template;
71
+ readonly preprocessor?: Preprocessor;
72
+ readonly tailwind?: boolean;
73
+ /** AI assistant files to scaffold: `true` = all, `false` = none, omitted = ask. */
74
+ readonly ai?: boolean;
28
75
  readonly install?: boolean;
29
76
  readonly git?: boolean;
30
77
  readonly pm?: string;
@@ -40,79 +87,165 @@ function bail<T>(value: T | symbol): asserts value is T {
40
87
  }
41
88
  }
42
89
 
43
- function isValidName(name: string): true | string {
44
- if (!name.trim()) return 'Please enter a project name.';
45
- if (!/^[a-z0-9._@/-]+$/i.test(name)) return 'Use letters, numbers, dashes, dots or slashes.';
46
- return true;
47
- }
48
-
49
90
  async function isEmptyDir(dir: string): Promise<boolean> {
50
91
  try {
51
92
  const entries = await fs.readdir(dir);
52
93
  return entries.length === 0;
53
94
  } catch {
54
- return true; // doesn't exist yet
95
+ return true;
55
96
  }
56
97
  }
57
98
 
58
99
  /** Builds the full file map (relative path → contents) for a scaffolded project. */
59
- function scaffold(name: string, template: Template): Record<string, string> {
100
+ function scaffold(
101
+ name: string,
102
+ template: Template,
103
+ features: StyleFeatures,
104
+ aiTools: readonly string[],
105
+ ): Record<string, string> {
60
106
  const toilVersion = version();
107
+ const devDependencies: Record<string, string> = {
108
+ '@types/react': '^19.2.15',
109
+ '@types/react-dom': '^19.2.3',
110
+ eslint: '^10.2.0',
111
+ prettier: '^3.8.1',
112
+ toilscript: '^0.1.2',
113
+ typescript: '^6.0.3',
114
+ };
115
+ for (const dep of requiredPackages(features).sort()) {
116
+ devDependencies[dep] = PKG_VERSION[dep] ?? 'latest';
117
+ }
61
118
  const pkg = {
62
119
  name: path.basename(name),
63
120
  private: true,
64
121
  type: 'module',
65
122
  scripts: {
66
123
  dev: 'toiljs dev',
67
- build: 'toiljs build',
124
+ build: 'toiljs build && toilscript --target release',
125
+ 'build:client': 'toiljs build',
126
+ 'build:server': 'toilscript --target release',
68
127
  lint: 'eslint client',
69
128
  typecheck: 'tsc --noEmit',
70
- format: 'prettier --write "client/**/*.{ts,tsx}"',
129
+ format: 'prettier --write "client/**/*.{ts,tsx,css,scss,less}" "client/public/**/*.html"',
71
130
  },
72
131
  dependencies: {
73
132
  toiljs: `^${toilVersion}`,
74
133
  react: '^19.2.6',
75
134
  'react-dom': '^19.2.6',
76
135
  },
77
- devDependencies: {
78
- '@types/react': '^19.2.15',
79
- '@types/react-dom': '^19.2.3',
80
- eslint: '^10.2.0',
81
- prettier: '^3.8.1',
82
- typescript: '^6.0.3',
83
- },
136
+ devDependencies,
84
137
  };
85
138
 
86
139
  const files: Record<string, string> = {
87
140
  'package.json': JSON.stringify(pkg, null, 4) + '\n',
88
141
  'toil.config.ts':
89
142
  "import { defineConfig } from 'toiljs/compiler';\n\n" +
90
- 'export default defineConfig({\n client: {\n outDir: \'dist\',\n },\n});\n',
143
+ 'export default defineConfig({});\n',
91
144
  'tsconfig.json':
92
145
  '{\n "extends": "toiljs/tsconfig",\n "include": ["client", "toil-env.d.ts"]\n}\n',
93
146
  'eslint.config.js': "import toiljs from 'toiljs/eslint';\n\nexport default toiljs;\n",
94
147
  '.prettierrc': '"toiljs/prettier"\n',
95
- '.gitignore': 'node_modules\ndist\n.toil\ntoil-env.d.ts\n',
96
- // Written upfront so the project type-checks before its first build; regenerated by build/dev.
148
+ '.gitignore': 'node_modules\nbuild\n.toil\ntoil-env.d.ts\n',
149
+ 'client/public/index.html':
150
+ '<!doctype html>\n<html lang="en">\n <head>\n' +
151
+ ' <meta charset="utf-8" />\n' +
152
+ ' <meta name="viewport" content="width=device-width, initial-scale=1" />\n' +
153
+ ' <meta name="theme-color" content="#080D11" />\n' +
154
+ ' <meta name="description" content="" />\n' +
155
+ ' <link rel="icon" type="image/svg+xml" href="/favicon.svg" />\n' +
156
+ ' <link rel="manifest" href="/manifest.webmanifest" />\n' +
157
+ ` <title>${path.basename(name)}</title>\n` +
158
+ ' </head>\n <body>\n <div id="root"></div>\n </body>\n</html>\n',
159
+ 'client/public/favicon.svg':
160
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">\n' +
161
+ ' <defs>\n' +
162
+ ' <linearGradient id="g" x1="0" y1="0" x2="1" y2="1">\n' +
163
+ ' <stop offset="0" stop-color="#2563FF" />\n' +
164
+ ' <stop offset="0.5" stop-color="#7C3AED" />\n' +
165
+ ' <stop offset="1" stop-color="#22E3AB" />\n' +
166
+ ' </linearGradient>\n' +
167
+ ' </defs>\n' +
168
+ ' <rect width="32" height="32" rx="7" fill="#080D11" />\n' +
169
+ ' <path d="M9 10h14v3.2h-5.4V24h-3.2V13.2H9z" fill="url(#g)" />\n' +
170
+ '</svg>\n',
171
+ 'client/public/robots.txt': 'User-agent: *\nAllow: /\n',
172
+ 'client/public/manifest.webmanifest':
173
+ JSON.stringify(
174
+ {
175
+ name: path.basename(name),
176
+ short_name: path.basename(name),
177
+ start_url: '/',
178
+ display: 'standalone',
179
+ background_color: '#080D11',
180
+ theme_color: '#080D11',
181
+ icons: [{ src: '/favicon.svg', type: 'image/svg+xml', sizes: 'any' }],
182
+ },
183
+ null,
184
+ 4,
185
+ ) + '\n',
186
+ 'client/public/images/.gitkeep': '# Place images and other static assets here; served at /images/*.\n',
187
+ 'client/toil.tsx':
188
+ "import { routes, layout, notFound } from 'toiljs/routes';\n\n" +
189
+ styleImportLines(features).join('\n') +
190
+ '\n\n' +
191
+ 'Toil.mount(routes, layout, notFound);\n',
192
+ [`client/${styleEntry(features.preprocessor)}`]: DEFAULT_STYLE_CONTENT,
193
+ 'client/components/.gitkeep': '# Place shared React components here.\n',
97
194
  'toil-env.d.ts': TOIL_ENV_DTS,
195
+ 'toilconfig.json':
196
+ JSON.stringify(
197
+ {
198
+ entries: ['server/main.ts'],
199
+ targets: {
200
+ release: {
201
+ outFile: 'build/server/release.wasm',
202
+ textFile: 'build/server/release.wat',
203
+ },
204
+ },
205
+ options: {
206
+ sourceMap: false,
207
+ optimizeLevel: 3,
208
+ shrinkLevel: 1,
209
+ converge: true,
210
+ noAssert: false,
211
+ enable: [
212
+ 'sign-extension',
213
+ 'mutable-globals',
214
+ 'nontrapping-f2i',
215
+ 'bulk-memory',
216
+ 'simd',
217
+ 'reference-types',
218
+ 'multi-value',
219
+ ],
220
+ runtime: 'stub',
221
+ memoryBase: 0,
222
+ initialMemory: 1,
223
+ debug: false,
224
+ trapMode: 'allow',
225
+ },
226
+ },
227
+ null,
228
+ 4,
229
+ ) + '\n',
230
+ 'server/tsconfig.json':
231
+ JSON.stringify(
232
+ {
233
+ extends: 'toilscript/std/assembly.json',
234
+ include: ['./**/*.ts'],
235
+ },
236
+ null,
237
+ 4,
238
+ ) + '\n',
239
+ 'server/index.ts': 'export function add(a: i32, b: i32): i32 {\n return a + b;\n}\n',
240
+ 'server/main.ts':
241
+ "import { add } from './index';\n\n" +
242
+ '@main\nfunction run(): i32 {\n return add(40, 2);\n}\n',
98
243
  'README.md': ['# ' + path.basename(name), '', 'A [toiljs](https://toil.org) app.', '', '## Develop', '', ' npm install', ' npm run dev', '', '## Build', '', ' npm run build', ''].join('\n'),
99
244
  'client/layout.tsx': `import { type ReactNode } from 'react';
100
245
 
101
- import { Link } from 'toiljs/client';
102
-
103
- const styles = \`
104
- :root { color-scheme: dark; }
105
- body { margin: 0; background: #080D11; color: #F5F6FA; font-family: system-ui, -apple-system, sans-serif; line-height: 1.6; }
106
- a { color: #2563FF; text-decoration: none; }
107
- a:hover { color: #22E3AB; }
108
- code { background: #11161f; color: #22E3AB; padding: 0.1rem 0.4rem; border-radius: 4px; font-size: 0.9em; }
109
- h1 { background: linear-gradient(90deg, #2563FF, #7C3AED, #22E3AB); -webkit-background-clip: text; background-clip: text; color: transparent; }
110
- \`;
111
-
112
246
  export default function Layout({ children }: { children?: ReactNode }) {
113
247
  return (
114
248
  <div style={{ maxWidth: 680, margin: '0 auto', padding: '3rem 1.5rem' }}>
115
- <style>{styles}</style>
116
249
  <header
117
250
  style={{
118
251
  display: 'flex',
@@ -124,7 +257,7 @@ export default function Layout({ children }: { children?: ReactNode }) {
124
257
  }}>
125
258
  <strong style={{ color: '#2563FF', fontSize: '1.1rem' }}>${path.basename(name)}</strong>
126
259
  <nav style={{ display: 'flex', gap: '1rem' }}>
127
- <Link href="/">home</Link>${template === 'app' ? '\n <Link href="/about">about</Link>' : ''}
260
+ <Toil.Link href="/">home</Toil.Link>${template === 'app' ? '\n <Toil.Link href="/about">about</Toil.Link>' : ''}
128
261
  </nav>
129
262
  </header>
130
263
  {children}
@@ -133,31 +266,39 @@ export default function Layout({ children }: { children?: ReactNode }) {
133
266
  }
134
267
  `,
135
268
  'client/routes/index.tsx':
136
- "import { Link } from 'toiljs/client';\n\n" +
137
269
  'export default function Home() {\n' +
138
270
  ' return (\n <main>\n' +
139
271
  ' <h1>Welcome to toiljs</h1>\n' +
140
272
  ' <p>File-based routing, bundled by Vite, zero config.</p>\n' +
141
273
  (template === 'app'
142
- ? ' <p>\n <Link href="/about">About</Link> · <Link href="/blog/42">Blog post 42</Link>\n </p>\n'
274
+ ? ' <p>\n <Toil.Link href="/about">About</Toil.Link> · <Toil.Link href="/blog/42">Blog post 42</Toil.Link>\n </p>\n'
143
275
  : '') +
144
276
  ' </main>\n );\n}\n',
145
277
  };
146
278
 
147
279
  if (template === 'app') {
148
280
  files['client/routes/about.tsx'] =
149
- "import { Link } from 'toiljs/client';\n\n" +
150
281
  'export default function About() {\n' +
151
282
  ' return (\n <main>\n <h1>About</h1>\n' +
152
283
  ' <p>\n This page is served by <code>client/routes/about.tsx</code>.\n </p>\n' +
153
- ' <Link href="/">Back home</Link>\n </main>\n );\n}\n';
284
+ ' <Toil.Link href="/">Back home</Toil.Link>\n </main>\n );\n}\n';
154
285
  files['client/routes/blog/[id].tsx'] =
155
- "import { Link, useParams } from 'toiljs/client';\n\n" +
156
286
  'export default function BlogPost() {\n' +
157
- ' const { id } = useParams();\n' +
287
+ ' const { id } = Toil.useParams();\n' +
158
288
  ' return (\n <main>\n <h1>Blog post {id}</h1>\n' +
159
289
  ' <p>\n Dynamic route from <code>client/routes/blog/[id].tsx</code>.\n </p>\n' +
160
- ' <Link href="/">Back home</Link>\n </main>\n );\n}\n';
290
+ ' <Toil.Link href="/">Back home</Toil.Link>\n </main>\n );\n}\n';
291
+ }
292
+
293
+ if (features.tailwind) {
294
+ files[`client/${TAILWIND_ENTRY}`] = TAILWIND_CSS;
295
+ }
296
+
297
+ // Selected AI-assistant pointer files at the root (committed). The real docs are always seeded
298
+ // under .toil/docs (gitignored; regenerated by dev/build) since the framework manages them.
299
+ Object.assign(files, aiHelperFiles(aiTools));
300
+ for (const [name, content] of Object.entries(TOIL_DOCS)) {
301
+ files[`.toil/docs/${name}`] = content;
161
302
  }
162
303
 
163
304
  return files;
@@ -171,27 +312,10 @@ async function writeFiles(dir: string, files: Record<string, string>): Promise<v
171
312
  }
172
313
  }
173
314
 
174
- function run(cmd: string, args: string[], cwd: string): Promise<void> {
175
- return new Promise((resolve, reject) => {
176
- // On Windows `npm`/`pnpm`/`yarn` are `.cmd` shims that need a shell to launch. Passing an
177
- // args array together with `shell: true` is deprecated (DEP0190), so pass the whole command
178
- // as one string there (the args are fixed, not user input). POSIX runs it directly.
179
- const onWindows = process.platform === 'win32';
180
- const child = onWindows
181
- ? spawn([cmd, ...args].join(' '), { cwd, stdio: 'ignore', shell: true })
182
- : spawn(cmd, args, { cwd, stdio: 'ignore' });
183
- child.on('error', reject);
184
- child.on('close', (code) =>
185
- code === 0 ? resolve() : reject(new Error(`${cmd} exited with code ${String(code)}`)),
186
- );
187
- });
188
- }
189
-
190
315
  /** Runs the create flow (interactive unless `--yes`). */
191
316
  export async function runCreate(opts: CreateOptions): Promise<void> {
192
317
  intro(accent(' toiljs create '));
193
318
 
194
- // 1. Project name
195
319
  let name = opts.name;
196
320
  if (!name) {
197
321
  if (opts.yes) {
@@ -216,10 +340,13 @@ export async function runCreate(opts: CreateOptions): Promise<void> {
216
340
  process.exit(1);
217
341
  }
218
342
 
219
- const targetDir = path.resolve(opts.cwd, name);
343
+ const targetDir = resolveProjectDir(opts.cwd, name);
344
+ if (targetDir === null) {
345
+ cancel('Project name must stay inside the current directory (no "..", no absolute paths).');
346
+ process.exit(1);
347
+ }
220
348
  const rel = path.relative(opts.cwd, targetDir) || '.';
221
349
 
222
- // 2. Guard against clobbering a non-empty dir
223
350
  if (!(await isEmptyDir(targetDir))) {
224
351
  if (opts.yes) {
225
352
  cancel(`Directory ${pc.cyan(rel)} is not empty.`);
@@ -236,7 +363,6 @@ export async function runCreate(opts: CreateOptions): Promise<void> {
236
363
  }
237
364
  }
238
365
 
239
- // 3. Template
240
366
  let template: Template = opts.template ?? 'app';
241
367
  if (!opts.template && !opts.yes) {
242
368
  const templateOptions: TemplateOption[] = [
@@ -248,10 +374,46 @@ export async function runCreate(opts: CreateOptions): Promise<void> {
248
374
  template = choice === 'minimal' ? 'minimal' : 'app';
249
375
  }
250
376
 
251
- // 4. Options: git + install
377
+ let preprocessor: Preprocessor = opts.preprocessor ?? 'css';
378
+ let tailwind = opts.tailwind ?? false;
379
+ if (!opts.yes) {
380
+ if (opts.preprocessor === undefined) {
381
+ const choice = await select<Preprocessor>({
382
+ message: 'Styling',
383
+ options: PREPROCESSORS.map((value) => ({ value, label: PREPROCESSOR_LABEL[value] })),
384
+ initialValue: 'css',
385
+ });
386
+ bail(choice);
387
+ preprocessor = choice;
388
+ }
389
+ if (opts.tailwind === undefined) {
390
+ const tw = await confirm({ message: 'Add Tailwind CSS?', initialValue: false });
391
+ bail(tw);
392
+ tailwind = tw;
393
+ }
394
+ }
395
+ const features: StyleFeatures = { preprocessor, tailwind };
396
+
397
+ // AI assistant files: --ai = all, --no-ai = none, otherwise ask (default: all selected).
398
+ let aiTools: string[] = opts.ai === false ? [] : [...AI_HELPER_IDS];
399
+ if (opts.ai === undefined && !opts.yes) {
400
+ const picked = await multiselect<string>({
401
+ message: 'AI assistant files (read by Claude, Cursor, Codex, Copilot)',
402
+ options: AI_HELPERS.map((h) => ({ value: h.id, label: h.label })),
403
+ initialValues: [...AI_HELPER_IDS],
404
+ required: false,
405
+ });
406
+ bail(picked);
407
+ aiTools = picked;
408
+ }
409
+
252
410
  let initGit = opts.git ?? false;
253
411
  let install = opts.install ?? false;
254
412
  const pm = opts.pm ?? 'npm';
413
+ if (!isPackageManager(pm)) {
414
+ cancel(`Unsupported package manager: ${pm} (use npm, pnpm, yarn, or bun).`);
415
+ process.exit(1);
416
+ }
255
417
  if (!opts.yes) {
256
418
  if (opts.git === undefined) {
257
419
  const g = await confirm({ message: 'Initialize a git repository?', initialValue: true });
@@ -265,13 +427,11 @@ export async function runCreate(opts: CreateOptions): Promise<void> {
265
427
  }
266
428
  }
267
429
 
268
- // 5. Scaffold
269
430
  const s = spinner();
270
431
  s.start('Scaffolding project');
271
- await writeFiles(targetDir, scaffold(name, template));
432
+ await writeFiles(targetDir, scaffold(name, template, features, aiTools));
272
433
  s.stop(`Scaffolded ${pc.cyan(rel)}`);
273
434
 
274
- // 6. git init (best-effort)
275
435
  if (initGit) {
276
436
  const g = spinner();
277
437
  g.start('Initializing git repository');
@@ -284,7 +444,6 @@ export async function runCreate(opts: CreateOptions): Promise<void> {
284
444
  }
285
445
  }
286
446
 
287
- // 7. Install (best-effort)
288
447
  if (install) {
289
448
  const i = spinner();
290
449
  i.start(`Installing dependencies with ${pm}`);
@@ -297,7 +456,6 @@ export async function runCreate(opts: CreateOptions): Promise<void> {
297
456
  }
298
457
  }
299
458
 
300
- // 8. Next steps
301
459
  const steps: string[] = [];
302
460
  if (rel !== '.') steps.push(`cd ${rel}`);
303
461
  if (!install) steps.push('npm install');
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Pure description of toiljs's optional client styling features — a CSS preprocessor and Tailwind —
3
+ * shared by `create` (scaffold) and `configure` (toggle on existing projects). Dependency-light
4
+ * (no node IO) so it can be unit-tested; the file writes and package-manager calls live in the
5
+ * commands. Preprocessor and Tailwind are independent: Tailwind lives in its own `.css` entry so
6
+ * it never passes through (and breaks on) a preprocessor's `@import` resolution.
7
+ */
8
+
9
+ /** Supported CSS preprocessor (`css` = none). */
10
+ export type Preprocessor = 'css' | 'sass' | 'less' | 'stylus';
11
+
12
+ /** The two independently-toggleable styling features of a project. */
13
+ export interface StyleFeatures {
14
+ readonly preprocessor: Preprocessor;
15
+ readonly tailwind: boolean;
16
+ }
17
+
18
+ export const PREPROCESSORS: readonly Preprocessor[] = ['css', 'sass', 'less', 'stylus'];
19
+
20
+ /** Main stylesheet extension for each preprocessor. */
21
+ export const STYLE_EXT: Record<Preprocessor, string> = {
22
+ css: 'css',
23
+ sass: 'scss',
24
+ less: 'less',
25
+ stylus: 'styl',
26
+ };
27
+
28
+ /** npm package that enables each preprocessor in Vite (plain CSS needs none). */
29
+ export const PREPROCESSOR_PKG: Record<Preprocessor, string | null> = {
30
+ css: null,
31
+ sass: 'sass',
32
+ less: 'less',
33
+ stylus: 'stylus',
34
+ };
35
+
36
+ /** Tailwind v4 packages. The framework auto-wires the Vite plugin when `@tailwindcss/vite` resolves. */
37
+ export const TAILWIND_PKGS: readonly string[] = ['tailwindcss', '@tailwindcss/vite'];
38
+
39
+ /** Pinned versions for every package these features may install. */
40
+ export const PKG_VERSION: Record<string, string> = {
41
+ sass: '^1.83.0',
42
+ less: '^4.2.1',
43
+ stylus: '^0.64.0',
44
+ tailwindcss: '^4.0.0',
45
+ '@tailwindcss/vite': '^4.0.0',
46
+ };
47
+
48
+ /** Dedicated Tailwind entry (kept `.css` so no preprocessor touches its `@import`). */
49
+ export const TAILWIND_ENTRY = 'styles/tailwind.css';
50
+ export const TAILWIND_CSS = `@import 'tailwindcss';\n`;
51
+
52
+ /** Path (relative to `client/`) of the main stylesheet for a preprocessor. */
53
+ export function styleEntry(p: Preprocessor): string {
54
+ return `styles/main.${STYLE_EXT[p]}`;
55
+ }
56
+
57
+ /** The preprocessor whose main stylesheet uses `ext` (with or without a leading dot), or null. */
58
+ export function preprocessorForExt(ext: string): Preprocessor | null {
59
+ const e = ext.replace(/^\./, '');
60
+ if (e === 'sass') return 'sass';
61
+ return PREPROCESSORS.find((p) => STYLE_EXT[p] === e) ?? null;
62
+ }
63
+
64
+ /** Packages required by a feature set (preprocessor package + Tailwind packages). */
65
+ export function requiredPackages(f: StyleFeatures): string[] {
66
+ const pkgs: string[] = [];
67
+ const pp = PREPROCESSOR_PKG[f.preprocessor];
68
+ if (pp) pkgs.push(pp);
69
+ if (f.tailwind) pkgs.push(...TAILWIND_PKGS);
70
+ return pkgs;
71
+ }
72
+
73
+ /** Managed packages to add and remove when moving from `from` to `to`. */
74
+ export function packageDiff(
75
+ from: StyleFeatures,
76
+ to: StyleFeatures,
77
+ ): { add: string[]; remove: string[] } {
78
+ const want = new Set(requiredPackages(to));
79
+ const had = new Set(requiredPackages(from));
80
+ return {
81
+ add: [...want].filter((p) => !had.has(p)),
82
+ remove: [...had].filter((p) => !want.has(p)),
83
+ };
84
+ }
85
+
86
+ /** The side-effect style imports for the app entry, Tailwind first so app CSS can override it. */
87
+ export function styleImportLines(f: StyleFeatures): string[] {
88
+ const lines: string[] = [];
89
+ if (f.tailwind) lines.push(`import './${TAILWIND_ENTRY}';`);
90
+ lines.push(`import './${styleEntry(f.preprocessor)}';`);
91
+ return lines;
92
+ }
93
+
94
+ /**
95
+ * Rewrites the `./styles/*` side-effect imports in an app entry (`client/toil.tsx`) to match
96
+ * `features`, preserving the rest of the file. Existing style imports are removed and the new
97
+ * block is placed after the `toiljs/routes` import (or the last import, or the top).
98
+ */
99
+ export function setStyleImports(source: string, f: StyleFeatures): string {
100
+ const stripped = source.replace(/^[ \t]*import\s+['"]\.\/styles\/[^'"]+['"];?[ \t]*\r?\n/gm, '');
101
+ const block = styleImportLines(f).join('\n') + '\n';
102
+
103
+ const lines = stripped.split('\n');
104
+ const routesIdx = lines.findIndex((l) => /from\s+['"]toiljs\/routes['"]/.test(l));
105
+ let insertAt: number;
106
+ if (routesIdx !== -1) {
107
+ insertAt = routesIdx + 1;
108
+ } else {
109
+ const lastImport = lines.reduce((acc, l, i) => (/^\s*import\s/.test(l) ? i : acc), -1);
110
+ insertAt = lastImport + 1;
111
+ }
112
+ const head = lines.slice(0, insertAt).join('\n');
113
+ const tail = lines.slice(insertAt).join('\n');
114
+ return `${head}\n\n${block}\n${tail}`.replace(/\n{3,}/g, '\n\n');
115
+ }
116
+
117
+ /** Detects the active preprocessor from a project's combined dependency map. */
118
+ export function detectPreprocessor(deps: Record<string, string>): Preprocessor {
119
+ if ('sass' in deps) return 'sass';
120
+ if ('less' in deps) return 'less';
121
+ if ('stylus' in deps) return 'stylus';
122
+ return 'css';
123
+ }
124
+
125
+ /** Whether Tailwind is installed in a project's combined dependency map. */
126
+ export function detectTailwind(deps: Record<string, string>): boolean {
127
+ return '@tailwindcss/vite' in deps || 'tailwindcss' in deps;
128
+ }