@tanstack/cta-cli 0.24.0 → 0.25.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.
package/dist/cli.js CHANGED
@@ -11,7 +11,7 @@ import { promptForAddOns, promptForCreateOptions } from './options.js';
11
11
  import { normalizeOptions } from './command-line.js';
12
12
  import { createUIEnvironment } from './ui-environment.js';
13
13
  import { convertTemplateToMode } from './utils.js';
14
- // This CLI assumes that all of the registered frameworks have the same set of toolchains, modes, etc.
14
+ // This CLI assumes that all of the registered frameworks have the same set of toolchains, hosts, modes, etc.
15
15
  export function cli({ name, appName, forcedMode, forcedAddOns = [], defaultTemplate = 'javascript', defaultFramework, craCompatible = false, webBase, }) {
16
16
  const environment = createUIEnvironment(appName, false);
17
17
  const program = new Command();
@@ -24,6 +24,14 @@ export function cli({ name, appName, forcedMode, forcedAddOns = [], defaultTempl
24
24
  }
25
25
  }
26
26
  }
27
+ const hosts = new Set();
28
+ for (const framework of getFrameworks()) {
29
+ for (const addOn of framework.getAddOns()) {
30
+ if (addOn.type === 'host') {
31
+ hosts.add(addOn.id);
32
+ }
33
+ }
34
+ }
27
35
  let defaultMode = forcedMode;
28
36
  const supportedModes = new Set();
29
37
  for (const framework of getFrameworks()) {
@@ -191,6 +199,14 @@ Remove your node_modules directory and package lock file and re-install.`);
191
199
  }
192
200
  return value;
193
201
  });
202
+ if (hosts.size > 0) {
203
+ program.option(`--host <${Array.from(hosts).join('|')}>`, `Explicitly tell the CLI to use this hosting provider`, (value) => {
204
+ if (!hosts.has(value)) {
205
+ throw new InvalidArgumentError(`Invalid host: ${value}. The following are allowed: ${Array.from(hosts).join(', ')}`);
206
+ }
207
+ return value;
208
+ });
209
+ }
194
210
  if (toolchains.size > 0) {
195
211
  program.option(`--toolchain <${Array.from(toolchains).join('|')}>`, `Explicitly tell the CLI to use this toolchain`, (value) => {
196
212
  if (!toolchains.has(value)) {
@@ -249,13 +265,14 @@ Remove your node_modules directory and package lock file and re-install.`);
249
265
  }
