Skip to content

Commit c495a0a

Browse files
committed
chore: UI refactoring
1 parent a13f51a commit c495a0a

19 files changed

+378
-344
lines changed

packages/cta-engine/src/add-to-app.ts

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
import { formatCommand } from './utils.js'
1313
import { packageManagerInstall } from './package-manager.js'
1414
import {
15-
getBinaryFile,
1615
isBase64,
1716
recursivelyGatherFilesFromEnvironment,
1817
} from './file-helpers.js'

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { Environment, Options } from './types.js'
66

77
export type PersistedOptions = Omit<
88
Partial<Options>,
9-
'addOns' | 'chosenAddOns' | 'framework' | 'starter'
9+
'addOns' | 'chosenAddOns' | 'framework' | 'starter' | 'targetDir'
1010
> & {
1111
framework: string
1212
version: number

packages/cta-engine/src/custom-add-ons/shared.ts

+38-6
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import { finalizeAddOns } from '../add-ons.js'
66
import { getFrameworkById } from '../frameworks.js'
77
import { readConfigFileFromEnvironment } from '../config-file.js'
88
import { readFileHelper } from '../file-helpers.js'
9+
import { loadStarter } from '../custom-add-ons/starter.js'
910

10-
import type { Environment, Mode, Options } from '../types.js'
11+
import type { Environment, Mode, Options, SerializedOptions } from '../types.js'
1112
import type { PersistedOptions } from '../config-file.js'
1213

1314
export function createPackageAdditions(
@@ -61,15 +62,46 @@ export function createPackageAdditions(
6162
export async function createAppOptionsFromPersisted(
6263
json: PersistedOptions,
6364
): Promise<Options> {
64-
const framework = getFrameworkById(json.framework)
65+
/* eslint-disable unused-imports/no-unused-vars */
66+
const { version, ...rest } = json
67+
/* eslint-enable unused-imports/no-unused-vars */
68+
const framework = getFrameworkById(rest.framework)
6569
return {
66-
...json,
67-
framework,
68-
addOns: true,
70+
...rest,
71+
mode: json.mode as Mode,
72+
projectName: json.projectName!,
73+
typescript: json.typescript!,
74+
tailwind: json.tailwind!,
75+
git: json.git!,
76+
packageManager: json.packageManager!,
77+
targetDir: '',
78+
framework: framework!,
79+
starter: json.starter ? await loadStarter(json.starter) : undefined,
6980
chosenAddOns: await finalizeAddOns(framework!, json.mode as Mode, [
7081
...json.existingAddOns,
7182
]),
72-
} as Options
83+
}
84+
}
85+
86+
export function createSerializedOptionsFromPersisted(
87+
json: PersistedOptions,
88+
): SerializedOptions {
89+
/* eslint-disable unused-imports/no-unused-vars */
90+
const { version, ...rest } = json
91+
/* eslint-enable unused-imports/no-unused-vars */
92+
return {
93+
...rest,
94+
mode: json.mode as Mode,
95+
projectName: json.projectName!,
96+
typescript: json.typescript!,
97+
tailwind: json.tailwind!,
98+
git: json.git!,
99+
packageManager: json.packageManager!,
100+
targetDir: '',
101+
framework: json.framework,
102+
starter: json.starter,
103+
chosenAddOns: json.existingAddOns,
104+
}
73105
}
74106

75107
export async function runCreateApp(options: Required<Options>) {

packages/cta-engine/src/index.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ export { formatCommand } from './utils.js'
4444

4545
export { initStarter, compileStarter } from './custom-add-ons/starter.js'
4646
export { initAddOn, compileAddOn } from './custom-add-ons/add-on.js'
47-
export { createAppOptionsFromPersisted } from './custom-add-ons/shared.js'
47+
export {
48+
createAppOptionsFromPersisted,
49+
createSerializedOptionsFromPersisted,
50+
} from './custom-add-ons/shared.js'
4851

4952
export { createSerializedOptions } from './options.js'
5053

packages/cta-engine/src/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ export type SerializedOptions = Omit<
137137
> & {
138138
chosenAddOns: Array<string>
139139
starter?: string | undefined
140-
framework?: string | undefined
140+
framework: string
141141
}
142142

143143
type ProjectEnvironment = {

packages/cta-engine/tests/add-to-app.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,8 @@ describe('writeFiles', () => {
216216
// It's ok for unchanged.jpg not to be written, because it matches the existing file
217217
expect(output.files).toEqual({
218218
'./unchanged.jpg': 'base64::foobaz',
219-
'./changing.jpg': 'hello',
220-
'./new.jpg': 'hello',
219+
'./changing.jpg': 'base64::aGVsbG8=',
220+
'./new.jpg': 'base64::aGVsbG8=',
221221
})
222222
})
223223

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { readFileSync } from 'node:fs'
2+
import { resolve } from 'node:path'
3+
4+
import {
5+
addToApp,
6+
createDefaultEnvironment,
7+
createMemoryEnvironment,
8+
recursivelyGatherFiles,
9+
} from '@tanstack/cta-engine'
10+
11+
import { createAppWrapper } from './create-app-wrapper.js'
12+
13+
import { getProjectPath } from '@/engine-handling/server-environment.js'
14+
import {
15+
cleanUpFileArray,
16+
cleanUpFiles,
17+
} from '@/engine-handling/file-helpers.js'
18+
19+
export async function addToAppWrapper(
20+
addOns: Array<string>,
21+
opts: {
22+
dryRun?: boolean
23+
stream?: boolean
24+
},
25+
) {
26+
const projectPath = getProjectPath()
27+
28+
const persistedOptions = JSON.parse(
29+
readFileSync(resolve(projectPath, '.cta.json')),
30+
)
31+
32+
const newAddons: Array<string> = []
33+
for (const addOn of addOns) {
34+
if (!persistedOptions.existingAddOns.includes(addOn)) {
35+
newAddons.push(addOn)
36+
}
37+
}
38+
39+
if (newAddons.length === 0) {
40+
return await createAppWrapper(persistedOptions, opts)
41+
}
42+
43+
async function createEnvironment() {
44+
if (opts.dryRun) {
45+
const { environment, output } = createMemoryEnvironment(projectPath)
46+
environment.writeFile(
47+
resolve(projectPath, '.cta.json'),
48+
JSON.stringify(persistedOptions, null, 2),
49+
)
50+
51+
const localFiles = await cleanUpFiles(
52+
await recursivelyGatherFiles(projectPath, false),
53+
)
54+
for (const file of Object.keys(localFiles)) {
55+
environment.writeFile(resolve(projectPath, file), localFiles[file])
56+
}
57+
return { environment, output }
58+
}
59+
return {
60+
environment: createDefaultEnvironment(),
61+
output: { files: {}, deletedFiles: [], commands: [] },
62+
}
63+
}
64+
65+
const { environment, output } = await createEnvironment()
66+
67+
if (opts.stream) {
68+
return new ReadableStream({
69+
start(controller) {
70+
environment.startStep = (message) => {
71+
console.log(message)
72+
controller.enqueue(new TextEncoder().encode(`${message}\n`))
73+
}
74+
environment.finishStep = (message) => {
75+
console.log(message)
76+
controller.enqueue(new TextEncoder().encode(`${message}\n`))
77+
}
78+
79+
environment.startRun()
80+
addToApp(environment, newAddons, projectPath, {
81+
forced: true,
82+
}).then(() => {
83+
environment.finishRun()
84+
controller.close()
85+
})
86+
},
87+
})
88+
} else {
89+
environment.startRun()
90+
await addToApp(environment, newAddons, projectPath, {
91+
forced: true,
92+
})
93+
environment.finishRun()
94+
95+
output.files = cleanUpFiles(output.files, projectPath)
96+
output.deletedFiles = cleanUpFileArray(output.deletedFiles, projectPath)
97+
return output
98+
}
99+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { resolve } from 'node:path'
2+
3+
import {
4+
createApp,
5+
createDefaultEnvironment,
6+
createMemoryEnvironment,
7+
finalizeAddOns,
8+
getFrameworkById,
9+
loadStarter,
10+
} from '@tanstack/cta-engine'
11+
12+
import { registerFrameworks } from './framework-registration'
13+
14+
import { cleanUpFileArray, cleanUpFiles } from './file-helpers'
15+
import { getApplicationMode, getProjectPath } from './server-environment'
16+
17+
import type { Options, SerializedOptions, Starter } from '@tanstack/cta-engine'
18+
19+
export async function createAppWrapper(
20+
projectOptions: SerializedOptions,
21+
opts: { dryRun?: boolean; stream?: boolean },
22+
) {
23+
registerFrameworks()
24+
25+
const framework = getFrameworkById(projectOptions.framework)!
26+
27+
let starter: Starter | undefined
28+
const addOns: Array<string> = [...projectOptions.chosenAddOns]
29+
if (projectOptions.starter) {
30+
starter = await loadStarter(projectOptions.starter)
31+
for (const addOn of starter.dependsOn ?? []) {
32+
addOns.push(addOn)
33+
}
34+
}
35+
const chosenAddOns = await finalizeAddOns(
36+
framework,
37+
projectOptions.mode,
38+
addOns,
39+
)
40+
41+
const projectPath = getProjectPath()
42+
const targetDir =
43+
getApplicationMode() === 'add'
44+
? projectOptions.targetDir
45+
: resolve(projectPath, projectOptions.projectName)
46+
47+
const options: Options = {
48+
...projectOptions,
49+
targetDir,
50+
starter,
51+
framework,
52+
chosenAddOns,
53+
}
54+
55+
function createEnvironment() {
56+
if (opts.dryRun) {
57+
return createMemoryEnvironment(targetDir)
58+
}
59+
return {
60+
environment: createDefaultEnvironment(),
61+
output: { files: {}, deletedFiles: [], commands: [] },
62+
}
63+
}
64+
65+
const { environment, output } = createEnvironment()
66+
67+
if (opts.stream) {
68+
return new ReadableStream({
69+
start(controller) {
70+
environment.startStep = (message) => {
71+
console.log(message)
72+
controller.enqueue(new TextEncoder().encode(`${message}\n`))
73+
}
74+
environment.finishStep = (message) => {
75+
console.log(message)
76+
controller.enqueue(new TextEncoder().encode(`${message}\n`))
77+
}
78+
79+
createApp(environment, options).then(() => {
80+
controller.close()
81+
})
82+
},
83+
})
84+
} else {
85+
await createApp(environment, options)
86+
87+
output.files = cleanUpFiles(output.files, targetDir)
88+
output.deletedFiles = cleanUpFileArray(output.deletedFiles, targetDir)
89+
90+
return output
91+
}
92+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { register as registerReactCra } from '@tanstack/cta-framework-react-cra'
2+
import { register as registerSolid } from '@tanstack/cta-framework-solid'
3+
4+
let registered = false
5+
6+
export function registerFrameworks() {
7+
if (registered) return
8+
registerReactCra()
9+
registerSolid()
10+
registered = true
11+
}

0 commit comments

Comments
 (0)