@tanstack/cta-engine 0.14.3 → 0.15.0

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 (343) hide show
  1. package/dist/add-ons.js +5 -91
  2. package/dist/add-to-app.js +171 -0
  3. package/dist/config-file.js +34 -11
  4. package/dist/constants.js +0 -2
  5. package/dist/create-app.js +142 -451
  6. package/dist/custom-add-ons/add-on.js +175 -0
  7. package/dist/custom-add-ons/shared.js +116 -0
  8. package/dist/custom-add-ons/starter.js +84 -0
  9. package/dist/environment.js +67 -44
  10. package/dist/file-helpers.js +165 -0
  11. package/dist/frameworks.js +92 -0
  12. package/dist/index.js +18 -1
  13. package/dist/integrations/git.js +4 -0
  14. package/dist/integrations/shadcn.js +33 -0
  15. package/dist/options.js +9 -333
  16. package/dist/package-json.js +48 -0
  17. package/dist/package-manager.js +51 -6
  18. package/dist/registry.js +56 -0
  19. package/dist/special-steps/index.js +24 -0
  20. package/dist/special-steps/rimraf-node-modules.js +16 -0
  21. package/dist/template-file.js +112 -0
  22. package/dist/types/add-ons.d.ts +3 -8
  23. package/dist/types/add-to-app.d.ts +17 -0
  24. package/dist/types/config-file.d.ts +7 -4
  25. package/dist/types/constants.d.ts +0 -3
  26. package/dist/types/create-app.d.ts +1 -7
  27. package/dist/types/custom-add-ons/add-on.d.ts +69 -0
  28. package/dist/types/custom-add-ons/shared.d.ts +15 -0
  29. package/dist/types/custom-add-ons/starter.d.ts +7 -0
  30. package/dist/types/environment.d.ts +2 -1
  31. package/dist/types/file-helpers.d.ts +15 -0
  32. package/dist/types/frameworks.d.ts +7 -0
  33. package/dist/types/index.d.ts +21 -1
  34. package/dist/types/integrations/git.d.ts +2 -0
  35. package/dist/types/integrations/shadcn.d.ts +2 -0
  36. package/dist/types/options.d.ts +2 -6
  37. package/dist/types/package-json.d.ts +7 -0
  38. package/dist/types/package-manager.d.ts +18 -1
  39. package/dist/types/registry.d.ts +25 -0
  40. package/dist/types/special-steps/index.d.ts +2 -0
  41. package/dist/types/special-steps/rimraf-node-modules.d.ts +2 -0
  42. package/dist/types/template-file.d.ts +2 -0
  43. package/dist/types/types.d.ts +788 -85
  44. package/dist/types/utils.d.ts +5 -0
  45. package/dist/types.js +65 -1
  46. package/dist/utils.js +9 -0
  47. package/package.json +9 -12
  48. package/src/add-ons.ts +7 -123
  49. package/src/add-to-app.ts +276 -0
  50. package/src/config-file.ts +51 -20
  51. package/src/constants.ts +0 -5
  52. package/src/create-app.ts +180 -730
  53. package/src/custom-add-ons/add-on.ts +261 -0
  54. package/src/custom-add-ons/shared.ts +160 -0
  55. package/src/custom-add-ons/starter.ts +126 -0
  56. package/src/environment.ts +80 -45
  57. package/src/file-helpers.ts +235 -0
  58. package/src/frameworks.ts +134 -0
  59. package/src/index.ts +85 -1
  60. package/src/integrations/git.ts +7 -0
  61. package/src/integrations/shadcn.ts +54 -0
  62. package/src/options.ts +8 -409
  63. package/src/package-json.ts +69 -0
  64. package/src/package-manager.ts +80 -9
  65. package/src/registry.ts +92 -0
  66. package/src/special-steps/index.ts +36 -0
  67. package/src/special-steps/rimraf-node-modules.ts +25 -0
  68. package/src/template-file.ts +150 -0
  69. package/src/types.ts +175 -87
  70. package/src/utils.ts +17 -0
  71. package/tests/add-ons.test.ts +67 -0
  72. package/tests/add-to-app.test.ts +358 -0
  73. package/tests/config-file.test.ts +105 -0
  74. package/tests/create-app.test.ts +120 -0
  75. package/tests/custom-add-ons/add-on.test.ts +12 -0
  76. package/tests/custom-add-ons/shared.test.ts +253 -0
  77. package/tests/custom-add-ons/starter.test.ts +58 -0
  78. package/tests/environment.test.ts +115 -0
  79. package/tests/file-helper.test.ts +90 -0
  80. package/tests/frameworks.test.ts +95 -0
  81. package/tests/index.test.ts +9 -0
  82. package/tests/integrations/git.test.ts +20 -0
  83. package/tests/integrations/shadcn.test.ts +91 -0
  84. package/tests/options.test.ts +42 -0
  85. package/tests/package-json.test.ts +63 -0
  86. package/tests/package-manager.test.ts +154 -0
  87. package/tests/setupVitest.ts +6 -0
  88. package/tests/template-file.test.ts +178 -0
  89. package/tests/utils.test.ts +23 -0
  90. package/vitest.config.ts +21 -0
  91. package/dist/add.js +0 -125
  92. package/dist/cli.js +0 -132
  93. package/dist/custom-add-on.js +0 -254
  94. package/dist/file-helper.js +0 -18
  95. package/dist/mcp.js +0 -229
  96. package/dist/templates.js +0 -6
  97. package/dist/toolchain.js +0 -6
  98. package/dist/types/add.d.ts +0 -3
  99. package/dist/types/cli.d.ts +0 -7
  100. package/dist/types/custom-add-on.d.ts +0 -3
  101. package/dist/types/file-helper.d.ts +0 -2
  102. package/dist/types/mcp.d.ts +0 -7
  103. package/dist/types/templates.d.ts +0 -1
  104. package/dist/types/toolchain.d.ts +0 -3
  105. package/src/add.ts +0 -186
  106. package/src/cli.ts +0 -210
  107. package/src/custom-add-on.ts +0 -325
  108. package/src/file-helper.ts +0 -20
  109. package/src/mcp.ts +0 -302
  110. package/src/templates.ts +0 -7
  111. package/src/toolchain.ts +0 -7
  112. package/templates/react/add-on/clerk/README.md +0 -3
  113. package/templates/react/add-on/clerk/assets/_dot_env.local.append +0 -2
  114. package/templates/react/add-on/clerk/assets/src/integrations/clerk/header-user.tsx +0 -19
  115. package/templates/react/add-on/clerk/assets/src/integrations/clerk/provider.tsx +0 -18
  116. package/templates/react/add-on/clerk/assets/src/routes/demo.clerk.tsx +0 -20
  117. package/templates/react/add-on/clerk/info.json +0 -13
  118. package/templates/react/add-on/clerk/package.json +0 -5
  119. package/templates/react/add-on/convex/README.md +0 -4
  120. package/templates/react/add-on/convex/assets/_dot_cursorrules.append +0 -93
  121. package/templates/react/add-on/convex/assets/_dot_env.local.append +0 -3
  122. package/templates/react/add-on/convex/assets/convex/products.ts +0 -8
  123. package/templates/react/add-on/convex/assets/convex/schema.ts +0 -10
  124. package/templates/react/add-on/convex/assets/src/integrations/convex/provider.tsx +0 -20
  125. package/templates/react/add-on/convex/assets/src/routes/demo.convex.tsx +0 -33
  126. package/templates/react/add-on/convex/info.json +0 -13
  127. package/templates/react/add-on/convex/package.json +0 -6
  128. package/templates/react/add-on/form/assets/src/components/demo.FormComponents.tsx.ejs +0 -300
  129. package/templates/react/add-on/form/assets/src/hooks/demo.form-context.ts +0 -4
  130. package/templates/react/add-on/form/assets/src/hooks/demo.form.ts +0 -22
  131. package/templates/react/add-on/form/assets/src/routes/demo.form.address.tsx.ejs +0 -213
  132. package/templates/react/add-on/form/assets/src/routes/demo.form.simple.tsx.ejs +0 -77
  133. package/templates/react/add-on/form/info.json +0 -26
  134. package/templates/react/add-on/form/package.json +0 -6
  135. package/templates/react/add-on/module-federation/assets/module-federation.config.js.ejs +0 -31
  136. package/templates/react/add-on/module-federation/assets/src/demo-mf-component.tsx +0 -3
  137. package/templates/react/add-on/module-federation/assets/src/demo-mf-self-contained.tsx +0 -11
  138. package/templates/react/add-on/module-federation/info.json +0 -7
  139. package/templates/react/add-on/module-federation/package.json +0 -5
  140. package/templates/react/add-on/netlify/README.md +0 -11
  141. package/templates/react/add-on/netlify/info.json +0 -7
  142. package/templates/react/add-on/sentry/assets/_dot_cursorrules.append +0 -22
  143. package/templates/react/add-on/sentry/assets/_dot_env.local.append +0 -11
  144. package/templates/react/add-on/sentry/assets/src/app/global-middleware.ts +0 -11
  145. package/templates/react/add-on/sentry/assets/src/routes/demo.sentry.testing.tsx +0 -489
  146. package/templates/react/add-on/sentry/info.json +0 -14
  147. package/templates/react/add-on/sentry/package.json +0 -5
  148. package/templates/react/add-on/shadcn/README.md +0 -7
  149. package/templates/react/add-on/shadcn/assets/_dot_cursorrules.append +0 -7
  150. package/templates/react/add-on/shadcn/assets/components.json +0 -21
  151. package/templates/react/add-on/shadcn/assets/src/lib/utils.ts +0 -6
  152. package/templates/react/add-on/shadcn/assets/src/styles.css +0 -138
  153. package/templates/react/add-on/shadcn/info.json +0 -7
  154. package/templates/react/add-on/shadcn/package.json +0 -9
  155. package/templates/react/add-on/start/assets/_dot_gitignore.append +0 -2
  156. package/templates/react/add-on/start/assets/app.config.ts.ejs +0 -32
  157. package/templates/react/add-on/start/assets/src/api.ts +0 -6
  158. package/templates/react/add-on/start/assets/src/client.tsx.ejs +0 -33
  159. package/templates/react/add-on/start/assets/src/router.tsx.ejs +0 -48
  160. package/templates/react/add-on/start/assets/src/routes/api.demo-names.ts +0 -11
  161. package/templates/react/add-on/start/assets/src/routes/demo.start.api-request.tsx.ejs +0 -33
  162. package/templates/react/add-on/start/assets/src/routes/demo.start.server-funcs.tsx +0 -50
  163. package/templates/react/add-on/start/assets/src/ssr.tsx.ejs +0 -30
  164. package/templates/react/add-on/start/info.json +0 -18
  165. package/templates/react/add-on/start/package.json +0 -13
  166. package/templates/react/add-on/store/assets/src/lib/demo-store.ts +0 -13
  167. package/templates/react/add-on/store/assets/src/routes/demo.store.tsx.ejs +0 -75
  168. package/templates/react/add-on/store/info.json +0 -13
  169. package/templates/react/add-on/store/package.json +0 -6
  170. package/templates/react/add-on/t3env/README.md +0 -16
  171. package/templates/react/add-on/t3env/assets/src/env.ts +0 -39
  172. package/templates/react/add-on/t3env/info.json +0 -10
  173. package/templates/react/add-on/t3env/package.json +0 -6
  174. package/templates/react/add-on/tRPC/assets/src/integrations/trpc/init.ts +0 -9
  175. package/templates/react/add-on/tRPC/assets/src/integrations/trpc/react.ts +0 -4
  176. package/templates/react/add-on/tRPC/assets/src/integrations/trpc/router.ts +0 -18
  177. package/templates/react/add-on/tRPC/assets/src/routes/api.trpc.$.tsx +0 -16
  178. package/templates/react/add-on/tRPC/info.json +0 -9
  179. package/templates/react/add-on/tRPC/package.json +0 -9
  180. package/templates/react/add-on/table/assets/src/data/demo-table-data.ts +0 -50
  181. package/templates/react/add-on/table/assets/src/routes/demo.table.tsx.ejs +0 -373
  182. package/templates/react/add-on/table/info.json +0 -13
  183. package/templates/react/add-on/table/package.json +0 -7
  184. package/templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/layout.tsx +0 -5
  185. package/templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/root-provider.tsx.ejs +0 -70
  186. package/templates/react/add-on/tanstack-query/assets/src/routes/demo.tanstack-query.tsx.ejs +0 -53
  187. package/templates/react/add-on/tanstack-query/info.json +0 -13
  188. package/templates/react/add-on/tanstack-query/package.json +0 -6
  189. package/templates/react/base/README.md.ejs +0 -558
  190. package/templates/react/base/_dot_gitignore +0 -5
  191. package/templates/react/base/_dot_vscode/settings.biome.json +0 -38
  192. package/templates/react/base/_dot_vscode/settings.json +0 -11
  193. package/templates/react/base/index.html.ejs +0 -20
  194. package/templates/react/base/package.biome.json +0 -10
  195. package/templates/react/base/package.eslintprettier.json +0 -11
  196. package/templates/react/base/package.json +0 -30
  197. package/templates/react/base/package.ts.json +0 -7
  198. package/templates/react/base/package.tw.json +0 -6
  199. package/templates/react/base/public/favicon.ico +0 -0
  200. package/templates/react/base/public/logo192.png +0 -0
  201. package/templates/react/base/public/logo512.png +0 -0
  202. package/templates/react/base/public/manifest.json +0 -25
  203. package/templates/react/base/public/robots.txt +0 -3
  204. package/templates/react/base/src/App.css +0 -38
  205. package/templates/react/base/src/App.test.tsx.ejs +0 -10
  206. package/templates/react/base/src/App.tsx.ejs +0 -74
  207. package/templates/react/base/src/components/Header.tsx.ejs +0 -27
  208. package/templates/react/base/src/logo.svg +0 -44
  209. package/templates/react/base/src/reportWebVitals.ts.ejs +0 -28
  210. package/templates/react/base/src/styles.css.ejs +0 -15
  211. package/templates/react/base/toolchain/.prettierignore +0 -3
  212. package/templates/react/base/toolchain/biome.json +0 -31
  213. package/templates/react/base/toolchain/eslint.config.js +0 -5
  214. package/templates/react/base/toolchain/prettier.config.js +0 -10
  215. package/templates/react/base/tsconfig.json.ejs +0 -29
  216. package/templates/react/base/vite.config.js.ejs +0 -23
  217. package/templates/react/code-router/src/main.tsx.ejs +0 -92
  218. package/templates/react/example/tanchat/README.md +0 -37
  219. package/templates/react/example/tanchat/assets/_dot_env.local.append +0 -2
  220. package/templates/react/example/tanchat/assets/public/example-guitar-flowers.jpg +0 -0
  221. package/templates/react/example/tanchat/assets/public/example-guitar-motherboard.jpg +0 -0
  222. package/templates/react/example/tanchat/assets/public/example-guitar-racing.jpg +0 -0
  223. package/templates/react/example/tanchat/assets/public/example-guitar-steamer-trunk.jpg +0 -0
  224. package/templates/react/example/tanchat/assets/public/example-guitar-superhero.jpg +0 -0
  225. package/templates/react/example/tanchat/assets/public/example-guitar-traveling.jpg +0 -0
  226. package/templates/react/example/tanchat/assets/public/example-guitar-video-games.jpg +0 -0
  227. package/templates/react/example/tanchat/assets/src/components/example-AIAssistant.tsx +0 -173
  228. package/templates/react/example/tanchat/assets/src/components/example-GuitarRecommendation.tsx +0 -47
  229. package/templates/react/example/tanchat/assets/src/data/example-guitars.ts +0 -83
  230. package/templates/react/example/tanchat/assets/src/demo.index.css +0 -220
  231. package/templates/react/example/tanchat/assets/src/integrations/tanchat/header-user.tsx +0 -5
  232. package/templates/react/example/tanchat/assets/src/routes/api.messages.ts +0 -24
  233. package/templates/react/example/tanchat/assets/src/routes/api.sse.ts +0 -23
  234. package/templates/react/example/tanchat/assets/src/routes/example.chat.tsx +0 -159
  235. package/templates/react/example/tanchat/assets/src/routes/example.guitars/$guitarId.tsx +0 -50
  236. package/templates/react/example/tanchat/assets/src/routes/example.guitars/index.tsx +0 -54
  237. package/templates/react/example/tanchat/assets/src/store/example-assistant.ts +0 -3
  238. package/templates/react/example/tanchat/assets/src/utils/demo.ai.ts +0 -62
  239. package/templates/react/example/tanchat/assets/src/utils/demo.sse.ts +0 -31
  240. package/templates/react/example/tanchat/assets/src/utils/demo.tools.ts +0 -47
  241. package/templates/react/example/tanchat/info.json +0 -19
  242. package/templates/react/example/tanchat/package.json +0 -16
  243. package/templates/react/file-router/package.fr.json +0 -5
  244. package/templates/react/file-router/src/main.tsx.ejs +0 -55
  245. package/templates/react/file-router/src/routes/__root.tsx.ejs +0 -82
  246. package/templates/solid/add-on/form/assets/src/routes/demo.form.tsx.ejs +0 -352
  247. package/templates/solid/add-on/form/info.json +0 -13
  248. package/templates/solid/add-on/form/package.json +0 -5
  249. package/templates/solid/add-on/module-federation/assets/module-federation.config.js.ejs +0 -27
  250. package/templates/solid/add-on/module-federation/assets/src/demo-mf-component.tsx +0 -3
  251. package/templates/solid/add-on/module-federation/assets/src/demo-mf-self-contained.tsx +0 -9
  252. package/templates/solid/add-on/module-federation/info.json +0 -7
  253. package/templates/solid/add-on/module-federation/package.json +0 -5
  254. package/templates/solid/add-on/sentry/assets/_dot_cursorrules.append +0 -22
  255. package/templates/solid/add-on/sentry/assets/_dot_env.local.append +0 -2
  256. package/templates/solid/add-on/sentry/assets/src/routes/demo.sentry.bad-event-handler.tsx +0 -20
  257. package/templates/solid/add-on/sentry/info.json +0 -13
  258. package/templates/solid/add-on/sentry/package.json +0 -5
  259. package/templates/solid/add-on/solid-ui/README.md +0 -9
  260. package/templates/solid/add-on/solid-ui/assets/src/lib/utils.ts +0 -6
  261. package/templates/solid/add-on/solid-ui/assets/src/styles.css +0 -138
  262. package/templates/solid/add-on/solid-ui/assets/ui.config.json +0 -13
  263. package/templates/solid/add-on/solid-ui/info.json +0 -11
  264. package/templates/solid/add-on/solid-ui/package.json +0 -9
  265. package/templates/solid/add-on/start/assets/app.config.ts +0 -16
  266. package/templates/solid/add-on/start/assets/src/api.ts +0 -6
  267. package/templates/solid/add-on/start/assets/src/client.tsx +0 -7
  268. package/templates/solid/add-on/start/assets/src/router.tsx.ejs +0 -24
  269. package/templates/solid/add-on/start/assets/src/routes/demo.start.server-funcs.tsx +0 -49
  270. package/templates/solid/add-on/start/assets/src/ssr.tsx +0 -12
  271. package/templates/solid/add-on/start/info.json +0 -14
  272. package/templates/solid/add-on/start/package.json +0 -12
  273. package/templates/solid/add-on/store/assets/src/lib/demo-store.ts +0 -13
  274. package/templates/solid/add-on/store/assets/src/routes/demo.store.tsx.ejs +0 -77
  275. package/templates/solid/add-on/store/info.json +0 -13
  276. package/templates/solid/add-on/store/package.json +0 -6
  277. package/templates/solid/add-on/t3env/README.md +0 -16
  278. package/templates/solid/add-on/t3env/assets/src/env.ts +0 -39
  279. package/templates/solid/add-on/t3env/info.json +0 -10
  280. package/templates/solid/add-on/t3env/package.json +0 -6
  281. package/templates/solid/add-on/tanstack-query/assets/src/integrations/tanstack-query/header-user.tsx +0 -5
  282. package/templates/solid/add-on/tanstack-query/assets/src/integrations/tanstack-query/provider.tsx +0 -15
  283. package/templates/solid/add-on/tanstack-query/assets/src/routes/demo.tanstack-query.tsx +0 -30
  284. package/templates/solid/add-on/tanstack-query/info.json +0 -13
  285. package/templates/solid/add-on/tanstack-query/package.json +0 -6
  286. package/templates/solid/base/README.md.ejs +0 -215
  287. package/templates/solid/base/_dot_cursorrules.append +0 -35
  288. package/templates/solid/base/_dot_gitignore +0 -5
  289. package/templates/solid/base/_dot_vscode/settings.biome.json +0 -38
  290. package/templates/solid/base/_dot_vscode/settings.json +0 -11
  291. package/templates/solid/base/index.html.ejs +0 -20
  292. package/templates/solid/base/package.biome.json +0 -10
  293. package/templates/solid/base/package.eslintprettier.json +0 -11
  294. package/templates/solid/base/package.json +0 -23
  295. package/templates/solid/base/package.ts.json +0 -5
  296. package/templates/solid/base/package.tw.json +0 -6
  297. package/templates/solid/base/public/favicon.ico +0 -0
  298. package/templates/solid/base/public/logo192.png +0 -0
  299. package/templates/solid/base/public/logo512.png +0 -0
  300. package/templates/solid/base/public/manifest.json +0 -25
  301. package/templates/solid/base/public/robots.txt +0 -3
  302. package/templates/solid/base/src/App.css +0 -0
  303. package/templates/solid/base/src/App.tsx.ejs +0 -47
  304. package/templates/solid/base/src/components/Header.tsx.ejs +0 -26
  305. package/templates/solid/base/src/logo.svg +0 -120
  306. package/templates/solid/base/src/styles.css.ejs +0 -15
  307. package/templates/solid/base/toolchain/.prettierignore +0 -3
  308. package/templates/solid/base/toolchain/biome.json +0 -31
  309. package/templates/solid/base/toolchain/eslint.config.js +0 -5
  310. package/templates/solid/base/toolchain/prettier.config.js +0 -10
  311. package/templates/solid/base/tsconfig.json.ejs +0 -31
  312. package/templates/solid/base/vite.config.js.ejs +0 -22
  313. package/templates/solid/code-router/src/main.tsx.ejs +0 -71
  314. package/templates/solid/example/tanchat/README.md +0 -52
  315. package/templates/solid/example/tanchat/assets/ai-streaming-server/README.md +0 -110
  316. package/templates/solid/example/tanchat/assets/ai-streaming-server/_dot_env.example +0 -1
  317. package/templates/solid/example/tanchat/assets/ai-streaming-server/package.json +0 -26
  318. package/templates/solid/example/tanchat/assets/ai-streaming-server/src/index.ts +0 -102
  319. package/templates/solid/example/tanchat/assets/ai-streaming-server/tsconfig.json +0 -15
  320. package/templates/solid/example/tanchat/assets/src/components/demo.SettingsDialog.tsx +0 -149
  321. package/templates/solid/example/tanchat/assets/src/demo.index.css +0 -227
  322. package/templates/solid/example/tanchat/assets/src/lib/demo-store.ts +0 -13
  323. package/templates/solid/example/tanchat/assets/src/routes/example.chat.tsx +0 -435
  324. package/templates/solid/example/tanchat/assets/src/store/demo.hooks.ts +0 -17
  325. package/templates/solid/example/tanchat/assets/src/store/demo.store.ts +0 -133
  326. package/templates/solid/example/tanchat/info.json +0 -14
  327. package/templates/solid/example/tanchat/package.json +0 -7
  328. package/templates/solid/file-router/package.fr.json +0 -5
  329. package/templates/solid/file-router/src/main.tsx.ejs +0 -47
  330. package/templates/solid/file-router/src/routes/__root.tsx.ejs +0 -41
  331. package/templates/solid/file-router/src/routes/index.tsx +0 -43
  332. package/tests/cra.test.ts +0 -293
  333. package/tests/snapshots/cra/cr-js-npm.json +0 -33
  334. package/tests/snapshots/cra/cr-ts-npm.json +0 -34
  335. package/tests/snapshots/cra/cr-ts-start-npm.json +0 -38
  336. package/tests/snapshots/cra/fr-ts-npm.json +0 -34
  337. package/tests/snapshots/cra/fr-ts-tw-npm.json +0 -33
  338. package/tests/snapshots/cra/solid-cr-js-npm.json +0 -31
  339. package/tests/snapshots/cra/solid-cr-ts-npm.json +0 -32
  340. package/tests/snapshots/cra/solid-cr-ts-start-npm.json +0 -36
  341. package/tests/snapshots/cra/solid-fr-ts-npm.json +0 -33
  342. package/tests/snapshots/cra/solid-fr-ts-tw-npm.json +0 -32
  343. package/tests/test-utilities.ts +0 -87
