toiljs 0.0.4 → 0.0.6

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