@sapphire/cli 1.5.0-next.2945f09.0 → 1.5.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/CHANGELOG.md +10 -0
- package/dist/cli.js +19 -19
- package/dist/commands/generate.js +44 -45
- package/dist/commands/init.js +25 -26
- package/dist/commands/new.js +107 -104
- package/dist/constants.js +1 -1
- package/dist/functions/CommandExists.js +27 -27
- package/dist/functions/CreateFileFromTemplate.js +34 -34
- package/dist/functions/FileExists.js +3 -3
- package/dist/prompts/PromptInit.js +60 -60
- package/dist/prompts/PromptNew.js +69 -69
- package/package.json +10 -15
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
# [1.5.0](https://github.com/sapphiredev/cli/compare/v1.4.0...v1.5.0) - (2023-04-10)
|
|
6
|
+
|
|
7
|
+
## 🐛 Bug Fixes
|
|
8
|
+
|
|
9
|
+
- **deps:** Update dependency execa to v7 (#203) ([dd78817](https://github.com/sapphiredev/cli/commit/dd78817e287246ae17c5e0ca947a04adf49fb86c))
|
|
10
|
+
|
|
11
|
+
## 🚀 Features
|
|
12
|
+
|
|
13
|
+
- **templates:** Add route component (#215) ([2945f09](https://github.com/sapphiredev/cli/commit/2945f09a663421362ea3f34f28900fd193acf5d7))
|
|
14
|
+
|
|
5
15
|
# [1.4.0](https://github.com/sapphiredev/cli/compare/v1.3.1...v1.4.0) - (2023-01-29)
|
|
6
16
|
|
|
7
17
|
## 🏠 Refactor
|
package/dist/cli.js
CHANGED
|
@@ -11,26 +11,26 @@ const sapphire = new Command();
|
|
|
11
11
|
const packageFile = new URL('../package.json', import.meta.url);
|
|
12
12
|
const packageJson = JSON.parse(await readFile(packageFile, 'utf-8'));
|
|
13
13
|
sapphire //
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
.name('sapphire')
|
|
15
|
+
.version(packageJson.version);
|
|
16
16
|
sapphire
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
.command('new')
|
|
18
|
+
.description('creates a new Sapphire project')
|
|
19
|
+
.alias('n')
|
|
20
|
+
.argument('[name]', 'project name')
|
|
21
|
+
.option('-v, --verbose')
|
|
22
|
+
.action(newCmd);
|
|
23
23
|
sapphire
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
.command('generate')
|
|
25
|
+
.description('generates a component/piece')
|
|
26
|
+
.alias('g')
|
|
27
|
+
.argument('<component>', 'component/piece name')
|
|
28
|
+
.argument('<name>', 'file name')
|
|
29
|
+
.action(generateCmd);
|
|
30
30
|
sapphire //
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
.command('init')
|
|
32
|
+
.description('creates a config file on an existing Sapphire project')
|
|
33
|
+
.alias('i')
|
|
34
|
+
.action(initCmd);
|
|
35
35
|
sapphire.parse(process.argv);
|
|
36
|
-
//# sourceMappingURL=cli.js.map
|
|
36
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -10,53 +10,52 @@ import { readFile } from 'node:fs/promises';
|
|
|
10
10
|
import { basename, join } from 'node:path';
|
|
11
11
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
12
12
|
async function createComponent(component, name, config, configLoc) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
throw new Error("Can't find the template.");
|
|
13
|
+
const { projectLanguage } = config;
|
|
14
|
+
if (!projectLanguage) {
|
|
15
|
+
throw new Error("There is no 'projectLanguage' field in .sapphirerc.json");
|
|
16
|
+
}
|
|
17
|
+
const template = `${component.toLowerCase()}.${projectLanguage}.sapphire`;
|
|
18
|
+
const corePath = `${componentsFolder}${template}`;
|
|
19
|
+
const userPath = config.customFileTemplates.enabled ? join(configLoc, config.customFileTemplates.location, template) : null;
|
|
20
|
+
const target = join(configLoc, config.locations.base, '%L%', `${name}.${projectLanguage}`);
|
|
21
|
+
const params = { name: basename(name) };
|
|
22
|
+
if (userPath && (await fileExists(userPath))) {
|
|
23
|
+
return CreateFileFromTemplate(userPath, target, config, params, true, true);
|
|
24
|
+
} else if (await fileExists(corePath)) {
|
|
25
|
+
return CreateFileFromTemplate(`components/${template}`, target, config, params, false, true);
|
|
26
|
+
}
|
|
27
|
+
throw new Error("Can't find the template.");
|
|
29
28
|
}
|
|
30
29
|
async function fetchConfig() {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
const a = await Promise.race([findUp('.sapphirerc.json', { cwd: '.' }), sleep(5000)]);
|
|
31
|
+
if (a) {
|
|
32
|
+
return a;
|
|
33
|
+
}
|
|
34
|
+
return Promise.race([findUp('.sapphirerc.yml', { cwd: '.' }), sleep(5000)]);
|
|
36
35
|
}
|
|
37
36
|
export default async (component, name) => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
37
|
+
const spinner = new Spinner(`Creating a ${component.toLowerCase()}`).start();
|
|
38
|
+
const fail = (error, additionalExecution) => {
|
|
39
|
+
spinner.error({ text: error });
|
|
40
|
+
additionalExecution?.();
|
|
41
|
+
process.exit(1);
|
|
42
|
+
};
|
|
43
|
+
const configLoc = await fetchConfig();
|
|
44
|
+
if (!configLoc) {
|
|
45
|
+
return fail("Can't find the Sapphire CLI config.");
|
|
46
|
+
}
|
|
47
|
+
const config = configLoc.endsWith('json') ? JSON.parse(await readFile(configLoc, 'utf8')) : load(await readFile(configLoc, 'utf8'));
|
|
48
|
+
if (!config) {
|
|
49
|
+
return fail("Can't parse the Sapphire CLI config.");
|
|
50
|
+
}
|
|
51
|
+
const result = await Result.fromAsync(() => createComponent(component, name, config, configLoc.replace(/.sapphirerc.(json|yml)/g, '')));
|
|
52
|
+
return result.match({
|
|
53
|
+
ok: () => {
|
|
54
|
+
spinner.success();
|
|
55
|
+
console.log(blueBright('Done!'));
|
|
56
|
+
process.exit(0);
|
|
57
|
+
},
|
|
58
|
+
err: (error) => fail(error.message, () => console.log(red(error.message)))
|
|
59
|
+
});
|
|
61
60
|
};
|
|
62
|
-
//# sourceMappingURL=generate.js.map
|
|
61
|
+
//# sourceMappingURL=generate.js.map
|
package/dist/commands/init.js
CHANGED
|
@@ -5,30 +5,29 @@ import { dump } from 'js-yaml';
|
|
|
5
5
|
import { writeFile } from 'node:fs/promises';
|
|
6
6
|
import prompts from 'prompts';
|
|
7
7
|
export default async () => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
process.exit(0);
|
|
8
|
+
const packageJson = await findUp('package.json');
|
|
9
|
+
if (!packageJson) {
|
|
10
|
+
console.log(red("Can't find package.json"));
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
const response = await prompts(PromptInit);
|
|
14
|
+
if (!response.preconditions) process.exit(1);
|
|
15
|
+
const config = {
|
|
16
|
+
projectLanguage: response.projectLanguage,
|
|
17
|
+
locations: {
|
|
18
|
+
base: response.base,
|
|
19
|
+
arguments: response.arguments,
|
|
20
|
+
commands: response.commands,
|
|
21
|
+
listeners: response.listeners,
|
|
22
|
+
preconditions: response.preconditions
|
|
23
|
+
},
|
|
24
|
+
customFileTemplates: {
|
|
25
|
+
enabled: response.cftEnabled,
|
|
26
|
+
location: response.cftLocation ?? ''
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const file = response.configFormat === 'json' ? JSON.stringify(config, null, 2) : dump(config);
|
|
30
|
+
await writeFile(packageJson.replace('package.json', `.sapphirerc.${response.configFormat}`), file);
|
|
31
|
+
process.exit(0);
|
|
33
32
|
};
|
|
34
|
-
//# sourceMappingURL=init.js.map
|
|
33
|
+
//# sourceMappingURL=init.js.map
|
package/dist/commands/new.js
CHANGED
|
@@ -11,124 +11,127 @@ import { cp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
|
11
11
|
import { resolve } from 'node:path';
|
|
12
12
|
import prompts from 'prompts';
|
|
13
13
|
async function editPackageJson(location, name) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return result.isOk();
|
|
14
|
+
const pjLocation = `./${location}/package.json`;
|
|
15
|
+
const output = JSON.parse(await readFile(pjLocation, 'utf8'));
|
|
16
|
+
if (!output) throw new Error("Can't read file.");
|
|
17
|
+
output.name = name;
|
|
18
|
+
const result = await Result.fromAsync(() => writeFile(pjLocation, JSON.stringify(output, null, 2)));
|
|
19
|
+
return result.isOk();
|
|
21
20
|
}
|
|
22
21
|
async function installDeps(location, pm, verbose) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
22
|
+
const value = await execa(pm.toLowerCase(), ['install'], {
|
|
23
|
+
stdio: verbose ? 'inherit' : undefined,
|
|
24
|
+
cwd: `./${location}/`
|
|
25
|
+
});
|
|
26
|
+
if (value.exitCode !== 0) {
|
|
27
|
+
throw new Error('An unknown error occurred while installing the dependencies. Try running Sapphire CLI with "--verbose" flag.');
|
|
28
|
+
}
|
|
29
|
+
const oppositeLockfiles = {
|
|
30
|
+
npm: ['yarn.lock', 'pnpm-lock.yaml'],
|
|
31
|
+
yarn: ['package-lock.json', 'pnpm-lock.yaml'],
|
|
32
|
+
pnpm: ['package-lock.json', 'yarn.lock']
|
|
33
|
+
};
|
|
34
|
+
const lockfiles = pm === 'npm' ? oppositeLockfiles.npm : pm === 'Yarn' ? oppositeLockfiles.yarn : oppositeLockfiles.pnpm;
|
|
35
|
+
for (const lockfile of lockfiles) {
|
|
36
|
+
if (await fileExists(lockfile)) {
|
|
37
|
+
await rm(lockfile);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return true;
|
|
42
41
|
}
|
|
43
42
|
async function configureYarnRc(location, name, value) {
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
await execa('yarn', ['config', 'set', name, value], { cwd: `./${location}/` });
|
|
44
|
+
return true;
|
|
46
45
|
}
|
|
47
46
|
async function installYarnV3(location, verbose) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
47
|
+
const value = await execa('yarn', ['set', 'version', 'berry'], {
|
|
48
|
+
stdio: verbose ? 'inherit' : undefined,
|
|
49
|
+
cwd: `./${location}/`
|
|
50
|
+
});
|
|
51
|
+
if (value.exitCode !== 0) {
|
|
52
|
+
throw new Error('An unknown error occurred while installing Yarn v3. Try running Sapphire CLI with "--verbose" flag.');
|
|
53
|
+
}
|
|
54
|
+
await Promise.all([
|
|
55
|
+
//
|
|
56
|
+
configureYarnRc(location, 'enableGlobalCache', 'true'),
|
|
57
|
+
configureYarnRc(location, 'nodeLinker', 'node-modules')
|
|
58
|
+
]);
|
|
59
|
+
return true;
|
|
61
60
|
}
|
|
62
61
|
async function installYarnTypescriptPlugin(location) {
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
await execa('yarn', ['plugin', 'import', 'typescript'], { cwd: `./${location}/` });
|
|
63
|
+
return true;
|
|
65
64
|
}
|
|
66
65
|
async function initializeGitRepo(location) {
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
await execa('git', ['init'], { cwd: `./${location}/` });
|
|
67
|
+
return true;
|
|
69
68
|
}
|
|
70
69
|
async function runJob(job, name) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
70
|
+
const spinner = new Spinner(name).start();
|
|
71
|
+
const result = await Result.fromAsync(() => job());
|
|
72
|
+
return result.match({
|
|
73
|
+
ok: () => {
|
|
74
|
+
spinner.success();
|
|
75
|
+
return true;
|
|
76
|
+
},
|
|
77
|
+
err: (error) => {
|
|
78
|
+
spinner.error({ text: red(error.message) });
|
|
79
|
+
console.error(red(error.message));
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
84
83
|
}
|
|
85
84
|
async function cloneRepo(location, verbose) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
85
|
+
const value = await execa('git', ['clone', repoUrl, `${location}/ghr`], { stdio: verbose ? 'inherit' : undefined });
|
|
86
|
+
if (value.exitCode !== 0) {
|
|
87
|
+
throw new Error('An unknown error occurred while cloning the repository. Try running Sapphire CLI with "--verbose" flag.');
|
|
88
|
+
}
|
|
89
|
+
return true;
|
|
91
90
|
}
|
|
92
91
|
export default async (name, flags) => {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
92
|
+
const response = await prompts(PromptNew(name, await CommandExists('yarn'), await CommandExists('pnpm')));
|
|
93
|
+
if (!response.projectName || !response.projectLang || !response.projectTemplate || !response.packageManager) {
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
const projectName = response.projectName === '.' ? '' : response.projectName;
|
|
97
|
+
const stpJob = async () => {
|
|
98
|
+
await cp(`./${response.projectName}/ghr/examples/${response.projectTemplate}/.`, `./${response.projectName}/`, { recursive: true });
|
|
99
|
+
for (const p of ['.gitignore', '.prettierignore']) {
|
|
100
|
+
await cp(`./${response.projectName}/ghr/${p}`, `./${response.projectName}/${p}`, { recursive: true });
|
|
101
|
+
}
|
|
102
|
+
await rm(`./${response.projectName}/ghr`, { recursive: true, force: true });
|
|
103
|
+
await CreateFileFromTemplate(
|
|
104
|
+
`.sapphirerc.${response.configFormat}.sapphire`,
|
|
105
|
+
resolve(`./${response.projectName}/.sapphirerc.${response.configFormat}`),
|
|
106
|
+
null,
|
|
107
|
+
{
|
|
108
|
+
language: response.projectLang
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
await editPackageJson(response.projectName, projectName);
|
|
112
|
+
if (response.packageManager === 'pnpm') {
|
|
113
|
+
await writeFile(`./${response.projectName}/.npmrc`, '# pnpm only\nshamefully-hoist=true\npublic-hoist-pattern[]=@sapphire/*');
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
const jobs = [
|
|
117
|
+
[() => cloneRepo(response.projectName, flags.verbose), 'Cloning the repository'],
|
|
118
|
+
[stpJob, 'Setting up the project']
|
|
119
|
+
];
|
|
120
|
+
if (response.git) {
|
|
121
|
+
jobs.push([() => initializeGitRepo(response.projectName), 'Initializing git repo']);
|
|
122
|
+
}
|
|
123
|
+
if (response.yarnV3) {
|
|
124
|
+
jobs.push([() => installYarnV3(response.projectName, flags.verbose), 'Installing Yarn v3']);
|
|
125
|
+
if (response.projectLang === 'ts') jobs.push([() => installYarnTypescriptPlugin(response.projectName), 'Installing Yarn Typescript Plugin']);
|
|
126
|
+
}
|
|
127
|
+
jobs.push([
|
|
128
|
+
() => installDeps(response.projectName, response.packageManager, flags.verbose),
|
|
129
|
+
`Installing dependencies using ${response.packageManager}`
|
|
130
|
+
]);
|
|
131
|
+
for (const [job, name] of jobs) {
|
|
132
|
+
await runJob(job, name).catch(() => process.exit(1));
|
|
133
|
+
}
|
|
134
|
+
console.log(blueBright('Done!'));
|
|
135
|
+
process.exit(0);
|
|
133
136
|
};
|
|
134
|
-
//# sourceMappingURL=new.js.map
|
|
137
|
+
//# sourceMappingURL=new.js.map
|
package/dist/constants.js
CHANGED
|
@@ -6,4 +6,4 @@ export const rootFolder = fileURLToPath(rootURL);
|
|
|
6
6
|
export const templatesFolder = fileURLToPath(templatesURL);
|
|
7
7
|
export const componentsFolder = fileURLToPath(componentsURL);
|
|
8
8
|
export const repoUrl = 'https://github.com/sapphiredev/examples.git';
|
|
9
|
-
//# sourceMappingURL=constants.js.map
|
|
9
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -28,40 +28,40 @@ import { constants } from 'node:fs';
|
|
|
28
28
|
import { access } from 'node:fs/promises';
|
|
29
29
|
const windows = process.platform === 'win32';
|
|
30
30
|
async function isExecutable(command) {
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
const result = await Result.fromAsync(() => access(command, constants.X_OK));
|
|
32
|
+
return result.isErr();
|
|
33
33
|
}
|
|
34
34
|
function cleanWindowsCommand(input) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
if (/[^A-Za-z0-9_\/:=-]/.test(input)) {
|
|
36
|
+
input = `'${input.replace(/'/g, "'\\''")}'`;
|
|
37
|
+
input = input.replace(/^(?:'')+/g, '').replace(/\\'''/g, "\\'");
|
|
38
|
+
}
|
|
39
|
+
return input;
|
|
40
40
|
}
|
|
41
41
|
async function commandExistsUnix(command) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
42
|
+
if (await fileExists(command)) {
|
|
43
|
+
if (await isExecutable(command)) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const result = await Result.fromAsync(() => execa('which', [command]));
|
|
48
|
+
return result.match({
|
|
49
|
+
err: () => false,
|
|
50
|
+
ok: (value) => Boolean(value.stdout)
|
|
51
|
+
});
|
|
52
52
|
}
|
|
53
53
|
const invalidWindowsCommandNameRegex = /[\x00-\x1f<>:"|?*]/;
|
|
54
54
|
async function commandExistsWindows(command) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
55
|
+
if (invalidWindowsCommandNameRegex.test(command)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
const result = await Result.fromAsync(async () => execa('where', [cleanWindowsCommand(command)]));
|
|
59
|
+
return result.match({
|
|
60
|
+
err: () => fileExists(command),
|
|
61
|
+
ok: () => true
|
|
62
|
+
});
|
|
63
63
|
}
|
|
64
64
|
export async function CommandExists(command) {
|
|
65
|
-
|
|
65
|
+
return windows ? commandExistsWindows(command) : commandExistsUnix(command);
|
|
66
66
|
}
|
|
67
|
-
//# sourceMappingURL=CommandExists.js.map
|
|
67
|
+
//# sourceMappingURL=CommandExists.js.map
|
|
@@ -3,42 +3,42 @@ import { fileExists } from '#functions/FileExists';
|
|
|
3
3
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
4
4
|
import { dirname, resolve } from 'node:path';
|
|
5
5
|
export async function CreateFileFromTemplate(template, target, config, params, custom = false, component = false) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
6
|
+
const location = custom ? template : `${templatesFolder}${template}`;
|
|
7
|
+
const output = {};
|
|
8
|
+
if (component) {
|
|
9
|
+
const [c, f] = await getComponentTemplateWithConfig(location);
|
|
10
|
+
output.c = c;
|
|
11
|
+
output.f = f;
|
|
12
|
+
}
|
|
13
|
+
output.f ??= await readFile(location, 'utf8');
|
|
14
|
+
if (!output.f) {
|
|
15
|
+
throw new Error("Can't read file.");
|
|
16
|
+
}
|
|
17
|
+
if (params) {
|
|
18
|
+
for (const param of Object.entries(params)) {
|
|
19
|
+
output.f = output.f.replaceAll(`{{${param[0]}}}`, param[1]);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (!output || (component && (!output.c || !output.c.category))) {
|
|
23
|
+
throw new Error('Invalid template.');
|
|
24
|
+
}
|
|
25
|
+
const dir = component ? config.locations[output.c.category] : null;
|
|
26
|
+
const ta = component ? target.replace('%L%', dir) : target;
|
|
27
|
+
if (await fileExists(ta)) {
|
|
28
|
+
throw new Error('Component already exists');
|
|
29
|
+
}
|
|
30
|
+
await writeFileRecursive(ta, output.f);
|
|
31
|
+
return true;
|
|
32
32
|
}
|
|
33
33
|
async function getComponentTemplateWithConfig(path) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
const file = await readFile(path, 'utf8');
|
|
35
|
+
const fa = file.split(/---(\r\n|\r|\n|)/gm);
|
|
36
|
+
return [JSON.parse(fa[0]), fa[2]];
|
|
37
37
|
}
|
|
38
38
|
async function writeFileRecursive(target, data) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
const resolvedTarget = resolve(target);
|
|
40
|
+
const dir = dirname(resolvedTarget);
|
|
41
|
+
await mkdir(dir, { recursive: true });
|
|
42
|
+
return writeFile(resolvedTarget, data);
|
|
43
43
|
}
|
|
44
|
-
//# sourceMappingURL=CreateFileFromTemplate.js.map
|
|
44
|
+
//# sourceMappingURL=CreateFileFromTemplate.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Result } from '@sapphire/result';
|
|
2
2
|
import { access } from 'node:fs/promises';
|
|
3
3
|
export async function fileExists(filePath) {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const result = await Result.fromAsync(() => access(filePath));
|
|
5
|
+
return result.isOk();
|
|
6
6
|
}
|
|
7
|
-
//# sourceMappingURL=FileExists.js.map
|
|
7
|
+
//# sourceMappingURL=FileExists.js.map
|
|
@@ -1,62 +1,62 @@
|
|
|
1
1
|
export const PromptInit = [
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
2
|
+
{
|
|
3
|
+
type: 'select',
|
|
4
|
+
name: 'configFormat',
|
|
5
|
+
message: 'What format do you want your config file to be in?',
|
|
6
|
+
choices: [
|
|
7
|
+
{ title: 'JSON', value: 'json' },
|
|
8
|
+
{ title: 'YAML', value: 'yml' }
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
type: 'select',
|
|
13
|
+
name: 'projectLanguage',
|
|
14
|
+
message: 'Choose the language used in your project',
|
|
15
|
+
choices: [
|
|
16
|
+
{ title: 'TypeScript', value: 'ts' },
|
|
17
|
+
{ title: 'JavaScript', value: 'js' }
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
type: 'text',
|
|
22
|
+
name: 'base',
|
|
23
|
+
message: 'Your base directory',
|
|
24
|
+
initial: 'src'
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
type: 'text',
|
|
28
|
+
name: 'commands',
|
|
29
|
+
message: 'Where do you store your commands? (do not include the base)',
|
|
30
|
+
initial: 'commands'
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
type: 'text',
|
|
34
|
+
name: 'listeners',
|
|
35
|
+
message: 'Where do you store your listeners? (do not include the base)',
|
|
36
|
+
initial: 'listeners'
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
type: 'text',
|
|
40
|
+
name: 'arguments',
|
|
41
|
+
message: 'Where do you store your arguments? (do not include the base)',
|
|
42
|
+
initial: 'arguments'
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
type: 'text',
|
|
46
|
+
name: 'preconditions',
|
|
47
|
+
message: 'Where do you store your preconditions? (do not include the base)',
|
|
48
|
+
initial: 'preconditions'
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
type: 'confirm',
|
|
52
|
+
name: 'cftEnabled',
|
|
53
|
+
message: 'Do you want to enable custom file templates?'
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
type: (prev) => (prev ? 'text' : null),
|
|
57
|
+
name: 'cftLocation',
|
|
58
|
+
message: 'Where do you store your custom file templates?',
|
|
59
|
+
initial: 'templates'
|
|
60
|
+
}
|
|
61
61
|
];
|
|
62
|
-
//# sourceMappingURL=PromptInit.js.map
|
|
62
|
+
//# sourceMappingURL=PromptInit.js.map
|
|
@@ -1,75 +1,75 @@
|
|
|
1
1
|
const tsTemplates = [
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
{ title: 'Starter template (Recommended)', value: 'with-typescript-starter' },
|
|
3
|
+
{ title: 'Complete template', value: 'with-typescript-complete' },
|
|
4
|
+
{ title: 'with Docker', value: 'with-docker' },
|
|
5
|
+
{ title: 'with tsup', value: 'with-tsup' },
|
|
6
|
+
{ title: 'with SWC', value: 'with-swc' }
|
|
7
7
|
];
|
|
8
8
|
const jsTemplates = [
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
{ title: 'with ESM (Recommended)', value: 'with-esm' },
|
|
10
|
+
{ title: 'with CommonJS', value: 'with-javascript' }
|
|
11
11
|
];
|
|
12
12
|
export const PromptNew = (projectName, yarn, pnpm) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
13
|
+
const pmChoices = [
|
|
14
|
+
{
|
|
15
|
+
title: `Yarn (Recommended) ${yarn ? '' : '(Not installed)'}`,
|
|
16
|
+
value: 'Yarn',
|
|
17
|
+
disabled: !yarn
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
title: `pnpm ${pnpm ? '' : '(Not Installed)'}`,
|
|
21
|
+
value: 'pnpm',
|
|
22
|
+
disabled: !pnpm
|
|
23
|
+
},
|
|
24
|
+
{ title: 'npm', value: 'npm' }
|
|
25
|
+
];
|
|
26
|
+
return [
|
|
27
|
+
{
|
|
28
|
+
type: 'text',
|
|
29
|
+
name: 'projectName',
|
|
30
|
+
message: "What's the name of your project?",
|
|
31
|
+
initial: projectName ?? 'my-sapphire-bot'
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
type: 'select',
|
|
35
|
+
name: 'projectLang',
|
|
36
|
+
message: 'Choose a language for your project',
|
|
37
|
+
choices: [
|
|
38
|
+
{ title: 'TypeScript (Recommended)', value: 'ts' },
|
|
39
|
+
{ title: 'JavaScript', value: 'js' }
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: 'select',
|
|
44
|
+
name: 'projectTemplate',
|
|
45
|
+
message: 'Choose a template for your project',
|
|
46
|
+
choices: (prev) => (prev === 'ts' ? tsTemplates : jsTemplates)
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
type: 'select',
|
|
50
|
+
name: 'configFormat',
|
|
51
|
+
message: 'What format do you want your config file to be in?',
|
|
52
|
+
choices: [
|
|
53
|
+
{ title: 'JSON', value: 'json' },
|
|
54
|
+
{ title: 'YAML', value: 'yml' }
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
type: 'select',
|
|
59
|
+
name: 'packageManager',
|
|
60
|
+
message: 'What package manager do you want to use?',
|
|
61
|
+
choices: yarn ? pmChoices : pmChoices.slice().reverse()
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
type: (prev) => (prev === 'Yarn' ? 'confirm' : false),
|
|
65
|
+
name: 'yarnV3',
|
|
66
|
+
message: 'Do you want to use Yarn v3?'
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
type: 'confirm',
|
|
70
|
+
name: 'git',
|
|
71
|
+
message: 'Do you want to create a git repository for this project?'
|
|
72
|
+
}
|
|
73
|
+
];
|
|
74
74
|
};
|
|
75
|
-
//# sourceMappingURL=PromptNew.js.map
|
|
75
|
+
//# sourceMappingURL=PromptNew.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sapphire/cli",
|
|
3
|
-
"version": "1.5.0
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "CLI for Sapphire Framework",
|
|
5
5
|
"author": "@sapphire",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,17 +17,12 @@
|
|
|
17
17
|
},
|
|
18
18
|
"sideEffects": "false",
|
|
19
19
|
"files": [
|
|
20
|
-
"dist",
|
|
21
|
-
"!dist/*.tsbuildinfo",
|
|
22
|
-
"!dist/**/*.js.map",
|
|
23
|
-
"!dist/**/*.d.ts",
|
|
24
|
-
"!dist/**/*.d.ts.map",
|
|
20
|
+
"dist/**/*.js",
|
|
25
21
|
"templates"
|
|
26
22
|
],
|
|
27
23
|
"scripts": {
|
|
28
24
|
"lint": "eslint src --ext ts --fix",
|
|
29
|
-
"format": "prettier --write
|
|
30
|
-
"update": "yarn upgrade-interactive",
|
|
25
|
+
"format": "prettier --write .",
|
|
31
26
|
"build": "tsc -b src",
|
|
32
27
|
"clean": "tsc -b src --clean",
|
|
33
28
|
"watch": "tsc -b src -w",
|
|
@@ -39,7 +34,7 @@
|
|
|
39
34
|
},
|
|
40
35
|
"dependencies": {
|
|
41
36
|
"@favware/colorette-spinner": "^1.0.1",
|
|
42
|
-
"@sapphire/result": "^2.6.
|
|
37
|
+
"@sapphire/result": "^2.6.1",
|
|
43
38
|
"colorette": "^2.0.19",
|
|
44
39
|
"commander": "^10.0.0",
|
|
45
40
|
"execa": "^7.1.1",
|
|
@@ -53,14 +48,14 @@
|
|
|
53
48
|
"@commitlint/config-conventional": "^17.4.4",
|
|
54
49
|
"@favware/cliff-jumper": "^2.0.0",
|
|
55
50
|
"@favware/npm-deprecate": "^1.0.7",
|
|
56
|
-
"@sapphire/eslint-config": "^4.
|
|
51
|
+
"@sapphire/eslint-config": "^4.4.0",
|
|
57
52
|
"@sapphire/prettier-config": "^1.4.5",
|
|
58
|
-
"@sapphire/ts-config": "^
|
|
53
|
+
"@sapphire/ts-config": "^4.0.0",
|
|
59
54
|
"@types/js-yaml": "^4.0.5",
|
|
60
55
|
"@types/node": "^18.15.11",
|
|
61
56
|
"@types/prompts": "^2.4.4",
|
|
62
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
63
|
-
"@typescript-eslint/parser": "^5.
|
|
57
|
+
"@typescript-eslint/eslint-plugin": "^5.58.0",
|
|
58
|
+
"@typescript-eslint/parser": "^5.58.0",
|
|
64
59
|
"cz-conventional-changelog": "^3.3.0",
|
|
65
60
|
"eslint": "^8.38.0",
|
|
66
61
|
"eslint-config-prettier": "^8.8.0",
|
|
@@ -72,7 +67,7 @@
|
|
|
72
67
|
"prettier": "^2.8.7",
|
|
73
68
|
"pretty-quick": "^3.1.3",
|
|
74
69
|
"ts-node": "^10.9.1",
|
|
75
|
-
"typescript": "^
|
|
70
|
+
"typescript": "^5.0.4"
|
|
76
71
|
},
|
|
77
72
|
"resolutions": {
|
|
78
73
|
"ansi-regex": "^5.0.1",
|
|
@@ -80,7 +75,7 @@
|
|
|
80
75
|
},
|
|
81
76
|
"engines": {
|
|
82
77
|
"node": ">=v16.6.0",
|
|
83
|
-
"npm": ">=7
|
|
78
|
+
"npm": ">=7"
|
|
84
79
|
},
|
|
85
80
|
"keywords": [
|
|
86
81
|
"@sapphire/cli",
|