package/src/create-app.ts CHANGED
@@ -1,702 +1,208 @@
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
- ) {
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()
23
23
  for (const file of files) {
24
- let targetFileName = file.replace('.tw', '')
25
- if (toRoot) {
26
- const fileNoPath = targetFileName.split('/').pop()
27
- targetFileName = fileNoPath ? `./${fileNoPath}` : targetFileName
28
- }
29
- await environment.copyFile(
30
- resolve(templateDir, file),
31
- resolve(targetDir, targetFileName),
32
- )
33
- }
34
- }
35
- }
36
-
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
- }
43
-
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
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)
73
33
  }
74
- return command
75
34
  }
76
35
 
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
36
+ const deletedFiles = await bundle.getDeletedFiles()
37
+ for (const file of deletedFiles) {
38
+ await environment.deleteFile(resolve(options.targetDir, file))
92
39
  }
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,
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)
138
40
  }
139
- }
140
41
 
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
- },
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')
49
+
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
63
+ }
205
64
  }
206
65
  }
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
- }
66
+ if (wroteAddonFiles) {
67
+ environment.finishStep('write-addon-files', 'Add-on files written')
237
68
  }
238
69
 
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
- }
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')
255
78
  }
256
79
 
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
-
80
+ environment.startStep({
81
+ id: 'write-package-json',
82
+ type: 'file',
83
+ message: 'Writing package.json...',
84
+ })
264
85
  await environment.writeFile(
265
- resolve(targetDir, 'package.json'),
266
- JSON.stringify(packageJSON, null, 2),
86
+ resolve(options.targetDir, './package.json'),
87
+ JSON.stringify(createPackageJSON(options), null, 2),
267
88
  )
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')
268
98
  }
