@tanstack/cta-engine 0.10.0-alpha.6 → 0.11.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 +6 -6
- package/dist/add.js +2 -4
- package/dist/cli.js +41 -28
- package/dist/create-app.js +9 -3
- package/dist/custom-add-on.js +4 -4
- package/dist/file-helper.js +18 -0
- package/dist/mcp.js +128 -110
- package/dist/options.js +30 -11
- package/dist/types/add-ons.d.ts +5 -2
- package/dist/types/cli.d.ts +6 -1
- package/dist/types/create-app.d.ts +3 -1
- package/dist/types/file-helper.d.ts +2 -0
- package/dist/types/mcp.d.ts +7 -1
- package/dist/types/options.d.ts +5 -2
- package/dist/types/types.d.ts +2 -1
- package/package.json +1 -1
- package/src/add-ons.ts +18 -9
- package/src/add.ts +7 -5
- package/src/cli.ts +80 -54
- package/src/create-app.ts +15 -2
- package/src/custom-add-on.ts +9 -7
- package/src/file-helper.ts +20 -0
- package/src/mcp.ts +192 -142
- package/src/options.ts +57 -17
- package/src/types.ts +3 -1
- package/tsconfig.json +7 -1
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Environment, Options } from './types.js';
|
|
2
|
-
export declare function createApp(options: Options, { silent, environment, cwd, }: {
|
|
2
|
+
export declare function createApp(options: Options, { silent, environment, cwd, appName, }: {
|
|
3
3
|
silent?: boolean;
|
|
4
4
|
environment: Environment;
|
|
5
5
|
cwd?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
appName?: string;
|
|
6
8
|
}): Promise<void>;
|
package/dist/types/mcp.d.ts
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import type { TemplateOptions } from './types.js';
|
|
2
|
+
export default function runServer(sse: boolean, { forcedAddOns, appName, name, }: {
|
|
3
|
+
forcedMode?: TemplateOptions;
|
|
4
|
+
forcedAddOns?: Array<string>;
|
|
5
|
+
appName?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
}): Promise<void>;
|
package/dist/types/options.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import type { CliOptions, Options } from './types.js';
|
|
2
|
-
export declare function normalizeOptions(cliOptions: CliOptions): Promise<Options | undefined>;
|
|
3
|
-
export declare function promptForOptions(cliOptions: CliOptions
|
|
2
|
+
export declare function normalizeOptions(cliOptions: CliOptions, forcedAddOns?: Array<string>): Promise<Options | undefined>;
|
|
3
|
+
export declare function promptForOptions(cliOptions: CliOptions, { forcedAddOns, forcedMode, }: {
|
|
4
|
+
forcedAddOns?: Array<string>;
|
|
5
|
+
forcedMode?: 'typescript' | 'javascript' | 'file-router';
|
|
6
|
+
}): Promise<Required<Options>>;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { CODE_ROUTER, FILE_ROUTER } from './constants.js';
|
|
|
2
2
|
import type { PackageManager } from './package-manager.js';
|
|
3
3
|
import type { ToolChain } from './toolchain.js';
|
|
4
4
|
export type Framework = 'solid' | 'react';
|
|
5
|
+
export type TemplateOptions = 'typescript' | 'javascript' | 'file-router';
|
|
5
6
|
export interface Options {
|
|
6
7
|
framework: Framework;
|
|
7
8
|
projectName: string;
|
|
@@ -17,7 +18,7 @@ export interface Options {
|
|
|
17
18
|
overlay?: AddOn | undefined;
|
|
18
19
|
}
|
|
19
20
|
export interface CliOptions {
|
|
20
|
-
template?:
|
|
21
|
+
template?: TemplateOptions;
|
|
21
22
|
framework?: Framework;
|
|
22
23
|
tailwind?: boolean;
|
|
23
24
|
packageManager?: PackageManager;
|
package/package.json
CHANGED
package/src/add-ons.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises'
|
|
2
|
-
import { existsSync,
|
|
2
|
+
import { existsSync, readdirSync, statSync } from 'node:fs'
|
|
3
3
|
import { resolve } from 'node:path'
|
|
4
4
|
import chalk from 'chalk'
|
|
5
|
-
import { getTemplatesRoot } from './templates.js'
|
|
6
5
|
|
|
6
|
+
import { getTemplatesRoot } from './templates.js'
|
|
7
7
|
import { DEFAULT_FRAMEWORK } from './constants.js'
|
|
8
|
-
import
|
|
8
|
+
import { readFileHelper } from './file-helper.js'
|
|
9
|
+
|
|
10
|
+
import type { AddOn, CliOptions, Framework, TemplateOptions } from './types.js'
|
|
9
11
|
|
|
10
12
|
function isDirectory(path: string): boolean {
|
|
11
13
|
return statSync(path).isDirectory()
|
|
@@ -18,7 +20,7 @@ function findFilesRecursively(path: string, files: Record<string, string>) {
|
|
|
18
20
|
if (isDirectory(filePath)) {
|
|
19
21
|
findFilesRecursively(filePath, files)
|
|
20
22
|
} else {
|
|
21
|
-
files[filePath] =
|
|
23
|
+
files[filePath] = readFileHelper(filePath)
|
|
22
24
|
}
|
|
23
25
|
}
|
|
24
26
|
}
|
|
@@ -121,14 +123,21 @@ export async function finalizeAddOns(
|
|
|
121
123
|
return finalAddOns
|
|
122
124
|
}
|
|
123
125
|
|
|
124
|
-
export async function listAddOns(
|
|
125
|
-
|
|
126
|
-
|
|
126
|
+
export async function listAddOns(
|
|
127
|
+
options: CliOptions,
|
|
128
|
+
{
|
|
129
|
+
forcedMode,
|
|
130
|
+
forcedAddOns = [],
|
|
131
|
+
}: {
|
|
132
|
+
forcedMode?: TemplateOptions
|
|
133
|
+
forcedAddOns?: Array<string>
|
|
134
|
+
},
|
|
135
|
+
) {
|
|
127
136
|
const addOns = await getAllAddOns(
|
|
128
137
|
options.framework || DEFAULT_FRAMEWORK,
|
|
129
|
-
|
|
138
|
+
forcedMode || options.template || 'typescript',
|
|
130
139
|
)
|
|
131
|
-
for (const addOn of addOns) {
|
|
140
|
+
for (const addOn of addOns.filter((a) => !forcedAddOns.includes(a.id))) {
|
|
132
141
|
console.log(`${chalk.bold(addOn.id)}: ${addOn.description}`)
|
|
133
142
|
}
|
|
134
143
|
}
|
package/src/add.ts
CHANGED
|
@@ -25,7 +25,7 @@ import { readConfigFile, writeConfigFile } from './config-file.js'
|
|
|
25
25
|
|
|
26
26
|
import type { PersistedOptions } from './config-file.js'
|
|
27
27
|
|
|
28
|
-
import type { Options } from './types.js'
|
|
28
|
+
import type { Framework, Options } from './types.js'
|
|
29
29
|
|
|
30
30
|
function isDirectory(path: string) {
|
|
31
31
|
return statSync(path).isDirectory()
|
|
@@ -43,10 +43,11 @@ async function createOptions(
|
|
|
43
43
|
return {
|
|
44
44
|
...json,
|
|
45
45
|
tailwind: true,
|
|
46
|
-
chosenAddOns: await finalizeAddOns(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
chosenAddOns: await finalizeAddOns(
|
|
47
|
+
json.framework as Framework,
|
|
48
|
+
json.mode as string,
|
|
49
|
+
[...json.existingAddOns, ...addOns],
|
|
50
|
+
),
|
|
50
51
|
} as Required<Options>
|
|
51
52
|
}
|
|
52
53
|
|
|
@@ -56,6 +57,7 @@ async function runCreateApp(options: Required<Options>) {
|
|
|
56
57
|
silent: true,
|
|
57
58
|
environment,
|
|
58
59
|
cwd: process.cwd(),
|
|
60
|
+
name: 'create-tsrouter-app',
|
|
59
61
|
})
|
|
60
62
|
return output
|
|
61
63
|
}
|
package/src/cli.ts
CHANGED
|
@@ -18,12 +18,20 @@ import type { PackageManager } from './package-manager.js'
|
|
|
18
18
|
import type { ToolChain } from './toolchain.js'
|
|
19
19
|
import type { CliOptions, Framework } from './types.js'
|
|
20
20
|
|
|
21
|
-
export function cli(
|
|
21
|
+
export function cli({
|
|
22
|
+
name,
|
|
23
|
+
appName,
|
|
24
|
+
forcedMode,
|
|
25
|
+
forcedAddOns,
|
|
26
|
+
}: {
|
|
27
|
+
name: string
|
|
28
|
+
appName: string
|
|
29
|
+
forcedMode?: 'typescript' | 'javascript' | 'file-router'
|
|
30
|
+
forcedAddOns?: Array<string>
|
|
31
|
+
}) {
|
|
22
32
|
const program = new Command()
|
|
23
33
|
|
|
24
|
-
program
|
|
25
|
-
.name('create-tsrouter-app')
|
|
26
|
-
.description('CLI to create a new TanStack application')
|
|
34
|
+
program.name(name).description(`CLI to create a new ${appName} application`)
|
|
27
35
|
|
|
28
36
|
// program
|
|
29
37
|
// .command('add')
|
|
@@ -46,26 +54,10 @@ export function cli() {
|
|
|
46
54
|
// await initAddOn('overlay')
|
|
47
55
|
// })
|
|
48
56
|
|
|
49
|
-
program
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
.option
|
|
53
|
-
.option<Framework>(
|
|
54
|
-
'--framework <type>',
|
|
55
|
-
'project framework (solid, react)',
|
|
56
|
-
(value) => {
|
|
57
|
-
if (!SUPPORTED_FRAMEWORKS.includes(value as Framework)) {
|
|
58
|
-
throw new InvalidArgumentError(
|
|
59
|
-
`Invalid framework: ${value}. Only the following are allowed: ${SUPPORTED_FRAMEWORKS.join(
|
|
60
|
-
', ',
|
|
61
|
-
)}`,
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
return value as Framework
|
|
65
|
-
},
|
|
66
|
-
DEFAULT_FRAMEWORK,
|
|
67
|
-
)
|
|
68
|
-
.option<'typescript' | 'javascript' | 'file-router'>(
|
|
57
|
+
program.argument('[project-name]', 'name of the project')
|
|
58
|
+
|
|
59
|
+
if (!forcedMode) {
|
|
60
|
+
program.option<'typescript' | 'javascript' | 'file-router'>(
|
|
69
61
|
'--template <type>',
|
|
70
62
|
'project template (typescript, javascript, file-router)',
|
|
71
63
|
(value) => {
|
|
@@ -81,6 +73,24 @@ export function cli() {
|
|
|
81
73
|
return value
|
|
82
74
|
},
|
|
83
75
|
)
|
|
76
|
+
}
|
|
77
|
+
program
|
|
78
|
+
.option<Framework>(
|
|
79
|
+
'--framework <type>',
|
|
80
|
+
'project framework (solid, react)',
|
|
81
|
+
(value) => {
|
|
82
|
+
if (!SUPPORTED_FRAMEWORKS.includes(value as Framework)) {
|
|
83
|
+
throw new InvalidArgumentError(
|
|
84
|
+
`Invalid framework: ${value}. Only the following are allowed: ${SUPPORTED_FRAMEWORKS.join(
|
|
85
|
+
', ',
|
|
86
|
+
)}`,
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
return value as Framework
|
|
90
|
+
},
|
|
91
|
+
DEFAULT_FRAMEWORK,
|
|
92
|
+
)
|
|
93
|
+
// .option('--overlay [url]', 'add an overlay from a URL', false)
|
|
84
94
|
.option<PackageManager>(
|
|
85
95
|
`--package-manager <${SUPPORTED_PACKAGE_MANAGERS.join('|')}>`,
|
|
86
96
|
`Explicitly tell the CLI to use this package manager`,
|
|
@@ -122,42 +132,58 @@ export function cli() {
|
|
|
122
132
|
},
|
|
123
133
|
)
|
|
124
134
|
.option('--list-add-ons', 'list all available add-ons', false)
|
|
125
|
-
.option('--
|
|
135
|
+
.option('--no-git', 'do not create a git repository')
|
|
136
|
+
.option('--target-dir <path>', 'the directory to create the project in')
|
|
126
137
|
.option('--mcp', 'run the MCP server', false)
|
|
127
138
|
.option('--mcp-sse', 'run the MCP server in SSE mode', false)
|
|
128
|
-
.action(async (projectName: string, options: CliOptions) => {
|
|
129
|
-
if (options.listAddOns) {
|
|
130
|
-
await listAddOns(options)
|
|
131
|
-
} else if (options.mcp || options.mcpSse) {
|
|
132
|
-
await runServer(!!options.mcpSse)
|
|
133
|
-
} else {
|
|
134
|
-
try {
|
|
135
|
-
const cliOptions = {
|
|
136
|
-
projectName,
|
|
137
|
-
...options,
|
|
138
|
-
} as CliOptions
|
|
139
139
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
140
|
+
program.action(async (projectName: string, options: CliOptions) => {
|
|
141
|
+
if (options.listAddOns) {
|
|
142
|
+
await listAddOns(options, {
|
|
143
|
+
forcedMode,
|
|
144
|
+
forcedAddOns,
|
|
145
|
+
})
|
|
146
|
+
} else if (options.mcp || options.mcpSse) {
|
|
147
|
+
await runServer(!!options.mcpSse, {
|
|
148
|
+
forcedMode,
|
|
149
|
+
forcedAddOns,
|
|
150
|
+
appName,
|
|
151
|
+
})
|
|
152
|
+
} else {
|
|
153
|
+
try {
|
|
154
|
+
const cliOptions = {
|
|
155
|
+
projectName,
|
|
156
|
+
...options,
|
|
157
|
+
} as CliOptions
|
|
158
|
+
|
|
159
|
+
if (forcedMode) {
|
|
160
|
+
cliOptions.template = forcedMode
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
let finalOptions = await normalizeOptions(cliOptions, forcedAddOns)
|
|
164
|
+
if (finalOptions) {
|
|
165
|
+
intro(`Creating a new ${appName} app in ${projectName}...`)
|
|
166
|
+
} else {
|
|
167
|
+
intro(`Let's configure your ${appName} application`)
|
|
168
|
+
finalOptions = await promptForOptions(cliOptions, {
|
|
169
|
+
forcedMode,
|
|
170
|
+
forcedAddOns,
|
|
150
171
|
})
|
|
151
|
-
} catch (error) {
|
|
152
|
-
log.error(
|
|
153
|
-
error instanceof Error
|
|
154
|
-
? error.message
|
|
155
|
-
: 'An unknown error occurred',
|
|
156
|
-
)
|
|
157
|
-
process.exit(1)
|
|
158
172
|
}
|
|
173
|
+
await createApp(finalOptions, {
|
|
174
|
+
environment: createDefaultEnvironment(),
|
|
175
|
+
cwd: options.targetDir || undefined,
|
|
176
|
+
name,
|
|
177
|
+
appName,
|
|
178
|
+
})
|
|
179
|
+
} catch (error) {
|
|
180
|
+
log.error(
|
|
181
|
+
error instanceof Error ? error.message : 'An unknown error occurred',
|
|
182
|
+
)
|
|
183
|
+
process.exit(1)
|
|
159
184
|
}
|
|
160
|
-
}
|
|
185
|
+
}
|
|
186
|
+
})
|
|
161
187
|
|
|
162
188
|
program.parse()
|
|
163
189
|
}
|
package/src/create-app.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { CODE_ROUTER, FILE_ROUTER } from './constants.js'
|
|
|
9
9
|
import { sortObject } from './utils.js'
|
|
10
10
|
import { writeConfigFile } from './config-file.js'
|
|
11
11
|
import { packageManagerExecute } from './package-manager.js'
|
|
12
|
+
import { getBinaryFile } from './file-helper.js'
|
|
12
13
|
|
|
13
14
|
import type { AddOn, Environment, Options } from './types.js'
|
|
14
15
|
|
|
@@ -287,6 +288,15 @@ async function copyAddOnFile(
|
|
|
287
288
|
|
|
288
289
|
const finalTargetPath = resolve(dirname(targetPath), targetFile)
|
|
289
290
|
|
|
291
|
+
const binaryContent = getBinaryFile(content)
|
|
292
|
+
if (binaryContent) {
|
|
293
|
+
await environment.writeFile(
|
|
294
|
+
finalTargetPath,
|
|
295
|
+
binaryContent as unknown as string,
|
|
296
|
+
)
|
|
297
|
+
return
|
|
298
|
+
}
|
|
299
|
+
|
|
290
300
|
if (isTemplate) {
|
|
291
301
|
await templateFile(content, finalTargetPath)
|
|
292
302
|
} else {
|
|
@@ -304,10 +314,13 @@ export async function createApp(
|
|
|
304
314
|
silent = false,
|
|
305
315
|
environment,
|
|
306
316
|
cwd,
|
|
317
|
+
appName = 'TanStack',
|
|
307
318
|
}: {
|
|
308
319
|
silent?: boolean
|
|
309
320
|
environment: Environment
|
|
310
321
|
cwd?: string
|
|
322
|
+
name?: string
|
|
323
|
+
appName?: string
|
|
311
324
|
},
|
|
312
325
|
) {
|
|
313
326
|
environment.startRun()
|
|
@@ -496,7 +509,7 @@ export async function createApp(
|
|
|
496
509
|
// Copy all the asset files from the addons
|
|
497
510
|
const s = silent ? null : spinner()
|
|
498
511
|
for (const type of ['add-on', 'example']) {
|
|
499
|
-
for (const phase of ['setup', 'add-on']) {
|
|
512
|
+
for (const phase of ['setup', 'add-on', 'example']) {
|
|
500
513
|
for (const addOn of options.chosenAddOns.filter(
|
|
501
514
|
(addOn) => addOn.phase === phase && addOn.type === type,
|
|
502
515
|
)) {
|
|
@@ -780,7 +793,7 @@ ${environment.getErrors().join('\n')}`
|
|
|
780
793
|
startCommand = `deno ${isAddOnEnabled('start') ? 'task dev' : 'start'}`
|
|
781
794
|
}
|
|
782
795
|
|
|
783
|
-
outro(`Your
|
|
796
|
+
outro(`Your ${appName} app is ready in '${basename(targetDir)}'.
|
|
784
797
|
|
|
785
798
|
Use the following commands to start your app:
|
|
786
799
|
% cd ${options.projectName}
|
package/src/custom-add-on.ts
CHANGED
|
@@ -7,8 +7,9 @@ import { createMemoryEnvironment } from './environment.js'
|
|
|
7
7
|
import { createApp } from './create-app.js'
|
|
8
8
|
import { readConfigFile } from './config-file.js'
|
|
9
9
|
import { finalizeAddOns } from './add-ons.js'
|
|
10
|
+
import { readFileHelper } from './file-helper.js'
|
|
10
11
|
|
|
11
|
-
import type { Options } from './types.js'
|
|
12
|
+
import type { Framework, Options } from './types.js'
|
|
12
13
|
import type { PersistedOptions } from './config-file.js'
|
|
13
14
|
|
|
14
15
|
type AddOnMode = 'add-on' | 'overlay'
|
|
@@ -106,9 +107,11 @@ async function createOptions(
|
|
|
106
107
|
): Promise<Required<Options>> {
|
|
107
108
|
return {
|
|
108
109
|
...json,
|
|
109
|
-
chosenAddOns: await finalizeAddOns(
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
chosenAddOns: await finalizeAddOns(
|
|
111
|
+
json.framework as Framework,
|
|
112
|
+
json.mode as string,
|
|
113
|
+
[...json.existingAddOns],
|
|
114
|
+
),
|
|
112
115
|
} as Required<Options>
|
|
113
116
|
}
|
|
114
117
|
|
|
@@ -118,6 +121,7 @@ async function runCreateApp(options: Required<Options>) {
|
|
|
118
121
|
silent: true,
|
|
119
122
|
environment,
|
|
120
123
|
cwd: process.cwd(),
|
|
124
|
+
name: 'create-tsrouter-app',
|
|
121
125
|
})
|
|
122
126
|
return output
|
|
123
127
|
}
|
|
@@ -131,9 +135,7 @@ async function recursivelyGatherFiles(
|
|
|
131
135
|
if (file.isDirectory()) {
|
|
132
136
|
await recursivelyGatherFiles(resolve(path, file.name), files)
|
|
133
137
|
} else {
|
|
134
|
-
files[resolve(path, file.name)] = (
|
|
135
|
-
await readFile(resolve(path, file.name))
|
|
136
|
-
).toString()
|
|
138
|
+
files[resolve(path, file.name)] = readFileHelper(resolve(path, file.name))
|
|
137
139
|
}
|
|
138
140
|
}
|
|
139
141
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { extname } from 'node:path'
|
|
3
|
+
|
|
4
|
+
const BINARY_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico']
|
|
5
|
+
|
|
6
|
+
export function readFileHelper(path: string): string {
|
|
7
|
+
if (BINARY_EXTENSIONS.includes(extname(path))) {
|
|
8
|
+
return `base64::${readFileSync(path).toString('base64')}`
|
|
9
|
+
} else {
|
|
10
|
+
return readFileSync(path, 'utf-8').toString()
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function getBinaryFile(content: string): string | null {
|
|
15
|
+
if (content.startsWith('base64::')) {
|
|
16
|
+
const binaryContent = Buffer.from(content.replace('base64::', ''), 'base64')
|
|
17
|
+
return binaryContent as unknown as string
|
|
18
|
+
}
|
|
19
|
+
return null
|
|
20
|
+
}
|