@tanstack/cta-cli 0.10.0-alpha.19 → 0.10.0-alpha.21
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 +82 -33
- package/dist/command-line.js +75 -0
- package/dist/mcp.js +170 -0
- package/dist/options.js +40 -331
- package/dist/types/cli.d.ts +3 -1
- package/dist/types/command-line.d.ts +3 -0
- package/dist/types/mcp.d.ts +7 -0
- package/dist/types/options.d.ts +2 -3
- package/dist/types/types.d.ts +3 -1
- package/dist/types/ui-environment.d.ts +1 -1
- package/dist/types/ui-prompts.d.ts +10 -0
- package/dist/types/utils.d.ts +3 -0
- package/dist/ui-environment.js +45 -42
- package/dist/ui-prompts.js +140 -0
- package/dist/utils.js +7 -0
- package/package.json +10 -6
- package/src/cli.ts +102 -46
- package/src/command-line.ts +111 -0
- package/src/mcp.ts +247 -0
- package/src/options.ts +69 -395
- package/src/types.ts +4 -1
- package/src/ui-environment.ts +54 -44
- package/src/ui-prompts.ts +187 -0
- package/src/utils.ts +11 -0
- package/tests/command-line.test.ts +205 -0
- package/tests/index.test.ts +9 -0
- package/tests/options.test.ts +287 -0
- package/tests/setupVitest.ts +6 -0
- package/tests/ui-environment.test.ts +97 -0
- package/tests/ui-prompts.test.ts +233 -0
- package/vitest.config.js +7 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { cancel, confirm, isCancel, multiselect, select, text, } from '@clack/prompts';
|
|
2
|
+
import { CODE_ROUTER, DEFAULT_PACKAGE_MANAGER, FILE_ROUTER, SUPPORTED_PACKAGE_MANAGERS, getAllAddOns, } from '@tanstack/cta-engine';
|
|
3
|
+
export async function getProjectName() {
|
|
4
|
+
const value = await text({
|
|
5
|
+
message: 'What would you like to name your project?',
|
|
6
|
+
defaultValue: 'my-app',
|
|
7
|
+
validate(value) {
|
|
8
|
+
if (!value) {
|
|
9
|
+
return 'Please enter a name';
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
if (isCancel(value)) {
|
|
14
|
+
cancel('Operation cancelled.');
|
|
15
|
+
process.exit(0);
|
|
16
|
+
}
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
export async function selectRouterType() {
|
|
20
|
+
const routerType = await select({
|
|
21
|
+
message: 'Select the router type:',
|
|
22
|
+
options: [
|
|
23
|
+
{
|
|
24
|
+
value: FILE_ROUTER,
|
|
25
|
+
label: 'File Router - File-based routing structure',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
value: CODE_ROUTER,
|
|
29
|
+
label: 'Code Router - Traditional code-based routing',
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
initialValue: FILE_ROUTER,
|
|
33
|
+
});
|
|
34
|
+
if (isCancel(routerType)) {
|
|
35
|
+
cancel('Operation cancelled.');
|
|
36
|
+
process.exit(0);
|
|
37
|
+
}
|
|
38
|
+
return routerType;
|
|
39
|
+
}
|
|
40
|
+
export async function selectTypescript() {
|
|
41
|
+
const typescriptEnable = await confirm({
|
|
42
|
+
message: 'Would you like to use TypeScript?',
|
|
43
|
+
initialValue: true,
|
|
44
|
+
});
|
|
45
|
+
if (isCancel(typescriptEnable)) {
|
|
46
|
+
cancel('Operation cancelled.');
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
return typescriptEnable;
|
|
50
|
+
}
|
|
51
|
+
export async function selectTailwind() {
|
|
52
|
+
const tailwind = await confirm({
|
|
53
|
+
message: 'Would you like to use Tailwind CSS?',
|
|
54
|
+
initialValue: true,
|
|
55
|
+
});
|
|
56
|
+
if (isCancel(tailwind)) {
|
|
57
|
+
cancel('Operation cancelled.');
|
|
58
|
+
process.exit(0);
|
|
59
|
+
}
|
|
60
|
+
return tailwind;
|
|
61
|
+
}
|
|
62
|
+
export async function selectPackageManager() {
|
|
63
|
+
const packageManager = await select({
|
|
64
|
+
message: 'Select package manager:',
|
|
65
|
+
options: SUPPORTED_PACKAGE_MANAGERS.map((pm) => ({
|
|
66
|
+
value: pm,
|
|
67
|
+
label: pm,
|
|
68
|
+
})),
|
|
69
|
+
initialValue: DEFAULT_PACKAGE_MANAGER,
|
|
70
|
+
});
|
|
71
|
+
if (isCancel(packageManager)) {
|
|
72
|
+
cancel('Operation cancelled.');
|
|
73
|
+
process.exit(0);
|
|
74
|
+
}
|
|
75
|
+
return packageManager;
|
|
76
|
+
}
|
|
77
|
+
export async function selectAddOns(framework, mode, type, message, forcedAddOns = []) {
|
|
78
|
+
const allAddOns = await getAllAddOns(framework, mode);
|
|
79
|
+
const addOns = allAddOns.filter((addOn) => addOn.type === type);
|
|
80
|
+
if (addOns.length === 0) {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
const value = await multiselect({
|
|
84
|
+
message,
|
|
85
|
+
options: addOns
|
|
86
|
+
.filter((addOn) => !forcedAddOns.includes(addOn.id))
|
|
87
|
+
.map((addOn) => ({
|
|
88
|
+
value: addOn.id,
|
|
89
|
+
label: addOn.name,
|
|
90
|
+
hint: addOn.description,
|
|
91
|
+
})),
|
|
92
|
+
required: false,
|
|
93
|
+
});
|
|
94
|
+
if (isCancel(value)) {
|
|
95
|
+
cancel('Operation cancelled.');
|
|
96
|
+
process.exit(0);
|
|
97
|
+
}
|
|
98
|
+
return value;
|
|
99
|
+
}
|
|
100
|
+
export async function selectGit() {
|
|
101
|
+
const git = await confirm({
|
|
102
|
+
message: 'Would you like to initialize a new git repository?',
|
|
103
|
+
initialValue: true,
|
|
104
|
+
});
|
|
105
|
+
if (isCancel(git)) {
|
|
106
|
+
cancel('Operation cancelled.');
|
|
107
|
+
process.exit(0);
|
|
108
|
+
}
|
|
109
|
+
return git;
|
|
110
|
+
}
|
|
111
|
+
export async function selectToolchain(framework, toolchain) {
|
|
112
|
+
const toolchains = new Set();
|
|
113
|
+
for (const addOn of framework.getAddOns()) {
|
|
114
|
+
if (addOn.type === 'toolchain') {
|
|
115
|
+
toolchains.add(addOn);
|
|
116
|
+
if (toolchain && addOn.id === toolchain) {
|
|
117
|
+
return toolchain;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const tc = await select({
|
|
122
|
+
message: 'Select toolchain',
|
|
123
|
+
options: [
|
|
124
|
+
{
|
|
125
|
+
value: undefined,
|
|
126
|
+
label: 'None',
|
|
127
|
+
},
|
|
128
|
+
...Array.from(toolchains).map((tc) => ({
|
|
129
|
+
value: tc.id,
|
|
130
|
+
label: tc.name,
|
|
131
|
+
})),
|
|
132
|
+
],
|
|
133
|
+
initialValue: undefined,
|
|
134
|
+
});
|
|
135
|
+
if (isCancel(tc)) {
|
|
136
|
+
cancel('Operation cancelled.');
|
|
137
|
+
process.exit(0);
|
|
138
|
+
}
|
|
139
|
+
return tc;
|
|
140
|
+
}
|
package/dist/utils.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/cta-cli",
|
|
3
|
-
"version": "0.10.0-alpha.
|
|
3
|
+
"version": "0.10.0-alpha.21",
|
|
4
4
|
"description": "Tanstack Application Builder CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -24,19 +24,23 @@
|
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@clack/prompts": "^0.10.0",
|
|
27
|
+
"@modelcontextprotocol/sdk": "^1.6.0",
|
|
27
28
|
"chalk": "^5.4.1",
|
|
28
29
|
"commander": "^13.1.0",
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"@tanstack/cta-
|
|
32
|
-
"@tanstack/cta-
|
|
30
|
+
"express": "^4.21.2",
|
|
31
|
+
"zod": "^3.24.2",
|
|
32
|
+
"@tanstack/cta-ui": "0.10.0-alpha.21",
|
|
33
|
+
"@tanstack/cta-engine": "0.10.0-alpha.21"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
36
|
"@tanstack/config": "^0.16.2",
|
|
37
|
+
"@types/express": "^5.0.1",
|
|
36
38
|
"@types/node": "^22.13.4",
|
|
39
|
+
"@vitest/coverage-v8": "3.1.1",
|
|
37
40
|
"eslint": "^9.20.0",
|
|
38
41
|
"typescript": "^5.6.3",
|
|
39
|
-
"vitest": "^3.
|
|
42
|
+
"vitest": "^3.1.1",
|
|
43
|
+
"vitest-fetch-mock": "^0.4.5"
|
|
40
44
|
},
|
|
41
45
|
"scripts": {}
|
|
42
46
|
}
|
package/src/cli.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolve } from 'node:path'
|
|
1
2
|
import { Command, InvalidArgumentError } from 'commander'
|
|
2
3
|
import { intro, log } from '@clack/prompts'
|
|
3
4
|
import chalk from 'chalk'
|
|
@@ -5,44 +6,50 @@ import chalk from 'chalk'
|
|
|
5
6
|
import {
|
|
6
7
|
SUPPORTED_PACKAGE_MANAGERS,
|
|
7
8
|
addToApp,
|
|
9
|
+
compileAddOn,
|
|
10
|
+
compileStarter,
|
|
8
11
|
createApp,
|
|
12
|
+
createSerializedOptions,
|
|
9
13
|
getAllAddOns,
|
|
10
14
|
getFrameworkById,
|
|
11
15
|
getFrameworkByName,
|
|
12
16
|
getFrameworks,
|
|
17
|
+
initAddOn,
|
|
18
|
+
initStarter,
|
|
13
19
|
} from '@tanstack/cta-engine'
|
|
14
|
-
import { initAddOn } from '@tanstack/cta-custom-add-on'
|
|
15
|
-
|
|
16
|
-
import { runMCPServer } from '@tanstack/cta-mcp'
|
|
17
20
|
|
|
18
21
|
import { launchUI } from '@tanstack/cta-ui'
|
|
19
22
|
|
|
20
|
-
import {
|
|
23
|
+
import { runMCPServer } from './mcp.js'
|
|
24
|
+
|
|
25
|
+
import { promptForOptions } from './options.js'
|
|
26
|
+
import { normalizeOptions } from './command-line.js'
|
|
21
27
|
|
|
22
28
|
import { createUIEnvironment } from './ui-environment.js'
|
|
29
|
+
import { convertTemplateToMode } from './utils.js'
|
|
23
30
|
|
|
24
|
-
import type {
|
|
25
|
-
Mode,
|
|
26
|
-
Options,
|
|
27
|
-
PackageManager,
|
|
28
|
-
TemplateOptions,
|
|
29
|
-
} from '@tanstack/cta-engine'
|
|
31
|
+
import type { Mode, Options, PackageManager } from '@tanstack/cta-engine'
|
|
30
32
|
|
|
31
|
-
import type { CliOptions } from './types.js'
|
|
33
|
+
import type { CliOptions, TemplateOptions } from './types.js'
|
|
32
34
|
|
|
33
35
|
async function listAddOns(
|
|
34
36
|
options: CliOptions,
|
|
35
37
|
{
|
|
36
38
|
forcedMode,
|
|
37
|
-
forcedAddOns
|
|
39
|
+
forcedAddOns,
|
|
40
|
+
defaultTemplate,
|
|
38
41
|
}: {
|
|
39
|
-
forcedMode?:
|
|
40
|
-
forcedAddOns
|
|
42
|
+
forcedMode?: Mode
|
|
43
|
+
forcedAddOns: Array<string>
|
|
44
|
+
defaultTemplate?: TemplateOptions
|
|
41
45
|
},
|
|
42
46
|
) {
|
|
43
47
|
const addOns = await getAllAddOns(
|
|
44
48
|
getFrameworkById(options.framework || 'react-cra')!,
|
|
45
|
-
forcedMode ||
|
|
49
|
+
forcedMode ||
|
|
50
|
+
convertTemplateToMode(
|
|
51
|
+
options.template || defaultTemplate || 'javascript',
|
|
52
|
+
),
|
|
46
53
|
)
|
|
47
54
|
for (const addOn of addOns.filter((a) => !forcedAddOns.includes(a.id))) {
|
|
48
55
|
console.log(`${chalk.bold(addOn.id)}: ${addOn.description}`)
|
|
@@ -53,14 +60,16 @@ export function cli({
|
|
|
53
60
|
name,
|
|
54
61
|
appName,
|
|
55
62
|
forcedMode,
|
|
56
|
-
forcedAddOns,
|
|
63
|
+
forcedAddOns = [],
|
|
64
|
+
defaultTemplate = 'javascript',
|
|
57
65
|
}: {
|
|
58
66
|
name: string
|
|
59
67
|
appName: string
|
|
60
68
|
forcedMode?: Mode
|
|
61
69
|
forcedAddOns?: Array<string>
|
|
70
|
+
defaultTemplate?: TemplateOptions
|
|
62
71
|
}) {
|
|
63
|
-
const environment = createUIEnvironment()
|
|
72
|
+
const environment = createUIEnvironment(appName, false)
|
|
64
73
|
|
|
65
74
|
const program = new Command()
|
|
66
75
|
|
|
@@ -79,37 +88,61 @@ export function cli({
|
|
|
79
88
|
|
|
80
89
|
program
|
|
81
90
|
.command('add')
|
|
82
|
-
.argument(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
)
|
|
91
|
+
.argument(
|
|
92
|
+
'[add-on...]',
|
|
93
|
+
'Name of the add-ons (or add-ons separated by spaces or commas)',
|
|
94
|
+
)
|
|
95
|
+
.option('--forced', 'Force the add-on to be added', false)
|
|
96
|
+
.option('--ui', 'Add with the UI')
|
|
97
|
+
.action(async (addOns: Array<string>) => {
|
|
98
|
+
const parsedAddOns: Array<string> = []
|
|
99
|
+
for (const addOn of addOns) {
|
|
100
|
+
if (addOn.includes(',') || addOn.includes(' ')) {
|
|
101
|
+
parsedAddOns.push(
|
|
102
|
+
...addOn.split(/[\s,]+/).map((addon) => addon.trim()),
|
|
103
|
+
)
|
|
104
|
+
} else {
|
|
105
|
+
parsedAddOns.push(addOn.trim())
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (program.opts().ui) {
|
|
109
|
+
launchUI({
|
|
110
|
+
mode: 'add',
|
|
111
|
+
addOns: parsedAddOns,
|
|
112
|
+
})
|
|
113
|
+
} else {
|
|
114
|
+
await addToApp(environment, parsedAddOns, process.cwd(), {
|
|
115
|
+
forced: program.opts().forced,
|
|
116
|
+
})
|
|
117
|
+
}
|
|
91
118
|
})
|
|
92
119
|
|
|
93
120
|
const addOnCommand = program.command('add-on')
|
|
94
|
-
|
|
95
121
|
addOnCommand
|
|
96
|
-
.command('
|
|
97
|
-
.description('
|
|
122
|
+
.command('init')
|
|
123
|
+
.description('Initialize an add-on from the current project')
|
|
98
124
|
.action(async () => {
|
|
99
|
-
await initAddOn(
|
|
125
|
+
await initAddOn(environment)
|
|
100
126
|
})
|
|
101
127
|
addOnCommand
|
|
102
|
-
.command('
|
|
103
|
-
.description('
|
|
128
|
+
.command('compile')
|
|
129
|
+
.description('Update add-on from the current project')
|
|
104
130
|
.action(async () => {
|
|
105
|
-
|
|
131
|
+
await compileAddOn(environment)
|
|
106
132
|
})
|
|
107
133
|
|
|
108
|
-
program
|
|
109
|
-
|
|
110
|
-
.
|
|
134
|
+
const starterCommand = program.command('starter')
|
|
135
|
+
starterCommand
|
|
136
|
+
.command('init')
|
|
137
|
+
.description('Initialize a project starter from the current project')
|
|
138
|
+
.action(async () => {
|
|
139
|
+
await initStarter(environment)
|
|
140
|
+
})
|
|
141
|
+
starterCommand
|
|
142
|
+
.command('compile')
|
|
143
|
+
.description('Compile the starter JSON file for the current project')
|
|
111
144
|
.action(async () => {
|
|
112
|
-
await
|
|
145
|
+
await compileStarter(environment)
|
|
113
146
|
})
|
|
114
147
|
|
|
115
148
|
program.argument('[project-name]', 'name of the project')
|
|
@@ -201,16 +234,18 @@ export function cli({
|
|
|
201
234
|
)
|
|
202
235
|
.option('--mcp', 'run the MCP server', false)
|
|
203
236
|
.option('--mcp-sse', 'run the MCP server in SSE mode', false)
|
|
237
|
+
.option('--ui', 'Add with the UI')
|
|
204
238
|
|
|
205
239
|
program.action(async (projectName: string, options: CliOptions) => {
|
|
206
240
|
if (options.listAddOns) {
|
|
207
241
|
await listAddOns(options, {
|
|
208
|
-
forcedMode
|
|
242
|
+
forcedMode,
|
|
209
243
|
forcedAddOns,
|
|
244
|
+
defaultTemplate,
|
|
210
245
|
})
|
|
211
246
|
} else if (options.mcp || options.mcpSse) {
|
|
212
247
|
await runMCPServer(!!options.mcpSse, {
|
|
213
|
-
forcedMode
|
|
248
|
+
forcedMode,
|
|
214
249
|
forcedAddOns,
|
|
215
250
|
appName,
|
|
216
251
|
})
|
|
@@ -240,22 +275,43 @@ export function cli({
|
|
|
240
275
|
)
|
|
241
276
|
}
|
|
242
277
|
|
|
278
|
+
if (options.ui) {
|
|
279
|
+
const defaultOptions: Options = {
|
|
280
|
+
framework: getFrameworkById(cliOptions.framework || 'react-cra')!,
|
|
281
|
+
mode: 'file-router',
|
|
282
|
+
chosenAddOns: [],
|
|
283
|
+
packageManager: 'pnpm',
|
|
284
|
+
projectName: projectName || 'my-app',
|
|
285
|
+
targetDir: resolve(process.cwd(), projectName || 'my-app'),
|
|
286
|
+
typescript: true,
|
|
287
|
+
tailwind: true,
|
|
288
|
+
git: true,
|
|
289
|
+
}
|
|
290
|
+
launchUI({
|
|
291
|
+
mode: 'setup',
|
|
292
|
+
options: createSerializedOptions(finalOptions || defaultOptions),
|
|
293
|
+
})
|
|
294
|
+
return
|
|
295
|
+
}
|
|
296
|
+
|
|
243
297
|
if (finalOptions) {
|
|
244
298
|
intro(`Creating a new ${appName} app in ${projectName}...`)
|
|
245
299
|
} else {
|
|
246
300
|
intro(`Let's configure your ${appName} application`)
|
|
247
301
|
finalOptions = await promptForOptions(cliOptions, {
|
|
248
|
-
forcedMode
|
|
302
|
+
forcedMode,
|
|
249
303
|
forcedAddOns,
|
|
250
304
|
})
|
|
251
305
|
}
|
|
252
306
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
307
|
+
if (!finalOptions) {
|
|
308
|
+
throw new Error('No options were provided')
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
finalOptions.targetDir =
|
|
312
|
+
options.targetDir || resolve(process.cwd(), finalOptions.projectName)
|
|
313
|
+
|
|
314
|
+
await createApp(environment, finalOptions)
|
|
259
315
|
} catch (error) {
|
|
260
316
|
log.error(
|
|
261
317
|
error instanceof Error ? error.message : 'An unknown error occurred',
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { resolve } from 'node:path'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
CODE_ROUTER,
|
|
5
|
+
DEFAULT_PACKAGE_MANAGER,
|
|
6
|
+
FILE_ROUTER,
|
|
7
|
+
finalizeAddOns,
|
|
8
|
+
getFrameworkById,
|
|
9
|
+
getPackageManager,
|
|
10
|
+
loadStarter,
|
|
11
|
+
} from '@tanstack/cta-engine'
|
|
12
|
+
|
|
13
|
+
import type { Mode, Options } from '@tanstack/cta-engine'
|
|
14
|
+
|
|
15
|
+
import type { CliOptions } from './types.js'
|
|
16
|
+
|
|
17
|
+
export async function normalizeOptions(
|
|
18
|
+
cliOptions: CliOptions,
|
|
19
|
+
forcedMode?: Mode,
|
|
20
|
+
forcedAddOns?: Array<string>,
|
|
21
|
+
): Promise<Options | undefined> {
|
|
22
|
+
const projectName = (cliOptions.projectName ?? '').trim()
|
|
23
|
+
if (!projectName) {
|
|
24
|
+
return undefined
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let typescript =
|
|
28
|
+
cliOptions.template === 'typescript' ||
|
|
29
|
+
cliOptions.template === 'file-router' ||
|
|
30
|
+
cliOptions.framework === 'solid'
|
|
31
|
+
|
|
32
|
+
let tailwind = !!cliOptions.tailwind
|
|
33
|
+
if (cliOptions.framework === 'solid') {
|
|
34
|
+
tailwind = true
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let mode: typeof FILE_ROUTER | typeof CODE_ROUTER =
|
|
38
|
+
forcedMode || cliOptions.template === 'file-router'
|
|
39
|
+
? FILE_ROUTER
|
|
40
|
+
: CODE_ROUTER
|
|
41
|
+
|
|
42
|
+
const starter = cliOptions.starter
|
|
43
|
+
? await loadStarter(cliOptions.starter)
|
|
44
|
+
: undefined
|
|
45
|
+
|
|
46
|
+
if (starter) {
|
|
47
|
+
tailwind = starter.tailwind
|
|
48
|
+
typescript = starter.typescript
|
|
49
|
+
cliOptions.framework = starter.framework
|
|
50
|
+
mode = starter.mode as Mode
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const framework = getFrameworkById(cliOptions.framework || 'react-cra')!
|
|
54
|
+
|
|
55
|
+
async function selectAddOns() {
|
|
56
|
+
// Edge case for Windows Powershell
|
|
57
|
+
if (Array.isArray(cliOptions.addOns) && cliOptions.addOns.length === 1) {
|
|
58
|
+
const parseSeparatedArgs = cliOptions.addOns[0].split(' ')
|
|
59
|
+
if (parseSeparatedArgs.length > 1) {
|
|
60
|
+
cliOptions.addOns = parseSeparatedArgs
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (
|
|
65
|
+
Array.isArray(cliOptions.addOns) ||
|
|
66
|
+
starter?.dependsOn ||
|
|
67
|
+
forcedAddOns ||
|
|
68
|
+
cliOptions.toolchain
|
|
69
|
+
) {
|
|
70
|
+
const selectedAddOns = new Set<string>([
|
|
71
|
+
...(starter?.dependsOn || []),
|
|
72
|
+
...(forcedAddOns || []),
|
|
73
|
+
])
|
|
74
|
+
if (cliOptions.addOns && Array.isArray(cliOptions.addOns)) {
|
|
75
|
+
for (const a of cliOptions.addOns) {
|
|
76
|
+
selectedAddOns.add(a)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (cliOptions.toolchain) {
|
|
80
|
+
selectedAddOns.add(cliOptions.toolchain)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return await finalizeAddOns(framework, mode, Array.from(selectedAddOns))
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return []
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const chosenAddOns = await selectAddOns()
|
|
90
|
+
|
|
91
|
+
if (chosenAddOns.length) {
|
|
92
|
+
tailwind = true
|
|
93
|
+
typescript = true
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
projectName: projectName,
|
|
98
|
+
targetDir: resolve(process.cwd(), projectName),
|
|
99
|
+
framework,
|
|
100
|
+
mode,
|
|
101
|
+
typescript,
|
|
102
|
+
tailwind,
|
|
103
|
+
packageManager:
|
|
104
|
+
cliOptions.packageManager ||
|
|
105
|
+
getPackageManager() ||
|
|
106
|
+
DEFAULT_PACKAGE_MANAGER,
|
|
107
|
+
git: !!cliOptions.git,
|
|
108
|
+
chosenAddOns,
|
|
109
|
+
starter: starter,
|
|
110
|
+
}
|
|
111
|
+
}
|