269
99
 
270
- async function copyAddOnFile(
100
+ async function runCommandsAndInstallDependencies(
271
101
  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(
312
102
  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
- },
325
103
  ) {
326
- environment.startRun()
327
-
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
- }
339
-
340
- const copyFiles = createCopyFiles(environment, targetDir)
341
- const templateFileFromContent = createTemplateFile(
342
- environment,
343
- options.projectName,
344
- options,
345
- targetDir,
346
- )
347
-
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,
363
- )
364
- }
365
-
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
- }
104
+ const s = environment.spinner()
387
105
 
388
- if (addOn.command && addOn.command.command) {
389
- await environment.execute(
390
- addOn.command.command,
391
- addOn.command.args || [],
392
- resolve(targetDir),
393
- )
394
- }
395
- }
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
- )
411
- }
412
-
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')
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
+ })
441
114
 
442
- copyFiles(templateDirBase, ['./src/logo.svg'])
115
+ await setupGit(environment, options.targetDir)
443
116
 
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,
117
+ environment.finishStep(
118
+ 'initialize-git-repository',
119
+ 'Initialized git repository',
457
120
  )
121
+ s.stop(`Initialized git repository`)
458
122
  }
459
123
 
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
- )
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)
470
129
  }
471
130
  }
472
- if (!isAddOnEnabled('start')) {
473
- await templateFile(templateDirBase, './index.html.ejs')
131
+ if (specialSteps.size) {
132
+ await runSpecialSteps(environment, options, Array.from(specialSteps))
474
133
  }
475
134
 
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(
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(
493
143
  environment,
494
- options.projectName,
495
- options,
496
- templateDirBase,
497
- templateDirRouter,
498
- targetDir,
499
- options.chosenAddOns.map((addOn) => addOn.packageAdditions),
144
+ options.targetDir,
145
+ options.packageManager,
500
146
  )
147
+ environment.finishStep('install-dependencies', 'Installed dependencies')
148
+ s.stop(`Installed dependencies`)
501
149
 
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'),
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,
556
154
  )) {
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,
155
+ s.start(`Running commands for ${addOn.name}...`)
156
+ const cmd = formatCommand({
157
+ command: addOn.command!.command,
158
+ args: addOn.command!.args || [],
626
159
  })
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',
160
+ environment.startStep({
161
+ id: 'run-commands',
162
+ type: 'command',
163
+ message: cmd,
164
+ })
165
+ await environment.execute(
166
+ addOn.command!.command,
167
+ addOn.command!.args || [],
168
+ options.targetDir,
681
169
  )
170
+ environment.finishStep('run-commands', 'Setup commands complete')
171
+ s.stop(`${addOn.name} commands complete`)
682
172
  }
