@tanstack/cta-cli 0.10.0-alpha.18 → 0.10.0-alpha.20

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/options.js CHANGED
@@ -1,358 +1,70 @@
1
- import { cancel, confirm, isCancel, multiselect, select, text, } from '@clack/prompts';
2
- import { CODE_ROUTER, DEFAULT_PACKAGE_MANAGER, FILE_ROUTER, SUPPORTED_PACKAGE_MANAGERS, finalizeAddOns, getAllAddOns, getFrameworkById, getPackageManager, loadRemoteAddOn, } from '@tanstack/cta-engine';
3
- // If all CLI options are provided, use them directly
4
- export async function normalizeOptions(cliOptions, forcedMode, forcedAddOns) {
5
- // in some cases, if you use windows/powershell, the argument for addons
6
- // if sepparated by comma is not really passed as an array, but as a string
7
- // with spaces, We need to normalize this edge case.
8
- if (Array.isArray(cliOptions.addOns) && cliOptions.addOns.length === 1) {
9
- const parseSeparatedArgs = cliOptions.addOns[0].split(' ');
10
- if (parseSeparatedArgs.length > 1) {
11
- cliOptions.addOns = parseSeparatedArgs;
12
- }
13
- }
14
- if (cliOptions.projectName) {
15
- let typescript = cliOptions.template === 'typescript' ||
16
- cliOptions.template === 'file-router' ||
17
- cliOptions.framework === 'solid';
18
- let tailwind = !!cliOptions.tailwind;
19
- if (cliOptions.framework === 'solid') {
20
- tailwind = true;
21
- }
22
- let mode = cliOptions.template === 'file-router' ? FILE_ROUTER : CODE_ROUTER;
23
- const starter = cliOptions.starter
24
- ? (await loadRemoteAddOn(cliOptions.starter))
25
- : undefined;
26
- if (starter) {
27
- tailwind = starter.tailwind;
28
- typescript = starter.typescript;
29
- cliOptions.framework = starter.framework;
30
- mode = starter.mode;
31
- }
32
- let addOns = false;
33
- let chosenAddOns = [];
34
- if (Array.isArray(cliOptions.addOns) ||
35
- starter?.dependsOn ||
36
- forcedAddOns ||
37
- cliOptions.toolchain) {
38
- addOns = true;
39
- let finalAddOns = Array.from(new Set([...(starter?.dependsOn || []), ...(forcedAddOns || [])]));
40
- if (cliOptions.addOns && Array.isArray(cliOptions.addOns)) {
41
- finalAddOns = Array.from(new Set([
42
- ...(forcedAddOns || []),
43
- ...finalAddOns,
44
- ...cliOptions.addOns,
45
- ]));
46
- }
47
- const framework = getFrameworkById(cliOptions.framework || 'react-cra');
48
- if (cliOptions.toolchain) {
49
- finalAddOns.push(cliOptions.toolchain);
50
- }
51
- chosenAddOns = await finalizeAddOns(framework, forcedMode || cliOptions.template === 'file-router'
52
- ? FILE_ROUTER
53
- : CODE_ROUTER, finalAddOns);
54
- tailwind = true;
55
- typescript = true;
56
- }
57
- return {
58
- // TODO: This is a bit to fix the default framework
59
- framework: getFrameworkById(cliOptions.framework || 'react-cra'),
60
- projectName: cliOptions.projectName,
61
- typescript,
62
- tailwind,
63
- packageManager: cliOptions.packageManager ||
64
- getPackageManager() ||
65
- DEFAULT_PACKAGE_MANAGER,
66
- mode,
67
- git: !!cliOptions.git,
68
- addOns,
69
- chosenAddOns,
70
- variableValues: {},
71
- starter,
72
- };
73
- }
74
- }
75
- async function collectVariables(variables) {
76
- const responses = {};
77
- for (const variable of variables) {
78
- if (variable.type === 'string') {
79
- const response = await text({
80
- message: variable.description,
81
- initialValue: variable.default,
82
- });
83
- if (isCancel(response)) {
84
- cancel('Operation cancelled.');
85
- process.exit(0);
86
- }
87
- responses[variable.name] = response;
88
- }
89
- else if (variable.type === 'number') {
90
- const response = await text({
91
- message: variable.description,
92
- initialValue: variable.default.toString(),
93
- });
94
- if (isCancel(response)) {
95
- cancel('Operation cancelled.');
96
- process.exit(0);
97
- }
98
- responses[variable.name] = Number(response);
99
- }
100
- else {
101
- const response = await confirm({
102
- message: variable.description,
103
- initialValue: variable.default === true,
104
- });
105
- if (isCancel(response)) {
106
- cancel('Operation cancelled.');
107
- process.exit(0);
108
- }
109
- responses[variable.name] = response;
110
- }
111
- }
112
- return responses;
113
- }
1
+ import { CODE_ROUTER, FILE_ROUTER, finalizeAddOns, getFrameworkById, getPackageManager, } from '@tanstack/cta-engine';
2
+ import { getProjectName, selectAddOns, selectGit, selectPackageManager, selectRouterType, selectTailwind, selectToolchain, selectTypescript, } from './ui-prompts.js';
114
3
  export async function promptForOptions(cliOptions, { forcedAddOns = [], forcedMode, }) {
115
4
  const options = {};
116
- const framework = getFrameworkById(cliOptions.framework || 'react-cra');
117
- options.framework = framework;
118
- // TODO: This is a bit of a hack to ensure that the framework is solid
119
- if (options.framework.id === 'solid') {
120
- options.typescript = true;
121
- options.tailwind = true;
122
- }
123
- if (cliOptions.addOns) {
124
- options.typescript = true;
125
- }
126
- if (!cliOptions.projectName) {
127
- const value = await text({
128
- message: 'What would you like to name your project?',
129
- defaultValue: 'my-app',
130
- validate(value) {
131
- if (!value) {
132
- return 'Please enter a name';
133
- }
134
- },
135
- });
136
- if (isCancel(value)) {
137
- cancel('Operation cancelled.');
138
- process.exit(0);
139
- }
140
- options.projectName = value;
141
- }
5
+ options.framework = getFrameworkById(cliOptions.framework || 'react-cra');
6
+ options.projectName = cliOptions.projectName || (await getProjectName());
142
7
  // Router type selection
143
- if (!cliOptions.template && !forcedMode) {
144
- const routerType = await select({
145
- message: 'Select the router type:',
146
- options: [
147
- {
148
- value: FILE_ROUTER,
149
- label: 'File Router - File-based routing structure',
150
- },
151
- {
152
- value: CODE_ROUTER,
153
- label: 'Code Router - Traditional code-based routing',
154
- },
155
- ],
156
- initialValue: FILE_ROUTER,
157
- });
158
- if (isCancel(routerType)) {
159
- cancel('Operation cancelled.');
160
- process.exit(0);
161
- }
162
- options.mode = routerType;
163
- }
164
- else if (forcedMode) {
165
- options.mode = forcedMode === 'file-router' ? FILE_ROUTER : CODE_ROUTER;
166
- options.typescript = options.mode === FILE_ROUTER;
8
+ if (forcedMode) {
9
+ options.mode = forcedMode;
167
10
  }
168
- else {
11
+ else if (cliOptions.template) {
169
12
  options.mode =
170
13
  cliOptions.template === 'file-router' ? FILE_ROUTER : CODE_ROUTER;
171
- if (options.mode === FILE_ROUTER) {
172
- options.typescript = true;
173
- }
14
+ }
15
+ else {
16
+ options.mode = await selectRouterType();
174
17
  }
175
18
  // TypeScript selection (if using Code Router)
176
- if (!options.typescript) {
177
- if (options.mode === CODE_ROUTER) {
178
- const typescriptEnable = await confirm({
179
- message: 'Would you like to use TypeScript?',
180
- initialValue: true,
181
- });
182
- if (isCancel(typescriptEnable)) {
183
- cancel('Operation cancelled.');
184
- process.exit(0);
185
- }
186
- options.typescript = typescriptEnable;
187
- }
188
- else {
189
- options.typescript = true;
190
- }
19
+ options.typescript =
20
+ options.mode === FILE_ROUTER || options.framework.id === 'solid';
21
+ if (!options.typescript && options.mode === CODE_ROUTER) {
22
+ options.typescript = await selectTypescript();
191
23
  }
192
24
  // Tailwind selection
193
25
  if (!cliOptions.tailwind && options.framework.id === 'react-cra') {
194
- const tailwind = await confirm({
195
- message: 'Would you like to use Tailwind CSS?',
196
- initialValue: true,
197
- });
198
- if (isCancel(tailwind)) {
199
- cancel('Operation cancelled.');
200
- process.exit(0);
201
- }
202
- options.tailwind = tailwind;
26
+ options.tailwind = await selectTailwind();
203
27
  }
204
28
  else {
205
- // TODO: This is a bit of a hack to ensure that the framework is solid
206
- options.tailwind = options.framework.id === 'solid' || !!cliOptions.tailwind;
29
+ options.tailwind = true;
207
30
  }
208
31
  // Package manager selection
209
- if (cliOptions.packageManager === undefined) {
210
- const detectedPackageManager = getPackageManager();
211
- if (!detectedPackageManager) {
212
- const pm = await select({
213
- message: 'Select package manager:',
214
- options: SUPPORTED_PACKAGE_MANAGERS.map((pm) => ({
215
- value: pm,
216
- label: pm,
217
- })),
218
- initialValue: DEFAULT_PACKAGE_MANAGER,
219
- });
220
- if (isCancel(pm)) {
221
- cancel('Operation cancelled.');
222
- process.exit(0);
223
- }
224
- options.packageManager = pm;
225
- }
226
- else {
227
- options.packageManager = detectedPackageManager;
228
- }
32
+ if (cliOptions.packageManager) {
33
+ options.packageManager = cliOptions.packageManager;
229
34
  }
230
35
  else {
231
- options.packageManager = cliOptions.packageManager;
36
+ const detectedPackageManager = await getPackageManager();
37
+ options.packageManager =
38
+ detectedPackageManager || (await selectPackageManager());
232
39
  }
233
40
  // Toolchain selection
234
- let toolchain = undefined;
235
- if (cliOptions.toolchain === undefined) {
236
- const toolchains = new Set();
237
- for (const addOn of framework.getAddOns()) {
238
- if (addOn.type === 'toolchain') {
239
- toolchains.add(addOn);
240
- }
241
- }
242
- const tc = await select({
243
- message: 'Select toolchain',
244
- options: [
245
- {
246
- value: undefined,
247
- label: 'None',
248
- },
249
- ...Array.from(toolchains).map((tc) => ({
250
- value: tc,
251
- label: tc.name,
252
- })),
253
- ],
254
- initialValue: undefined,
255
- });
256
- if (isCancel(tc)) {
257
- cancel('Operation cancelled.');
258
- process.exit(0);
259
- }
260
- toolchain = tc;
41
+ const toolchain = await selectToolchain(options.framework, cliOptions.toolchain);
42
+ // Add-ons selection
43
+ const addOns = new Set();
44
+ if (toolchain) {
45
+ addOns.add(toolchain);
261
46
  }
262
- else {
263
- for (const addOn of framework.getAddOns()) {
264
- if (addOn.type === 'toolchain' && addOn.id === cliOptions.toolchain) {
265
- toolchain = addOn;
266
- }
267
- }
47
+ for (const addOn of forcedAddOns) {
48
+ addOns.add(addOn);
268
49
  }
269
- options.chosenAddOns = toolchain ? [toolchain] : [];
270
50
  if (Array.isArray(cliOptions.addOns)) {
271
- options.chosenAddOns = await finalizeAddOns(options.framework, options.mode, Array.from(new Set([...cliOptions.addOns, ...forcedAddOns, toolchain?.id])).filter(Boolean));
272
- options.tailwind = true;
273
- }
274
- else if (cliOptions.addOns) {
275
- // Select any add-ons
276
- const allAddOns = await getAllAddOns(options.framework, options.mode);
277
- const addOns = allAddOns.filter((addOn) => addOn.type === 'add-on');
278
- let selectedAddOns = [];
279
- if (options.typescript && addOns.length > 0) {
280
- const value = await multiselect({
281
- message: 'What add-ons would you like for your project:',
282
- options: addOns
283
- .filter((addOn) => !forcedAddOns.includes(addOn.id))
284
- .map((addOn) => ({
285
- value: addOn.id,
286
- label: addOn.name,
287
- hint: addOn.description,
288
- })),
289
- required: false,
290
- });
291
- if (isCancel(value)) {
292
- cancel('Operation cancelled.');
293
- process.exit(0);
294
- }
295
- selectedAddOns = value;
51
+ for (const addOn of cliOptions.addOns) {
52
+ addOns.add(addOn);
296
53
  }
297
- // Select any examples
298
- let selectedExamples = [];
299
- const examples = allAddOns.filter((addOn) => addOn.type === 'example');
300
- if (options.typescript && examples.length > 0) {
301
- const value = await multiselect({
302
- message: 'Would you like any examples?',
303
- options: examples
304
- .filter((addOn) => !forcedAddOns.includes(addOn.id))
305
- .map((addOn) => ({
306
- value: addOn.id,
307
- label: addOn.name,
308
- hint: addOn.description,
309
- })),
310
- required: false,
311
- });
312
- if (isCancel(value)) {
313
- cancel('Operation cancelled.');
314
- process.exit(0);
315
- }
316
- selectedExamples = value;
317
- }
318
- if (selectedAddOns.length > 0 ||
319
- selectedExamples.length > 0 ||
320
- forcedAddOns.length > 0 ||
321
- toolchain) {
322
- options.chosenAddOns = await finalizeAddOns(options.framework, options.mode, Array.from(new Set([
323
- ...selectedAddOns,
324
- ...selectedExamples,
325
- ...forcedAddOns,
326
- toolchain?.id,
327
- ])).filter(Boolean));
328
- options.tailwind = true;
329
- }
330
- }
331
- else if (forcedAddOns.length > 0) {
332
- options.chosenAddOns = await finalizeAddOns(options.framework, options.mode, Array.from(new Set([...forcedAddOns, toolchain?.id])).filter(Boolean));
333
54
  }
334
- // Collect variables
335
- const variables = [];
336
- for (const addOn of options.chosenAddOns) {
337
- for (const variable of addOn.variables ?? []) {
338
- variables.push(variable);
55
+ else {
56
+ for (const addOn of await selectAddOns(options.framework, options.mode, 'add-on', 'What add-ons would you like for your project?', forcedAddOns)) {
57
+ addOns.add(addOn);
339
58
  }
340
- }
341
- options.variableValues = await collectVariables(variables);
342
- // Git selection
343
- if (cliOptions.git === undefined) {
344
- const git = await confirm({
345
- message: 'Would you like to initialize a new git repository?',
346
- initialValue: true,
347
- });
348
- if (isCancel(git)) {
349
- cancel('Operation cancelled.');
350
- process.exit(0);
59
+ for (const addOn of await selectAddOns(options.framework, options.mode, 'example', 'Would you like any examples?', forcedAddOns)) {
60
+ addOns.add(addOn);
351
61
  }
352
- options.git = git;
353
62
  }
354
- else {
355
- options.git = !!cliOptions.git;
63
+ options.chosenAddOns = Array.from(await finalizeAddOns(options.framework, options.mode, Array.from(addOns)));
64
+ if (options.chosenAddOns.length) {
65
+ options.tailwind = true;
66
+ options.typescript = true;
356
67
  }
68
+ options.git = cliOptions.git || (await selectGit());
357
69
  return options;
358
70
  }
@@ -1,7 +1,9 @@
1
1
  import type { Mode } from '@tanstack/cta-engine';
2
- export declare function cli({ name, appName, forcedMode, forcedAddOns, }: {
2
+ import type { TemplateOptions } from './types.js';
3
+ export declare function cli({ name, appName, forcedMode, forcedAddOns, defaultTemplate, }: {
3
4
  name: string;
4
5
  appName: string;
5
6
  forcedMode?: Mode;
6
7
  forcedAddOns?: Array<string>;
8
+ defaultTemplate?: TemplateOptions;
7
9
  }): void;
@@ -0,0 +1,3 @@
1
+ import type { Mode, Options } from '@tanstack/cta-engine';
2
+ import type { CliOptions } from './types.js';
3
+ export declare function normalizeOptions(cliOptions: CliOptions, forcedMode?: Mode, forcedAddOns?: Array<string>): Promise<Options | undefined>;
@@ -0,0 +1,7 @@
1
+ import type { Mode } from '@tanstack/cta-engine';
2
+ export declare function runMCPServer(sse: boolean, { forcedAddOns, appName, name, }: {
3
+ forcedMode?: Mode;
4
+ forcedAddOns?: Array<string>;
5
+ appName?: string;
6
+ name?: string;
7
+ }): Promise<void>;
@@ -1,7 +1,6 @@
1
- import type { Mode, Options, TemplateOptions } from '@tanstack/cta-engine';
1
+ import type { Mode, Options } from '@tanstack/cta-engine';
2
2
  import type { CliOptions } from './types.js';
3
- export declare function normalizeOptions(cliOptions: CliOptions, forcedMode?: Mode, forcedAddOns?: Array<string>): Promise<Options | undefined>;
4
3
  export declare function promptForOptions(cliOptions: CliOptions, { forcedAddOns, forcedMode, }: {
5
4
  forcedAddOns?: Array<string>;
6
- forcedMode?: TemplateOptions;
7
- }): Promise<Required<Options>>;
5
+ forcedMode?: Mode;
6
+ }): Promise<Required<Options> | undefined>;
@@ -1,4 +1,5 @@
1
- import type { PackageManager, TemplateOptions } from '@tanstack/cta-engine';
1
+ import type { PackageManager } from '@tanstack/cta-engine';
2
+ export type TemplateOptions = 'typescript' | 'javascript' | 'file-router';
2
3
  export interface CliOptions {
3
4
  template?: TemplateOptions;
4
5
  framework?: string;
@@ -13,4 +14,6 @@ export interface CliOptions {
13
14
  mcpSse?: boolean;
14
15
  starter?: string;
15
16
  targetDir?: string;
17
+ interactive?: boolean;
18
+ ui?: boolean;
16
19
  }
@@ -1,2 +1,2 @@
1
1
  import type { Environment } from '@tanstack/cta-engine';
2
- export declare function createUIEnvironment(): Environment;
2
+ export declare function createUIEnvironment(appName: string, silent: boolean): Environment;
@@ -0,0 +1,10 @@
1
+ import type { Mode, PackageManager } from '@tanstack/cta-engine';
2
+ import type { Framework } from '@tanstack/cta-engine/dist/types/types.js';
3
+ export declare function getProjectName(): Promise<string>;
4
+ export declare function selectRouterType(): Promise<Mode>;
5
+ export declare function selectTypescript(): Promise<boolean>;
6
+ export declare function selectTailwind(): Promise<boolean>;
7
+ export declare function selectPackageManager(): Promise<PackageManager>;
8
+ export declare function selectAddOns(framework: Framework, mode: Mode, type: string, message: string, forcedAddOns?: Array<string>): Promise<Array<string>>;
9
+ export declare function selectGit(): Promise<boolean>;
10
+ export declare function selectToolchain(framework: Framework, toolchain?: string): Promise<string | undefined>;
@@ -0,0 +1,3 @@
1
+ import type { Mode } from '@tanstack/cta-engine';
2
+ import type { TemplateOptions } from './types.js';
3
+ export declare function convertTemplateToMode(template: TemplateOptions): Mode;
@@ -1,49 +1,52 @@
1
1
  import { cancel, confirm, intro, isCancel, log, outro, spinner, } from '@clack/prompts';
2
2
  import chalk from 'chalk';
3
3
  import { createDefaultEnvironment } from '@tanstack/cta-engine';
4
- export function createUIEnvironment() {
4
+ export function createUIEnvironment(appName, silent) {
5
5
  const defaultEnvironment = createDefaultEnvironment();
6
- return {
6
+ let newEnvironment = {
7
7
  ...defaultEnvironment,
8
- intro: (message) => {
9
- intro(message);
10
- },
11
- outro: (message) => {
12
- outro(message);
13
- },
14
- info: (title, message) => {
15
- console.log('info', title, message);
16
- log.info(`${title ? chalk.red(title) : ''}${message ? chalk.green(message) : ''}`);
17
- },
18
- error: (title, message) => {
19
- console.log('error', title, message);
20
- log.error(`${title ? `${title}: ` : ''}${message}`);
21
- },
22
- warn: (title, message) => {
23
- console.log('warn', title, message);
24
- log.warn(`${title ? `${title}: ` : ''}${message}`);
25
- },
26
- confirm: async (message) => {
27
- console.log('confirm', message);
28
- const shouldContinue = await confirm({
29
- message,
30
- });
31
- if (isCancel(shouldContinue)) {
32
- cancel('Operation cancelled.');
33
- process.exit(0);
34
- }
35
- return shouldContinue;
36
- },
37
- spinner: () => {
38
- const s = spinner();
39
- return {
40
- start: (message) => {
41
- s.start(message);
42
- },
43
- stop: (message) => {
44
- s.stop(message);
45
- },
46
- };
47
- },
8
+ appName,
48
9
  };
10
+ if (!silent) {
11
+ newEnvironment = {
12
+ ...newEnvironment,
13
+ intro: (message) => {
14
+ intro(message);
15
+ },
16
+ outro: (message) => {
17
+ outro(message);
18
+ },
19
+ info: (title, message) => {
20
+ log.info(`${title ? chalk.red(title) : ''}${message ? chalk.green(message) : ''}`);
21
+ },
22
+ error: (title, message) => {
23
+ log.error(`${title ? `${title}: ` : ''}${message}`);
24
+ },
25
+ warn: (title, message) => {
26
+ log.warn(`${title ? `${title}: ` : ''}${message}`);
27
+ },
28
+ confirm: async (message) => {
29
+ const shouldContinue = await confirm({
30
+ message,
31
+ });
32
+ if (isCancel(shouldContinue)) {
33
+ cancel('Operation cancelled.');
34
+ process.exit(0);
35
+ }
36
+ return shouldContinue;
37
+ },
38
+ spinner: () => {
39
+ const s = spinner();
40
+ return {
41
+ start: (message) => {
42
+ s.start(message);
43
+ },
44
+ stop: (message) => {
45
+ s.stop(message);
46
+ },
47
+ };
48
+ },
49
+ };
50
+ }
51
+ return newEnvironment;
49
52
  }