create-tsrouter-app 0.2.0 → 0.3.0-alpha.2

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 (72) hide show
  1. package/dist/add-ons.js +53 -0
  2. package/dist/cli.js +51 -0
  3. package/dist/constants.js +2 -0
  4. package/dist/create-app.js +285 -0
  5. package/dist/index.js +2 -347
  6. package/dist/options.js +231 -0
  7. package/dist/types.js +1 -0
  8. package/package.json +4 -3
  9. package/src/add-ons.ts +141 -0
  10. package/src/cli.ts +74 -0
  11. package/src/constants.ts +2 -0
  12. package/src/create-app.ts +445 -0
  13. package/src/index.ts +2 -507
  14. package/src/options.ts +264 -0
  15. package/src/types.ts +24 -0
  16. package/templates/add-on/clerk/README.md +3 -0
  17. package/templates/add-on/clerk/assets/.env.local.append +2 -0
  18. package/templates/add-on/clerk/assets/src/routes/demo.clerk.tsx +20 -0
  19. package/templates/add-on/clerk/info.json +28 -0
  20. package/templates/add-on/clerk/package.json +5 -0
  21. package/templates/add-on/convex/README.md +4 -0
  22. package/templates/add-on/convex/assets/.cursorrules.append +93 -0
  23. package/templates/add-on/convex/assets/.env.local.append +3 -0
  24. package/templates/add-on/convex/assets/convex/products.ts +8 -0
  25. package/templates/add-on/convex/assets/convex/schema.ts +10 -0
  26. package/templates/add-on/convex/assets/src/routes/demo.convex.tsx +33 -0
  27. package/templates/add-on/convex/info.json +27 -0
  28. package/templates/add-on/convex/package.json +6 -0
  29. package/templates/add-on/form/assets/src/routes/demo.form.tsx +50 -0
  30. package/templates/add-on/form/info.json +12 -0
  31. package/templates/add-on/form/package.json +5 -0
  32. package/templates/add-on/netlify/README.md +11 -0
  33. package/templates/add-on/netlify/info.json +6 -0
  34. package/templates/add-on/react-query/assets/src/routes/demo.react-query.tsx +30 -0
  35. package/templates/add-on/react-query/info.json +30 -0
  36. package/templates/add-on/react-query/package.json +6 -0
  37. package/templates/add-on/sentry/assets/.cursorrules +22 -0
  38. package/templates/add-on/sentry/assets/.env.local.append +2 -0
  39. package/templates/add-on/sentry/assets/src/routes/demo.sentry.bad-server-func.tsx +29 -0
  40. package/templates/add-on/sentry/info.json +13 -0
  41. package/templates/add-on/sentry/package.json +5 -0
  42. package/templates/add-on/shadcn/README.md +7 -0
  43. package/templates/add-on/shadcn/info.json +10 -0
  44. package/templates/add-on/start/assets/app.config.ts +16 -0
  45. package/templates/add-on/start/assets/postcss.config.ts +5 -0
  46. package/templates/add-on/start/assets/src/api.ts +6 -0
  47. package/templates/add-on/start/assets/src/client.tsx +10 -0
  48. package/templates/add-on/start/assets/src/router.tsx.ejs +34 -0
  49. package/templates/add-on/start/assets/src/routes/api.demo-names.ts +11 -0
  50. package/templates/add-on/start/assets/src/routes/demo.start.api-request.tsx.ejs +33 -0
  51. package/templates/add-on/start/assets/src/routes/demo.start.server-funcs.tsx +49 -0
  52. package/templates/add-on/start/assets/src/ssr.tsx +12 -0
  53. package/templates/add-on/start/info.json +18 -0
  54. package/templates/add-on/start/package.json +14 -0
  55. package/templates/add-on/store/assets/src/lib/demo-store.ts +5 -0
  56. package/templates/add-on/store/assets/src/routes/demo.store.page1.tsx +30 -0
  57. package/templates/add-on/store/assets/src/routes/demo.store.page2.tsx +30 -0
  58. package/templates/add-on/store/info.json +16 -0
  59. package/templates/add-on/store/package.json +6 -0
  60. package/templates/base/README.md.ejs +9 -0
  61. package/templates/base/package.json +1 -0
  62. package/templates/base/{tsconfig.json → tsconfig.json.ejs} +5 -1
  63. package/templates/base/vite.config.js.ejs +8 -0
  64. package/templates/example/ai-chat/assets/.env.local.append +2 -0
  65. package/templates/example/ai-chat/assets/src/routes/example.ai-chat.tsx.ejs +81 -0
  66. package/templates/example/ai-chat/info.json +27 -0
  67. package/templates/example/ai-chat/package.json +1 -0
  68. package/templates/file-router/src/components/Header.tsx.ejs +27 -0
  69. package/templates/file-router/src/routes/__root.tsx.ejs +80 -0
  70. package/templates/file-router/src/routes/__root.tsx +0 -11
  71. /package/dist/{utils/getPackageManager.js → package-manager.js} +0 -0
  72. /package/src/{utils/getPackageManager.ts → package-manager.ts} +0 -0