250
266
  if (options.ui) {
251
267
  const optionsFromCLI = await normalizeOptions(cliOptions, defaultMode, forcedAddOns, { disableNameCheck: true });
268
+ const options = {
269
+ ...createSerializedOptions(optionsFromCLI),
270
+ projectName: 'my-app',
271
+ targetDir: resolve(process.cwd(), 'my-app'),
272
+ };
252
273
  launchUI({
253
274
  mode: 'setup',
254
- options: {
255
- ...createSerializedOptions(optionsFromCLI),
256
- projectName: 'my-app',
257
- targetDir: resolve(process.cwd(), 'my-app'),
258
- },
275
+ options,
259
276
  forcedRouterMode: defaultMode,
260
277
  forcedAddOns,
261
278
  environmentFactory: () => createUIEnvironment(appName, false),
@@ -40,7 +40,8 @@ export async function normalizeOptions(cliOptions, forcedMode, forcedAddOns, opt
40
40
  if (Array.isArray(cliOptions.addOns) ||
41
41
  starter?.dependsOn ||
42
42
  forcedAddOns ||
43
- cliOptions.toolchain) {
43
+ cliOptions.toolchain ||
44
+ cliOptions.host) {
44
45
  const selectedAddOns = new Set([
45
46
  ...(starter?.dependsOn || []),
46
47
  ...(forcedAddOns || []),
@@ -53,6 +54,12 @@ export async function normalizeOptions(cliOptions, forcedMode, forcedAddOns, opt
53
54
  if (cliOptions.toolchain) {
54
55
  selectedAddOns.add(cliOptions.toolchain);
55
56
  }
57
+ if (cliOptions.host) {
58
+ selectedAddOns.add(cliOptions.host);
59
+ }
60
+ if (!cliOptions.host) {
61
+ selectedAddOns.add('nitro');
62
+ }
56
63
  return await finalizeAddOns(framework, mode, Array.from(selectedAddOns));
57
64
  }
58
65
  return [];
package/dist/options.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { intro } from '@clack/prompts';
2
2
  import { finalizeAddOns, getFrameworkById, getPackageManager, readConfigFile, } from '@tanstack/cta-engine';
3
- import { getProjectName, selectAddOns, selectGit, selectPackageManager, selectRouterType, selectTailwind, selectToolchain, selectTypescript, } from './ui-prompts.js';
3
+ import { getProjectName, selectAddOns, selectGit, selectPackageManager, selectRouterType, selectTailwind, selectToolchain, selectHost, selectTypescript, } from './ui-prompts.js';
4
4
  export async function promptForCreateOptions(cliOptions, { forcedAddOns = [], forcedMode, }) {
5
5
  const options = {};
6
6
  options.framework = getFrameworkById(cliOptions.framework || 'react-cra');
@@ -45,11 +45,16 @@ export async function promptForCreateOptions(cliOptions, { forcedAddOns = [], fo
45
45
  }
46
46
  // Toolchain selection
47
47
  const toolchain = await selectToolchain(options.framework, cliOptions.toolchain);
48
+ // Host selection
49
+ const host = await selectHost(options.framework, cliOptions.host);
48
50
  // Add-ons selection
49
51
  const addOns = new Set();
50
52
  if (toolchain) {
51
53
  addOns.add(toolchain);
52
54
  }
55
+ if (host) {
56
+ addOns.add(host);
57
+ }
53
58
  for (const addOn of forcedAddOns) {
54
59
  addOns.add(addOn);
55
60
  }
@@ -6,6 +6,7 @@ export interface CliOptions {
6
6
  tailwind?: boolean;
7
7
  packageManager?: PackageManager;
8
8
  toolchain?: string;
9
+ host?: string;
9
10
  projectName?: string;
10
11
  git?: boolean;
11
12
  addOns?: Array<string> | boolean;
@@ -8,3 +8,4 @@ export declare function selectPackageManager(): Promise<PackageManager>;
8
8
  export declare function selectAddOns(framework: Framework, mode: string, type: string, message: string, forcedAddOns?: Array<string>): Promise<Array<string>>;
9
9
  export declare function selectGit(): Promise<boolean>;
10
10
  export declare function selectToolchain(framework: Framework, toolchain?: string): Promise<string | undefined>;
11
+ export declare function selectHost(framework: Framework, host?: string): Promise<string | undefined>;
@@ -138,3 +138,31 @@ export async function selectToolchain(framework, toolchain) {
138
138
  }
139
139
  return tc;
140
140
  }
141
+ export async function selectHost(framework, host) {
142
+ const hosts = new Set();
143
+ for (const addOn of framework
144
+ .getAddOns()
145
+ .sort((a, b) => a.name.localeCompare(b.name))) {
146
+ if (addOn.type === 'host') {
147
+ hosts.add(addOn);
148
+ if (host && addOn.id === host) {
149
+ return host;
150
+ }
151
+ }
152
+ }
153
+ const hp = await select({
154
+ message: 'Select hosting provider',
155
+ options: [
156
+ ...Array.from(hosts).map((h) => ({
157
+ value: h.id,
158
+ label: h.name,
159
+ })),
160
+ ],
161
+ initialValue: undefined,
162
+ });
163
+ if (isCancel(hp)) {
164
+ cancel('Operation cancelled.');
165
+ process.exit(0);
166
+ }
167
+ return hp;
168
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/cta-cli",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
4
  "description": "Tanstack Application Builder CLI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -30,8 +30,8 @@
30
30
  "express": "^4.21.2",
31
31
  "semver": "^7.7.2",
32
32
  "zod": "^3.24.2",
33
- "@tanstack/cta-engine": "0.24.0",
34
- "@tanstack/cta-ui": "0.24.0"
33
+ "@tanstack/cta-engine": "0.25.0",
34
+ "@tanstack/cta-ui": "0.25.0"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@tanstack/config": "^0.16.2",
package/src/cli.ts CHANGED
@@ -33,7 +33,7 @@ import { convertTemplateToMode } from './utils.js'
33
33
  import type { CliOptions, TemplateOptions } from './types.js'
34
34
  import type { Options, PackageManager } from '@tanstack/cta-engine'
35
35
 
36
- // This CLI assumes that all of the registered frameworks have the same set of toolchains, modes, etc.
36
+ // This CLI assumes that all of the registered frameworks have the same set of toolchains, hosts, modes, etc.
37
37
 
38
38
  export function cli({
39
39
  name,
@@ -69,6 +69,15 @@ export function cli({
69
69
  }
70
70
  }
71
71
 
72
+ const hosts = new Set<string>()
73
+ for (const framework of getFrameworks()) {
74
+ for (const addOn of framework.getAddOns()) {
75
+ if (addOn.type === 'host') {
76
+ hosts.add(addOn.id)
77
+ }
78
+ }
79
+ }
80
+
72
81
  let defaultMode: string | undefined = forcedMode
73
82
  const supportedModes = new Set<string>()
74
83
  for (const framework of getFrameworks()) {
@@ -295,6 +304,23 @@ Remove your node_modules directory and package lock file and re-install.`,
295
304
  },
296
305
  )
297
306
 
307
+ if (hosts.size > 0) {
308
+ program.option<string>(
309
+ `--host <${Array.from(hosts).join('|')}>`,
310
+ `Explicitly tell the CLI to use this hosting provider`,
311
+ (value) => {
312
+ if (!hosts.has(value)) {
313
+ throw new InvalidArgumentError(
314
+ `Invalid host: ${value}. The following are allowed: ${Array.from(
315
+ hosts,
316
+ ).join(', ')}`,
317
+ )
318
+ }
319
+ return value
320
+ },
321
+ )
322
+ }
323
+
298
324
  if (toolchains.size > 0) {
299
325
  program.option<string>(
300
326
  `--toolchain <${Array.from(toolchains).join('|')}>`,
@@ -385,13 +411,14 @@ Remove your node_modules directory and package lock file and re-install.`,
385
411
  forcedAddOns,
386
412
  { disableNameCheck: true },
387
413
  )
414
+ const options = {
415
+ ...createSerializedOptions(optionsFromCLI!),
416
+ projectName: 'my-app',
417
+ targetDir: resolve(process.cwd(), 'my-app'),
418
+ }
388
419
  launchUI({
389
420
  mode: 'setup',
390
- options: {
391
- ...createSerializedOptions(optionsFromCLI!),
392
- projectName: 'my-app',
393
- targetDir: resolve(process.cwd(), 'my-app'),
394
- },
421
+ options,
395
422
  forcedRouterMode: defaultMode,
396
423
  forcedAddOns,
397
424
  environmentFactory: () => createUIEnvironment(appName, false),
@@ -74,7 +74,8 @@ export async function normalizeOptions(
74
74
  Array.isArray(cliOptions.addOns) ||
75
75
  starter?.dependsOn ||
76
76
  forcedAddOns ||
77
- cliOptions.toolchain
77
+ cliOptions.toolchain ||
78
+ cliOptions.host
78
79
  ) {
79
80
  const selectedAddOns = new Set<string>([
80
81
  ...(starter?.dependsOn || []),
@@ -88,6 +89,13 @@ export async function normalizeOptions(
88
89
  if (cliOptions.toolchain) {
89
90
  selectedAddOns.add(cliOptions.toolchain)
90
91
  }
92
+ if (cliOptions.host) {
93
+ selectedAddOns.add(cliOptions.host)
94
+ }
95
+
96
+ if (!cliOptions.host) {
97
+ selectedAddOns.add('nitro')
98
+ }
91
99
 
92
100
  return await finalizeAddOns(framework, mode, Array.from(selectedAddOns))
93
101
  }
package/src/options.ts CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  selectRouterType,
16
16
  selectTailwind,
17
17
  selectToolchain,
18
+ selectHost,
18
19
  selectTypescript,
19
20
  } from './ui-prompts.js'
20
21
 
@@ -84,12 +85,18 @@ export async function promptForCreateOptions(
84
85
  cliOptions.toolchain,
85
86
  )
86
87
 
88
+ // Host selection
89
+ const host = await selectHost(options.framework, cliOptions.host)
90
+
87
91
  // Add-ons selection
88
92
  const addOns: Set<string> = new Set()
89
93
 
90
94
  if (toolchain) {
91
95
  addOns.add(toolchain)
92
96
  }
97
+ if (host) {
98
+ addOns.add(host)
99
+ }
93
100
 
94
101
  for (const addOn of forcedAddOns) {
95
102
  addOns.add(addOn)
package/src/types.ts CHANGED
@@ -8,6 +8,7 @@ export interface CliOptions {
8
8
  tailwind?: boolean
9
9
  packageManager?: PackageManager
10
10
  toolchain?: string
11
+ host?: string
11
12
  projectName?: string
12
13
  git?: boolean
13
14
  addOns?: Array<string> | boolean
package/src/ui-prompts.ts CHANGED
@@ -183,3 +183,38 @@ export async function selectToolchain(
183
183
 
184
184
  return tc
185
185
  }
186
+
187
+ export async function selectHost(
188
+ framework: Framework,
189
+ host?: string,
190
+ ): Promise<string | undefined> {
191
+ const hosts = new Set<AddOn>()
192
+ for (const addOn of framework
193
+ .getAddOns()
194
+ .sort((a, b) => a.name.localeCompare(b.name))) {
195
+ if (addOn.type === 'host') {
196
+ hosts.add(addOn)
197
+ if (host && addOn.id === host) {
198
+ return host
199
+ }
200
+ }
201
+ }
202
+
203
+ const hp = await select({
204
+ message: 'Select hosting provider',
205
+ options: [
206
+ ...Array.from(hosts).map((h) => ({
207
+ value: h.id,
208
+ label: h.name,
209
+ })),
210
+ ],
211
+ initialValue: undefined,
212
+ })
213
+
214
+ if (isCancel(hp)) {
215
+ cancel('Operation cancelled.')
216
+ process.exit(0)
217
+ }
218
+
219
+ return hp as string
220
+ }
@@ -62,7 +62,14 @@ describe('normalizeOptions', () => {
62
62
  __testRegisterFramework({
63
63
  id: 'solid',
64
64
  name: 'Solid',
65
- getAddOns: () => [],
65
+ getAddOns: () => [
66
+ {
67
+ id: 'nitro',
68
+ name: 'nitro',
69
+ modes: ['file-router'],
70
+ default: true,
71
+ },
72
+ ],
66
73
  supportedModes: {
67
74
  'code-router': {
68
75
  displayName: 'Code Router',
@@ -95,10 +102,11 @@ describe('normalizeOptions', () => {
95
102
  const options = await normalizeOptions({
96
103
  projectName: 'test',
97
104
  starter: 'https://github.com/cta-dev/cta-starter-solid',
105
+ host: 'nitro',
98
106
  })
99
107
  expect(options?.mode).toBe('file-router')
100
108
  expect(options?.tailwind).toBe(true)
101
- expect(options?.typescript).toBe(false)
109
+ expect(options?.typescript).toBe(true)
102
110
  expect(options?.framework?.id).toBe('solid')
103
111
  })
104
112
 
@@ -123,6 +131,12 @@ describe('normalizeOptions', () => {
123
131
  name: 'foobar',
124
132
  modes: ['file-router'],
125
133
  },
134
+ {
135
+ id: 'nitro',
136
+ name: 'nitro',
137
+ modes: ['file-router'],
138
+ default: true,
139
+ },
126
140
  ],
127
141
  })
128
142
  const options = await normalizeOptions(
@@ -151,6 +165,12 @@ describe('normalizeOptions', () => {
151
165
  name: 'baz',
152
166
  modes: ['file-router'],
153
167
  },
168
+ {
169
+ id: 'nitro',
170
+ name: 'nitro',
171
+ modes: ['file-router'],
172
+ default: true,
173
+ },
154
174
  ],
155
175
  })
156
176
  const options = await normalizeOptions(
@@ -179,6 +199,12 @@ describe('normalizeOptions', () => {
179
199
  name: 'Biome',
180
200
  modes: ['file-router', 'code-router'],
181
201
  },
202
+ {
203
+ id: 'nitro',
204
+ name: 'nitro',
205
+ modes: ['file-router', 'code-router'],
206
+ default: true,
207
+ },
182
208
  ],
183
209
  })
184
210
  const options = await normalizeOptions({
@@ -205,6 +231,12 @@ describe('normalizeOptions', () => {
205
231
  name: 'baz',
206
232
  modes: ['file-router', 'code-router'],
207
233
  },
234
+ {
235
+ id: 'nitro',
236
+ name: 'nitro',
237
+ modes: ['file-router', 'code-router'],
238
+ default: true,
239
+ },
208
240
  ],
209
241
  })
210
242
  const options = await normalizeOptions({