@tanstack/cta-engine 0.10.0-alpha.21 → 0.10.0-alpha.25

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 (340) hide show
  1. package/dist/add-ons.js +91 -5
  2. package/dist/add.js +125 -0
  3. package/dist/cli.js +132 -0
  4. package/dist/config-file.js +9 -14
  5. package/dist/constants.js +2 -0
  6. package/dist/create-app.js +451 -142
  7. package/dist/custom-add-on.js +254 -0
  8. package/dist/environment.js +32 -64
  9. package/dist/file-helper.js +18 -0
  10. package/dist/index.js +1 -17
  11. package/dist/mcp.js +229 -0
  12. package/dist/options.js +333 -9
  13. package/dist/package-manager.js +6 -51
  14. package/dist/templates.js +6 -0
  15. package/dist/toolchain.js +6 -0
  16. package/dist/types/add-ons.d.ts +8 -3
  17. package/dist/types/add.d.ts +3 -0
  18. package/dist/types/cli.d.ts +7 -0
  19. package/dist/types/config-file.d.ts +4 -6
  20. package/dist/types/constants.d.ts +3 -0
  21. package/dist/types/create-app.d.ts +7 -1
  22. package/dist/types/custom-add-on.d.ts +3 -0
  23. package/dist/types/environment.d.ts +1 -2
  24. package/dist/types/file-helper.d.ts +2 -0
  25. package/dist/types/index.d.ts +1 -20
  26. package/dist/types/mcp.d.ts +7 -0
  27. package/dist/types/options.d.ts +6 -2
  28. package/dist/types/package-manager.d.ts +1 -18
  29. package/dist/types/templates.d.ts +1 -0
  30. package/dist/types/toolchain.d.ts +3 -0
  31. package/dist/types/types.d.ts +85 -788
  32. package/dist/types/utils.d.ts +0 -5
  33. package/dist/types.js +1 -65
  34. package/dist/utils.js +0 -9
  35. package/package.json +12 -9
  36. package/src/add-ons.ts +123 -7
  37. package/src/add.ts +186 -0
  38. package/src/cli.ts +210 -0
  39. package/src/config-file.ts +17 -26
  40. package/src/constants.ts +5 -0
  41. package/src/create-app.ts +730 -180
  42. package/src/custom-add-on.ts +325 -0
  43. package/src/environment.ts +33 -77
  44. package/src/file-helper.ts +20 -0
  45. package/src/index.ts +1 -77
  46. package/src/mcp.ts +302 -0
  47. package/src/options.ts +409 -8
  48. package/src/package-manager.ts +9 -80
  49. package/src/templates.ts +7 -0
  50. package/src/toolchain.ts +7 -0
  51. package/src/types.ts +87 -175
  52. package/src/utils.ts +0 -17
  53. package/templates/react/add-on/clerk/README.md +3 -0
  54. package/templates/react/add-on/clerk/assets/_dot_env.local.append +2 -0
  55. package/templates/react/add-on/clerk/assets/src/integrations/clerk/header-user.tsx +19 -0
  56. package/templates/react/add-on/clerk/assets/src/integrations/clerk/provider.tsx +18 -0
  57. package/templates/react/add-on/clerk/assets/src/routes/demo.clerk.tsx +20 -0
  58. package/templates/react/add-on/clerk/info.json +13 -0
  59. package/templates/react/add-on/clerk/package.json +5 -0
  60. package/templates/react/add-on/convex/README.md +4 -0
  61. package/templates/react/add-on/convex/assets/_dot_cursorrules.append +93 -0
  62. package/templates/react/add-on/convex/assets/_dot_env.local.append +3 -0
  63. package/templates/react/add-on/convex/assets/convex/products.ts +8 -0
  64. package/templates/react/add-on/convex/assets/convex/schema.ts +10 -0
  65. package/templates/react/add-on/convex/assets/src/integrations/convex/provider.tsx +20 -0
  66. package/templates/react/add-on/convex/assets/src/routes/demo.convex.tsx +33 -0
  67. package/templates/react/add-on/convex/info.json +13 -0
  68. package/templates/react/add-on/convex/package.json +6 -0
  69. package/templates/react/add-on/form/assets/src/components/demo.FormComponents.tsx.ejs +300 -0
  70. package/templates/react/add-on/form/assets/src/hooks/demo.form-context.ts +4 -0
  71. package/templates/react/add-on/form/assets/src/hooks/demo.form.ts +22 -0
  72. package/templates/react/add-on/form/assets/src/routes/demo.form.address.tsx.ejs +213 -0
  73. package/templates/react/add-on/form/assets/src/routes/demo.form.simple.tsx.ejs +77 -0
  74. package/templates/react/add-on/form/info.json +26 -0
  75. package/templates/react/add-on/form/package.json +6 -0
  76. package/templates/react/add-on/module-federation/assets/module-federation.config.js.ejs +31 -0
  77. package/templates/react/add-on/module-federation/assets/src/demo-mf-component.tsx +3 -0
  78. package/templates/react/add-on/module-federation/assets/src/demo-mf-self-contained.tsx +11 -0
  79. package/templates/react/add-on/module-federation/info.json +7 -0
  80. package/templates/react/add-on/module-federation/package.json +5 -0
  81. package/templates/react/add-on/netlify/README.md +11 -0
  82. package/templates/react/add-on/netlify/info.json +7 -0
  83. package/templates/react/add-on/sentry/assets/_dot_cursorrules.append +22 -0
  84. package/templates/react/add-on/sentry/assets/_dot_env.local.append +11 -0
  85. package/templates/react/add-on/sentry/assets/src/app/global-middleware.ts +11 -0
  86. package/templates/react/add-on/sentry/assets/src/routes/demo.sentry.testing.tsx +489 -0
  87. package/templates/react/add-on/sentry/info.json +14 -0
  88. package/templates/react/add-on/sentry/package.json +5 -0
  89. package/templates/react/add-on/shadcn/README.md +7 -0
  90. package/templates/react/add-on/shadcn/assets/_dot_cursorrules.append +7 -0
  91. package/templates/react/add-on/shadcn/assets/components.json +21 -0
  92. package/templates/react/add-on/shadcn/assets/src/lib/utils.ts +6 -0
  93. package/templates/react/add-on/shadcn/assets/src/styles.css +138 -0
  94. package/templates/react/add-on/shadcn/info.json +7 -0
  95. package/templates/react/add-on/shadcn/package.json +9 -0
  96. package/templates/react/add-on/start/assets/_dot_gitignore.append +2 -0
  97. package/templates/react/add-on/start/assets/app.config.ts.ejs +32 -0
  98. package/templates/react/add-on/start/assets/src/api.ts +6 -0
  99. package/templates/react/add-on/start/assets/src/client.tsx.ejs +33 -0
  100. package/templates/react/add-on/start/assets/src/router.tsx.ejs +48 -0
  101. package/templates/react/add-on/start/assets/src/routes/api.demo-names.ts +11 -0
  102. package/templates/react/add-on/start/assets/src/routes/demo.start.api-request.tsx.ejs +33 -0
  103. package/templates/react/add-on/start/assets/src/routes/demo.start.server-funcs.tsx +50 -0
  104. package/templates/react/add-on/start/assets/src/ssr.tsx.ejs +30 -0
  105. package/templates/react/add-on/start/info.json +18 -0
  106. package/templates/react/add-on/start/package.json +13 -0
  107. package/templates/react/add-on/store/assets/src/lib/demo-store.ts +13 -0
  108. package/templates/react/add-on/store/assets/src/routes/demo.store.tsx.ejs +75 -0
  109. package/templates/react/add-on/store/info.json +13 -0
  110. package/templates/react/add-on/store/package.json +6 -0
  111. package/templates/react/add-on/t3env/README.md +16 -0
  112. package/templates/react/add-on/t3env/assets/src/env.ts +39 -0
  113. package/templates/react/add-on/t3env/info.json +10 -0
  114. package/templates/react/add-on/t3env/package.json +6 -0
  115. package/templates/react/add-on/tRPC/assets/src/integrations/trpc/init.ts +9 -0
  116. package/templates/react/add-on/tRPC/assets/src/integrations/trpc/react.ts +4 -0
  117. package/templates/react/add-on/tRPC/assets/src/integrations/trpc/router.ts +18 -0
  118. package/templates/react/add-on/tRPC/assets/src/routes/api.trpc.$.tsx +16 -0
  119. package/templates/react/add-on/tRPC/info.json +9 -0
  120. package/templates/react/add-on/tRPC/package.json +9 -0
  121. package/templates/react/add-on/table/assets/src/data/demo-table-data.ts +50 -0
  122. package/templates/react/add-on/table/assets/src/routes/demo.table.tsx.ejs +373 -0
  123. package/templates/react/add-on/table/info.json +13 -0
  124. package/templates/react/add-on/table/package.json +7 -0
  125. package/templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/layout.tsx +5 -0
  126. package/templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/root-provider.tsx.ejs +70 -0
  127. package/templates/react/add-on/tanstack-query/assets/src/routes/demo.tanstack-query.tsx.ejs +53 -0
  128. package/templates/react/add-on/tanstack-query/info.json +13 -0
  129. package/templates/react/add-on/tanstack-query/package.json +6 -0
  130. package/templates/react/base/README.md.ejs +558 -0
  131. package/templates/react/base/_dot_gitignore +5 -0
  132. package/templates/react/base/_dot_vscode/settings.biome.json +35 -0
  133. package/templates/react/base/_dot_vscode/settings.json +11 -0
  134. package/templates/react/base/index.html.ejs +20 -0
  135. package/templates/react/base/package.biome.json +10 -0
  136. package/templates/react/base/package.eslintprettier.json +11 -0
  137. package/templates/react/base/package.json +30 -0
  138. package/templates/react/base/package.ts.json +7 -0
  139. package/templates/react/base/package.tw.json +6 -0
  140. package/templates/react/base/public/favicon.ico +0 -0
  141. package/templates/react/base/public/logo192.png +0 -0
  142. package/templates/react/base/public/logo512.png +0 -0
  143. package/templates/react/base/public/manifest.json +25 -0
  144. package/templates/react/base/public/robots.txt +3 -0
  145. package/templates/react/base/src/App.css +38 -0
  146. package/templates/react/base/src/App.test.tsx.ejs +10 -0
  147. package/templates/react/base/src/App.tsx.ejs +74 -0
  148. package/templates/react/base/src/components/Header.tsx.ejs +27 -0
  149. package/templates/react/base/src/logo.svg +44 -0
  150. package/templates/react/base/src/reportWebVitals.ts.ejs +28 -0
  151. package/templates/react/base/src/styles.css.ejs +15 -0
  152. package/templates/react/base/toolchain/.prettierignore +3 -0
  153. package/templates/react/base/toolchain/biome.json +31 -0
  154. package/templates/react/base/toolchain/eslint.config.js +5 -0
  155. package/templates/react/base/toolchain/prettier.config.js +10 -0
  156. package/templates/react/base/tsconfig.json.ejs +29 -0
  157. package/templates/react/base/vite.config.js.ejs +23 -0
  158. package/templates/react/code-router/src/main.tsx.ejs +92 -0
  159. package/templates/react/example/tanchat/README.md +37 -0
  160. package/templates/react/example/tanchat/assets/_dot_env.local.append +2 -0
  161. package/templates/react/example/tanchat/assets/public/example-guitar-flowers.jpg +0 -0
  162. package/templates/react/example/tanchat/assets/public/example-guitar-motherboard.jpg +0 -0
  163. package/templates/react/example/tanchat/assets/public/example-guitar-racing.jpg +0 -0
  164. package/templates/react/example/tanchat/assets/public/example-guitar-steamer-trunk.jpg +0 -0
  165. package/templates/react/example/tanchat/assets/public/example-guitar-superhero.jpg +0 -0
  166. package/templates/react/example/tanchat/assets/public/example-guitar-traveling.jpg +0 -0
  167. package/templates/react/example/tanchat/assets/public/example-guitar-video-games.jpg +0 -0
  168. package/templates/react/example/tanchat/assets/src/components/example-AIAssistant.tsx +173 -0
  169. package/templates/react/example/tanchat/assets/src/components/example-GuitarRecommendation.tsx +47 -0
  170. package/templates/react/example/tanchat/assets/src/data/example-guitars.ts +83 -0
  171. package/templates/react/example/tanchat/assets/src/demo.index.css +220 -0
  172. package/templates/react/example/tanchat/assets/src/integrations/tanchat/header-user.tsx +5 -0
  173. package/templates/react/example/tanchat/assets/src/routes/api.messages.ts +24 -0
  174. package/templates/react/example/tanchat/assets/src/routes/api.sse.ts +23 -0
  175. package/templates/react/example/tanchat/assets/src/routes/example.chat.tsx +159 -0
  176. package/templates/react/example/tanchat/assets/src/routes/example.guitars/$guitarId.tsx +50 -0
  177. package/templates/react/example/tanchat/assets/src/routes/example.guitars/index.tsx +54 -0
  178. package/templates/react/example/tanchat/assets/src/store/example-assistant.ts +3 -0
  179. package/templates/react/example/tanchat/assets/src/utils/demo.ai.ts +62 -0
  180. package/templates/react/example/tanchat/assets/src/utils/demo.sse.ts +31 -0
  181. package/templates/react/example/tanchat/assets/src/utils/demo.tools.ts +47 -0
  182. package/templates/react/example/tanchat/info.json +19 -0
  183. package/templates/react/example/tanchat/package.json +16 -0
  184. package/templates/react/file-router/package.fr.json +5 -0
  185. package/templates/react/file-router/src/main.tsx.ejs +55 -0
  186. package/templates/react/file-router/src/routes/__root.tsx.ejs +82 -0
  187. package/templates/solid/add-on/form/assets/src/routes/demo.form.tsx.ejs +352 -0
  188. package/templates/solid/add-on/form/info.json +13 -0
  189. package/templates/solid/add-on/form/package.json +5 -0
  190. package/templates/solid/add-on/module-federation/assets/module-federation.config.js.ejs +27 -0
  191. package/templates/solid/add-on/module-federation/assets/src/demo-mf-component.tsx +3 -0
  192. package/templates/solid/add-on/module-federation/assets/src/demo-mf-self-contained.tsx +9 -0
  193. package/templates/solid/add-on/module-federation/info.json +7 -0
  194. package/templates/solid/add-on/module-federation/package.json +5 -0
  195. package/templates/solid/add-on/sentry/assets/_dot_cursorrules.append +22 -0
  196. package/templates/solid/add-on/sentry/assets/_dot_env.local.append +2 -0
  197. package/templates/solid/add-on/sentry/assets/src/routes/demo.sentry.bad-event-handler.tsx +20 -0
  198. package/templates/solid/add-on/sentry/info.json +13 -0
  199. package/templates/solid/add-on/sentry/package.json +5 -0
  200. package/templates/solid/add-on/solid-ui/README.md +9 -0
  201. package/templates/solid/add-on/solid-ui/assets/src/lib/utils.ts +6 -0
  202. package/templates/solid/add-on/solid-ui/assets/src/styles.css +138 -0
  203. package/templates/solid/add-on/solid-ui/assets/ui.config.json +13 -0
  204. package/templates/solid/add-on/solid-ui/info.json +11 -0
  205. package/templates/solid/add-on/solid-ui/package.json +9 -0
  206. package/templates/solid/add-on/start/assets/app.config.ts +16 -0
  207. package/templates/solid/add-on/start/assets/src/api.ts +6 -0
  208. package/templates/solid/add-on/start/assets/src/client.tsx +7 -0
  209. package/templates/solid/add-on/start/assets/src/router.tsx.ejs +24 -0
  210. package/templates/solid/add-on/start/assets/src/routes/demo.start.server-funcs.tsx +49 -0
  211. package/templates/solid/add-on/start/assets/src/ssr.tsx +12 -0
  212. package/templates/solid/add-on/start/info.json +14 -0
  213. package/templates/solid/add-on/start/package.json +12 -0
  214. package/templates/solid/add-on/store/assets/src/lib/demo-store.ts +13 -0
  215. package/templates/solid/add-on/store/assets/src/routes/demo.store.tsx.ejs +77 -0
  216. package/templates/solid/add-on/store/info.json +13 -0
  217. package/templates/solid/add-on/store/package.json +6 -0
  218. package/templates/solid/add-on/t3env/README.md +16 -0
  219. package/templates/solid/add-on/t3env/assets/src/env.ts +39 -0
  220. package/templates/solid/add-on/t3env/info.json +10 -0
  221. package/templates/solid/add-on/t3env/package.json +6 -0
  222. package/templates/solid/add-on/tanstack-query/assets/src/integrations/tanstack-query/header-user.tsx +5 -0
  223. package/templates/solid/add-on/tanstack-query/assets/src/integrations/tanstack-query/provider.tsx +15 -0
  224. package/templates/solid/add-on/tanstack-query/assets/src/routes/demo.tanstack-query.tsx +30 -0
  225. package/templates/solid/add-on/tanstack-query/info.json +13 -0
  226. package/templates/solid/add-on/tanstack-query/package.json +6 -0
  227. package/templates/solid/base/README.md.ejs +215 -0
  228. package/templates/solid/base/_dot_cursorrules.append +35 -0
  229. package/templates/solid/base/_dot_gitignore +5 -0
  230. package/templates/solid/base/_dot_vscode/settings.biome.json +35 -0
  231. package/templates/solid/base/_dot_vscode/settings.json +11 -0
  232. package/templates/solid/base/index.html.ejs +20 -0
  233. package/templates/solid/base/package.biome.json +10 -0
  234. package/templates/solid/base/package.eslintprettier.json +11 -0
  235. package/templates/solid/base/package.json +23 -0
  236. package/templates/solid/base/package.ts.json +5 -0
  237. package/templates/solid/base/package.tw.json +6 -0
  238. package/templates/solid/base/public/favicon.ico +0 -0
  239. package/templates/solid/base/public/logo192.png +0 -0
  240. package/templates/solid/base/public/logo512.png +0 -0
  241. package/templates/solid/base/public/manifest.json +25 -0
  242. package/templates/solid/base/public/robots.txt +3 -0
  243. package/templates/solid/base/src/App.css +0 -0
  244. package/templates/solid/base/src/App.tsx.ejs +47 -0
  245. package/templates/solid/base/src/components/Header.tsx.ejs +26 -0
  246. package/templates/solid/base/src/logo.svg +120 -0
  247. package/templates/solid/base/src/styles.css.ejs +15 -0
  248. package/templates/solid/base/toolchain/.prettierignore +3 -0
  249. package/templates/solid/base/toolchain/biome.json +31 -0
  250. package/templates/solid/base/toolchain/eslint.config.js +5 -0
  251. package/templates/solid/base/toolchain/prettier.config.js +10 -0
  252. package/templates/solid/base/tsconfig.json.ejs +31 -0
  253. package/templates/solid/base/vite.config.js.ejs +22 -0
  254. package/templates/solid/code-router/src/main.tsx.ejs +71 -0
  255. package/templates/solid/example/tanchat/README.md +52 -0
  256. package/templates/solid/example/tanchat/assets/ai-streaming-server/README.md +110 -0
  257. package/templates/solid/example/tanchat/assets/ai-streaming-server/_dot_env.example +1 -0
  258. package/templates/solid/example/tanchat/assets/ai-streaming-server/package.json +26 -0
  259. package/templates/solid/example/tanchat/assets/ai-streaming-server/src/index.ts +102 -0
  260. package/templates/solid/example/tanchat/assets/ai-streaming-server/tsconfig.json +15 -0
  261. package/templates/solid/example/tanchat/assets/src/components/demo.SettingsDialog.tsx +149 -0
  262. package/templates/solid/example/tanchat/assets/src/demo.index.css +227 -0
  263. package/templates/solid/example/tanchat/assets/src/lib/demo-store.ts +13 -0
  264. package/templates/solid/example/tanchat/assets/src/routes/example.chat.tsx +435 -0
  265. package/templates/solid/example/tanchat/assets/src/store/demo.hooks.ts +17 -0
  266. package/templates/solid/example/tanchat/assets/src/store/demo.store.ts +133 -0
  267. package/templates/solid/example/tanchat/info.json +14 -0
  268. package/templates/solid/example/tanchat/package.json +7 -0
  269. package/templates/solid/file-router/package.fr.json +5 -0
  270. package/templates/solid/file-router/src/main.tsx.ejs +47 -0
  271. package/templates/solid/file-router/src/routes/__root.tsx.ejs +41 -0
  272. package/templates/solid/file-router/src/routes/index.tsx +43 -0
  273. package/tests/cra.test.ts +293 -0
  274. package/tests/snapshots/cra/cr-js-npm.json +33 -0
  275. package/tests/snapshots/cra/cr-ts-npm.json +34 -0
  276. package/tests/snapshots/cra/cr-ts-start-npm.json +38 -0
  277. package/tests/snapshots/cra/fr-ts-npm.json +34 -0
  278. package/tests/snapshots/cra/fr-ts-tw-npm.json +33 -0
  279. package/tests/snapshots/cra/solid-cr-js-npm.json +31 -0
  280. package/tests/snapshots/cra/solid-cr-ts-npm.json +32 -0
  281. package/tests/snapshots/cra/solid-cr-ts-start-npm.json +36 -0
  282. package/tests/snapshots/cra/solid-fr-ts-npm.json +33 -0
  283. package/tests/snapshots/cra/solid-fr-ts-tw-npm.json +32 -0
  284. package/tests/test-utilities.ts +87 -0
  285. package/dist/add-to-app.js +0 -169
  286. package/dist/custom-add-ons/add-on.js +0 -175
  287. package/dist/custom-add-ons/shared.js +0 -117
  288. package/dist/custom-add-ons/starter.js +0 -84
  289. package/dist/file-helpers.js +0 -165
  290. package/dist/frameworks.js +0 -92
  291. package/dist/integrations/git.js +0 -4
  292. package/dist/integrations/shadcn.js +0 -33
  293. package/dist/package-json.js +0 -48
  294. package/dist/special-steps/index.js +0 -24
  295. package/dist/special-steps/rimraf-node-modules.js +0 -16
  296. package/dist/template-file.js +0 -112
  297. package/dist/types/add-to-app.d.ts +0 -17
  298. package/dist/types/custom-add-ons/add-on.d.ts +0 -69
  299. package/dist/types/custom-add-ons/shared.d.ts +0 -15
  300. package/dist/types/custom-add-ons/starter.d.ts +0 -7
  301. package/dist/types/file-helpers.d.ts +0 -15
  302. package/dist/types/frameworks.d.ts +0 -7
  303. package/dist/types/integrations/git.d.ts +0 -2
  304. package/dist/types/integrations/shadcn.d.ts +0 -2
  305. package/dist/types/package-json.d.ts +0 -7
  306. package/dist/types/special-steps/index.d.ts +0 -2
  307. package/dist/types/special-steps/rimraf-node-modules.d.ts +0 -2
  308. package/dist/types/template-file.d.ts +0 -2
  309. package/src/add-to-app.ts +0 -274
  310. package/src/custom-add-ons/add-on.ts +0 -261
  311. package/src/custom-add-ons/shared.ts +0 -161
  312. package/src/custom-add-ons/starter.ts +0 -126
  313. package/src/file-helpers.ts +0 -235
  314. package/src/frameworks.ts +0 -134
  315. package/src/integrations/git.ts +0 -7
  316. package/src/integrations/shadcn.ts +0 -54
  317. package/src/package-json.ts +0 -69
  318. package/src/special-steps/index.ts +0 -36
  319. package/src/special-steps/rimraf-node-modules.ts +0 -25
  320. package/src/template-file.ts +0 -150
  321. package/tests/add-ons.test.ts +0 -67
  322. package/tests/add-to-app.test.ts +0 -358
  323. package/tests/config-file.test.ts +0 -68
  324. package/tests/create-app.test.ts +0 -120
  325. package/tests/custom-add-ons/add-on.test.ts +0 -12
  326. package/tests/custom-add-ons/shared.test.ts +0 -257
  327. package/tests/custom-add-ons/starter.test.ts +0 -58
  328. package/tests/environment.test.ts +0 -115
  329. package/tests/file-helper.test.ts +0 -90
  330. package/tests/frameworks.test.ts +0 -95
  331. package/tests/index.test.ts +0 -9
  332. package/tests/integrations/git.test.ts +0 -20
  333. package/tests/integrations/shadcn.test.ts +0 -91
  334. package/tests/options.test.ts +0 -42
  335. package/tests/package-json.test.ts +0 -63
  336. package/tests/package-manager.test.ts +0 -154
  337. package/tests/setupVitest.ts +0 -6
  338. package/tests/template-file.test.ts +0 -178
  339. package/tests/utils.test.ts +0 -23
  340. package/vitest.config.ts +0 -21