package/dist/index.js CHANGED
@@ -1,348 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import { copyFile, mkdir, readFile, writeFile } from 'node:fs/promises';
3
- import { existsSync } from 'node:fs';
4
- import { resolve } from 'node:path';
5
- import { fileURLToPath } from 'node:url';
6
- import { Command, InvalidArgumentError } from 'commander';
7
- import { cancel, confirm, intro, isCancel, log, outro, select, spinner, text, } from '@clack/prompts';
8
- import { execa } from 'execa';
9
- import { render } from 'ejs';
10
- import { DEFAULT_PACKAGE_MANAGER, SUPPORTED_PACKAGE_MANAGERS, getPackageManager, } from './utils/getPackageManager.js';
11
- const program = new Command();
12
- const CODE_ROUTER = 'code-router';
13
- const FILE_ROUTER = 'file-router';
14
- function sortObject(obj) {
15
- return Object.keys(obj)
16
- .sort()
17
- .reduce((acc, key) => {
18
- acc[key] = obj[key];
19
- return acc;
20
- }, {});
21
- }
22
- function createCopyFile(targetDir) {
23
- return async function copyFiles(templateDir, files) {
24
- for (const file of files) {
25
- const targetFileName = file.replace('.tw', '');
26
- await copyFile(resolve(templateDir, file), resolve(targetDir, targetFileName));
27
- }
28
- };
29
- }
30
- function createTemplateFile(projectName, options, targetDir) {
31
- return async function templateFile(templateDir, file, targetFileName) {
32
- const templateValues = {
33
- packageManager: options.packageManager,
34
- projectName: projectName,
35
- typescript: options.typescript,
36
- tailwind: options.tailwind,
37
- js: options.typescript ? 'ts' : 'js',
38
- jsx: options.typescript ? 'tsx' : 'jsx',
39
- fileRouter: options.mode === FILE_ROUTER,
40
- codeRouter: options.mode === CODE_ROUTER,
41
- };
42
- const template = await readFile(resolve(templateDir, file), 'utf-8');
43
- const content = render(template, templateValues);
44
- const target = targetFileName ?? file.replace('.ejs', '');
45
- await writeFile(resolve(targetDir, target), content);
46
- };
47
- }
48
- async function createPackageJSON(projectName, options, templateDir, routerDir, targetDir) {
49
- let packageJSON = JSON.parse(await readFile(resolve(templateDir, 'package.json'), 'utf8'));
50
- packageJSON.name = projectName;
51
- if (options.typescript) {
52
- const tsPackageJSON = JSON.parse(await readFile(resolve(templateDir, 'package.ts.json'), 'utf8'));
53
- packageJSON = {
54
- ...packageJSON,
55
- devDependencies: {
56
- ...packageJSON.devDependencies,
57
- ...tsPackageJSON.devDependencies,
58
- },
59
- };
60
- }
61
- if (options.tailwind) {
62
- const twPackageJSON = JSON.parse(await readFile(resolve(templateDir, 'package.tw.json'), 'utf8'));
63
- packageJSON = {
64
- ...packageJSON,
65
- dependencies: {
66
- ...packageJSON.dependencies,
67
- ...twPackageJSON.dependencies,
68
- },
69
- };
70
- }
71
- if (options.mode === FILE_ROUTER) {
72
- const frPackageJSON = JSON.parse(await readFile(resolve(routerDir, 'package.fr.json'), 'utf8'));
73
- packageJSON = {
74
- ...packageJSON,
75
- dependencies: {
76
- ...packageJSON.dependencies,
77
- ...frPackageJSON.dependencies,
78
- },
79
- };
80
- }
81
- packageJSON.dependencies = sortObject(packageJSON.dependencies);
82
- packageJSON.devDependencies = sortObject(packageJSON.devDependencies);
83
- await writeFile(resolve(targetDir, 'package.json'), JSON.stringify(packageJSON, null, 2));
84
- }
85
- async function createApp(options) {
86
- const templateDirBase = fileURLToPath(new URL('../templates/base', import.meta.url));
87
- const templateDirRouter = fileURLToPath(new URL(`../templates/${options.mode}`, import.meta.url));
88
- const targetDir = resolve(process.cwd(), options.projectName);
89
- if (existsSync(targetDir)) {
90
- log.error(`Directory "${options.projectName}" already exists`);
91
- return;
92
- }
93
- const copyFiles = createCopyFile(targetDir);
94
- const templateFile = createTemplateFile(options.projectName, options, targetDir);
95
- intro(`Creating a new TanStack app in ${targetDir}...`);
96
- // Make the root directory
97
- await mkdir(targetDir, { recursive: true });
98
- // Setup the .vscode directory
99
- await mkdir(resolve(targetDir, '.vscode'), { recursive: true });
100
- await copyFile(resolve(templateDirBase, '.vscode/settings.json'), resolve(targetDir, '.vscode/settings.json'));
101
- // Fill the public directory
102
- await mkdir(resolve(targetDir, 'public'), { recursive: true });
103
- copyFiles(templateDirBase, [
104
- './public/robots.txt',
105
- './public/favicon.ico',
106
- './public/manifest.json',
107
- './public/logo192.png',
108
- './public/logo512.png',
109
- ]);
110
- // Make the src directory
111
- await mkdir(resolve(targetDir, 'src'), { recursive: true });
112
- if (options.mode === FILE_ROUTER) {
113
- await mkdir(resolve(targetDir, 'src/routes'), { recursive: true });
114
- }
115
- // Copy in Vite and Tailwind config and CSS
116
- if (!options.tailwind) {
117
- await copyFiles(templateDirBase, ['./src/App.css']);
118
- }
119
- await templateFile(templateDirBase, './vite.config.js.ejs');
120
- await templateFile(templateDirBase, './src/styles.css.ejs');
121
- copyFiles(templateDirBase, ['./src/logo.svg']);
122
- // Setup the app component. There are four variations, typescript/javascript and tailwind/non-tailwind.
123
- if (options.mode === FILE_ROUTER) {
124
- copyFiles(templateDirRouter, ['./src/routes/__root.tsx']);
125
- await templateFile(templateDirBase, './src/App.tsx.ejs', './src/routes/index.tsx');
126
- }
127
- else {
128
- await templateFile(templateDirBase, './src/App.tsx.ejs', options.typescript ? undefined : './src/App.jsx');
129
- await templateFile(templateDirBase, './src/App.test.tsx.ejs', options.typescript ? undefined : './src/App.test.jsx');
130
- }
131
- // Create the main entry point
132
- if (options.typescript) {
133
- await templateFile(templateDirRouter, './src/main.tsx.ejs');
134
- }
135
- else {
136
- await templateFile(templateDirRouter, './src/main.tsx.ejs', './src/main.jsx');
137
- }
138
- // Setup the main, reportWebVitals and index.html files
139
- if (options.typescript) {
140
- await templateFile(templateDirBase, './src/reportWebVitals.ts.ejs');
141
- }
142
- else {
143
- await templateFile(templateDirBase, './src/reportWebVitals.ts.ejs', './src/reportWebVitals.js');
144
- }
145
- await templateFile(templateDirBase, './index.html.ejs');
146
- // Setup tsconfig
147
- if (options.typescript) {
148
- await copyFiles(templateDirBase, ['./tsconfig.json']);
149
- }
150
- // Setup the package.json file, optionally with typescript and tailwind
151
- await createPackageJSON(options.projectName, options, templateDirBase, templateDirRouter, targetDir);
152
- // Add .gitignore
153
- await copyFile(resolve(templateDirBase, 'gitignore'), resolve(targetDir, '.gitignore'));
154
- // Create the README.md
155
- await templateFile(templateDirBase, 'README.md.ejs');
156
- // Install dependencies
157
- const s = spinner();
158
- s.start(`Installing dependencies via ${options.packageManager}...`);
159
- await execa(options.packageManager, ['install'], { cwd: targetDir });
160
- s.stop(`Installed dependencies`);
161
- if (options.git) {
162
- s.start(`Initializing git repository...`);
163
- await execa('git', ['init'], { cwd: targetDir });
164
- s.stop(`Initialized git repository`);
165
- }
166
- outro(`Created your new TanStack app in ${targetDir}.
167
-
168
- Use the following commands to start your app:
169
-
170
- % cd ${options.projectName}
171
- % ${options.packageManager} start
172
-
173
- Please read README.md for more information on testing, styling, adding routes, react-query, etc.
174
- `);
175
- }
176
- // If all CLI options are provided, use them directly
177
- function normalizeOptions(cliOptions) {
178
- if (cliOptions.projectName) {
179
- const typescript = cliOptions.template === 'typescript' ||
180
- cliOptions.template === 'file-router';
181
- return {
182
- projectName: cliOptions.projectName,
183
- typescript,
184
- tailwind: !!cliOptions.tailwind,
185
- packageManager: cliOptions.packageManager || DEFAULT_PACKAGE_MANAGER,
186
- mode: cliOptions.template === 'file-router' ? FILE_ROUTER : CODE_ROUTER,
187
- git: !!cliOptions.git,
188
- };
189
- }
190
- }
191
- async function promptForOptions(cliOptions) {
192
- const options = {};
193
- if (!cliOptions.projectName) {
194
- const value = await text({
195
- message: 'What would you like to name your project?',
196
- defaultValue: 'my-app',
197
- validate(value) {
198
- if (!value) {
199
- return 'Please enter a name';
200
- }
201
- },
202
- });
203
- if (isCancel(value)) {
204
- cancel('Operation cancelled.');
205
- process.exit(0);
206
- }
207
- options.projectName = value;
208
- }
209
- // Router type selection
210
- if (!cliOptions.template) {
211
- const routerType = await select({
212
- message: 'Select the router type:',
213
- options: [
214
- {
215
- value: FILE_ROUTER,
216
- label: 'File Router - File-based routing structure',
217
- },
218
- {
219
- value: CODE_ROUTER,
220
- label: 'Code Router - Traditional code-based routing',
221
- },
222
- ],
223
- initialValue: FILE_ROUTER,
224
- });
225
- if (isCancel(routerType)) {
226
- cancel('Operation cancelled.');
227
- process.exit(0);
228
- }
229
- options.mode = routerType;
230
- }
231
- else {
232
- options.mode = cliOptions.template;
233
- if (options.mode === FILE_ROUTER) {
234
- options.typescript = true;
235
- }
236
- }
237
- // TypeScript selection (if using Code Router)
238
- if (!options.typescript) {
239
- if (options.mode === CODE_ROUTER) {
240
- const typescriptEnable = await confirm({
241
- message: 'Would you like to use TypeScript?',
242
- initialValue: true,
243
- });
244
- if (isCancel(typescriptEnable)) {
245
- cancel('Operation cancelled.');
246
- process.exit(0);
247
- }
248
- options.typescript = typescriptEnable;
249
- }
250
- else {
251
- options.typescript = true;
252
- }
253
- }
254
- // Tailwind selection
255
- if (cliOptions.tailwind === undefined) {
256
- const tailwind = await confirm({
257
- message: 'Would you like to use Tailwind CSS?',
258
- initialValue: true,
259
- });
260
- if (isCancel(tailwind)) {
261
- cancel('Operation cancelled.');
262
- process.exit(0);
263
- }
264
- options.tailwind = tailwind;
265
- }
266
- else {
267
- options.tailwind = cliOptions.tailwind;
268
- }
269
- // Package manager selection
270
- if (cliOptions.packageManager === undefined) {
271
- const detectedPackageManager = getPackageManager();
272
- if (!detectedPackageManager) {
273
- const pm = await select({
274
- message: 'Select package manager:',
275
- options: SUPPORTED_PACKAGE_MANAGERS.map((pm) => ({
276
- value: pm,
277
- label: pm,
278
- })),
279
- initialValue: DEFAULT_PACKAGE_MANAGER,
280
- });
281
- if (isCancel(pm)) {
282
- cancel('Operation cancelled.');
283
- process.exit(0);
284
- }
285
- options.packageManager = pm;
286
- }
287
- else {
288
- options.packageManager = detectedPackageManager;
289
- }
290
- }
291
- else {
292
- options.packageManager = cliOptions.packageManager;
293
- }
294
- // Git selection
295
- if (cliOptions.git === undefined) {
296
- const git = await confirm({
297
- message: 'Would you like to initialize a new git repository?',
298
- initialValue: true,
299
- });
300
- if (isCancel(git)) {
301
- cancel('Operation cancelled.');
302
- process.exit(0);
303
- }
304
- options.git = git;
305
- }
306
- else {
307
- options.git = !!cliOptions.git;
308
- }
309
- return options;
310
- }
311
- program
312
- .name('create-tsrouter-app')
313
- .description('CLI to create a new TanStack application')
314
- .argument('[project-name]', 'name of the project')
315
- .option('--no-git', 'do not create a git repository')
316
- .option('--template <type>', 'project template (typescript, javascript, file-router)', (value) => {
317
- if (value !== 'typescript' &&
318
- value !== 'javascript' &&
319
- value !== 'file-router') {
320
- throw new InvalidArgumentError(`Invalid template: ${value}. Only the following are allowed: typescript, javascript, file-router`);
321
- }
322
- return value;
323
- })
324
- .option(`--package-manager <${SUPPORTED_PACKAGE_MANAGERS.join('|')}>`, `Explicitly tell the CLI to use this package manager`, (value) => {
325
- if (!SUPPORTED_PACKAGE_MANAGERS.includes(value)) {
326
- throw new InvalidArgumentError(`Invalid package manager: ${value}. Only the following are allowed: ${SUPPORTED_PACKAGE_MANAGERS.join(', ')}`);
327
- }
328
- return value;
329
- })
330
- .option('--tailwind', 'add Tailwind CSS')
331
- .action(async (projectName, options) => {
332
- try {
333
- const cliOptions = {
334
- projectName,
335
- ...options,
336
- };
337
- let finalOptions = normalizeOptions(cliOptions);
338
- if (!finalOptions) {
339
- finalOptions = await promptForOptions(cliOptions);
340
- }
341
- await createApp(finalOptions);
342
- }
343
- catch (error) {
344
- log.error(error instanceof Error ? error.message : 'An unknown error occurred');
345
- process.exit(1);
346
- }
347
- });
348
- program.parse();
2
+ import { cli } from './cli.js';
3
+ cli();
@@ -0,0 +1,231 @@
1
+ import { cancel, confirm, isCancel, multiselect, select, text, } from '@clack/prompts';
2
+ import { DEFAULT_PACKAGE_MANAGER, SUPPORTED_PACKAGE_MANAGERS, getPackageManager, } from './package-manager.js';
3
+ import { CODE_ROUTER, FILE_ROUTER } from './constants.js';
4
+ import { finalizeAddOns, getAllAddOns } from './add-ons.js';
5
+ // If all CLI options are provided, use them directly
6
+ export function normalizeOptions(cliOptions) {
7
+ if (cliOptions.projectName) {
8
+ const typescript = cliOptions.template === 'typescript' ||
9
+ cliOptions.template === 'file-router';
10
+ return {
11
+ projectName: cliOptions.projectName,
12
+ typescript,
13
+ tailwind: !!cliOptions.tailwind,
14
+ packageManager: cliOptions.packageManager || DEFAULT_PACKAGE_MANAGER,
15
+ mode: cliOptions.template === 'file-router' ? FILE_ROUTER : CODE_ROUTER,
16
+ git: !!cliOptions.git,
17
+ addOns: !!cliOptions.addOns,
18
+ chosenAddOns: [],
19
+ variableValues: {},
20
+ };
21
+ }
22
+ }
23
+ async function collectVariables(variables) {
24
+ const responses = {};
25
+ for (const variable of variables) {
26
+ if (variable.type === 'string') {
27
+ const response = await text({
28
+ message: variable.description,
29
+ initialValue: variable.default,
30
+ });
31
+ if (isCancel(response)) {
32
+ cancel('Operation cancelled.');
33
+ process.exit(0);
34
+ }
35
+ responses[variable.name] = response;
36
+ }
37
+ else if (variable.type === 'number') {
38
+ const response = await text({
39
+ message: variable.description,
40
+ initialValue: variable.default.toString(),
41
+ });
42
+ if (isCancel(response)) {
43
+ cancel('Operation cancelled.');
44
+ process.exit(0);
45
+ }
46
+ responses[variable.name] = Number(response);
47
+ }
48
+ else {
49
+ const response = await confirm({
50
+ message: variable.description,
51
+ initialValue: variable.default === true,
52
+ });
53
+ if (isCancel(response)) {
54
+ cancel('Operation cancelled.');
55
+ process.exit(0);
56
+ }
57
+ responses[variable.name] = response;
58
+ }
59
+ }
60
+ return responses;
61
+ }
62
+ export async function promptForOptions(cliOptions) {
63
+ const options = {};
64
+ if (!cliOptions.projectName) {
65
+ const value = await text({
66
+ message: 'What would you like to name your project?',
67
+ defaultValue: 'my-app',
68
+ validate(value) {
69
+ if (!value) {
70
+ return 'Please enter a name';
71
+ }
72
+ },
73
+ });
74
+ if (isCancel(value)) {
75
+ cancel('Operation cancelled.');
76
+ process.exit(0);
77
+ }
78
+ options.projectName = value;
79
+ }
80
+ // Router type selection
81
+ if (!cliOptions.template) {
82
+ const routerType = await select({
83
+ message: 'Select the router type:',
84
+ options: [
85
+ {
86
+ value: FILE_ROUTER,
87
+ label: 'File Router - File-based routing structure',
88
+ },
89
+ {
90
+ value: CODE_ROUTER,
91
+ label: 'Code Router - Traditional code-based routing',
92
+ },
93
+ ],
94
+ initialValue: FILE_ROUTER,
95
+ });
96
+ if (isCancel(routerType)) {
97
+ cancel('Operation cancelled.');
98
+ process.exit(0);
99
+ }
100
+ options.mode = routerType;
101
+ }
102
+ else {
103
+ options.mode = cliOptions.template;
104
+ if (options.mode === FILE_ROUTER) {
105
+ options.typescript = true;
106
+ }
107
+ }
108
+ // TypeScript selection (if using Code Router)
109
+ if (!options.typescript) {
110
+ if (options.mode === CODE_ROUTER) {
111
+ const typescriptEnable = await confirm({
112
+ message: 'Would you like to use TypeScript?',
113
+ initialValue: true,
114
+ });
115
+ if (isCancel(typescriptEnable)) {
116
+ cancel('Operation cancelled.');
117
+ process.exit(0);
118
+ }
119
+ options.typescript = typescriptEnable;
120
+ }
121
+ else {
122
+ options.typescript = true;
123
+ }
124
+ }
125
+ // Tailwind selection
126
+ if (cliOptions.tailwind === undefined) {
127
+ const tailwind = await confirm({
128
+ message: 'Would you like to use Tailwind CSS?',
129
+ initialValue: true,
130
+ });
131
+ if (isCancel(tailwind)) {
132
+ cancel('Operation cancelled.');
133
+ process.exit(0);
134
+ }
135
+ options.tailwind = tailwind;
136
+ }
137
+ else {
138
+ options.tailwind = cliOptions.tailwind;
139
+ }
140
+ // Package manager selection
141
+ if (cliOptions.packageManager === undefined) {
142
+ const detectedPackageManager = getPackageManager();
143
+ if (!detectedPackageManager) {
144
+ const pm = await select({
145
+ message: 'Select package manager:',
146
+ options: SUPPORTED_PACKAGE_MANAGERS.map((pm) => ({
147
+ value: pm,
148
+ label: pm,
149
+ })),
150
+ initialValue: DEFAULT_PACKAGE_MANAGER,
151
+ });
152
+ if (isCancel(pm)) {
153
+ cancel('Operation cancelled.');
154
+ process.exit(0);
155
+ }
156
+ options.packageManager = pm;
157
+ }
158
+ else {
159
+ options.packageManager = detectedPackageManager;
160
+ }
161
+ }
162
+ else {
163
+ options.packageManager = cliOptions.packageManager;
164
+ }
165
+ // Select any add-ons
166
+ if (options.mode === FILE_ROUTER && cliOptions.addOns) {
167
+ const addOns = await getAllAddOns();
168
+ const selectedAddOns = await multiselect({
169
+ message: 'What add-ons would you like for your project:',
170
+ options: addOns
171
+ .filter((addOn) => addOn.type === 'add-on')
172
+ .map((addOn) => ({
173
+ value: addOn.id,
174
+ label: addOn.name,
175
+ hint: addOn.description,
176
+ })),
177
+ required: false,
178
+ });
179
+ if (isCancel(selectedAddOns)) {
180
+ cancel('Operation cancelled.');
181
+ process.exit(0);
182
+ }
183
+ const selectedExamples = await multiselect({
184
+ message: 'Would you like any examples?',
185
+ options: addOns
186
+ .filter((addOn) => addOn.type === 'example')
187
+ .map((addOn) => ({
188
+ value: addOn.id,
189
+ label: addOn.name,
190
+ hint: addOn.description,
191
+ })),
192
+ required: false,
193
+ });
194
+ if (isCancel(selectedExamples)) {
195
+ cancel('Operation cancelled.');
196
+ process.exit(0);
197
+ }
198
+ options.chosenAddOns = await finalizeAddOns([
199
+ ...selectedAddOns,
200
+ ...selectedExamples,
201
+ ]);
202
+ options.tailwind = true;
203
+ }
204
+ else {
205
+ options.chosenAddOns = [];
206
+ }
207
+ // Collect variables
208
+ const variables = [];
209
+ for (const addOn of options.chosenAddOns) {
210
+ for (const variable of addOn.variables ?? []) {
211
+ variables.push(variable);
212
+ }
213
+ }
214
+ options.variableValues = await collectVariables(variables);
215
+ // Git selection
216
+ if (cliOptions.git === undefined) {
217
+ const git = await confirm({
218
+ message: 'Would you like to initialize a new git repository?',
219
+ initialValue: true,
220
+ });
221
+ if (isCancel(git)) {
222
+ cancel('Operation cancelled.');
223
+ process.exit(0);
224
+ }
225
+ options.git = git;
226
+ }
227
+ else {
228
+ options.git = !!cliOptions.git;
229
+ }
230
+ return options;
231
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-tsrouter-app",
3
- "version": "0.2.0",
3
+ "version": "0.3.0-alpha.2",
4
4
  "description": "Tanstack Application Builder",
5
5
  "bin": "./dist/index.js",
6
6
  "type": "module",
@@ -23,9 +23,11 @@
23
23
  "license": "MIT",
24
24
  "dependencies": {
25
25
  "@clack/prompts": "^0.10.0",
26
+ "chalk": "^5.4.1",
26
27
  "commander": "^13.1.0",
27
28
  "ejs": "^3.1.10",
28
- "execa": "^9.5.2"
29
+ "execa": "^9.5.2",
30
+ "prettier": "^3.5.0"
29
31
  },
30
32
  "devDependencies": {
31
33
  "@tanstack/config": "^0.16.2",
@@ -34,7 +36,6 @@
34
36
  "eslint": "^9.20.0",
35
37
  "eslint-plugin-react-hooks": "^5.1.0",
36
38
  "eslint-plugin-unused-imports": "^4.1.4",
37
- "prettier": "^3.5.0",
38
39
  "typescript": "^5.6.3"
39
40
  },
40
41
  "scripts": {}