683
173
  }
684
174
 
175
+ // Adding starter
685
176
  if (
686
- routes.length > 0 ||
687
- options.chosenAddOns.length > 0 ||
688
- integrations.length > 0
177
+ options.starter &&
178
+ options.starter.command &&
179
+ options.starter.command.command
689
180
  ) {
690
- await templateFile(
691
- templateDirBase,
692
- './src/components/Header.tsx.ejs',
693
- './src/components/Header.tsx',
694
- {
695
- integrations,
696
- },
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,
697
196
  )
197
+
198
+ environment.finishStep('run-starter-command', 'Starter command complete')
199
+ s.stop(`${options.starter.name} commands complete`)
698
200
  }
699
201
 
202
+ await installShadcnComponents(environment, options.targetDir, options)
203
+ }
204
+
205
+ function report(environment: Environment, options: Options) {
700
206
  const warnings: Array<string> = []
701
207
  for (const addOn of options.chosenAddOns) {
702
208
  if (addOn.warning) {
@@ -704,94 +210,38 @@ export async function createApp(
704
210
  }
705
211
  }
706
212
 
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
-
726
213
  if (warnings.length > 0) {
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`)
214
+ environment.warn('Warnings', warnings.join('\n'))
768
215
  }
769
216
 
770
- await writeConfigFile(environment, targetDir, options)
771
-
772
- environment.finishRun()
773
-
217
+ // Format errors
774
218
  let errorStatement = ''
775
219
  if (environment.getErrors().length) {
776
220
  errorStatement = `
777
221
 
778
- ${chalk.red('Errors were encountered during this process:')}
222
+ Errors were encountered during the creation of your app:
779
223
 
780
224
  ${environment.getErrors().join('\n')}`
781
225
  }
782
226
 
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)}'.
227
+ environment.outro(
228
+ `Your ${environment.appName} app is ready in '${basename(options.targetDir)}'.
790
229
 
791
230
  Use the following commands to start your app:
792
231
  % cd ${options.projectName}
793
- % ${startCommand}
232
+ % ${formatCommand(
233
+ getPackageManagerScriptCommand(options.packageManager, ['dev']),
234
+ )}
794
235
 
795
- Please check the README.md for more information on testing, styling, adding routes, react-query, etc.${errorStatement}`)
796
- }
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()
245
+
246
+ report(environment, options)
797
247
  }