@tanstack/cta-engine 0.28.0 → 0.29.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/add-ons.js +13 -0
- package/dist/add-to-app.js +15 -1
- package/dist/create-app.js +12 -2
- package/dist/custom-add-ons/shared.js +7 -4
- package/dist/environment.js +16 -5
- package/dist/frameworks.js +5 -0
- package/dist/index.js +1 -1
- package/dist/package-json.js +32 -2
- package/dist/special-steps/index.js +3 -1
- package/dist/special-steps/post-init-script.js +31 -0
- package/dist/template-file.js +7 -0
- package/dist/types/add-ons.d.ts +1 -0
- package/dist/types/custom-add-ons/add-on.d.ts +14 -3
- package/dist/types/index.d.ts +2 -2
- package/dist/types/registry.d.ts +8 -8
- package/dist/types/special-steps/post-init-script.d.ts +2 -0
- package/dist/types/types.d.ts +433 -32
- package/dist/types.js +17 -0
- package/package.json +1 -1
- package/src/add-ons.ts +18 -0
- package/src/add-to-app.ts +20 -1
- package/src/create-app.ts +17 -0
- package/src/custom-add-ons/shared.ts +7 -4
- package/src/environment.ts +15 -5
- package/src/frameworks.ts +6 -1
- package/src/index.ts +5 -1
- package/src/package-json.ts +40 -4
- package/src/special-steps/index.ts +3 -1
- package/src/special-steps/post-init-script.ts +52 -0
- package/src/template-file.ts +8 -0
- package/src/types.ts +37 -1
- package/tests/add-on-options.test.ts +332 -0
- package/tests/conditional-packages.test.ts +418 -0
- package/tests/filename-processing.test.ts +275 -0
- package/tests/package-json.test.ts +3 -3
- package/tests/special-steps.test.ts +165 -0
- package/tests/template-context.test.ts +314 -0
package/dist/types.js
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
import z from 'zod';
|
|
2
|
+
export const AddOnSelectOptionSchema = z.object({
|
|
3
|
+
type: z.literal('select'),
|
|
4
|
+
label: z.string(),
|
|
5
|
+
description: z.string().optional(),
|
|
6
|
+
default: z.string(),
|
|
7
|
+
options: z.array(z.object({
|
|
8
|
+
value: z.string(),
|
|
9
|
+
label: z.string(),
|
|
10
|
+
})),
|
|
11
|
+
});
|
|
12
|
+
export const AddOnOptionSchema = z.discriminatedUnion('type', [
|
|
13
|
+
AddOnSelectOptionSchema,
|
|
14
|
+
]);
|
|
15
|
+
export const AddOnOptionsSchema = z.record(z.string(), AddOnOptionSchema);
|
|
2
16
|
export const AddOnBaseSchema = z.object({
|
|
3
17
|
id: z.string(),
|
|
4
18
|
name: z.string(),
|
|
@@ -36,6 +50,8 @@ export const AddOnBaseSchema = z.object({
|
|
|
36
50
|
logo: z.string().optional(),
|
|
37
51
|
addOnSpecialSteps: z.array(z.string()).optional(),
|
|
38
52
|
createSpecialSteps: z.array(z.string()).optional(),
|
|
53
|
+
postInitSpecialSteps: z.array(z.string()).optional(),
|
|
54
|
+
options: AddOnOptionsSchema.optional(),
|
|
39
55
|
default: z.boolean().optional(),
|
|
40
56
|
});
|
|
41
57
|
export const StarterSchema = AddOnBaseSchema.extend({
|
|
@@ -65,4 +81,5 @@ export const AddOnInfoSchema = AddOnBaseSchema.extend({
|
|
|
65
81
|
export const AddOnCompiledSchema = AddOnInfoSchema.extend({
|
|
66
82
|
files: z.record(z.string(), z.string()),
|
|
67
83
|
deletedFiles: z.array(z.string()),
|
|
84
|
+
packageTemplate: z.string().optional(),
|
|
68
85
|
});
|
package/package.json
CHANGED
package/src/add-ons.ts
CHANGED
|
@@ -47,3 +47,21 @@ export async function finalizeAddOns(
|
|
|
47
47
|
function loadAddOn(addOn: AddOn): AddOn {
|
|
48
48
|
return addOn
|
|
49
49
|
}
|
|
50
|
+
|
|
51
|
+
export function populateAddOnOptionsDefaults(
|
|
52
|
+
chosenAddOns: Array<AddOn>
|
|
53
|
+
): Record<string, Record<string, any>> {
|
|
54
|
+
const addOnOptions: Record<string, Record<string, any>> = {}
|
|
55
|
+
|
|
56
|
+
for (const addOn of chosenAddOns) {
|
|
57
|
+
if (addOn.options) {
|
|
58
|
+
const defaults: Record<string, any> = {}
|
|
59
|
+
for (const [optionKey, optionDef] of Object.entries(addOn.options)) {
|
|
60
|
+
defaults[optionKey] = optionDef.default
|
|
61
|
+
}
|
|
62
|
+
addOnOptions[addOn.id] = defaults
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return addOnOptions
|
|
67
|
+
}
|
package/src/add-to-app.ts
CHANGED
|
@@ -181,7 +181,9 @@ export async function runNewCommands(
|
|
|
181
181
|
type: 'command',
|
|
182
182
|
message: `Running ${formatCommand({ command: command.command, args: command.args })}...`,
|
|
183
183
|
})
|
|
184
|
-
await environment.execute(command.command, command.args, cwd
|
|
184
|
+
await environment.execute(command.command, command.args, cwd, {
|
|
185
|
+
inherit: true,
|
|
186
|
+
})
|
|
185
187
|
environment.finishStep('run-commands', 'Setup commands complete')
|
|
186
188
|
}
|
|
187
189
|
}
|
|
@@ -260,6 +262,23 @@ export async function addToApp(
|
|
|
260
262
|
s.stop(`Installed dependencies`)
|
|
261
263
|
environment.finishStep('install-dependencies', 'Dependencies installed')
|
|
262
264
|
|
|
265
|
+
// Run any post-init special steps for the new add-ons
|
|
266
|
+
const postInitSpecialSteps = new Set<string>([])
|
|
267
|
+
for (const addOn of newOptions.chosenAddOns) {
|
|
268
|
+
for (const step of addOn.postInitSpecialSteps || []) {
|
|
269
|
+
if (addOns.includes(addOn.id)) {
|
|
270
|
+
postInitSpecialSteps.add(step)
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (postInitSpecialSteps.size) {
|
|
275
|
+
await runSpecialSteps(
|
|
276
|
+
environment,
|
|
277
|
+
newOptions,
|
|
278
|
+
Array.from(postInitSpecialSteps),
|
|
279
|
+
)
|
|
280
|
+
}
|
|
281
|
+
|
|
263
282
|
// Handle new commands
|
|
264
283
|
|
|
265
284
|
await runNewCommands(environment, persistedOptions, cwd, output)
|
package/src/create-app.ts
CHANGED
|
@@ -147,6 +147,21 @@ async function runCommandsAndInstallDependencies(
|
|
|
147
147
|
environment.finishStep('install-dependencies', 'Installed dependencies')
|
|
148
148
|
s.stop(`Installed dependencies`)
|
|
149
149
|
|
|
150
|
+
// Run any post-init special steps for the new add-ons
|
|
151
|
+
const postInitSpecialSteps = new Set<string>([])
|
|
152
|
+
for (const addOn of options.chosenAddOns) {
|
|
153
|
+
for (const step of addOn.postInitSpecialSteps || []) {
|
|
154
|
+
postInitSpecialSteps.add(step)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (postInitSpecialSteps.size) {
|
|
158
|
+
await runSpecialSteps(
|
|
159
|
+
environment,
|
|
160
|
+
options,
|
|
161
|
+
Array.from(postInitSpecialSteps),
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
|
|
150
165
|
for (const phase of ['setup', 'add-on', 'example']) {
|
|
151
166
|
for (const addOn of options.chosenAddOns.filter(
|
|
152
167
|
(addOn) =>
|
|
@@ -166,6 +181,7 @@ async function runCommandsAndInstallDependencies(
|
|
|
166
181
|
addOn.command!.command,
|
|
167
182
|
addOn.command!.args || [],
|
|
168
183
|
options.targetDir,
|
|
184
|
+
{ inherit: true },
|
|
169
185
|
)
|
|
170
186
|
environment.finishStep('run-commands', 'Setup commands complete')
|
|
171
187
|
s.stop(`${addOn.name} commands complete`)
|
|
@@ -193,6 +209,7 @@ async function runCommandsAndInstallDependencies(
|
|
|
193
209
|
options.starter.command.command,
|
|
194
210
|
options.starter.command.args || [],
|
|
195
211
|
options.targetDir,
|
|
212
|
+
{ inherit: true },
|
|
196
213
|
)
|
|
197
214
|
|
|
198
215
|
environment.finishStep('run-starter-command', 'Starter command complete')
|
|
@@ -2,7 +2,7 @@ import { readdir } from 'node:fs/promises'
|
|
|
2
2
|
import { resolve } from 'node:path'
|
|
3
3
|
import { createApp } from '../create-app.js'
|
|
4
4
|
import { createMemoryEnvironment } from '../environment.js'
|
|
5
|
-
import { finalizeAddOns } from '../add-ons.js'
|
|
5
|
+
import { finalizeAddOns, populateAddOnOptionsDefaults } from '../add-ons.js'
|
|
6
6
|
import { getFrameworkById } from '../frameworks.js'
|
|
7
7
|
import { readConfigFileFromEnvironment } from '../config-file.js'
|
|
8
8
|
import { readFileHelper } from '../file-helpers.js'
|
|
@@ -66,6 +66,9 @@ export async function createAppOptionsFromPersisted(
|
|
|
66
66
|
const { version, ...rest } = json
|
|
67
67
|
/* eslint-enable unused-imports/no-unused-vars */
|
|
68
68
|
const framework = getFrameworkById(rest.framework)
|
|
69
|
+
const chosenAddOns = await finalizeAddOns(framework!, json.mode!, [
|
|
70
|
+
...json.chosenAddOns,
|
|
71
|
+
])
|
|
69
72
|
return {
|
|
70
73
|
...rest,
|
|
71
74
|
mode: json.mode!,
|
|
@@ -77,9 +80,8 @@ export async function createAppOptionsFromPersisted(
|
|
|
77
80
|
targetDir: '',
|
|
78
81
|
framework: framework!,
|
|
79
82
|
starter: json.starter ? await loadStarter(json.starter) : undefined,
|
|
80
|
-
chosenAddOns
|
|
81
|
-
|
|
82
|
-
]),
|
|
83
|
+
chosenAddOns,
|
|
84
|
+
addOnOptions: populateAddOnOptionsDefaults(chosenAddOns),
|
|
83
85
|
}
|
|
84
86
|
}
|
|
85
87
|
|
|
@@ -100,6 +102,7 @@ export function createSerializedOptionsFromPersisted(
|
|
|
100
102
|
targetDir: '',
|
|
101
103
|
framework: json.framework,
|
|
102
104
|
starter: json.starter,
|
|
105
|
+
addOnOptions: {},
|
|
103
106
|
}
|
|
104
107
|
}
|
|
105
108
|
|
package/src/environment.ts
CHANGED
|
@@ -46,12 +46,22 @@ export function createDefaultEnvironment(): Environment {
|
|
|
46
46
|
await mkdir(dirname(path), { recursive: true })
|
|
47
47
|
return writeFile(path, getBinaryFile(base64Contents) as string)
|
|
48
48
|
},
|
|
49
|
-
execute: async (command: string, args: Array<string>, cwd: string) => {
|
|
49
|
+
execute: async (command: string, args: Array<string>, cwd: string, options?: { inherit?: boolean }) => {
|
|
50
50
|
try {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
if (options?.inherit) {
|
|
52
|
+
// For commands that should show output directly to the user
|
|
53
|
+
await execa(command, args, {
|
|
54
|
+
cwd,
|
|
55
|
+
stdio: 'inherit',
|
|
56
|
+
})
|
|
57
|
+
return { stdout: '' }
|
|
58
|
+
} else {
|
|
59
|
+
// For commands where we need to capture output
|
|
60
|
+
const result = await execa(command, args, {
|
|
61
|
+
cwd,
|
|
62
|
+
})
|
|
63
|
+
return { stdout: result.stdout }
|
|
64
|
+
}
|
|
55
65
|
} catch {
|
|
56
66
|
errors.push(
|
|
57
67
|
`Command "${command} ${args.join(' ')}" did not run successfully. Please run this manually in your project.`,
|
package/src/frameworks.ts
CHANGED
|
@@ -56,11 +56,15 @@ export function scanAddOnDirectories(addOnsDirectories: Array<string>) {
|
|
|
56
56
|
const fileContent = readFileSync(filePath, 'utf-8')
|
|
57
57
|
const info = JSON.parse(fileContent)
|
|
58
58
|
|
|
59
|
-
let packageAdditions: Record<string,
|
|
59
|
+
let packageAdditions: Record<string, any> = {}
|
|
60
|
+
let packageTemplate: string | undefined = undefined
|
|
61
|
+
|
|
60
62
|
if (existsSync(resolve(addOnsBase, dir, 'package.json'))) {
|
|
61
63
|
packageAdditions = JSON.parse(
|
|
62
64
|
readFileSync(resolve(addOnsBase, dir, 'package.json'), 'utf-8'),
|
|
63
65
|
)
|
|
66
|
+
} else if (existsSync(resolve(addOnsBase, dir, 'package.json.ejs'))) {
|
|
67
|
+
packageTemplate = readFileSync(resolve(addOnsBase, dir, 'package.json.ejs'), 'utf-8')
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
let readme: string | undefined
|
|
@@ -97,6 +101,7 @@ export function scanAddOnDirectories(addOnsDirectories: Array<string>) {
|
|
|
97
101
|
...info,
|
|
98
102
|
id: dir,
|
|
99
103
|
packageAdditions,
|
|
104
|
+
packageTemplate,
|
|
100
105
|
readme,
|
|
101
106
|
files,
|
|
102
107
|
smallLogo,
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { createApp } from './create-app.js'
|
|
2
2
|
export { addToApp } from './add-to-app.js'
|
|
3
3
|
|
|
4
|
-
export { finalizeAddOns, getAllAddOns } from './add-ons.js'
|
|
4
|
+
export { finalizeAddOns, getAllAddOns, populateAddOnOptionsDefaults } from './add-ons.js'
|
|
5
5
|
|
|
6
6
|
export { loadRemoteAddOn } from './custom-add-ons/add-on.js'
|
|
7
7
|
export { loadStarter } from './custom-add-ons/starter.js'
|
|
@@ -73,6 +73,10 @@ export {
|
|
|
73
73
|
|
|
74
74
|
export type {
|
|
75
75
|
AddOn,
|
|
76
|
+
AddOnOption,
|
|
77
|
+
AddOnOptions,
|
|
78
|
+
AddOnSelectOption,
|
|
79
|
+
AddOnSelection,
|
|
76
80
|
Environment,
|
|
77
81
|
FileBundleHandler,
|
|
78
82
|
Framework,
|
package/src/package-json.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { render } from 'ejs'
|
|
1
2
|
import { sortObject } from './utils.js'
|
|
2
3
|
|
|
3
4
|
import type { Options } from './types.js'
|
|
@@ -8,6 +9,7 @@ export function mergePackageJSON(
|
|
|
8
9
|
) {
|
|
9
10
|
return {
|
|
10
11
|
...packageJSON,
|
|
12
|
+
...(overlayPackageJSON || {}),
|
|
11
13
|
dependencies: {
|
|
12
14
|
...packageJSON.dependencies,
|
|
13
15
|
...(overlayPackageJSON?.dependencies || {}),
|
|
@@ -42,10 +44,44 @@ export function createPackageJSON(options: Options) {
|
|
|
42
44
|
packageJSON = mergePackageJSON(packageJSON, addition)
|
|
43
45
|
}
|
|
44
46
|
|
|
45
|
-
for (const addOn of options.chosenAddOns
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
for (const addOn of options.chosenAddOns) {
|
|
48
|
+
let addOnPackageJSON = addOn.packageAdditions
|
|
49
|
+
|
|
50
|
+
// Process EJS template if present
|
|
51
|
+
if (addOn.packageTemplate) {
|
|
52
|
+
const templateValues = {
|
|
53
|
+
packageManager: options.packageManager,
|
|
54
|
+
projectName: options.projectName,
|
|
55
|
+
typescript: options.typescript,
|
|
56
|
+
tailwind: options.tailwind,
|
|
57
|
+
js: options.typescript ? 'ts' : 'js',
|
|
58
|
+
jsx: options.typescript ? 'tsx' : 'jsx',
|
|
59
|
+
fileRouter: options.mode === 'file-router',
|
|
60
|
+
codeRouter: options.mode === 'code-router',
|
|
61
|
+
addOnEnabled: options.chosenAddOns.reduce<Record<string, boolean>>(
|
|
62
|
+
(acc, addon) => {
|
|
63
|
+
acc[addon.id] = true
|
|
64
|
+
return acc
|
|
65
|
+
},
|
|
66
|
+
{},
|
|
67
|
+
),
|
|
68
|
+
addOnOption: options.addOnOptions,
|
|
69
|
+
addOns: options.chosenAddOns,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const renderedTemplate = render(addOn.packageTemplate, templateValues)
|
|
74
|
+
addOnPackageJSON = JSON.parse(renderedTemplate)
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.error(
|
|
77
|
+
`Error processing package.json.ejs for add-on ${addOn.id}:`,
|
|
78
|
+
error,
|
|
79
|
+
)
|
|
80
|
+
// Fall back to packageAdditions if template processing fails
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
packageJSON = mergePackageJSON(packageJSON, addOnPackageJSON)
|
|
49
85
|
}
|
|
50
86
|
|
|
51
87
|
if (options.starter) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { rimrafNodeModules } from './rimraf-node-modules.js'
|
|
2
|
+
import { postInitScript } from './post-init-script.js'
|
|
2
3
|
|
|
3
4
|
import type { Environment, Options } from '../types.js'
|
|
4
5
|
|
|
@@ -7,6 +8,7 @@ const specialStepsLookup: Record<
|
|
|
7
8
|
(environment: Environment, options: Options) => Promise<void>
|
|
8
9
|
> = {
|
|
9
10
|
'rimraf-node-modules': rimrafNodeModules,
|
|
11
|
+
'post-init-script': postInitScript,
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
export async function runSpecialSteps(
|
|
@@ -18,7 +20,7 @@ export async function runSpecialSteps(
|
|
|
18
20
|
environment.startStep({
|
|
19
21
|
id: 'special-steps',
|
|
20
22
|
type: 'command',
|
|
21
|
-
message: '
|
|
23
|
+
message: 'Running special steps...',
|
|
22
24
|
})
|
|
23
25
|
|
|
24
26
|
for (const step of specialSteps) {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
|
+
|
|
4
|
+
import { getPackageManagerScriptCommand } from '../package-manager.js'
|
|
5
|
+
|
|
6
|
+
import type { Environment, Options } from '../types.js'
|
|
7
|
+
|
|
8
|
+
export async function postInitScript(
|
|
9
|
+
environment: Environment,
|
|
10
|
+
options: Options,
|
|
11
|
+
) {
|
|
12
|
+
const packageJsonPath = resolve(options.targetDir, 'package.json')
|
|
13
|
+
|
|
14
|
+
if (!environment.exists(packageJsonPath)) {
|
|
15
|
+
environment.warn(
|
|
16
|
+
'Warning',
|
|
17
|
+
'No package.json found, skipping post-cta-init script',
|
|
18
|
+
)
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const packageJsonContent = readFileSync(packageJsonPath, 'utf-8')
|
|
24
|
+
const packageJson = JSON.parse(packageJsonContent)
|
|
25
|
+
|
|
26
|
+
if (!packageJson.scripts || !packageJson.scripts['post-cta-init']) {
|
|
27
|
+
// No post-cta-init script found, skip silently
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
environment.startStep({
|
|
32
|
+
id: 'post-init-script',
|
|
33
|
+
type: 'command',
|
|
34
|
+
message: 'Running post-cta-init script...',
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
const { command, args } = getPackageManagerScriptCommand(
|
|
38
|
+
options.packageManager,
|
|
39
|
+
['post-cta-init'],
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
await environment.execute(command, args, options.targetDir, {
|
|
43
|
+
inherit: true,
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
environment.finishStep('post-init-script', 'Post-cta-init script complete')
|
|
47
|
+
} catch (error) {
|
|
48
|
+
environment.error(
|
|
49
|
+
`Failed to run post-cta-init script: ${error instanceof Error ? error.message : String(error)}`,
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
}
|
package/src/template-file.ts
CHANGED
|
@@ -95,6 +95,7 @@ export function createTemplateFile(environment: Environment, options: Options) {
|
|
|
95
95
|
fileRouter: options.mode === 'file-router',
|
|
96
96
|
codeRouter: options.mode === 'code-router',
|
|
97
97
|
addOnEnabled,
|
|
98
|
+
addOnOption: options.addOnOptions,
|
|
98
99
|
addOns: options.chosenAddOns,
|
|
99
100
|
integrations,
|
|
100
101
|
routes,
|
|
@@ -135,6 +136,13 @@ export function createTemplateFile(environment: Environment, options: Options) {
|
|
|
135
136
|
|
|
136
137
|
let target = convertDotFilesAndPaths(file.replace('.ejs', ''))
|
|
137
138
|
|
|
139
|
+
// Strip option prefixes from filename (e.g., __postgres__schema.prisma -> schema.prisma)
|
|
140
|
+
const prefixMatch = target.match(/^(.+\/)?__([^_]+)__(.+)$/)
|
|
141
|
+
if (prefixMatch) {
|
|
142
|
+
const [, directory, , filename] = prefixMatch
|
|
143
|
+
target = (directory || '') + filename
|
|
144
|
+
}
|
|
145
|
+
|
|
138
146
|
let append = false
|
|
139
147
|
if (target.endsWith('.append')) {
|
|
140
148
|
append = true
|
package/src/types.ts
CHANGED
|
@@ -9,6 +9,25 @@ export type StatusStepType =
|
|
|
9
9
|
| 'package-manager'
|
|
10
10
|
| 'other'
|
|
11
11
|
|
|
12
|
+
export const AddOnSelectOptionSchema = z.object({
|
|
13
|
+
type: z.literal('select'),
|
|
14
|
+
label: z.string(),
|
|
15
|
+
description: z.string().optional(),
|
|
16
|
+
default: z.string(),
|
|
17
|
+
options: z.array(
|
|
18
|
+
z.object({
|
|
19
|
+
value: z.string(),
|
|
20
|
+
label: z.string(),
|
|
21
|
+
}),
|
|
22
|
+
),
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
export const AddOnOptionSchema = z.discriminatedUnion('type', [
|
|
26
|
+
AddOnSelectOptionSchema,
|
|
27
|
+
])
|
|
28
|
+
|
|
29
|
+
export const AddOnOptionsSchema = z.record(z.string(), AddOnOptionSchema)
|
|
30
|
+
|
|
12
31
|
export const AddOnBaseSchema = z.object({
|
|
13
32
|
id: z.string(),
|
|
14
33
|
name: z.string(),
|
|
@@ -48,6 +67,8 @@ export const AddOnBaseSchema = z.object({
|
|
|
48
67
|
logo: z.string().optional(),
|
|
49
68
|
addOnSpecialSteps: z.array(z.string()).optional(),
|
|
50
69
|
createSpecialSteps: z.array(z.string()).optional(),
|
|
70
|
+
postInitSpecialSteps: z.array(z.string()).optional(),
|
|
71
|
+
options: AddOnOptionsSchema.optional(),
|
|
51
72
|
default: z.boolean().optional(),
|
|
52
73
|
})
|
|
53
74
|
|
|
@@ -82,8 +103,15 @@ export const AddOnInfoSchema = AddOnBaseSchema.extend({
|
|
|
82
103
|
export const AddOnCompiledSchema = AddOnInfoSchema.extend({
|
|
83
104
|
files: z.record(z.string(), z.string()),
|
|
84
105
|
deletedFiles: z.array(z.string()),
|
|
106
|
+
packageTemplate: z.string().optional(),
|
|
85
107
|
})
|
|
86
108
|
|
|
109
|
+
export type AddOnSelectOption = z.infer<typeof AddOnSelectOptionSchema>
|
|
110
|
+
|
|
111
|
+
export type AddOnOption = z.infer<typeof AddOnOptionSchema>
|
|
112
|
+
|
|
113
|
+
export type AddOnOptions = z.infer<typeof AddOnOptionsSchema>
|
|
114
|
+
|
|
87
115
|
export type Integration = z.infer<typeof IntegrationSchema>
|
|
88
116
|
|
|
89
117
|
export type AddOnBase = z.infer<typeof AddOnBaseSchema>
|
|
@@ -96,13 +124,19 @@ export type AddOnInfo = z.infer<typeof AddOnInfoSchema>
|
|
|
96
124
|
|
|
97
125
|
export type AddOnCompiled = z.infer<typeof AddOnCompiledSchema>
|
|
98
126
|
|
|
127
|
+
export interface AddOnSelection {
|
|
128
|
+
id: string
|
|
129
|
+
enabled: boolean
|
|
130
|
+
options: Record<string, any>
|
|
131
|
+
}
|
|
132
|
+
|
|
99
133
|
export type FileBundleHandler = {
|
|
100
134
|
getFiles: () => Promise<Array<string>>
|
|
101
135
|
getFileContents: (path: string) => Promise<string>
|
|
102
136
|
getDeletedFiles: () => Promise<Array<string>>
|
|
103
137
|
}
|
|
104
138
|
|
|
105
|
-
export type AddOn =
|
|
139
|
+
export type AddOn = AddOnCompiled & FileBundleHandler
|
|
106
140
|
|
|
107
141
|
export type Starter = StarterCompiled & FileBundleHandler
|
|
108
142
|
|
|
@@ -146,6 +180,7 @@ export interface Options {
|
|
|
146
180
|
git: boolean
|
|
147
181
|
|
|
148
182
|
chosenAddOns: Array<AddOn>
|
|
183
|
+
addOnOptions: Record<string, Record<string, any>>
|
|
149
184
|
starter?: Starter | undefined
|
|
150
185
|
}
|
|
151
186
|
|
|
@@ -173,6 +208,7 @@ type FileEnvironment = {
|
|
|
173
208
|
command: string,
|
|
174
209
|
args: Array<string>,
|
|
175
210
|
cwd: string,
|
|
211
|
+
options?: { inherit?: boolean },
|
|
176
212
|
) => Promise<{ stdout: string }>
|
|
177
213
|
deleteFile: (path: string) => Promise<void>
|
|
178
214
|
|