package/src/create-app.ts CHANGED
@@ -1,208 +1,702 @@
1
- import { basename, resolve } from 'node:path'
2
-
3
- import { isBase64 } from './file-helpers.js'
4
- import { formatCommand } from './utils.js'
5
- import { writeConfigFileToEnvironment } from './config-file.js'
6
- import {
7
- getPackageManagerScriptCommand,
8
- packageManagerInstall,
9
- } from './package-manager.js'
10
- import { createPackageJSON } from './package-json.js'
11
- import { createTemplateFile } from './template-file.js'
12
- import { installShadcnComponents } from './integrations/shadcn.js'
13
- import { setupGit } from './integrations/git.js'
14
- import { runSpecialSteps } from './special-steps/index.js'
15
-
16
- import type { Environment, FileBundleHandler, Options } from './types.js'
17
-
18
- async function writeFiles(environment: Environment, options: Options) {
19
- const templateFileFromContent = createTemplateFile(environment, options)
20
-
21
- async function writeFileBundle(bundle: FileBundleHandler) {
22
- const files = await bundle.getFiles()
1
+ import { basename, dirname, resolve } from 'node:path'
2
+ import { log, outro, spinner } from '@clack/prompts'
3
+ import { render } from 'ejs'
4
+ import { format } from 'prettier'
5
+ import chalk from 'chalk'
6
+
7
+ import { getTemplatesRoot } from './templates.js'
8
+ import { CODE_ROUTER, FILE_ROUTER } from './constants.js'
9
+ import { sortObject } from './utils.js'
10
+ import { writeConfigFile } from './config-file.js'
11
+ import { packageManagerExecute } from './package-manager.js'
12
+ import { getBinaryFile } from './file-helper.js'
13
+
14
+ import type { AddOn, Environment, Options } from './types.js'
15
+
16
+ function createCopyFiles(environment: Environment, targetDir: string) {
17
+ return async function copyFiles(
18
+ templateDir: string,
19
+ files: Array<string>,
20
+ // optionally copy files from a folder to the root
21
+ toRoot?: boolean,
22
+ ) {
23
23
  for (const file of files) {
24
- const contents = await bundle.getFileContents(file)
25
- const isBinaryFile = isBase64(contents)
26
- if (isBinaryFile) {
27
- await environment.writeFileBase64(
28
- resolve(options.targetDir, file),
29
- contents,
30
- )
31
- } else {
32
- await templateFileFromContent(file, contents)
24
+ let targetFileName = file.replace('.tw', '')
25
+ if (toRoot) {
26
+ const fileNoPath = targetFileName.split('/').pop()
27
+ targetFileName = fileNoPath ? `./${fileNoPath}` : targetFileName
33
28
  }
34
- }
35
-
36
- const deletedFiles = await bundle.getDeletedFiles()
37
- for (const file of deletedFiles) {
38
- await environment.deleteFile(resolve(options.targetDir, file))
29
+ await environment.copyFile(
30
+ resolve(templateDir, file),
31
+ resolve(targetDir, targetFileName),
32
+ )
39
33
  }
40
34
  }
35
+ }
41
36
 
42
- environment.startStep({
43
- id: 'write-framework-files',
44
- type: 'file',
45
- message: 'Writing framework files...',
46
- })
47
- await writeFileBundle(options.framework)
48
- environment.finishStep('write-framework-files', 'Framework files written')
37
+ function jsSafeName(name: string) {
38
+ return name
39
+ .split(/[^a-zA-Z0-9]/)
40
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
41
+ .join('')
42
+ }
49
43
 
50
- let wroteAddonFiles = false
51
- for (const type of ['add-on', 'example', 'toolchain']) {
52
- for (const phase of ['setup', 'add-on', 'example']) {
53
- for (const addOn of options.chosenAddOns.filter(
54
- (addOn) => addOn.phase === phase && addOn.type === type,
55
- )) {
56
- environment.startStep({
57
- id: 'write-addon-files',
58
- type: 'file',
59
- message: `Writing ${addOn.name} files...`,
60
- })
61
- await writeFileBundle(addOn)
62
- wroteAddonFiles = true
44
+ function createTemplateFile(
45
+ environment: Environment,
46
+ projectName: string,
47
+ options: Options,
48
+ targetDir: string,
49
+ ) {
50
+ return async function templateFile(
51
+ file: string,
52
+ content: string,
53
+ targetFileName?: string,
54
+ extraTemplateValues?: Record<string, any>,
55
+ ) {
56
+ function getPackageManagerAddScript(
57
+ packageName: string,
58
+ isDev: boolean = false,
59
+ ) {
60
+ let command
61
+ switch (options.packageManager) {
62
+ case 'yarn':
63
+ case 'pnpm':
64
+ command = isDev
65
+ ? `${options.packageManager} add ${packageName} --dev`
66
+ : `${options.packageManager} add ${packageName}`
67
+ break
68
+ default:
69
+ command = isDev
70
+ ? `${options.packageManager} install ${packageName} -D`
71
+ : `${options.packageManager} install ${packageName}`
72
+ break
63
73
  }
74
+ return command
75
+ }
76
+
77
+ function getPackageManagerRunScript(scriptName: string) {
78
+ let command
79
+ switch (options.packageManager) {
80
+ case 'yarn':
81
+ case 'pnpm':
82
+ command = `${options.packageManager} ${scriptName}`
83
+ break
84
+ case 'deno':
85
+ command = `${options.packageManager} task ${scriptName}`
86
+ break
87
+ default:
88
+ command = `${options.packageManager} run ${scriptName}`
89
+ break
90
+ }
91
+ return command
92
+ }
93
+
94
+ const templateValues = {
95
+ packageManager: options.packageManager,
96
+ projectName: projectName,
97
+ typescript: options.typescript,
98
+ tailwind: options.tailwind,
99
+ toolchain: options.toolchain,
100
+ js: options.typescript ? 'ts' : 'js',
101
+ jsx: options.typescript ? 'tsx' : 'jsx',
102
+ fileRouter: options.mode === FILE_ROUTER,
103
+ codeRouter: options.mode === CODE_ROUTER,
104
+ addOnEnabled: options.chosenAddOns.reduce<Record<string, boolean>>(
105
+ (acc, addOn) => {
106
+ acc[addOn.id] = true
107
+ return acc
108
+ },
109
+ {},
110
+ ),
111
+ addOns: options.chosenAddOns,
112
+
113
+ ...extraTemplateValues,
114
+
115
+ getPackageManagerAddScript,
116
+ getPackageManagerRunScript,
64
117
  }
118
+
119
+ try {
120
+ content = render(content, templateValues)
121
+ } catch (error) {
122
+ console.error(chalk.red(`EJS error in file ${file}`))
123
+ console.error(error)
124
+ process.exit(1)
125
+ }
126
+ const target = targetFileName ?? file.replace('.ejs', '')
127
+
128
+ if (target.endsWith('.ts') || target.endsWith('.tsx')) {
129
+ content = await format(content, {
130
+ semi: false,
131
+ singleQuote: true,
132
+ trailingComma: 'all',
133
+ parser: 'typescript',
134
+ })
135
+ }
136
+
137
+ await environment.writeFile(resolve(targetDir, target), content)
65
138
  }
66
- if (wroteAddonFiles) {
67
- environment.finishStep('write-addon-files', 'Add-on files written')
139
+ }
140
+
141
+ async function createPackageJSON(
142
+ environment: Environment,
143
+ projectName: string,
144
+ options: Options,
145
+ templateDir: string,
146
+ routerDir: string,
147
+ targetDir: string,
148
+ addOns: Array<{
149
+ dependencies?: Record<string, string>
150
+ devDependencies?: Record<string, string>
151
+ scripts?: Record<string, string>
152
+ }>,
153
+ ) {
154
+ let packageJSON = JSON.parse(
155
+ await environment.readFile(resolve(templateDir, 'package.json'), 'utf8'),
156
+ )
157
+ packageJSON.name = projectName
158
+ if (options.typescript) {
159
+ const tsPackageJSON = JSON.parse(
160
+ await environment.readFile(
161
+ resolve(templateDir, 'package.ts.json'),
162
+ 'utf8',
163
+ ),
164
+ )
165
+ packageJSON = {
166
+ ...packageJSON,
167
+ devDependencies: {
168
+ ...packageJSON.devDependencies,
169
+ ...tsPackageJSON.devDependencies,
170
+ },
171
+ }
172
+ }
173
+ if (options.tailwind) {
174
+ const twPackageJSON = JSON.parse(
175
+ await environment.readFile(
176
+ resolve(templateDir, 'package.tw.json'),
177
+ 'utf8',
178
+ ),
179
+ )
180
+ packageJSON = {
181
+ ...packageJSON,
182
+ dependencies: {
183
+ ...packageJSON.dependencies,
184
+ ...twPackageJSON.dependencies,
185
+ },
186
+ }
187
+ }
188
+ if (options.toolchain === 'biome') {
189
+ const biomePackageJSON = JSON.parse(
190
+ await environment.readFile(
191
+ resolve(templateDir, 'package.biome.json'),
192
+ 'utf8',
193
+ ),
194
+ )
195
+ packageJSON = {
196
+ ...packageJSON,
197
+ scripts: {
198
+ ...packageJSON.scripts,
199
+ ...biomePackageJSON.scripts,
200
+ },
201
+ devDependencies: {
202
+ ...packageJSON.devDependencies,
203
+ ...biomePackageJSON.devDependencies,
204
+ },
205
+ }
206
+ }
207
+ if (options.toolchain === 'eslint+prettier') {
208
+ const eslintPrettierPackageJSON = JSON.parse(
209
+ await environment.readFile(
210
+ resolve(templateDir, 'package.eslintprettier.json'),
211
+ 'utf-8',
212
+ ),
213
+ )
214
+ packageJSON = {
215
+ ...packageJSON,
216
+ scripts: {
217
+ ...packageJSON.scripts,
218
+ ...eslintPrettierPackageJSON.scripts,
219
+ },
220
+ devDependencies: {
221
+ ...packageJSON.devDependencies,
222
+ ...eslintPrettierPackageJSON.devDependencies,
223
+ },
224
+ }
225
+ }
226
+ if (options.mode === FILE_ROUTER) {
227
+ const frPackageJSON = JSON.parse(
228
+ await environment.readFile(resolve(routerDir, 'package.fr.json'), 'utf8'),
229
+ )
230
+ packageJSON = {
231
+ ...packageJSON,
232
+ dependencies: {
233
+ ...packageJSON.dependencies,
234
+ ...frPackageJSON.dependencies,
235
+ },
236
+ }
68
237
  }
69
238
 
70
- if (options.starter) {
71
- environment.startStep({
72
- id: 'write-starter-files',
73
- type: 'file',
74
- message: 'Writing starter files...',
75
- })
76
- await writeFileBundle(options.starter)
77
- environment.finishStep('write-starter-files', 'Starter files written')
239
+ for (const addOn of addOns) {
240
+ packageJSON = {
241
+ ...packageJSON,
242
+ dependencies: {
243
+ ...packageJSON.dependencies,
244
+ ...addOn.dependencies,
245
+ },
246
+ devDependencies: {
247
+ ...packageJSON.devDependencies,
248
+ ...addOn.devDependencies,
249
+ },
250
+ scripts: {
251
+ ...packageJSON.scripts,
252
+ ...addOn.scripts,
253
+ },
254
+ }
78
255
  }
79
256
 
80
- environment.startStep({
81
- id: 'write-package-json',
82
- type: 'file',
83
- message: 'Writing package.json...',
84
- })
257
+ packageJSON.dependencies = sortObject(
258
+ packageJSON.dependencies as Record<string, string>,
259
+ )
260
+ packageJSON.devDependencies = sortObject(
261
+ packageJSON.devDependencies as Record<string, string>,
262
+ )
263
+
85
264
  await environment.writeFile(
86
- resolve(options.targetDir, './package.json'),
87
- JSON.stringify(createPackageJSON(options), null, 2),
265
+ resolve(targetDir, 'package.json'),
266
+ JSON.stringify(packageJSON, null, 2),
88
267
  )
89
- environment.finishStep('write-package-json', 'Package.json written')
90
-
91
- environment.startStep({
92
- id: 'write-config-file',
93
- type: 'file',
94
- message: 'Writing config file...',
95
- })
96
- await writeConfigFileToEnvironment(environment, options)
97
- environment.finishStep('write-config-file', 'Config file written')
98
268
  }
99
269
 
100
- async function runCommandsAndInstallDependencies(
270
+ async function copyAddOnFile(
101
271
  environment: Environment,
272
+ content: string,
273
+ target: string,
274
+ targetPath: string,
275
+ templateFile: (content: string, targetFileName: string) => Promise<void>,
276
+ ) {
277
+ let targetFile = basename(target).replace(/^_dot_/, '.')
278
+ let isTemplate = false
279
+ if (targetFile.endsWith('.ejs')) {
280
+ targetFile = targetFile.replace('.ejs', '')
281
+ isTemplate = true
282
+ }
283
+ let isAppend = false
284
+ if (targetFile.endsWith('.append')) {
285
+ targetFile = targetFile.replace('.append', '')
286
+ isAppend = true
287
+ }
288
+
289
+ const finalTargetPath = resolve(dirname(targetPath), targetFile)
290
+
291
+ const binaryContent = getBinaryFile(content)
292
+ if (binaryContent) {
293
+ await environment.writeFile(
294
+ finalTargetPath,
295
+ binaryContent as unknown as string,
296
+ )
297
+ return
298
+ }
299
+
300
+ if (isTemplate) {
301
+ await templateFile(content, finalTargetPath)
302
+ } else {
303
+ if (isAppend) {
304
+ await environment.appendFile(finalTargetPath, content)
305
+ } else {
306
+ await environment.writeFile(finalTargetPath, content)
307
+ }
308
+ }
309
+ }
310
+
311
+ export async function createApp(
102
312
  options: Options,
313
+ {
314
+ silent = false,
315
+ environment,
316
+ cwd,
317
+ appName = 'TanStack',
318
+ }: {
319
+ silent?: boolean
320
+ environment: Environment
321
+ cwd?: string
322
+ name?: string
323
+ appName?: string
324
+ },
103
325
  ) {
104
- const s = environment.spinner()
326
+ environment.startRun()
105
327
 
106
- // Setup git
107
- if (options.git) {
108
- s.start(`Initializing git repository...`)
109
- environment.startStep({
110
- id: 'initialize-git-repository',
111
- type: 'command',
112
- message: 'Initializing git repository...',
113
- })
328
+ const templateDirBase = resolve(getTemplatesRoot(), options.framework, 'base')
329
+ const templateDirRouter = resolve(
330
+ getTemplatesRoot(),
331
+ options.framework,
332
+ options.mode,
333
+ )
334
+
335
+ let targetDir: string = cwd || ''
336
+ if (!targetDir.length) {
337
+ targetDir = resolve(process.cwd(), options.projectName)
338
+ }
114
339
 
115
- await setupGit(environment, options.targetDir)
340
+ const copyFiles = createCopyFiles(environment, targetDir)
341
+ const templateFileFromContent = createTemplateFile(
342
+ environment,
343
+ options.projectName,
344
+ options,
345
+ targetDir,
346
+ )
116
347
 
117
- environment.finishStep(
118
- 'initialize-git-repository',
119
- 'Initialized git repository',
348
+ async function templateFile(
349
+ templateBase: string,
350
+ file: string,
351
+ targetFileName?: string,
352
+ extraTemplateValues?: Record<string, any>,
353
+ ) {
354
+ const content = await environment.readFile(
355
+ resolve(templateBase, file),
356
+ 'utf-8',
357
+ )
358
+ return templateFileFromContent(
359
+ file,
360
+ content.toString(),
361
+ targetFileName,
362
+ extraTemplateValues,
120
363
  )
121
- s.stop(`Initialized git repository`)
122
364
  }
123
365
 
124
- // Run any special steps for the new add-ons
125
- const specialSteps = new Set<string>([])
126
- for (const addOn of options.chosenAddOns) {
127
- for (const step of addOn.createSpecialSteps || []) {
128
- specialSteps.add(step)
366
+ const isAddOnEnabled = (id: string) =>
367
+ options.chosenAddOns.find((a) => a.id === id)
368
+
369
+ async function runAddOn(addOn: AddOn) {
370
+ if (addOn.files) {
371
+ for (const file of Object.keys(addOn.files)) {
372
+ await copyAddOnFile(
373
+ environment,
374
+ addOn.files[file],
375
+ file,
376
+ resolve(targetDir, file),
377
+ (content, targetFileName) =>
378
+ templateFileFromContent(targetFileName, content),
379
+ )
380
+ }
381
+ }
382
+ if (addOn.deletedFiles) {
383
+ for (const file of addOn.deletedFiles) {
384
+ await environment.deleteFile(resolve(targetDir, file))
385
+ }
386
+ }
387
+
388
+ if (addOn.command && addOn.command.command) {
389
+ await environment.execute(
390
+ addOn.command.command,
391
+ addOn.command.args || [],
392
+ resolve(targetDir),
393
+ )
129
394
  }
130
395
  }
131
- if (specialSteps.size) {
132
- await runSpecialSteps(environment, options, Array.from(specialSteps))
396
+
397
+ // Setup the .vscode directory
398
+ switch (options.toolchain) {
399
+ case 'biome':
400
+ await environment.copyFile(
401
+ resolve(templateDirBase, '_dot_vscode/settings.biome.json'),
402
+ resolve(targetDir, '.vscode/settings.json'),
403
+ )
404
+ break
405
+ case 'none':
406
+ default:
407
+ await environment.copyFile(
408
+ resolve(templateDirBase, '_dot_vscode/settings.json'),
409
+ resolve(targetDir, '.vscode/settings.json'),
410
+ )
133
411
  }
134
412
 
135
- // Install dependencies
136
- s.start(`Installing dependencies via ${options.packageManager}...`)
137
- environment.startStep({
138
- id: 'install-dependencies',
139
- type: 'package-manager',
140
- message: `Installing dependencies via ${options.packageManager}...`,
141
- })
142
- await packageManagerInstall(
413
+ // Fill the public directory
414
+ copyFiles(templateDirBase, [
415
+ './public/robots.txt',
416
+ './public/favicon.ico',
417
+ './public/manifest.json',
418
+ './public/logo192.png',
419
+ './public/logo512.png',
420
+ ])
421
+
422
+ // Check for a .cursorrules file
423
+ if (environment.exists(resolve(templateDirBase, '.cursorrules'))) {
424
+ await environment.copyFile(
425
+ resolve(templateDirBase, '.cursorrules'),
426
+ resolve(targetDir, '.cursorrules'),
427
+ )
428
+ }
429
+
430
+ // Copy in Vite and Tailwind config and CSS
431
+ if (!options.tailwind) {
432
+ await copyFiles(templateDirBase, ['./src/App.css'])
433
+ }
434
+
435
+ // Don't create a vite.config.js file if we are building a Start app
436
+ if (!isAddOnEnabled('start')) {
437
+ await templateFile(templateDirBase, './vite.config.js.ejs')
438
+ }
439
+
440
+ await templateFile(templateDirBase, './src/styles.css.ejs')
441
+
442
+ copyFiles(templateDirBase, ['./src/logo.svg'])
443
+
444
+ if (options.toolchain === 'biome') {
445
+ copyFiles(templateDirBase, ['./toolchain/biome.json'], true)
446
+ }
447
+
448
+ if (options.toolchain === 'eslint+prettier') {
449
+ copyFiles(
450
+ templateDirBase,
451
+ [
452
+ './toolchain/eslint.config.js',
453
+ './toolchain/prettier.config.js',
454
+ './toolchain/.prettierignore',
455
+ ],
456
+ true,
457
+ )
458
+ }
459
+
460
+ // Setup reportWebVitals
461
+ if (!isAddOnEnabled('start') && options.framework === 'react') {
462
+ if (options.typescript) {
463
+ await templateFile(templateDirBase, './src/reportWebVitals.ts.ejs')
464
+ } else {
465
+ await templateFile(
466
+ templateDirBase,
467
+ './src/reportWebVitals.ts.ejs',
468
+ './src/reportWebVitals.js',
469
+ )
470
+ }
471
+ }
472
+ if (!isAddOnEnabled('start')) {
473
+ await templateFile(templateDirBase, './index.html.ejs')
474
+ }
475
+
476
+ // Add .gitignore
477
+ await environment.copyFile(
478
+ resolve(templateDirBase, '_dot_gitignore'),
479
+ resolve(targetDir, '.gitignore'),
480
+ )
481
+
482
+ // Setup tsconfig
483
+ if (options.typescript) {
484
+ await templateFile(
485
+ templateDirBase,
486
+ './tsconfig.json.ejs',
487
+ './tsconfig.json',
488
+ )
489
+ }
490
+
491
+ // Setup the package.json file, optionally with typescript, tailwind and formatter/linter
492
+ await createPackageJSON(
143
493
  environment,
144
- options.targetDir,
145
- options.packageManager,
494
+ options.projectName,
495
+ options,
496
+ templateDirBase,
497
+ templateDirRouter,
498
+ targetDir,
499
+ options.chosenAddOns.map((addOn) => addOn.packageAdditions),
146
500
  )
147
- environment.finishStep('install-dependencies', 'Installed dependencies')
148
- s.stop(`Installed dependencies`)
149
501
 
150
- for (const phase of ['setup', 'add-on', 'example']) {
151
- for (const addOn of options.chosenAddOns.filter(
152
- (addOn) =>
153
- addOn.phase === phase && addOn.command && addOn.command.command,
502
+ // Copy all the asset files from the addons
503
+ const s = silent ? null : spinner()
504
+ for (const type of ['add-on', 'example']) {
505
+ for (const phase of ['setup', 'add-on', 'example']) {
506
+ for (const addOn of options.chosenAddOns.filter(
507
+ (addOn) => addOn.phase === phase && addOn.type === type,
508
+ )) {
509
+ s?.start(`Setting up ${addOn.name}...`)
510
+ await runAddOn(addOn)
511
+ s?.stop(`${addOn.name} setup complete`)
512
+ }
513
+ }
514
+ }
515
+
516
+ if (isAddOnEnabled('shadcn')) {
517
+ const shadcnComponents = new Set<string>()
518
+ for (const addOn of options.chosenAddOns) {
519
+ if (addOn.shadcnComponents) {
520
+ for (const component of addOn.shadcnComponents) {
521
+ shadcnComponents.add(component)
522
+ }
523
+ }
524
+ }
525
+ if (options.overlay) {
526
+ if (options.overlay.shadcnComponents) {
527
+ for (const component of options.overlay.shadcnComponents) {
528
+ shadcnComponents.add(component)
529
+ }
530
+ }
531
+ }
532
+
533
+ if (shadcnComponents.size > 0) {
534
+ s?.start(
535
+ `Installing shadcn components (${Array.from(shadcnComponents).join(', ')})...`,
536
+ )
537
+ await packageManagerExecute(
538
+ environment,
539
+ options.packageManager,
540
+ 'shadcn@latest',
541
+ ['add', '--silent', '--yes', ...shadcnComponents],
542
+ resolve(targetDir),
543
+ )
544
+ s?.stop(`Installed additional shadcn components`)
545
+ }
546
+ }
547
+
548
+ const integrations: Array<{
549
+ type: 'layout' | 'provider' | 'root-provider' | 'header-user'
550
+ name: string
551
+ path: string
552
+ }> = []
553
+ if (environment.exists(resolve(targetDir, 'src/integrations'))) {
554
+ for (const integration of environment.readdir(
555
+ resolve(targetDir, 'src/integrations'),
154
556
  )) {
155
- s.start(`Running commands for ${addOn.name}...`)
156
- const cmd = formatCommand({
157
- command: addOn.command!.command,
158
- args: addOn.command!.args || [],
159
- })
160
- environment.startStep({
161
- id: 'run-commands',
162
- type: 'command',
163
- message: cmd,
557
+ const integrationName = jsSafeName(integration)
558
+ if (
559
+ environment.exists(
560
+ resolve(targetDir, 'src/integrations', integration, 'layout.tsx'),
561
+ )
562
+ ) {
563
+ integrations.push({
564
+ type: 'layout',
565
+ name: `${integrationName}Layout`,
566
+ path: `integrations/${integration}/layout`,
567
+ })
568
+ }
569
+ if (
570
+ environment.exists(
571
+ resolve(targetDir, 'src/integrations', integration, 'provider.tsx'),
572
+ )
573
+ ) {
574
+ integrations.push({
575
+ type: 'provider',
576
+ name: `${integrationName}Provider`,
577
+ path: `integrations/${integration}/provider`,
578
+ })
579
+ }
580
+ if (
581
+ environment.exists(
582
+ resolve(
583
+ targetDir,
584
+ 'src/integrations',
585
+ integration,
586
+ 'root-provider.tsx',
587
+ ),
588
+ )
589
+ ) {
590
+ integrations.push({
591
+ type: 'root-provider',
592
+ name: integrationName,
593
+ path: `integrations/${integration}/root-provider`,
594
+ })
595
+ }
596
+ if (
597
+ environment.exists(
598
+ resolve(
599
+ targetDir,
600
+ 'src/integrations',
601
+ integration,
602
+ 'header-user.tsx',
603
+ ),
604
+ )
605
+ ) {
606
+ integrations.push({
607
+ type: 'header-user',
608
+ name: `${integrationName}Header`,
609
+ path: `integrations/${integration}/header-user`,
610
+ })
611
+ }
612
+ }
613
+ }
614
+
615
+ const routes: Array<{
616
+ path: string
617
+ name: string
618
+ }> = []
619
+ if (environment.exists(resolve(targetDir, 'src/routes'))) {
620
+ for (const file of environment.readdir(resolve(targetDir, 'src/routes'))) {
621
+ const name = file.replace(/\.tsx?|\.jsx?/, '')
622
+ const safeRouteName = jsSafeName(name)
623
+ routes.push({
624
+ path: `./routes/${name}`,
625
+ name: safeRouteName,
164
626
  })
165
- await environment.execute(
166
- addOn.command!.command,
167
- addOn.command!.args || [],
168
- options.targetDir,
627
+ }
628
+ }
629
+
630
+ // Create the main entry point
631
+ if (!isAddOnEnabled('start')) {
632
+ if (options.typescript) {
633
+ await templateFile(
634
+ templateDirRouter,
635
+ './src/main.tsx.ejs',
636
+ './src/main.tsx',
637
+ {
638
+ routes,
639
+ integrations,
640
+ },
641
+ )
642
+ } else {
643
+ await templateFile(
644
+ templateDirRouter,
645
+ './src/main.tsx.ejs',
646
+ './src/main.jsx',
647
+ {
648
+ routes,
649
+ integrations,
650
+ },
651
+ )
652
+ }
653
+ }
654
+
655
+ // Setup the app component. There are four variations, typescript/javascript and tailwind/non-tailwind.
656
+ if (options.mode === FILE_ROUTER) {
657
+ await templateFile(
658
+ templateDirRouter,
659
+ './src/routes/__root.tsx.ejs',
660
+ './src/routes/__root.tsx',
661
+ {
662
+ integrations,
663
+ },
664
+ )
665
+ await templateFile(
666
+ templateDirBase,
667
+ './src/App.tsx.ejs',
668
+ './src/routes/index.tsx',
669
+ )
670
+ } else {
671
+ await templateFile(
672
+ templateDirBase,
673
+ './src/App.tsx.ejs',
674
+ options.typescript ? undefined : './src/App.jsx',
675
+ )
676
+ if (options.framework === 'react') {
677
+ await templateFile(
678
+ templateDirBase,
679
+ './src/App.test.tsx.ejs',
680
+ options.typescript ? undefined : './src/App.test.jsx',
169
681
  )
170
- environment.finishStep('run-commands', 'Setup commands complete')
171
- s.stop(`${addOn.name} commands complete`)
172
682
  }
173
683
  }
174
684
 
175
- // Adding starter
176
685
  if (
177
- options.starter &&
178
- options.starter.command &&
179
- options.starter.command.command
686
+ routes.length > 0 ||
687
+ options.chosenAddOns.length > 0 ||
688
+ integrations.length > 0
180
689
  ) {
181
- s.start(`Setting up starter ${options.starter.name}...`)
182
- const cmd = formatCommand({
183
- command: options.starter.command.command,
184
- args: options.starter.command.args || [],
185
- })
186
- environment.startStep({
187
- id: 'run-starter-command',
188
- type: 'command',
189
- message: cmd,
190
- })
191
-
192
- await environment.execute(
193
- options.starter.command.command,
194
- options.starter.command.args || [],
195
- options.targetDir,
690
+ await templateFile(
691
+ templateDirBase,
692
+ './src/components/Header.tsx.ejs',
693
+ './src/components/Header.tsx',
694
+ {
695
+ integrations,
696
+ },
196
697
  )
197
-
198
- environment.finishStep('run-starter-command', 'Starter command complete')
199
- s.stop(`${options.starter.name} commands complete`)
200
698
  }
201
699
 
202
- await installShadcnComponents(environment, options.targetDir, options)
203
- }
204
-
205
- function report(environment: Environment, options: Options) {
206
700
  const warnings: Array<string> = []
207
701
  for (const addOn of options.chosenAddOns) {
208
702
  if (addOn.warning) {
@@ -210,38 +704,94 @@ function report(environment: Environment, options: Options) {
210
704
  }
211
705
  }
212
706
 
707
+ // Create the README.md
708
+ await templateFile(templateDirBase, 'README.md.ejs')
709
+
710
+ // Adding overlay
711
+ if (options.overlay) {
712
+ s?.start(`Setting up overlay ${options.overlay.name}...`)
713
+ await runAddOn(options.overlay)
714
+ s?.stop(`Overlay ${options.overlay.name} setup complete`)
715
+ }
716
+
717
+ // Install dependencies
718
+ s?.start(`Installing dependencies via ${options.packageManager}...`)
719
+ await environment.execute(
720
+ options.packageManager,
721
+ ['install'],
722
+ resolve(targetDir),
723
+ )
724
+ s?.stop(`Installed dependencies`)
725
+
213
726
  if (warnings.length > 0) {
214
- environment.warn('Warnings', warnings.join('\n'))
727
+ if (!silent) {
728
+ log.warn(chalk.red(warnings.join('\n')))
729
+ }
730
+ }
731
+
732
+ if (options.toolchain === 'biome') {
733
+ s?.start(`Applying toolchain ${options.toolchain}...`)
734
+ switch (options.packageManager) {
735
+ case 'pnpm':
736
+ // pnpm automatically forwards extra arguments
737
+ await environment.execute(
738
+ options.packageManager,
739
+ ['run', 'check', '--fix'],
740
+ resolve(targetDir),
741
+ )
742
+ break
743
+ default:
744
+ await environment.execute(
745
+ options.packageManager,
746
+ ['run', 'check', '--', '--fix'],
747
+ resolve(targetDir),
748
+ )
749
+ break
750
+ }
751
+ s?.stop(`Applied toolchain ${options.toolchain}...`)
752
+ }
753
+
754
+ if (options.toolchain === 'eslint+prettier') {
755
+ s?.start(`Applying toolchain ${options.toolchain}...`)
756
+ await environment.execute(
757
+ options.packageManager,
758
+ ['run', 'check'],
759
+ targetDir,
760
+ )
761
+ s?.stop(`Applied toolchain ${options.toolchain}...`)
762
+ }
763
+
764
+ if (options.git) {
765
+ s?.start(`Initializing git repository...`)
766
+ await environment.execute('git', ['init'], resolve(targetDir))
767
+ s?.stop(`Initialized git repository`)
215
768
  }
216
769
 
217
- // Format errors
770
+ await writeConfigFile(environment, targetDir, options)
771
+
772
+ environment.finishRun()
773
+
218
774
  let errorStatement = ''
219
775
  if (environment.getErrors().length) {
220
776
  errorStatement = `
221
777
 
222
- Errors were encountered during the creation of your app:
778
+ ${chalk.red('Errors were encountered during this process:')}
223
779
 
224
780
  ${environment.getErrors().join('\n')}`
225
781
  }
226
782
 
227
- environment.outro(
228
- `Your ${environment.appName} app is ready in '${basename(options.targetDir)}'.
783
+ if (!silent) {
784
+ let startCommand = `${options.packageManager} ${isAddOnEnabled('start') ? 'dev' : 'start'}`
785
+ if (options.packageManager === 'deno') {
786
+ startCommand = `deno ${isAddOnEnabled('start') ? 'task dev' : 'start'}`
787
+ }
788
+
789
+ outro(`Your ${appName} app is ready in '${basename(targetDir)}'.
229
790
 
230
791
  Use the following commands to start your app:
231
792
  % cd ${options.projectName}
232
- % ${formatCommand(
233
- getPackageManagerScriptCommand(options.packageManager, ['dev']),
234
- )}
235
-
236
- Please check the README.md for more information on testing, styling, adding routes, etc.${errorStatement}`,
237
- )
238
- }
239
-
240
- export async function createApp(environment: Environment, options: Options) {
241
- environment.startRun()
242
- await writeFiles(environment, options)
243
- await runCommandsAndInstallDependencies(environment, options)
244
- environment.finishRun()
793
+ % ${startCommand}
245
794
 
246
- report(environment, options)
795
+ Please check the README.md for more information on testing, styling, adding routes, react-query, etc.${errorStatement}`)
796
+ }
247
797
  }