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

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 +64 -32
  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 +77 -33
  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 -35
  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 -35
  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
@@ -3,13 +3,21 @@ import {
3
3
  copyFile,
4
4
  mkdir,
5
5
  readFile,
6
+ readdir,
6
7
  unlink,
7
8
  writeFile,
8
9
  } from 'node:fs/promises'
9
- import { existsSync, readdirSync, statSync } from 'node:fs'
10
+ import { existsSync, statSync } from 'node:fs'
10
11
  import { dirname } from 'node:path'
11
12
  import { execa } from 'execa'
12
13
  import { memfs } from 'memfs'
14
+ import { rimraf } from 'rimraf'
15
+
16
+ import {
17
+ cleanUpFileArray,
18
+ cleanUpFiles,
19
+ getBinaryFile,
20
+ } from './file-helpers.js'
13
21
 
14
22
  import type { Environment } from './types.js'
15
23
 
@@ -34,37 +42,63 @@ export function createDefaultEnvironment(): Environment {
34
42
  await mkdir(dirname(path), { recursive: true })
35
43
  return writeFile(path, contents)
36
44
  },
45
+ writeFileBase64: async (path: string, base64Contents: string) => {
46
+ await mkdir(dirname(path), { recursive: true })
47
+ return writeFile(path, getBinaryFile(base64Contents) as string)
48
+ },
37
49
  execute: async (command: string, args: Array<string>, cwd: string) => {
38
50
  try {
39
- await execa(command, args, {
51
+ const result = await execa(command, args, {
40
52
  cwd,
41
53
  })
54
+ return { stdout: result.stdout }
42
55
  } catch {
43
56
  errors.push(
44
57
  `Command "${command} ${args.join(' ')}" did not run successfully. Please run this manually in your project.`,
45
58
  )
59
+ return { stdout: '' }
46
60
  }
47
61
  },
48
62
  deleteFile: async (path: string) => {
49
- await unlink(path)
63
+ if (existsSync(path)) {
64
+ await unlink(path)
65
+ }
50
66
  },
51
67
 
52
- readFile: (path: string, encoding?: BufferEncoding) =>
53
- readFile(path, { encoding: encoding || 'utf8' }),
68
+ readFile: async (path: string) => {
69
+ return (await readFile(path)).toString()
70
+ },
54
71
  exists: (path: string) => existsSync(path),
55
- readdir: (path) => readdirSync(path),
56
- isDirectory: (path) => {
57
- const stat = statSync(path)
58
- return stat.isDirectory()
72
+ isDirectory: (path: string) => statSync(path).isDirectory(),
73
+ readdir: async (path: string) => readdir(path),
74
+ rimraf: async (path: string) => {
75
+ await rimraf(path)
59
76
  },
77
+
78
+ appName: 'TanStack',
79
+
80
+ startStep: () => {},
81
+ finishStep: () => {},
82
+
83
+ intro: () => {},
84
+ outro: () => {},
85
+ info: () => {},
86
+ error: () => {},
87
+ warn: () => {},
88
+ confirm: () => Promise.resolve(true),
89
+ spinner: () => ({
90
+ start: () => {},
91
+ stop: () => {},
92
+ }),
60
93
  }
61
94
  }
62
95
 
63
- export function createMemoryEnvironment() {
96
+ export function createMemoryEnvironment(returnPathsRelativeTo: string = '') {
64
97
  const environment = createDefaultEnvironment()
65
98
 
66
99
  const output: {
67
100
  files: Record<string, string>
101
+ deletedFiles: Array<string>
68
102
  commands: Array<{
69
103
  command: string
70
104
  args: Array<string>
@@ -72,6 +106,7 @@ export function createMemoryEnvironment() {
72
106
  } = {
73
107
  files: {},
74
108
  commands: [],
109
+ deletedFiles: [],
75
110
  }
76
111
 
77
112
  const { fs, vol } = memfs({})
@@ -99,43 +134,52 @@ export function createMemoryEnvironment() {
99
134
  command,
100
135
  args,
101
136
  })
102
- return Promise.resolve()
137
+ return Promise.resolve({ stdout: '' })
103
138
  }
104
- environment.readFile = async (path: string, encoding?: BufferEncoding) => {
105
- if (isTemplatePath(path)) {
106
- return (await readFile(path, encoding)).toString()
107
- }
108
- return fs.readFileSync(path, 'utf8').toString()
139
+ environment.readFile = async (path: string) => {
140
+ return Promise.resolve(fs.readFileSync(path, 'utf-8').toString())
109
141
  }
110
142
  environment.writeFile = async (path: string, contents: string) => {
111
143
  fs.mkdirSync(dirname(path), { recursive: true })
112
144
  await fs.writeFileSync(path, contents)
113
145
  }
114
- environment.deleteFile = async (path: string) => {
115
- await fs.unlinkSync(path)
146
+ environment.writeFileBase64 = async (path: string, contents: string) => {
147
+ // For the in-memory file system, we are not converting the base64 to binary
148
+ // because it's not needed.
149
+ fs.mkdirSync(dirname(path), { recursive: true })
150
+ await fs.writeFileSync(path, contents)
116
151
  }
117
- environment.exists = (path: string) => {
118
- if (isTemplatePath(path)) {
119
- return existsSync(path)
152
+ environment.deleteFile = async (path: string) => {
153
+ output.deletedFiles.push(path)
154
+ if (fs.existsSync(path)) {
155
+ await fs.unlinkSync(path)
120
156
  }
121
- return fs.existsSync(path)
122
157
  }
123
- environment.readdir = (path: string) => {
124
- if (isTemplatePath(path)) {
125
- return readdirSync(path)
158
+ environment.finishRun = () => {
159
+ output.files = vol.toJSON() as Record<string, string>
160
+ for (const file of Object.keys(output.files)) {
161
+ if (fs.statSync(file).isDirectory()) {
162
+ delete output.files[file]
163
+ }
126
164
  }
127
- return fs.readdirSync(path).map((file) => file.toString())
128
- }
129
- environment.isDirectory = (path) => {
130
- if (isTemplatePath(path)) {
131
- const stat = statSync(path)
132
- return stat.isDirectory()
165
+ if (returnPathsRelativeTo.length) {
166
+ output.files = cleanUpFiles(output.files, returnPathsRelativeTo)
167
+ output.deletedFiles = cleanUpFileArray(
168
+ output.deletedFiles,
169
+ returnPathsRelativeTo,
170
+ )
133
171
  }
172
+ }
173
+ environment.exists = (path: string) => {
174
+ return fs.existsSync(path)
175
+ }
176
+ environment.isDirectory = (path: string) => {
134
177
  return fs.statSync(path).isDirectory()
135
178
  }
136
- environment.finishRun = () => {
137
- output.files = vol.toJSON() as Record<string, string>
179
+ environment.readdir = async (path: string) => {
180
+ return Promise.resolve(fs.readdirSync(path).map((d) => d.toString()))
138
181
  }
182
+ environment.rimraf = async () => {}
139
183
 
140
184
  return {
141
185
  environment,
@@ -0,0 +1,235 @@
1
+ import { readdir } from 'node:fs/promises'
2
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'
3
+ import { basename, extname, resolve } from 'node:path'
4
+ import parseGitignore from 'parse-gitignore'
5
+ import ignore from 'ignore'
6
+
7
+ import type { Environment } from './types'
8
+
9
+ const BINARY_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico']
10
+
11
+ export function readFileHelper(path: string): string {
12
+ if (isBinaryFile(path)) {
13
+ return `base64::${readFileSync(path).toString('base64')}`
14
+ } else {
15
+ return readFileSync(path, 'utf-8').toString()
16
+ }
17
+ }
18
+
19
+ export function isBinaryFile(path: string): boolean {
20
+ return BINARY_EXTENSIONS.includes(extname(path))
21
+ }
22
+
23
+ export function convertBinaryContentsToBase64(contents: any): string {
24
+ return `base64::${Buffer.from(contents).toString('base64')}`
25
+ }
26
+
27
+ export function isBase64(content: string): boolean {
28
+ return content.startsWith('base64::')
29
+ }
30
+
31
+ export function getBinaryFile(content: string): string | null {
32
+ if (content.startsWith('base64::')) {
33
+ const binaryContent = Buffer.from(content.replace('base64::', ''), 'base64')
34
+ return binaryContent as unknown as string
35
+ }
36
+ return null
37
+ }
38
+
39
+ export function relativePath(from: string, to: string) {
40
+ const cleanedFrom = from.startsWith('./') ? from.slice(2) : from
41
+ const cleanedTo = to.startsWith('./') ? to.slice(2) : to
42
+
43
+ const fromSegments = cleanedFrom.split('/')
44
+ const toSegments = cleanedTo.split('/')
45
+
46
+ fromSegments.pop()
47
+ toSegments.pop()
48
+
49
+ let commonIndex = 0
50
+ while (
51
+ commonIndex < fromSegments.length &&
52
+ commonIndex < toSegments.length &&
53
+ fromSegments[commonIndex] === toSegments[commonIndex]
54
+ ) {
55
+ commonIndex++
56
+ }
57
+
58
+ const upLevels = fromSegments.length - commonIndex
59
+ const downLevels = toSegments.slice(commonIndex)
60
+
61
+ if (upLevels === 0 && downLevels.length === 0) {
62
+ return `./${basename(to)}`
63
+ } else if (upLevels === 0 && downLevels.length > 0) {
64
+ return `./${downLevels.join('/')}/${basename(to)}`
65
+ } else {
66
+ const relativePath = [...Array(upLevels).fill('..'), ...downLevels].join(
67
+ '/',
68
+ )
69
+ return `${relativePath}/${basename(to)}`
70
+ }
71
+ }
72
+
73
+ export function isDirectory(path: string): boolean {
74
+ return statSync(path).isDirectory()
75
+ }
76
+
77
+ export function findFilesRecursively(
78
+ path: string,
79
+ files: Record<string, string>,
80
+ ) {
81
+ const dirFiles = readdirSync(path)
82
+ for (const file of dirFiles) {
83
+ const filePath = resolve(path, file)
84
+ if (isDirectory(filePath)) {
85
+ findFilesRecursively(filePath, files)
86
+ } else {
87
+ files[filePath] = readFileHelper(filePath)
88
+ }
89
+ }
90
+ }
91
+
92
+ async function recursivelyGatherFilesHelper(
93
+ basePath: string,
94
+ path: string,
95
+ files: Record<string, string>,
96
+ ignore: (filePath: string) => boolean,
97
+ ) {
98
+ const dirFiles = await readdir(path, { withFileTypes: true })
99
+ for (const file of dirFiles) {
100
+ if (ignore(file.name)) {
101
+ continue
102
+ }
103
+ if (file.isDirectory()) {
104
+ await recursivelyGatherFilesHelper(
105
+ basePath,
106
+ resolve(path, file.name),
107
+ files,
108
+ ignore,
109
+ )
110
+ } else {
111
+ const filePath = resolve(path, file.name)
112
+ files[filePath.replace(basePath, '.')] = await readFileHelper(filePath)
113
+ }
114
+ }
115
+ }
116
+
117
+ export async function recursivelyGatherFiles(
118
+ path: string,
119
+ includeProjectFiles = true,
120
+ ) {
121
+ const ignore = createIgnore(path, includeProjectFiles)
122
+ const files: Record<string, string> = {}
123
+ await recursivelyGatherFilesHelper(path, path, files, ignore)
124
+ return files
125
+ }
126
+
127
+ async function recursivelyGatherFilesFromEnvironmentHelper(
128
+ environment: Environment,
129
+ basePath: string,
130
+ path: string,
131
+ files: Record<string, string>,
132
+ ignore: (filePath: string) => boolean,
133
+ ) {
134
+ const dirFiles = await environment.readdir(path)
135
+ for (const file of dirFiles) {
136
+ if (ignore(file)) {
137
+ continue
138
+ }
139
+ if (environment.isDirectory(resolve(path, file))) {
140
+ await recursivelyGatherFilesFromEnvironmentHelper(
141
+ environment,
142
+ basePath,
143
+ resolve(path, file),
144
+ files,
145
+ ignore,
146
+ )
147
+ } else {
148
+ const filePath = resolve(path, file)
149
+ files[filePath.replace(basePath, '.')] =
150
+ await environment.readFile(filePath)
151
+ }
152
+ }
153
+ }
154
+
155
+ export async function recursivelyGatherFilesFromEnvironment(
156
+ environment: Environment,
157
+ path: string,
158
+ includeProjectFiles = true,
159
+ ) {
160
+ const ignore = createIgnore(path, includeProjectFiles)
161
+ const files: Record<string, string> = {}
162
+ await recursivelyGatherFilesFromEnvironmentHelper(
163
+ environment,
164
+ path,
165
+ path,
166
+ files,
167
+ ignore,
168
+ )
169
+ return files
170
+ }
171
+
172
+ export const IGNORE_FILES = [
173
+ '.starter',
174
+ '.add-on',
175
+ '.cta.json',
176
+ '.git',
177
+ 'add-on-info.json',
178
+ 'add-on.json',
179
+ 'build',
180
+ 'bun.lock',
181
+ 'bun.lockb',
182
+ 'deno.lock',
183
+ 'dist',
184
+ 'node_modules',
185
+ 'package-lock.json',
186
+ 'pnpm-lock.yaml',
187
+ 'starter.json',
188
+ 'starter-info.json',
189
+ 'yarn.lock',
190
+ ]
191
+
192
+ const PROJECT_FILES = ['package.json']
193
+
194
+ export function createIgnore(path: string, includeProjectFiles = true) {
195
+ const ignoreList = existsSync(resolve(path, '.gitignore'))
196
+ ? (
197
+ parseGitignore(
198
+ readFileSync(resolve(path, '.gitignore')),
199
+ ) as unknown as { patterns: Array<string> }
200
+ ).patterns
201
+ : []
202
+ const ig = ignore().add(ignoreList)
203
+ return (filePath: string) => {
204
+ const fileName = basename(filePath)
205
+ if (
206
+ IGNORE_FILES.includes(fileName) ||
207
+ (includeProjectFiles && PROJECT_FILES.includes(fileName))
208
+ ) {
209
+ return true
210
+ }
211
+ const nameWithoutDotSlash = fileName.replace(/^\.\//, '')
212
+ return ig.ignores(nameWithoutDotSlash)
213
+ }
214
+ }
215
+
216
+ export function cleanUpFiles(
217
+ files: Record<string, string>,
218
+ targetDir?: string,
219
+ ) {
220
+ return Object.keys(files).reduce<Record<string, string>>((acc, file) => {
221
+ if (basename(file) !== '.cta.json') {
222
+ acc[targetDir ? file.replace(targetDir, '.') : file] = files[file]
223
+ }
224
+ return acc
225
+ }, {})
226
+ }
227
+
228
+ export function cleanUpFileArray(files: Array<string>, targetDir?: string) {
229
+ return files.reduce<Array<string>>((acc, file) => {
230
+ if (basename(file) !== '.cta.json') {
231
+ acc.push(targetDir ? file.replace(targetDir, '.') : file)
232
+ }
233
+ return acc
234
+ }, [])
235
+ }
@@ -0,0 +1,134 @@
1
+ import { existsSync, readFileSync, readdirSync } from 'node:fs'
2
+ import { resolve } from 'node:path'
3
+
4
+ import {
5
+ findFilesRecursively,
6
+ isDirectory,
7
+ readFileHelper,
8
+ } from './file-helpers.js'
9
+
10
+ import type { AddOn, Framework, FrameworkDefinition } from './types.js'
11
+
12
+ const frameworks: Array<Framework> = []
13
+
14
+ function getAddOns(framework: FrameworkDefinition) {
15
+ const addOns: Array<AddOn> = []
16
+
17
+ for (const addOnsBase of framework.addOnsDirectories) {
18
+ for (const dir of readdirSync(addOnsBase).filter((file) =>
19
+ isDirectory(resolve(addOnsBase, file)),
20
+ )) {
21
+ const filePath = resolve(addOnsBase, dir, 'info.json')
22
+ const fileContent = readFileSync(filePath, 'utf-8')
23
+ const info = JSON.parse(fileContent)
24
+
25
+ let packageAdditions: Record<string, string> = {}
26
+ if (existsSync(resolve(addOnsBase, dir, 'package.json'))) {
27
+ packageAdditions = JSON.parse(
28
+ readFileSync(resolve(addOnsBase, dir, 'package.json'), 'utf-8'),
29
+ )
30
+ }
31
+
32
+ let readme: string | undefined
33
+ if (existsSync(resolve(addOnsBase, dir, 'README.md'))) {
34
+ readme = readFileSync(resolve(addOnsBase, dir, 'README.md'), 'utf-8')
35
+ }
36
+
37
+ let smallLogo: string | undefined
38
+ if (existsSync(resolve(addOnsBase, dir, 'small-logo.svg'))) {
39
+ smallLogo = readFileSync(
40
+ resolve(addOnsBase, dir, 'small-logo.svg'),
41
+ 'utf-8',
42
+ )
43
+ }
44
+
45
+ const absoluteFiles: Record<string, string> = {}
46
+ const assetsDir = resolve(addOnsBase, dir, 'assets')
47
+ if (existsSync(assetsDir)) {
48
+ findFilesRecursively(assetsDir, absoluteFiles)
49
+ }
50
+ const files: Record<string, string> = {}
51
+ for (const file of Object.keys(absoluteFiles)) {
52
+ files[file.replace(assetsDir, '.')] = readFileHelper(file)
53
+ }
54
+
55
+ const getFiles = () => {
56
+ return Promise.resolve(Object.keys(files))
57
+ }
58
+ const getFileContents = (path: string) => {
59
+ return Promise.resolve(files[path])
60
+ }
61
+
62
+ addOns.push({
63
+ ...info,
64
+ id: dir,
65
+ packageAdditions,
66
+ readme,
67
+ files,
68
+ smallLogo,
69
+ getFiles,
70
+ getFileContents,
71
+ getDeletedFiles: () => Promise.resolve(info.deletedFiles ?? []),
72
+ })
73
+ }
74
+ }
75
+
76
+ return addOns
77
+ }
78
+
79
+ export function __testRegisterFramework(framework: Framework) {
80
+ frameworks.push(framework)
81
+ }
82
+
83
+ export function __testClearFrameworks() {
84
+ frameworks.length = 0
85
+ }
86
+
87
+ export function registerFramework(framework: FrameworkDefinition) {
88
+ const baseAssetsDirectory = resolve(framework.baseDirectory, 'base')
89
+
90
+ const basePackageJSON = JSON.parse(
91
+ readFileSync(resolve(baseAssetsDirectory, 'package.json'), 'utf8'),
92
+ )
93
+ const optionalPackages = JSON.parse(
94
+ readFileSync(resolve(framework.baseDirectory, 'packages.json'), 'utf8'),
95
+ )
96
+
97
+ const addOns = getAddOns(framework)
98
+
99
+ const frameworkWithBundler: Framework = {
100
+ ...framework,
101
+ getFiles: () => {
102
+ const files: Record<string, string> = {}
103
+ findFilesRecursively(baseAssetsDirectory, files)
104
+ return Promise.resolve(
105
+ Object.keys(files).map((path) =>
106
+ path.replace(baseAssetsDirectory, '.'),
107
+ ),
108
+ )
109
+ },
110
+ getFileContents: (path: string) => {
111
+ return Promise.resolve(readFileHelper(resolve(baseAssetsDirectory, path)))
112
+ },
113
+ getDeletedFiles: () => {
114
+ return Promise.resolve([])
115
+ },
116
+ basePackageJSON,
117
+ optionalPackages,
118
+ getAddOns: () => addOns,
119
+ }
120
+
121
+ frameworks.push(frameworkWithBundler)
122
+ }
123
+
124
+ export function getFrameworkById(id: string) {
125
+ return frameworks.find((framework) => framework.id === id)
126
+ }
127
+
128
+ export function getFrameworkByName(name: string) {
129
+ return frameworks.find((framework) => framework.name === name)
130
+ }
131
+
132
+ export function getFrameworks() {
133
+ return frameworks
134
+ }
package/src/index.ts CHANGED
@@ -1 +1,85 @@
1
- export { cli } from './cli.js'
1
+ export { createApp } from './create-app.js'
2
+ export { addToApp } from './add-to-app.js'
3
+
4
+ export { finalizeAddOns, getAllAddOns } from './add-ons.js'
5
+
6
+ export { loadRemoteAddOn } from './custom-add-ons/add-on.js'
7
+ export { loadStarter } from './custom-add-ons/starter.js'
8
+
9
+ export {
10
+ createMemoryEnvironment,
11
+ createDefaultEnvironment,
12
+ } from './environment.js'
13
+
14
+ export { CODE_ROUTER, CONFIG_FILE, FILE_ROUTER } from './constants.js'
15
+
16
+ export {
17
+ DEFAULT_PACKAGE_MANAGER,
18
+ SUPPORTED_PACKAGE_MANAGERS,
19
+ getPackageManager,
20
+ } from './package-manager.js'
21
+
22
+ export {
23
+ registerFramework,
24
+ getFrameworkById,
25
+ getFrameworkByName,
26
+ getFrameworks,
27
+ } from './frameworks.js'
28
+
29
+ export {
30
+ writeConfigFileToEnvironment,
31
+ readConfigFileFromEnvironment,
32
+ readConfigFile,
33
+ } from './config-file.js'
34
+
35
+ export {
36
+ cleanUpFiles,
37
+ cleanUpFileArray,
38
+ readFileHelper,
39
+ getBinaryFile,
40
+ recursivelyGatherFiles,
41
+ relativePath,
42
+ } from './file-helpers.js'
43
+
44
+ export { formatCommand } from './utils.js'
45
+
46
+ export { initStarter, compileStarter } from './custom-add-ons/starter.js'
47
+ export { initAddOn, compileAddOn } from './custom-add-ons/add-on.js'
48
+ export {
49
+ createAppOptionsFromPersisted,
50
+ createSerializedOptionsFromPersisted,
51
+ } from './custom-add-ons/shared.js'
52
+
53
+ export { createSerializedOptions } from './options.js'
54
+
55
+ export {
56
+ getRawRegistry,
57
+ getRegistry,
58
+ getRegistryAddOns,
59
+ getRegistryStarters,
60
+ } from './registry.js'
61
+
62
+ export {
63
+ StarterCompiledSchema,
64
+ StatusEvent,
65
+ StatusStepType,
66
+ StopEvent,
67
+ AddOnCompiledSchema,
68
+ AddOnInfoSchema,
69
+ IntegrationSchema,
70
+ } from './types.js'
71
+
72
+ export type {
73
+ AddOn,
74
+ Environment,
75
+ FileBundleHandler,
76
+ Framework,
77
+ FrameworkDefinition,
78
+ Mode,
79
+ Options,
80
+ SerializedOptions,
81
+ Starter,
82
+ StarterCompiled,
83
+ } from './types.js'
84
+ export type { PersistedOptions } from './config-file.js'
85
+ export type { PackageManager } from './package-manager.js'
@@ -0,0 +1,7 @@
1
+ import { resolve } from 'node:path'
2
+
3
+ import type { Environment } from '../types.js'
4
+
5
+ export async function setupGit(environment: Environment, targetDir: string) {
6
+ await environment.execute('git', ['init'], resolve(targetDir))
7
+ }
@@ -0,0 +1,54 @@
1
+ import { resolve } from 'node:path'
2
+ import { packageManagerExecute } from '../package-manager.js'
3
+ import type { Environment, Options } from '../types.js'
4
+
5
+ export async function installShadcnComponents(
6
+ environment: Environment,
7
+ targetDir: string,
8
+ options: Options,
9
+ ) {
10
+ const s = environment.spinner()
11
+
12
+ if (options.chosenAddOns.find((a) => a.id === 'shadcn')) {
13
+ const shadcnComponents = new Set<string>()
14
+ for (const addOn of options.chosenAddOns) {
15
+ if (addOn.shadcnComponents) {
16
+ for (const component of addOn.shadcnComponents) {
17
+ shadcnComponents.add(component)
18
+ }
19
+ }
20
+ }
21
+ if (options.starter) {
22
+ if (options.starter.shadcnComponents) {
23
+ for (const component of options.starter.shadcnComponents) {
24
+ shadcnComponents.add(component)
25
+ }
26
+ }
27
+ }
28
+
29
+ if (shadcnComponents.size > 0) {
30
+ s.start(
31
+ `Installing shadcn components (${Array.from(shadcnComponents).join(', ')})...`,
32
+ )
33
+ environment.startStep({
34
+ id: 'install-shadcn-components',
35
+ type: 'command',
36
+ message: `Installing shadcn components (${Array.from(shadcnComponents).join(', ')})...`,
37
+ })
38
+
39
+ await packageManagerExecute(
40
+ environment,
41
+ resolve(targetDir),
42
+ options.packageManager,
43
+ 'shadcn@latest',
44
+ ['add', '--silent', '--yes', ...Array.from(shadcnComponents)],
45
+ )
46
+
47
+ environment.finishStep(
48
+ 'install-shadcn-components',
49
+ 'Shadcn components installed',
50
+ )
51
+ s.stop(`Installed additional shadcn components`)
52
+ }
53
+ }
54
+ }