Skip to content

Commit 1f40851

Browse files
committed
chore: refactor toolchains
1 parent 52234cb commit 1f40851

File tree

82 files changed

+365
-363
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+365
-363
lines changed

packages/cta-cli/src/cli.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import chalk from 'chalk'
44

55
import {
66
SUPPORTED_PACKAGE_MANAGERS,
7-
SUPPORTED_TOOLCHAINS,
87
getAllAddOns,
98
getFrameworkById,
109
getFrameworkByName,
@@ -66,6 +65,15 @@ export function cli({
6665

6766
const availableFrameworks = getFrameworks().map((f) => f.name)
6867

68+
const toolchains = new Set<string>()
69+
for (const framework of getFrameworks()) {
70+
for (const addOn of framework.getAddOns()) {
71+
if (addOn.type === 'toolchain') {
72+
toolchains.add(addOn.id)
73+
}
74+
}
75+
}
76+
6977
program.name(name).description(`CLI to create a new ${appName} application`)
7078

7179
program
@@ -157,14 +165,14 @@ export function cli({
157165
},
158166
)
159167
.option<ToolChain>(
160-
`--toolchain <${SUPPORTED_TOOLCHAINS.join('|')}>`,
168+
`--toolchain <${Array.from(toolchains).join('|')}>`,
161169
`Explicitly tell the CLI to use this toolchain`,
162170
(value) => {
163-
if (!SUPPORTED_TOOLCHAINS.includes(value as ToolChain)) {
171+
if (!toolchains.has(value as ToolChain)) {
164172
throw new InvalidArgumentError(
165-
`Invalid toolchain: ${value}. The following are allowed: ${SUPPORTED_TOOLCHAINS.join(
166-
', ',
167-
)}`,
173+
`Invalid toolchain: ${value}. The following are allowed: ${Array.from(
174+
toolchains,
175+
).join(', ')}`,
168176
)
169177
}
170178
return value as ToolChain

packages/cta-cli/src/options.ts

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@ import {
1010
import {
1111
CODE_ROUTER,
1212
DEFAULT_PACKAGE_MANAGER,
13-
DEFAULT_TOOLCHAIN,
1413
FILE_ROUTER,
1514
SUPPORTED_PACKAGE_MANAGERS,
16-
SUPPORTED_TOOLCHAINS,
1715
finalizeAddOns,
1816
getAllAddOns,
1917
getFrameworkById,
@@ -78,7 +76,8 @@ export async function normalizeOptions(
7876
if (
7977
Array.isArray(cliOptions.addOns) ||
8078
starter?.dependsOn ||
81-
forcedAddOns
79+
forcedAddOns ||
80+
cliOptions.toolchain
8281
) {
8382
addOns = true
8483
let finalAddOns = Array.from(
@@ -94,6 +93,11 @@ export async function normalizeOptions(
9493
)
9594
}
9695
const framework = getFrameworkById(cliOptions.framework || 'react-cra')!
96+
97+
if (cliOptions.toolchain) {
98+
finalAddOns.push(cliOptions.toolchain)
99+
}
100+
97101
chosenAddOns = await finalizeAddOns(
98102
framework,
99103
forcedMode || cliOptions.template === 'file-router'
@@ -115,7 +119,6 @@ export async function normalizeOptions(
115119
cliOptions.packageManager ||
116120
getPackageManager() ||
117121
DEFAULT_PACKAGE_MANAGER,
118-
toolchain: cliOptions.toolchain || DEFAULT_TOOLCHAIN,
119122
mode,
120123
git: !!cliOptions.git,
121124
addOns,
@@ -297,30 +300,50 @@ export async function promptForOptions(
297300
}
298301

299302
// Toolchain selection
303+
let toolchain: AddOn | undefined = undefined
300304
if (cliOptions.toolchain === undefined) {
301-
const tc = await select({
305+
const toolchains = new Set<AddOn>()
306+
for (const addOn of framework.getAddOns()) {
307+
if (addOn.type === 'toolchain') {
308+
toolchains.add(addOn)
309+
}
310+
}
311+
312+
const tc = await select<AddOn | undefined>({
302313
message: 'Select toolchain',
303-
options: SUPPORTED_TOOLCHAINS.map((tc) => ({
304-
value: tc,
305-
label: tc,
306-
})),
307-
initialValue: DEFAULT_TOOLCHAIN,
314+
options: [
315+
{
316+
value: undefined,
317+
label: 'None',
318+
},
319+
...Array.from(toolchains).map((tc) => ({
320+
value: tc,
321+
label: tc.name,
322+
})),
323+
],
324+
initialValue: undefined,
308325
})
309326
if (isCancel(tc)) {
310327
cancel('Operation cancelled.')
311328
process.exit(0)
312329
}
313-
options.toolchain = tc
330+
toolchain = tc
314331
} else {
315-
options.toolchain = cliOptions.toolchain
332+
for (const addOn of framework.getAddOns()) {
333+
if (addOn.type === 'toolchain' && addOn.id === cliOptions.toolchain) {
334+
toolchain = addOn
335+
}
336+
}
316337
}
317338

318-
options.chosenAddOns = []
339+
options.chosenAddOns = toolchain ? [toolchain] : []
319340
if (Array.isArray(cliOptions.addOns)) {
320341
options.chosenAddOns = await finalizeAddOns(
321342
options.framework,
322343
options.mode,
323-
Array.from(new Set([...cliOptions.addOns, ...forcedAddOns])),
344+
Array.from(
345+
new Set([...cliOptions.addOns, ...forcedAddOns, toolchain?.id]),
346+
).filter(Boolean) as Array<string>,
324347
)
325348
options.tailwind = true
326349
} else if (cliOptions.addOns) {
@@ -374,22 +397,30 @@ export async function promptForOptions(
374397
if (
375398
selectedAddOns.length > 0 ||
376399
selectedExamples.length > 0 ||
377-
forcedAddOns.length > 0
400+
forcedAddOns.length > 0 ||
401+
toolchain
378402
) {
379403
options.chosenAddOns = await finalizeAddOns(
380404
options.framework,
381405
options.mode,
382406
Array.from(
383-
new Set([...selectedAddOns, ...selectedExamples, ...forcedAddOns]),
384-
),
407+
new Set([
408+
...selectedAddOns,
409+
...selectedExamples,
410+
...forcedAddOns,
411+
toolchain?.id,
412+
]),
413+
).filter(Boolean) as Array<string>,
385414
)
386415
options.tailwind = true
387416
}
388417
} else if (forcedAddOns.length > 0) {
389418
options.chosenAddOns = await finalizeAddOns(
390419
options.framework,
391420
options.mode,
392-
forcedAddOns,
421+
Array.from(new Set([...forcedAddOns, toolchain?.id])).filter(
422+
Boolean,
423+
) as Array<string>,
393424
)
394425
}
395426

packages/cta-cli/src/types.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
1-
import type {
2-
PackageManager,
3-
TemplateOptions,
4-
ToolChain,
5-
} from '@tanstack/cta-core'
1+
import type { PackageManager, TemplateOptions } from '@tanstack/cta-core'
62

73
export interface CliOptions {
84
template?: TemplateOptions
95
framework?: string
106
tailwind?: boolean
117
packageManager?: PackageManager
12-
toolchain?: ToolChain
8+
toolchain?: string
139
projectName?: string
1410
git?: boolean
1511
addOns?: Array<string> | boolean

packages/cta-core/src/add-ons.ts

Lines changed: 8 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,21 @@
1-
import { readFile } from 'node:fs/promises'
2-
import { existsSync, readdirSync } from 'node:fs'
3-
import { resolve } from 'node:path'
1+
import type { AddOn, Framework } from './types.js'
42

5-
import { readFileHelper } from './file-helper.js'
6-
import { findFilesRecursively, isDirectory } from './utils.js'
7-
8-
import type { AddOn, FrameworkDefinition } from './types.js'
9-
10-
export async function getAllAddOns(
11-
framework: FrameworkDefinition,
3+
export function getAllAddOns(
4+
framework: Framework,
125
template: string,
13-
): Promise<Array<AddOn>> {
14-
const addOns: Array<AddOn> = []
15-
16-
for (const type of ['add-on', 'example']) {
17-
const addOnsBase = framework.addOnsDirectory
18-
19-
if (!existsSync(addOnsBase)) {
20-
continue
21-
}
22-
23-
for (const dir of await readdirSync(addOnsBase).filter((file) =>
24-
isDirectory(resolve(addOnsBase, file)),
25-
)) {
26-
const filePath = resolve(addOnsBase, dir, 'info.json')
27-
const fileContent = await readFile(filePath, 'utf-8')
28-
const info = JSON.parse(fileContent)
29-
30-
if (!info.templates.includes(template)) {
31-
continue
32-
}
33-
34-
let packageAdditions: Record<string, string> = {}
35-
if (existsSync(resolve(addOnsBase, dir, 'package.json'))) {
36-
packageAdditions = JSON.parse(
37-
await readFile(resolve(addOnsBase, dir, 'package.json'), 'utf-8'),
38-
)
39-
}
40-
41-
let readme: string | undefined
42-
if (existsSync(resolve(addOnsBase, dir, 'README.md'))) {
43-
readme = await readFile(resolve(addOnsBase, dir, 'README.md'), 'utf-8')
44-
}
45-
46-
const absoluteFiles: Record<string, string> = {}
47-
const assetsDir = resolve(addOnsBase, dir, 'assets')
48-
if (existsSync(assetsDir)) {
49-
await findFilesRecursively(assetsDir, absoluteFiles)
50-
}
51-
const files: Record<string, string> = {}
52-
for (const file of Object.keys(absoluteFiles)) {
53-
files[file.replace(assetsDir, '.')] = await readFileHelper(file)
54-
}
55-
56-
const getFiles = () => {
57-
return Promise.resolve(Object.keys(files))
58-
}
59-
const getFileContents = (path: string) => {
60-
return Promise.resolve(files[path])
61-
}
62-
63-
addOns.push({
64-
...info,
65-
id: dir,
66-
type,
67-
packageAdditions,
68-
readme,
69-
files,
70-
deletedFiles: [],
71-
getFiles,
72-
getFileContents,
73-
})
74-
}
75-
}
76-
77-
return addOns
6+
): Array<AddOn> {
7+
return framework.getAddOns().filter((a) => a.templates.includes(template))
788
}
799

8010
// Turn the list of chosen add-on IDs into a final list of add-ons by resolving dependencies
8111
export async function finalizeAddOns(
82-
framework: FrameworkDefinition,
12+
framework: Framework,
8313
template: string,
8414
chosenAddOnIDs: Array<string>,
8515
): Promise<Array<AddOn>> {
8616
const finalAddOnIDs = new Set(chosenAddOnIDs)
8717

88-
const addOns = await getAllAddOns(framework, template)
18+
const addOns = getAllAddOns(framework, template)
8919

9020
for (const addOnID of finalAddOnIDs) {
9121
let addOn: AddOn | undefined
@@ -111,6 +41,7 @@ export async function finalizeAddOns(
11141
const finalAddOns = [...finalAddOnIDs].map(
11242
(id) => addOns.find((a) => a.id === id)!,
11343
)
44+
11445
return finalAddOns
11546
}
11647

packages/cta-core/src/config-file.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ export async function readConfigFile(
3939
try {
4040
const configFile = resolve(targetDir, CONFIG_FILE)
4141
const config = await readFile(configFile, 'utf8')
42+
43+
// TODO: Look for old config files and convert them to the new format
44+
4245
return JSON.parse(config)
4346
} catch {
4447
return null

0 commit comments

Comments
 (0)