@tanstack/cta-engine 0.10.0-alpha.18 → 0.10.0-alpha.20
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 +5 -14
- package/dist/add-to-app.js +118 -74
- package/dist/config-file.js +9 -7
- package/dist/create-app.js +111 -42
- package/dist/custom-add-ons/add-on.js +175 -0
- package/dist/custom-add-ons/shared.js +117 -0
- package/dist/custom-add-ons/starter.js +84 -0
- package/dist/environment.js +59 -12
- package/dist/file-helpers.js +108 -2
- package/dist/frameworks.js +15 -1
- package/dist/index.js +12 -5
- package/dist/integrations/shadcn.js +10 -4
- package/dist/options.js +9 -0
- package/dist/package-json.js +7 -4
- package/dist/special-steps/index.js +24 -0
- package/dist/special-steps/rimraf-node-modules.js +16 -0
- package/dist/template-file.js +3 -13
- package/dist/types/add-ons.d.ts +3 -4
- package/dist/types/add-to-app.d.ts +16 -3
- package/dist/types/config-file.d.ts +4 -3
- package/dist/types/create-app.d.ts +1 -7
- package/dist/types/custom-add-ons/add-on.d.ts +69 -0
- package/dist/types/custom-add-ons/shared.d.ts +15 -0
- package/dist/types/custom-add-ons/starter.d.ts +7 -0
- package/dist/types/environment.d.ts +2 -1
- package/dist/types/file-helpers.d.ts +10 -0
- package/dist/types/frameworks.d.ts +2 -0
- package/dist/types/index.d.ts +13 -6
- package/dist/types/integrations/shadcn.d.ts +1 -1
- package/dist/types/options.d.ts +2 -0
- package/dist/types/package-json.d.ts +5 -0
- package/dist/types/package-manager.d.ts +6 -2
- package/dist/types/special-steps/index.d.ts +2 -0
- package/dist/types/special-steps/rimraf-node-modules.d.ts +2 -0
- package/dist/types/template-file.d.ts +1 -1
- package/dist/types/types.d.ts +752 -70
- package/dist/types.js +65 -1
- package/package.json +9 -3
- package/src/add-ons.ts +7 -19
- package/src/add-to-app.ts +195 -101
- package/src/config-file.ts +16 -13
- package/src/create-app.ts +128 -84
- package/src/custom-add-ons/add-on.ts +261 -0
- package/src/custom-add-ons/shared.ts +161 -0
- package/src/custom-add-ons/starter.ts +126 -0
- package/src/environment.ts +70 -11
- package/src/file-helpers.ts +164 -2
- package/src/frameworks.ts +21 -1
- package/src/index.ts +46 -11
- package/src/integrations/shadcn.ts +14 -4
- package/src/options.ts +11 -0
- package/src/package-json.ts +13 -6
- package/src/special-steps/index.ts +36 -0
- package/src/special-steps/rimraf-node-modules.ts +25 -0
- package/src/template-file.ts +3 -18
- package/src/types.ts +143 -85
- package/tests/add-ons.test.ts +5 -5
- package/tests/add-to-app.test.ts +358 -0
- package/tests/config-file.test.ts +36 -7
- package/tests/create-app.test.ts +43 -68
- package/tests/custom-add-ons/add-on.test.ts +12 -0
- package/tests/custom-add-ons/shared.test.ts +257 -0
- package/tests/custom-add-ons/starter.test.ts +58 -0
- package/tests/environment.test.ts +90 -2
- package/tests/file-helper.test.ts +55 -2
- package/tests/frameworks.test.ts +95 -0
- package/tests/index.test.ts +9 -0
- package/tests/integrations/shadcn.test.ts +48 -63
- package/tests/options.test.ts +42 -0
- package/tests/setupVitest.ts +6 -0
- package/tests/template-file.test.ts +54 -93
- package/vitest.config.ts +21 -0
package/dist/add-ons.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { loadRemoteAddOn } from './custom-add-ons/add-on.js';
|
|
2
|
+
export function getAllAddOns(framework, mode) {
|
|
3
|
+
return framework.getAddOns().filter((a) => a.modes.includes(mode));
|
|
3
4
|
}
|
|
4
5
|
// Turn the list of chosen add-on IDs into a final list of add-ons by resolving dependencies
|
|
5
|
-
export async function finalizeAddOns(framework,
|
|
6
|
+
export async function finalizeAddOns(framework, mode, chosenAddOnIDs) {
|
|
6
7
|
const finalAddOnIDs = new Set(chosenAddOnIDs);
|
|
7
|
-
const addOns = getAllAddOns(framework,
|
|
8
|
+
const addOns = getAllAddOns(framework, mode);
|
|
8
9
|
for (const addOnID of finalAddOnIDs) {
|
|
9
10
|
let addOn;
|
|
10
11
|
const localAddOn = addOns.find((a) => a.id === addOnID);
|
|
@@ -32,13 +33,3 @@ export async function finalizeAddOns(framework, template, chosenAddOnIDs) {
|
|
|
32
33
|
function loadAddOn(addOn) {
|
|
33
34
|
return addOn;
|
|
34
35
|
}
|
|
35
|
-
export async function loadRemoteAddOn(url) {
|
|
36
|
-
const response = await fetch(url);
|
|
37
|
-
const fileContent = await response.json();
|
|
38
|
-
fileContent.id = url;
|
|
39
|
-
return {
|
|
40
|
-
...fileContent,
|
|
41
|
-
getFiles: () => Promise.resolve(Object.keys(fileContent.files)),
|
|
42
|
-
getFileContents: (path) => Promise.resolve(fileContent.files[path]),
|
|
43
|
-
};
|
|
44
|
-
}
|
package/dist/add-to-app.js
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { existsSync, statSync } from 'node:fs';
|
|
3
|
-
import { basename, dirname, resolve } from 'node:path';
|
|
4
|
-
import { execa, execaSync } from 'execa';
|
|
1
|
+
import { basename, resolve } from 'node:path';
|
|
5
2
|
import { CONFIG_FILE } from './constants.js';
|
|
6
3
|
import { finalizeAddOns } from './add-ons.js';
|
|
7
4
|
import { getFrameworkById } from './frameworks.js';
|
|
8
|
-
import {
|
|
5
|
+
import { createMemoryEnvironment } from './environment.js';
|
|
9
6
|
import { createApp } from './create-app.js';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
import { readConfigFileFromEnvironment, writeConfigFileToEnvironment, } from './config-file.js';
|
|
8
|
+
import { formatCommand } from './utils.js';
|
|
9
|
+
import { packageManagerInstall } from './package-manager.js';
|
|
10
|
+
import { isBase64, recursivelyGatherFilesFromEnvironment, } from './file-helpers.js';
|
|
11
|
+
import { mergePackageJSON } from './package-json.js';
|
|
12
|
+
import { runSpecialSteps } from './special-steps/index.js';
|
|
13
|
+
export async function hasPendingGitChanges(environment, cwd) {
|
|
14
|
+
const { stdout } = await environment.execute('git', ['status', '--porcelain'], cwd);
|
|
15
|
+
return stdout.length > 0;
|
|
14
16
|
}
|
|
15
|
-
async function
|
|
16
|
-
const status = await execaSync('git', ['status', '--porcelain']);
|
|
17
|
-
return status.stdout.length > 0;
|
|
18
|
-
}
|
|
19
|
-
async function createOptions(json, addOns) {
|
|
17
|
+
async function createOptions(json, addOns, targetDir) {
|
|
20
18
|
const framework = getFrameworkById(json.framework);
|
|
19
|
+
// TODO: Load the starter
|
|
21
20
|
return {
|
|
22
21
|
...json,
|
|
23
22
|
framework,
|
|
@@ -27,99 +26,144 @@ async function createOptions(json, addOns) {
|
|
|
27
26
|
...json.existingAddOns,
|
|
28
27
|
...addOns,
|
|
29
28
|
]),
|
|
29
|
+
targetDir,
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
async function runCreateApp(options) {
|
|
33
|
-
const { environment, output } = createMemoryEnvironment();
|
|
34
|
-
await createApp(
|
|
35
|
-
silent: true,
|
|
36
|
-
environment,
|
|
37
|
-
cwd: process.cwd(),
|
|
38
|
-
name: 'create-tsrouter-app',
|
|
39
|
-
});
|
|
33
|
+
const { environment, output } = createMemoryEnvironment(options.targetDir);
|
|
34
|
+
await createApp(environment, options);
|
|
40
35
|
return output;
|
|
41
36
|
}
|
|
42
|
-
export async function
|
|
43
|
-
const persistedOptions = await
|
|
37
|
+
export async function getCurrentConfiguration(environment, cwd) {
|
|
38
|
+
const persistedOptions = await readConfigFileFromEnvironment(environment, cwd);
|
|
44
39
|
if (!persistedOptions) {
|
|
45
40
|
environment.error('There is no .cta.json file in your project.', 'This is probably because this was created with an older version of create-tsrouter-app.');
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
if (!silent) {
|
|
49
|
-
environment.intro(`Adding ${addOns.join(', ')} to the project...`);
|
|
41
|
+
return undefined;
|
|
50
42
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const newOptions = await createOptions(persistedOptions, addOns);
|
|
56
|
-
const output = await runCreateApp(newOptions);
|
|
43
|
+
return persistedOptions;
|
|
44
|
+
}
|
|
45
|
+
export async function writeFiles(environment, cwd, output, forced) {
|
|
46
|
+
const currentFiles = await recursivelyGatherFilesFromEnvironment(environment, cwd, false);
|
|
57
47
|
const overwrittenFiles = [];
|
|
58
48
|
const changedFiles = [];
|
|
59
|
-
const contentMap = new Map();
|
|
60
49
|
for (const file of Object.keys(output.files)) {
|
|
61
|
-
const relativeFile = file.replace(
|
|
62
|
-
if (
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
if (['package.json', CONFIG_FILE].includes(basename(file)) ||
|
|
66
|
-
contents !== output.files[file]) {
|
|
67
|
-
overwrittenFiles.push(relativeFile);
|
|
68
|
-
contentMap.set(relativeFile, output.files[file]);
|
|
69
|
-
}
|
|
50
|
+
const relativeFile = file.replace(cwd, '');
|
|
51
|
+
if (currentFiles[relativeFile]) {
|
|
52
|
+
if (currentFiles[relativeFile] !== output.files[file]) {
|
|
53
|
+
overwrittenFiles.push(relativeFile);
|
|
70
54
|
}
|
|
71
55
|
}
|
|
72
56
|
else {
|
|
73
57
|
changedFiles.push(relativeFile);
|
|
74
|
-
contentMap.set(relativeFile, output.files[file]);
|
|
75
58
|
}
|
|
76
59
|
}
|
|
77
|
-
if (overwrittenFiles.length
|
|
78
|
-
environment.warn('The following will be overwritten:', overwrittenFiles.join('\n'));
|
|
60
|
+
if (!forced && overwrittenFiles.length) {
|
|
61
|
+
environment.warn('The following will be overwritten:', [...overwrittenFiles, ...output.deletedFiles].join('\n'));
|
|
79
62
|
const shouldContinue = await environment.confirm('Do you want to continue?');
|
|
80
63
|
if (!shouldContinue) {
|
|
81
|
-
|
|
64
|
+
throw new Error('User cancelled');
|
|
82
65
|
}
|
|
83
66
|
}
|
|
67
|
+
for (const file of output.deletedFiles) {
|
|
68
|
+
if (environment.exists(resolve(cwd, file))) {
|
|
69
|
+
await environment.deleteFile(resolve(cwd, file));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
environment.startStep({
|
|
73
|
+
id: 'write-files',
|
|
74
|
+
type: 'file',
|
|
75
|
+
message: 'Writing add-on files...',
|
|
76
|
+
});
|
|
84
77
|
for (const file of [...changedFiles, ...overwrittenFiles]) {
|
|
85
|
-
const targetFile = `.${file}`;
|
|
86
78
|
const fName = basename(file);
|
|
87
|
-
const contents =
|
|
79
|
+
const contents = output.files[file];
|
|
88
80
|
if (fName === 'package.json') {
|
|
89
|
-
const currentJson = JSON.parse(
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
currentJson.dependencies = sortObject({
|
|
93
|
-
...currentJson.dependencies,
|
|
94
|
-
...newJson.dependencies,
|
|
95
|
-
});
|
|
96
|
-
currentJson.devDependencies = sortObject({
|
|
97
|
-
...currentJson.devDependencies,
|
|
98
|
-
...newJson.devDependencies,
|
|
99
|
-
});
|
|
100
|
-
await writeFile(targetFile, JSON.stringify(currentJson, null, 2));
|
|
81
|
+
const currentJson = JSON.parse(await environment.readFile(resolve(cwd, file)));
|
|
82
|
+
const newJSON = mergePackageJSON(currentJson, JSON.parse(contents));
|
|
83
|
+
environment.writeFile(resolve(cwd, file), JSON.stringify(newJSON, null, 2));
|
|
101
84
|
}
|
|
102
85
|
else if (fName !== CONFIG_FILE) {
|
|
103
|
-
|
|
104
|
-
|
|
86
|
+
if (isBase64(contents)) {
|
|
87
|
+
await environment.writeFileBase64(resolve(cwd, file), contents);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
await environment.writeFile(resolve(cwd, file), contents);
|
|
91
|
+
}
|
|
105
92
|
}
|
|
106
93
|
}
|
|
107
|
-
|
|
108
|
-
|
|
94
|
+
environment.finishStep('write-files', 'Add-on files written');
|
|
95
|
+
}
|
|
96
|
+
export async function runNewCommands(environment, originalOptions, cwd, output) {
|
|
97
|
+
const originalOutput = await runCreateApp({
|
|
98
|
+
...(await createOptions(originalOptions, [], cwd)),
|
|
99
|
+
});
|
|
109
100
|
const originalCommands = new Set(originalOutput.commands.map((c) => [c.command, ...c.args].join(' ')));
|
|
110
101
|
for (const command of output.commands) {
|
|
111
102
|
const commandString = [command.command, ...command.args].join(' ');
|
|
112
103
|
if (!originalCommands.has(commandString)) {
|
|
113
|
-
|
|
104
|
+
environment.startStep({
|
|
105
|
+
id: 'run-commands',
|
|
106
|
+
type: 'command',
|
|
107
|
+
message: `Running ${formatCommand({ command: command.command, args: command.args })}...`,
|
|
108
|
+
});
|
|
109
|
+
await environment.execute(command.command, command.args, cwd);
|
|
110
|
+
environment.finishStep('run-commands', 'Setup commands complete');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
export async function addToApp(environment, addOns, cwd, options) {
|
|
115
|
+
const persistedOptions = await getCurrentConfiguration(environment, cwd);
|
|
116
|
+
if (!persistedOptions) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (!options?.forced && (await hasPendingGitChanges(environment, cwd))) {
|
|
120
|
+
environment.error('You have pending git changes.', 'Please commit or stash them before adding add-ons.');
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
environment.intro(`Adding ${addOns.join(', ')} to the project...`);
|
|
124
|
+
environment.startStep({
|
|
125
|
+
id: 'processing-new-app-setup',
|
|
126
|
+
type: 'file',
|
|
127
|
+
message: 'Processing new app setup...',
|
|
128
|
+
});
|
|
129
|
+
const newOptions = await createOptions(persistedOptions, addOns, cwd);
|
|
130
|
+
const output = await runCreateApp({
|
|
131
|
+
...newOptions,
|
|
132
|
+
targetDir: cwd,
|
|
133
|
+
});
|
|
134
|
+
await writeFiles(environment, cwd, output, !!options?.forced);
|
|
135
|
+
environment.finishStep('processing-new-app-setup', 'Application files written');
|
|
136
|
+
// Run any special steps for the new add-ons
|
|
137
|
+
const specialSteps = new Set([]);
|
|
138
|
+
for (const addOn of newOptions.chosenAddOns) {
|
|
139
|
+
for (const step of addOn.addOnSpecialSteps || []) {
|
|
140
|
+
if (addOns.includes(addOn.id)) {
|
|
141
|
+
specialSteps.add(step);
|
|
142
|
+
}
|
|
114
143
|
}
|
|
115
144
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const s = silent ? null : environment.spinner();
|
|
119
|
-
s?.start(`Installing dependencies via ${newOptions.packageManager}...`);
|
|
120
|
-
await realEnvironment.execute(newOptions.packageManager, ['install'], resolve(process.cwd()));
|
|
121
|
-
s?.stop(`Installed dependencies`);
|
|
122
|
-
if (!silent) {
|
|
123
|
-
environment.outro('Add-ons added successfully!');
|
|
145
|
+
if (specialSteps.size) {
|
|
146
|
+
await runSpecialSteps(environment, newOptions, Array.from(specialSteps));
|
|
124
147
|
}
|
|
148
|
+
// Install dependencies
|
|
149
|
+
environment.startStep({
|
|
150
|
+
id: 'install-dependencies',
|
|
151
|
+
type: 'package-manager',
|
|
152
|
+
message: `Installing dependencies via ${newOptions.packageManager}...`,
|
|
153
|
+
});
|
|
154
|
+
const s = environment.spinner();
|
|
155
|
+
s.start(`Installing dependencies via ${newOptions.packageManager}...`);
|
|
156
|
+
await packageManagerInstall(environment, newOptions.targetDir, newOptions.packageManager);
|
|
157
|
+
s.stop(`Installed dependencies`);
|
|
158
|
+
environment.finishStep('install-dependencies', 'Dependencies installed');
|
|
159
|
+
// Handle new commands
|
|
160
|
+
await runNewCommands(environment, persistedOptions, cwd, output);
|
|
161
|
+
environment.startStep({
|
|
162
|
+
id: 'write-config-file',
|
|
163
|
+
type: 'file',
|
|
164
|
+
message: 'Writing config file...',
|
|
165
|
+
});
|
|
166
|
+
writeConfigFileToEnvironment(environment, newOptions);
|
|
167
|
+
environment.finishStep('write-config-file', 'Config file written');
|
|
168
|
+
environment.outro('Add-ons added successfully!');
|
|
125
169
|
}
|
package/dist/config-file.js
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
2
1
|
import { resolve } from 'node:path';
|
|
3
2
|
import { CONFIG_FILE } from './constants.js';
|
|
4
|
-
|
|
3
|
+
function createPersistedOptions(options) {
|
|
5
4
|
/* eslint-disable unused-imports/no-unused-vars */
|
|
6
|
-
const {
|
|
5
|
+
const { chosenAddOns, framework, targetDir, ...rest } = options;
|
|
7
6
|
/* eslint-enable unused-imports/no-unused-vars */
|
|
8
|
-
|
|
7
|
+
return {
|
|
9
8
|
...rest,
|
|
10
9
|
version: 1,
|
|
11
10
|
framework: options.framework.id,
|
|
12
11
|
existingAddOns: options.chosenAddOns.map((addOn) => addOn.id),
|
|
12
|
+
starter: options.starter?.id ?? undefined,
|
|
13
13
|
};
|
|
14
|
-
await environment.writeFile(resolve(targetDir, CONFIG_FILE), JSON.stringify(persistedOptions, null, 2));
|
|
15
14
|
}
|
|
16
|
-
export async function
|
|
15
|
+
export async function writeConfigFileToEnvironment(environment, options) {
|
|
16
|
+
await environment.writeFile(resolve(options.targetDir, CONFIG_FILE), JSON.stringify(createPersistedOptions(options), null, 2));
|
|
17
|
+
}
|
|
18
|
+
export async function readConfigFileFromEnvironment(environment, targetDir) {
|
|
17
19
|
try {
|
|
18
20
|
const configFile = resolve(targetDir, CONFIG_FILE);
|
|
19
|
-
const config = await readFile(configFile
|
|
21
|
+
const config = await environment.readFile(configFile);
|
|
20
22
|
// TODO: Look for old config files and convert them to the new format
|
|
21
23
|
return JSON.parse(config);
|
|
22
24
|
}
|
package/dist/create-app.js
CHANGED
|
@@ -1,71 +1,152 @@
|
|
|
1
1
|
import { basename, resolve } from 'node:path';
|
|
2
|
-
import {
|
|
2
|
+
import { isBase64 } from './file-helpers.js';
|
|
3
3
|
import { formatCommand } from './utils.js';
|
|
4
|
-
import {
|
|
4
|
+
import { writeConfigFileToEnvironment } from './config-file.js';
|
|
5
5
|
import { getPackageManagerScriptCommand, packageManagerInstall, } from './package-manager.js';
|
|
6
6
|
import { createPackageJSON } from './package-json.js';
|
|
7
7
|
import { createTemplateFile } from './template-file.js';
|
|
8
8
|
import { installShadcnComponents } from './integrations/shadcn.js';
|
|
9
9
|
import { setupGit } from './integrations/git.js';
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
import { runSpecialSteps } from './special-steps/index.js';
|
|
11
|
+
async function writeFiles(environment, options) {
|
|
12
|
+
const templateFileFromContent = createTemplateFile(environment, options);
|
|
12
13
|
async function writeFileBundle(bundle) {
|
|
13
14
|
const files = await bundle.getFiles();
|
|
14
15
|
for (const file of files) {
|
|
15
16
|
const contents = await bundle.getFileContents(file);
|
|
16
|
-
const
|
|
17
|
-
if (
|
|
18
|
-
await environment.
|
|
17
|
+
const isBinaryFile = isBase64(contents);
|
|
18
|
+
if (isBinaryFile) {
|
|
19
|
+
await environment.writeFileBase64(resolve(options.targetDir, file), contents);
|
|
19
20
|
}
|
|
20
21
|
else {
|
|
21
22
|
await templateFileFromContent(file, contents);
|
|
22
23
|
}
|
|
23
24
|
}
|
|
25
|
+
const deletedFiles = await bundle.getDeletedFiles();
|
|
26
|
+
for (const file of deletedFiles) {
|
|
27
|
+
await environment.deleteFile(resolve(options.targetDir, file));
|
|
28
|
+
}
|
|
24
29
|
}
|
|
30
|
+
environment.startStep({
|
|
31
|
+
id: 'write-framework-files',
|
|
32
|
+
type: 'file',
|
|
33
|
+
message: 'Writing framework files...',
|
|
34
|
+
});
|
|
25
35
|
await writeFileBundle(options.framework);
|
|
36
|
+
environment.finishStep('write-framework-files', 'Framework files written');
|
|
37
|
+
let wroteAddonFiles = false;
|
|
26
38
|
for (const type of ['add-on', 'example', 'toolchain']) {
|
|
27
39
|
for (const phase of ['setup', 'add-on', 'example']) {
|
|
28
40
|
for (const addOn of options.chosenAddOns.filter((addOn) => addOn.phase === phase && addOn.type === type)) {
|
|
41
|
+
environment.startStep({
|
|
42
|
+
id: 'write-addon-files',
|
|
43
|
+
type: 'file',
|
|
44
|
+
message: `Writing ${addOn.name} files...`,
|
|
45
|
+
});
|
|
29
46
|
await writeFileBundle(addOn);
|
|
47
|
+
wroteAddonFiles = true;
|
|
30
48
|
}
|
|
31
49
|
}
|
|
32
50
|
}
|
|
51
|
+
if (wroteAddonFiles) {
|
|
52
|
+
environment.finishStep('write-addon-files', 'Add-on files written');
|
|
53
|
+
}
|
|
33
54
|
if (options.starter) {
|
|
55
|
+
environment.startStep({
|
|
56
|
+
id: 'write-starter-files',
|
|
57
|
+
type: 'file',
|
|
58
|
+
message: 'Writing starter files...',
|
|
59
|
+
});
|
|
34
60
|
await writeFileBundle(options.starter);
|
|
61
|
+
environment.finishStep('write-starter-files', 'Starter files written');
|
|
35
62
|
}
|
|
36
|
-
|
|
37
|
-
|
|
63
|
+
environment.startStep({
|
|
64
|
+
id: 'write-package-json',
|
|
65
|
+
type: 'file',
|
|
66
|
+
message: 'Writing package.json...',
|
|
67
|
+
});
|
|
68
|
+
await environment.writeFile(resolve(options.targetDir, './package.json'), JSON.stringify(createPackageJSON(options), null, 2));
|
|
69
|
+
environment.finishStep('write-package-json', 'Package.json written');
|
|
70
|
+
environment.startStep({
|
|
71
|
+
id: 'write-config-file',
|
|
72
|
+
type: 'file',
|
|
73
|
+
message: 'Writing config file...',
|
|
74
|
+
});
|
|
75
|
+
await writeConfigFileToEnvironment(environment, options);
|
|
76
|
+
environment.finishStep('write-config-file', 'Config file written');
|
|
38
77
|
}
|
|
39
|
-
async function runCommandsAndInstallDependencies(environment,
|
|
40
|
-
const s =
|
|
78
|
+
async function runCommandsAndInstallDependencies(environment, options) {
|
|
79
|
+
const s = environment.spinner();
|
|
41
80
|
// Setup git
|
|
42
81
|
if (options.git) {
|
|
43
|
-
s
|
|
44
|
-
|
|
45
|
-
|
|
82
|
+
s.start(`Initializing git repository...`);
|
|
83
|
+
environment.startStep({
|
|
84
|
+
id: 'initialize-git-repository',
|
|
85
|
+
type: 'command',
|
|
86
|
+
message: 'Initializing git repository...',
|
|
87
|
+
});
|
|
88
|
+
await setupGit(environment, options.targetDir);
|
|
89
|
+
environment.finishStep('initialize-git-repository', 'Initialized git repository');
|
|
90
|
+
s.stop(`Initialized git repository`);
|
|
91
|
+
}
|
|
92
|
+
// Run any special steps for the new add-ons
|
|
93
|
+
const specialSteps = new Set([]);
|
|
94
|
+
for (const addOn of options.chosenAddOns) {
|
|
95
|
+
for (const step of addOn.createSpecialSteps || []) {
|
|
96
|
+
specialSteps.add(step);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (specialSteps.size) {
|
|
100
|
+
await runSpecialSteps(environment, options, Array.from(specialSteps));
|
|
46
101
|
}
|
|
47
102
|
// Install dependencies
|
|
48
|
-
s
|
|
49
|
-
|
|
50
|
-
|
|
103
|
+
s.start(`Installing dependencies via ${options.packageManager}...`);
|
|
104
|
+
environment.startStep({
|
|
105
|
+
id: 'install-dependencies',
|
|
106
|
+
type: 'package-manager',
|
|
107
|
+
message: `Installing dependencies via ${options.packageManager}...`,
|
|
108
|
+
});
|
|
109
|
+
await packageManagerInstall(environment, options.targetDir, options.packageManager);
|
|
110
|
+
environment.finishStep('install-dependencies', 'Installed dependencies');
|
|
111
|
+
s.stop(`Installed dependencies`);
|
|
51
112
|
for (const phase of ['setup', 'add-on', 'example']) {
|
|
52
113
|
for (const addOn of options.chosenAddOns.filter((addOn) => addOn.phase === phase && addOn.command && addOn.command.command)) {
|
|
53
|
-
s
|
|
54
|
-
|
|
55
|
-
|
|
114
|
+
s.start(`Running commands for ${addOn.name}...`);
|
|
115
|
+
const cmd = formatCommand({
|
|
116
|
+
command: addOn.command.command,
|
|
117
|
+
args: addOn.command.args || [],
|
|
118
|
+
});
|
|
119
|
+
environment.startStep({
|
|
120
|
+
id: 'run-commands',
|
|
121
|
+
type: 'command',
|
|
122
|
+
message: cmd,
|
|
123
|
+
});
|
|
124
|
+
await environment.execute(addOn.command.command, addOn.command.args || [], options.targetDir);
|
|
125
|
+
environment.finishStep('run-commands', 'Setup commands complete');
|
|
126
|
+
s.stop(`${addOn.name} commands complete`);
|
|
56
127
|
}
|
|
57
128
|
}
|
|
58
129
|
// Adding starter
|
|
59
130
|
if (options.starter &&
|
|
60
131
|
options.starter.command &&
|
|
61
132
|
options.starter.command.command) {
|
|
62
|
-
s
|
|
63
|
-
|
|
64
|
-
|
|
133
|
+
s.start(`Setting up starter ${options.starter.name}...`);
|
|
134
|
+
const cmd = formatCommand({
|
|
135
|
+
command: options.starter.command.command,
|
|
136
|
+
args: options.starter.command.args || [],
|
|
137
|
+
});
|
|
138
|
+
environment.startStep({
|
|
139
|
+
id: 'run-starter-command',
|
|
140
|
+
type: 'command',
|
|
141
|
+
message: cmd,
|
|
142
|
+
});
|
|
143
|
+
await environment.execute(options.starter.command.command, options.starter.command.args || [], options.targetDir);
|
|
144
|
+
environment.finishStep('run-starter-command', 'Starter command complete');
|
|
145
|
+
s.stop(`${options.starter.name} commands complete`);
|
|
65
146
|
}
|
|
66
|
-
await installShadcnComponents(environment, targetDir, options
|
|
147
|
+
await installShadcnComponents(environment, options.targetDir, options);
|
|
67
148
|
}
|
|
68
|
-
function report(environment, options
|
|
149
|
+
function report(environment, options) {
|
|
69
150
|
const warnings = [];
|
|
70
151
|
for (const addOn of options.chosenAddOns) {
|
|
71
152
|
if (addOn.warning) {
|
|
@@ -84,7 +165,7 @@ Errors were encountered during this process:
|
|
|
84
165
|
|
|
85
166
|
${environment.getErrors().join('\n')}`;
|
|
86
167
|
}
|
|
87
|
-
environment.outro(`Your ${appName} app is ready in '${basename(targetDir)}'.
|
|
168
|
+
environment.outro(`Your ${environment.appName} app is ready in '${basename(options.targetDir)}'.
|
|
88
169
|
|
|
89
170
|
Use the following commands to start your app:
|
|
90
171
|
% cd ${options.projectName}
|
|
@@ -92,22 +173,10 @@ Use the following commands to start your app:
|
|
|
92
173
|
|
|
93
174
|
Please check the README.md for more information on testing, styling, adding routes, etc.${errorStatement}`);
|
|
94
175
|
}
|
|
95
|
-
export async function createApp(
|
|
176
|
+
export async function createApp(environment, options) {
|
|
96
177
|
environment.startRun();
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
targetDir = resolve(process.cwd(), options.projectName);
|
|
100
|
-
if (environment.exists(targetDir)) {
|
|
101
|
-
if (!silent) {
|
|
102
|
-
environment.error(`Directory "${options.projectName}" already exists`);
|
|
103
|
-
}
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
await writeFiles(environment, targetDir, options);
|
|
108
|
-
await runCommandsAndInstallDependencies(environment, targetDir, options, silent);
|
|
178
|
+
await writeFiles(environment, options);
|
|
179
|
+
await runCommandsAndInstallDependencies(environment, options);
|
|
109
180
|
environment.finishRun();
|
|
110
|
-
|
|
111
|
-
report(environment, options, appName, targetDir);
|
|
112
|
-
}
|
|
181
|
+
report(environment, options);
|
|
113
182
|
}
|