complete-cli 1.0.1 → 1.0.2
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/commands/CheckCommand.js +1 -2
- package/dist/commands/InitCommand.js +1 -1
- package/dist/commands/NukeCommand.js +1 -2
- package/dist/commands/PublishCommand.js +4 -5
- package/dist/commands/init/createProject.js +3 -4
- package/dist/commands/init/getAuthorName.js +1 -1
- package/dist/commands/init/packageManager.js +7 -7
- package/dist/commands/init/vsCodeInit.js +18 -8
- package/dist/git.js +12 -9
- package/dist/main.js +0 -2
- package/file-templates/dynamic/package.json +9 -10
- package/file-templates/static/scripts/build.ts +1 -2
- package/package.json +15 -20
- package/src/commands/CheckCommand.ts +1 -1
- package/src/commands/InitCommand.ts +1 -1
- package/src/commands/NukeCommand.ts +1 -2
- package/src/commands/PublishCommand.ts +4 -4
- package/src/commands/init/createProject.ts +3 -3
- package/src/commands/init/getAuthorName.ts +1 -1
- package/src/commands/init/packageManager.ts +8 -8
- package/src/commands/init/vsCodeInit.ts +27 -8
- package/src/git.ts +12 -9
- package/src/main.ts +0 -3
- package/dist/validateNoteVersion.js +0 -25
- package/src/validateNoteVersion.ts +0 -39
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { Command, Option } from "clipanion";
|
|
3
3
|
import { ReadonlySet } from "complete-common";
|
|
4
|
-
import { deleteFileOrDirectory, fatalError, isDirectory, isFile, readFile, writeFile, } from "complete-node";
|
|
5
|
-
import { $ } from "execa";
|
|
4
|
+
import { $, deleteFileOrDirectory, fatalError, isDirectory, isFile, readFile, writeFile, } from "complete-node";
|
|
6
5
|
import klawSync from "klaw-sync";
|
|
7
6
|
import path from "node:path";
|
|
8
7
|
import { ACTION_YML, ACTION_YML_TEMPLATE_PATH, CWD, TEMPLATES_DYNAMIC_DIR, TEMPLATES_STATIC_DIR, } from "../constants.js";
|
|
@@ -49,7 +49,7 @@ export class InitCommand extends Command {
|
|
|
49
49
|
});
|
|
50
50
|
async execute() {
|
|
51
51
|
promptStart();
|
|
52
|
-
const packageManager = getPackageManagerUsedForNewProject(this);
|
|
52
|
+
const packageManager = await getPackageManagerUsedForNewProject(this);
|
|
53
53
|
// Prompt the end-user for some information (and validate it as we go).
|
|
54
54
|
const { projectPath, createNewDir } = await getProjectPath(this.name, this.useCurrentDirectory, this.customDirectory, this.yes, this.forceName);
|
|
55
55
|
await checkIfProjectPathExists(projectPath, this.yes);
|
|
@@ -5,9 +5,8 @@ export class NukeCommand extends Command {
|
|
|
5
5
|
static usage = Command.Usage({
|
|
6
6
|
description: 'Delete the "node_modules" directory and the package lock file, then reinstall the dependencies for the project.',
|
|
7
7
|
});
|
|
8
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
9
8
|
async execute() {
|
|
10
|
-
nukeDependencies();
|
|
9
|
+
await nukeDependencies();
|
|
11
10
|
console.log("Successfully reinstalled dependencies from npm.");
|
|
12
11
|
}
|
|
13
12
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Command, Option } from "clipanion";
|
|
2
2
|
import { isSemanticVersion } from "complete-common";
|
|
3
|
-
import { fatalError, getPackageJSONField, getPackageJSONVersion, getPackageManagerInstallCommand, getPackageManagerLockFileName, getPackageManagersForProject, isFileAsync, isGitRepository, isGitRepositoryClean, isLoggedInToNPM, readFile, updatePackageJSONDependencies, writeFileAsync, } from "complete-node";
|
|
4
|
-
import { $ } from "execa";
|
|
3
|
+
import { $, fatalError, getPackageJSONField, getPackageJSONVersion, getPackageManagerInstallCommand, getPackageManagerLockFileName, getPackageManagersForProject, isFileAsync, isGitRepository, isGitRepositoryClean, isLoggedInToNPM, readFile, updatePackageJSONDependencies, writeFileAsync, } from "complete-node";
|
|
5
4
|
import path from "node:path";
|
|
6
5
|
import { CWD, DEFAULT_PACKAGE_MANAGER } from "../constants.js";
|
|
7
6
|
export class PublishCommand extends Command {
|
|
@@ -51,7 +50,7 @@ async function validate() {
|
|
|
51
50
|
* some other steps.
|
|
52
51
|
*/
|
|
53
52
|
async function prePublish(versionBumpType, dryRun, skipLint, skipUpdate) {
|
|
54
|
-
const packageManager = getPackageManagerUsedForExistingProject();
|
|
53
|
+
const packageManager = await getPackageManagerUsedForExistingProject();
|
|
55
54
|
await $ `git pull --rebase`;
|
|
56
55
|
await $ `git push`;
|
|
57
56
|
await updateDependencies(skipUpdate, dryRun, packageManager);
|
|
@@ -62,8 +61,8 @@ async function prePublish(versionBumpType, dryRun, skipLint, skipUpdate) {
|
|
|
62
61
|
await tryRunNPMScript("lint");
|
|
63
62
|
}
|
|
64
63
|
}
|
|
65
|
-
function getPackageManagerUsedForExistingProject() {
|
|
66
|
-
const packageManagers = getPackageManagersForProject(CWD);
|
|
64
|
+
async function getPackageManagerUsedForExistingProject() {
|
|
65
|
+
const packageManagers = await getPackageManagersForProject(CWD);
|
|
67
66
|
if (packageManagers.length > 1) {
|
|
68
67
|
const packageManagerLockFileNames = packageManagers
|
|
69
68
|
.map((packageManager) => getPackageManagerLockFileName(packageManager))
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { repeat } from "complete-common";
|
|
3
|
-
import { copyFileOrDirectory, getFileNamesInDirectory, getPackageManagerInstallCICommand, getPackageManagerInstallCommand, isFile, makeDirectory, readFile, renameFile, updatePackageJSONDependencies, writeFile, } from "complete-node";
|
|
4
|
-
import { $ } from "execa";
|
|
3
|
+
import { $, copyFileOrDirectory, getFileNamesInDirectory, getPackageManagerInstallCICommand, getPackageManagerInstallCommand, isFile, makeDirectory, readFile, renameFile, updatePackageJSONDependencies, writeFile, } from "complete-node";
|
|
5
4
|
import path from "node:path";
|
|
6
5
|
import { ACTION_YML, ACTION_YML_TEMPLATE_PATH, TEMPLATES_DYNAMIC_DIR, TEMPLATES_STATIC_DIR, } from "../../constants.js";
|
|
7
6
|
import { initGitRepository } from "../../git.js";
|
|
@@ -87,8 +86,8 @@ function copyDynamicFiles(projectName, authorName, projectPath, packageManager)
|
|
|
87
86
|
const templatePath = path.join(TEMPLATES_DYNAMIC_DIR, "package.json");
|
|
88
87
|
const template = readFile(templatePath);
|
|
89
88
|
const packageJSON = template
|
|
90
|
-
.replaceAll("
|
|
91
|
-
.replaceAll("
|
|
89
|
+
.replaceAll("project-name", projectName)
|
|
90
|
+
.replaceAll("author-name", authorName ?? "unknown");
|
|
92
91
|
const destinationPath = path.join(projectPath, "package.json");
|
|
93
92
|
writeFile(destinationPath, packageJSON);
|
|
94
93
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getGitHubUsername } from "../../git.js";
|
|
2
2
|
import { getInputString, promptError, promptLog } from "../../prompt.js";
|
|
3
3
|
export async function getAuthorName() {
|
|
4
|
-
const gitHubUsername = getGitHubUsername();
|
|
4
|
+
const gitHubUsername = await getGitHubUsername();
|
|
5
5
|
if (gitHubUsername !== undefined) {
|
|
6
6
|
return gitHubUsername;
|
|
7
7
|
}
|
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
-
import {
|
|
2
|
+
import { commandExists, PackageManager } from "complete-node";
|
|
3
3
|
import { DEFAULT_PACKAGE_MANAGER } from "../../constants.js";
|
|
4
4
|
import { promptError } from "../../prompt.js";
|
|
5
|
-
export function getPackageManagerUsedForNewProject(options) {
|
|
6
|
-
const packageManagerFromOptions = getPackageManagerFromOptions(options);
|
|
5
|
+
export async function getPackageManagerUsedForNewProject(options) {
|
|
6
|
+
const packageManagerFromOptions = await getPackageManagerFromOptions(options);
|
|
7
7
|
if (packageManagerFromOptions !== undefined) {
|
|
8
8
|
return packageManagerFromOptions;
|
|
9
9
|
}
|
|
10
10
|
return DEFAULT_PACKAGE_MANAGER;
|
|
11
11
|
}
|
|
12
|
-
function getPackageManagerFromOptions(options) {
|
|
12
|
+
async function getPackageManagerFromOptions(options) {
|
|
13
13
|
if (options.npm) {
|
|
14
|
-
const npmExists = commandExists("npm");
|
|
14
|
+
const npmExists = await commandExists("npm");
|
|
15
15
|
if (!npmExists) {
|
|
16
16
|
promptError(`You specified the "--npm" option, but "${chalk.green("npm")}" does not seem to be a valid command.`);
|
|
17
17
|
}
|
|
18
18
|
return PackageManager.npm;
|
|
19
19
|
}
|
|
20
20
|
if (options.yarn) {
|
|
21
|
-
const yarnExists = commandExists("yarn");
|
|
21
|
+
const yarnExists = await commandExists("yarn");
|
|
22
22
|
if (!yarnExists) {
|
|
23
23
|
promptError(`You specified the "--yarn" option, but "${chalk.green("yarn")}" does not seem to be a valid command.`);
|
|
24
24
|
}
|
|
25
25
|
return PackageManager.yarn;
|
|
26
26
|
}
|
|
27
27
|
if (options.pnpm) {
|
|
28
|
-
const pnpmExists = commandExists("pnpm");
|
|
28
|
+
const pnpmExists = await commandExists("pnpm");
|
|
29
29
|
if (!pnpmExists) {
|
|
30
30
|
promptError(`You specified the "--pnpm" option, but "${chalk.green("pnpm")}" does not seem to be a valid command.`);
|
|
31
31
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { commandExists, getJSONC, isFile } from "complete-node";
|
|
2
|
-
import { $ } from "execa";
|
|
1
|
+
import { $, commandExists, getJSONC, isFile } from "complete-node";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import { getInputYesNo, promptError, promptLog } from "../../prompt.js";
|
|
5
4
|
const VS_CODE_COMMANDS = [
|
|
@@ -9,7 +8,7 @@ const VS_CODE_COMMANDS = [
|
|
|
9
8
|
"code-insiders",
|
|
10
9
|
];
|
|
11
10
|
export async function vsCodeInit(projectPath, vscode, yes) {
|
|
12
|
-
const VSCodeCommand = getVSCodeCommand();
|
|
11
|
+
const VSCodeCommand = await getVSCodeCommand();
|
|
13
12
|
if (VSCodeCommand === undefined) {
|
|
14
13
|
promptLog('VSCode does not seem to be installed. (The "code" command is not in the path.) Skipping VSCode-related things.');
|
|
15
14
|
return;
|
|
@@ -17,8 +16,19 @@ export async function vsCodeInit(projectPath, vscode, yes) {
|
|
|
17
16
|
await installVSCodeExtensions(projectPath, VSCodeCommand);
|
|
18
17
|
await promptVSCode(projectPath, VSCodeCommand, vscode, yes);
|
|
19
18
|
}
|
|
20
|
-
function getVSCodeCommand() {
|
|
21
|
-
|
|
19
|
+
async function getVSCodeCommand() {
|
|
20
|
+
const commandCheckPromises = VS_CODE_COMMANDS.map((command) => ({
|
|
21
|
+
command,
|
|
22
|
+
existsPromise: commandExists(command),
|
|
23
|
+
}));
|
|
24
|
+
const commandChecks = await Promise.all(commandCheckPromises.map(async (check) => ({
|
|
25
|
+
command: check.command,
|
|
26
|
+
exists: await check.existsPromise,
|
|
27
|
+
})));
|
|
28
|
+
const existingCommands = commandChecks
|
|
29
|
+
.filter((check) => check.exists)
|
|
30
|
+
.map((check) => check.command);
|
|
31
|
+
return existingCommands[0];
|
|
22
32
|
}
|
|
23
33
|
async function installVSCodeExtensions(projectPath, vsCodeCommand) {
|
|
24
34
|
// Installing extensions from inside WSL on Windows will result in the VSCode process never
|
|
@@ -27,18 +37,18 @@ async function installVSCodeExtensions(projectPath, vsCodeCommand) {
|
|
|
27
37
|
if (process.platform === "linux") {
|
|
28
38
|
return;
|
|
29
39
|
}
|
|
30
|
-
const extensions = getExtensionsFromJSON(projectPath);
|
|
40
|
+
const extensions = await getExtensionsFromJSON(projectPath);
|
|
31
41
|
for (const extensionName of extensions) {
|
|
32
42
|
// eslint-disable-next-line no-await-in-loop
|
|
33
43
|
await $ `${vsCodeCommand} --install-extension ${extensionName}`;
|
|
34
44
|
}
|
|
35
45
|
}
|
|
36
|
-
function getExtensionsFromJSON(projectPath) {
|
|
46
|
+
async function getExtensionsFromJSON(projectPath) {
|
|
37
47
|
const extensionsJSONPath = path.join(projectPath, ".vscode", "extensions.json");
|
|
38
48
|
if (!isFile(extensionsJSONPath)) {
|
|
39
49
|
return [];
|
|
40
50
|
}
|
|
41
|
-
const extensionsJSON = getJSONC(extensionsJSONPath);
|
|
51
|
+
const extensionsJSON = await getJSONC(extensionsJSONPath);
|
|
42
52
|
const { recommendations } = extensionsJSON;
|
|
43
53
|
if (!Array.isArray(recommendations)) {
|
|
44
54
|
promptError('The "recommendations" field in the "extensions.json" file is not an array.');
|
package/dist/git.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
-
import { commandExists,
|
|
3
|
-
import { $ } from "execa";
|
|
2
|
+
import { $, commandExists, isFileAsync, readFileAsync } from "complete-node";
|
|
4
3
|
import path from "node:path";
|
|
5
4
|
import yaml from "yaml";
|
|
6
5
|
import { HOME_DIR, PROJECT_NAME, PROJECT_VERSION } from "./constants.js";
|
|
@@ -9,18 +8,20 @@ import { getInputString, getInputYesNo, promptLog } from "./prompt.js";
|
|
|
9
8
|
* If the GitHub CLI is installed, we can derive the user's GitHub username from their YAML
|
|
10
9
|
* configuration.
|
|
11
10
|
*/
|
|
12
|
-
export function getGitHubUsername() {
|
|
13
|
-
|
|
11
|
+
export async function getGitHubUsername() {
|
|
12
|
+
const ghExists = await commandExists("gh");
|
|
13
|
+
if (!ghExists) {
|
|
14
14
|
return undefined;
|
|
15
15
|
}
|
|
16
16
|
const githubCLIHostsPath = getGithubCLIHostsPath();
|
|
17
17
|
if (githubCLIHostsPath === undefined) {
|
|
18
18
|
return undefined;
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
const hostsPathExists = await isFileAsync(githubCLIHostsPath);
|
|
21
|
+
if (!hostsPathExists) {
|
|
21
22
|
return undefined;
|
|
22
23
|
}
|
|
23
|
-
const configYAMLRaw =
|
|
24
|
+
const configYAMLRaw = await readFileAsync(githubCLIHostsPath);
|
|
24
25
|
const configYAML = yaml.parse(configYAMLRaw);
|
|
25
26
|
const githubCom = configYAML["github.com"];
|
|
26
27
|
if (githubCom === undefined) {
|
|
@@ -53,11 +54,12 @@ export async function promptGitHubRepoOrGitRemoteURL(projectName, yes, skipGit)
|
|
|
53
54
|
return undefined;
|
|
54
55
|
}
|
|
55
56
|
// We do not need to prompt the user if they do not have Git installed.
|
|
56
|
-
|
|
57
|
+
const gitExists = await commandExists("git");
|
|
58
|
+
if (!gitExists) {
|
|
57
59
|
promptLog('Git does not seem to be installed. (The "git" command is not in the path.) Skipping Git-related things.');
|
|
58
60
|
return undefined;
|
|
59
61
|
}
|
|
60
|
-
const gitHubUsername = getGitHubUsername();
|
|
62
|
+
const gitHubUsername = await getGitHubUsername();
|
|
61
63
|
if (gitHubUsername !== undefined) {
|
|
62
64
|
const { exitCode } = await $ `gh repo view ${projectName}`;
|
|
63
65
|
const gitHubRepoExists = exitCode === 0;
|
|
@@ -105,7 +107,8 @@ function getGitRemoteURL(projectName, gitHubUsername) {
|
|
|
105
107
|
return `git@github.com:${gitHubUsername}/${projectName}.git`;
|
|
106
108
|
}
|
|
107
109
|
export async function initGitRepository(projectPath, gitRemoteURL) {
|
|
108
|
-
|
|
110
|
+
const gitExists = await commandExists("git");
|
|
111
|
+
if (!gitExists) {
|
|
109
112
|
return;
|
|
110
113
|
}
|
|
111
114
|
if (gitRemoteURL === undefined) {
|
package/dist/main.js
CHANGED
|
@@ -6,10 +6,8 @@ import { NukeCommand } from "./commands/NukeCommand.js";
|
|
|
6
6
|
import { PublishCommand } from "./commands/PublishCommand.js";
|
|
7
7
|
import { UpdateCommand } from "./commands/UpdateCommand.js";
|
|
8
8
|
import { PROJECT_NAME, PROJECT_VERSION } from "./constants.js";
|
|
9
|
-
import { validateNodeVersion } from "./validateNoteVersion.js";
|
|
10
9
|
await main();
|
|
11
10
|
async function main() {
|
|
12
|
-
validateNodeVersion();
|
|
13
11
|
const [_node, _app, ...args] = process.argv;
|
|
14
12
|
const cli = new Cli({
|
|
15
13
|
binaryLabel: PROJECT_NAME,
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "
|
|
2
|
+
"name": "project-name",
|
|
3
3
|
"version": "0.0.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [],
|
|
6
|
-
"homepage": "https://github.com/
|
|
6
|
+
"homepage": "https://github.com/author-name/project-name",
|
|
7
7
|
"bugs": {
|
|
8
|
-
"url": "https://github.com/
|
|
8
|
+
"url": "https://github.com/author-name/project-name/issues"
|
|
9
9
|
},
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
12
|
-
"url": "git+https://github.com/
|
|
12
|
+
"url": "git+https://github.com/author-name/project-name.git"
|
|
13
13
|
},
|
|
14
14
|
"license": "GPL-3.0",
|
|
15
|
-
"author": "
|
|
15
|
+
"author": "author-name",
|
|
16
16
|
"type": "module",
|
|
17
17
|
"files": [
|
|
18
18
|
"dist",
|
|
@@ -29,10 +29,9 @@
|
|
|
29
29
|
"update": "complete-cli update"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"complete-cli": "
|
|
33
|
-
"complete-lint": "
|
|
34
|
-
"complete-node": "
|
|
35
|
-
"
|
|
36
|
-
"typescript": "^0.0.1"
|
|
32
|
+
"complete-cli": "0.0.1",
|
|
33
|
+
"complete-lint": "0.0.1",
|
|
34
|
+
"complete-node": "0.0.1",
|
|
35
|
+
"typescript": "0.0.1"
|
|
37
36
|
}
|
|
38
37
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "complete-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "A command line tool for bootstrapping TypeScript projects.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript"
|
|
@@ -33,26 +33,21 @@
|
|
|
33
33
|
"start": "tsx ./src/main.ts",
|
|
34
34
|
"test": "glob \"./src/**/*.test.ts\" --cmd=\"node --import tsx --test --test-reporter spec\""
|
|
35
35
|
},
|
|
36
|
-
"dependencies": {
|
|
37
|
-
"@clack/prompts": "^0.10.0",
|
|
38
|
-
"chalk": "^5.4.1",
|
|
39
|
-
"clipanion": "^4.0.0-rc.4",
|
|
40
|
-
"complete-common": "^1.1.0",
|
|
41
|
-
"complete-node": "^2.1.0",
|
|
42
|
-
"execa": "^9.5.2",
|
|
43
|
-
"klaw-sync": "^6.0.0",
|
|
44
|
-
"yaml": "^2.7.0"
|
|
45
|
-
},
|
|
46
36
|
"devDependencies": {
|
|
47
|
-
"@
|
|
48
|
-
"@types/
|
|
49
|
-
"@types/
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
37
|
+
"@clack/prompts": "0.10.0",
|
|
38
|
+
"@types/klaw-sync": "6.0.5",
|
|
39
|
+
"@types/node": "22.13.5",
|
|
40
|
+
"chalk": "5.4.1",
|
|
41
|
+
"clipanion": "4.0.0-rc.4",
|
|
42
|
+
"complete-common": "^1.1.1",
|
|
43
|
+
"complete-node": "^3.0.1",
|
|
44
|
+
"glob": "11.0.1",
|
|
45
|
+
"klaw-sync": "6.0.0",
|
|
46
|
+
"typescript": "5.7.3",
|
|
47
|
+
"typescript-eslint": "8.24.1",
|
|
48
|
+
"webpack": "5.98.0",
|
|
49
|
+
"webpack-cli": "6.0.1",
|
|
50
|
+
"yaml": "2.7.0"
|
|
56
51
|
},
|
|
57
52
|
"engines": {
|
|
58
53
|
"node": ">= 20.11.0"
|
|
@@ -2,6 +2,7 @@ import chalk from "chalk";
|
|
|
2
2
|
import { Command, Option } from "clipanion";
|
|
3
3
|
import { ReadonlySet } from "complete-common";
|
|
4
4
|
import {
|
|
5
|
+
$,
|
|
5
6
|
deleteFileOrDirectory,
|
|
6
7
|
fatalError,
|
|
7
8
|
isDirectory,
|
|
@@ -9,7 +10,6 @@ import {
|
|
|
9
10
|
readFile,
|
|
10
11
|
writeFile,
|
|
11
12
|
} from "complete-node";
|
|
12
|
-
import { $ } from "execa";
|
|
13
13
|
import klawSync from "klaw-sync";
|
|
14
14
|
import path from "node:path";
|
|
15
15
|
import {
|
|
@@ -67,7 +67,7 @@ export class InitCommand extends Command {
|
|
|
67
67
|
async execute(): Promise<void> {
|
|
68
68
|
promptStart();
|
|
69
69
|
|
|
70
|
-
const packageManager = getPackageManagerUsedForNewProject(this);
|
|
70
|
+
const packageManager = await getPackageManagerUsedForNewProject(this);
|
|
71
71
|
|
|
72
72
|
// Prompt the end-user for some information (and validate it as we go).
|
|
73
73
|
const { projectPath, createNewDir } = await getProjectPath(
|
|
@@ -9,9 +9,8 @@ export class NukeCommand extends Command {
|
|
|
9
9
|
'Delete the "node_modules" directory and the package lock file, then reinstall the dependencies for the project.',
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
13
12
|
async execute(): Promise<void> {
|
|
14
|
-
nukeDependencies();
|
|
13
|
+
await nukeDependencies();
|
|
15
14
|
console.log("Successfully reinstalled dependencies from npm.");
|
|
16
15
|
}
|
|
17
16
|
}
|
|
@@ -2,6 +2,7 @@ import { Command, Option } from "clipanion";
|
|
|
2
2
|
import { isSemanticVersion } from "complete-common";
|
|
3
3
|
import type { PackageManager } from "complete-node";
|
|
4
4
|
import {
|
|
5
|
+
$,
|
|
5
6
|
fatalError,
|
|
6
7
|
getPackageJSONField,
|
|
7
8
|
getPackageJSONVersion,
|
|
@@ -16,7 +17,6 @@ import {
|
|
|
16
17
|
updatePackageJSONDependencies,
|
|
17
18
|
writeFileAsync,
|
|
18
19
|
} from "complete-node";
|
|
19
|
-
import { $ } from "execa";
|
|
20
20
|
import path from "node:path";
|
|
21
21
|
import { CWD, DEFAULT_PACKAGE_MANAGER } from "../constants.js";
|
|
22
22
|
|
|
@@ -96,7 +96,7 @@ async function prePublish(
|
|
|
96
96
|
skipLint: boolean,
|
|
97
97
|
skipUpdate: boolean,
|
|
98
98
|
) {
|
|
99
|
-
const packageManager = getPackageManagerUsedForExistingProject();
|
|
99
|
+
const packageManager = await getPackageManagerUsedForExistingProject();
|
|
100
100
|
|
|
101
101
|
await $`git pull --rebase`;
|
|
102
102
|
await $`git push`;
|
|
@@ -110,8 +110,8 @@ async function prePublish(
|
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
function getPackageManagerUsedForExistingProject(): PackageManager {
|
|
114
|
-
const packageManagers = getPackageManagersForProject(CWD);
|
|
113
|
+
async function getPackageManagerUsedForExistingProject(): Promise<PackageManager> {
|
|
114
|
+
const packageManagers = await getPackageManagersForProject(CWD);
|
|
115
115
|
if (packageManagers.length > 1) {
|
|
116
116
|
const packageManagerLockFileNames = packageManagers
|
|
117
117
|
.map((packageManager) => getPackageManagerLockFileName(packageManager))
|
|
@@ -2,6 +2,7 @@ import chalk from "chalk";
|
|
|
2
2
|
import { repeat } from "complete-common";
|
|
3
3
|
import type { PackageManager } from "complete-node";
|
|
4
4
|
import {
|
|
5
|
+
$,
|
|
5
6
|
copyFileOrDirectory,
|
|
6
7
|
getFileNamesInDirectory,
|
|
7
8
|
getPackageManagerInstallCICommand,
|
|
@@ -13,7 +14,6 @@ import {
|
|
|
13
14
|
updatePackageJSONDependencies,
|
|
14
15
|
writeFile,
|
|
15
16
|
} from "complete-node";
|
|
16
|
-
import { $ } from "execa";
|
|
17
17
|
import path from "node:path";
|
|
18
18
|
import {
|
|
19
19
|
ACTION_YML,
|
|
@@ -147,8 +147,8 @@ function copyDynamicFiles(
|
|
|
147
147
|
const template = readFile(templatePath);
|
|
148
148
|
|
|
149
149
|
const packageJSON = template
|
|
150
|
-
.replaceAll("
|
|
151
|
-
.replaceAll("
|
|
150
|
+
.replaceAll("project-name", projectName)
|
|
151
|
+
.replaceAll("author-name", authorName ?? "unknown");
|
|
152
152
|
|
|
153
153
|
const destinationPath = path.join(projectPath, "package.json");
|
|
154
154
|
writeFile(destinationPath, packageJSON);
|
|
@@ -2,7 +2,7 @@ import { getGitHubUsername } from "../../git.js";
|
|
|
2
2
|
import { getInputString, promptError, promptLog } from "../../prompt.js";
|
|
3
3
|
|
|
4
4
|
export async function getAuthorName(): Promise<string | undefined> {
|
|
5
|
-
const gitHubUsername = getGitHubUsername();
|
|
5
|
+
const gitHubUsername = await getGitHubUsername();
|
|
6
6
|
if (gitHubUsername !== undefined) {
|
|
7
7
|
return gitHubUsername;
|
|
8
8
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
-
import {
|
|
2
|
+
import { commandExists, PackageManager } from "complete-node";
|
|
3
3
|
import { DEFAULT_PACKAGE_MANAGER } from "../../constants.js";
|
|
4
4
|
import { promptError } from "../../prompt.js";
|
|
5
5
|
|
|
@@ -9,10 +9,10 @@ interface PackageManagerOptions {
|
|
|
9
9
|
pnpm: boolean;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export function getPackageManagerUsedForNewProject(
|
|
12
|
+
export async function getPackageManagerUsedForNewProject(
|
|
13
13
|
options: PackageManagerOptions,
|
|
14
|
-
): PackageManager {
|
|
15
|
-
const packageManagerFromOptions = getPackageManagerFromOptions(options);
|
|
14
|
+
): Promise<PackageManager> {
|
|
15
|
+
const packageManagerFromOptions = await getPackageManagerFromOptions(options);
|
|
16
16
|
if (packageManagerFromOptions !== undefined) {
|
|
17
17
|
return packageManagerFromOptions;
|
|
18
18
|
}
|
|
@@ -20,9 +20,9 @@ export function getPackageManagerUsedForNewProject(
|
|
|
20
20
|
return DEFAULT_PACKAGE_MANAGER;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
function getPackageManagerFromOptions(options: PackageManagerOptions) {
|
|
23
|
+
async function getPackageManagerFromOptions(options: PackageManagerOptions) {
|
|
24
24
|
if (options.npm) {
|
|
25
|
-
const npmExists = commandExists("npm");
|
|
25
|
+
const npmExists = await commandExists("npm");
|
|
26
26
|
if (!npmExists) {
|
|
27
27
|
promptError(
|
|
28
28
|
`You specified the "--npm" option, but "${chalk.green(
|
|
@@ -35,7 +35,7 @@ function getPackageManagerFromOptions(options: PackageManagerOptions) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
if (options.yarn) {
|
|
38
|
-
const yarnExists = commandExists("yarn");
|
|
38
|
+
const yarnExists = await commandExists("yarn");
|
|
39
39
|
if (!yarnExists) {
|
|
40
40
|
promptError(
|
|
41
41
|
`You specified the "--yarn" option, but "${chalk.green(
|
|
@@ -48,7 +48,7 @@ function getPackageManagerFromOptions(options: PackageManagerOptions) {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
if (options.pnpm) {
|
|
51
|
-
const pnpmExists = commandExists("pnpm");
|
|
51
|
+
const pnpmExists = await commandExists("pnpm");
|
|
52
52
|
if (!pnpmExists) {
|
|
53
53
|
promptError(
|
|
54
54
|
`You specified the "--pnpm" option, but "${chalk.green(
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { commandExists, getJSONC, isFile } from "complete-node";
|
|
2
|
-
import { $ } from "execa";
|
|
1
|
+
import { $, commandExists, getJSONC, isFile } from "complete-node";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import { getInputYesNo, promptError, promptLog } from "../../prompt.js";
|
|
5
4
|
|
|
@@ -15,7 +14,7 @@ export async function vsCodeInit(
|
|
|
15
14
|
vscode: boolean,
|
|
16
15
|
yes: boolean,
|
|
17
16
|
): Promise<void> {
|
|
18
|
-
const VSCodeCommand = getVSCodeCommand();
|
|
17
|
+
const VSCodeCommand = await getVSCodeCommand();
|
|
19
18
|
if (VSCodeCommand === undefined) {
|
|
20
19
|
promptLog(
|
|
21
20
|
'VSCode does not seem to be installed. (The "code" command is not in the path.) Skipping VSCode-related things.',
|
|
@@ -27,8 +26,26 @@ export async function vsCodeInit(
|
|
|
27
26
|
await promptVSCode(projectPath, VSCodeCommand, vscode, yes);
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
function getVSCodeCommand():
|
|
31
|
-
|
|
29
|
+
async function getVSCodeCommand(): Promise<
|
|
30
|
+
(typeof VS_CODE_COMMANDS)[number] | undefined
|
|
31
|
+
> {
|
|
32
|
+
const commandCheckPromises = VS_CODE_COMMANDS.map((command) => ({
|
|
33
|
+
command,
|
|
34
|
+
existsPromise: commandExists(command),
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
const commandChecks = await Promise.all(
|
|
38
|
+
commandCheckPromises.map(async (check) => ({
|
|
39
|
+
command: check.command,
|
|
40
|
+
exists: await check.existsPromise,
|
|
41
|
+
})),
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const existingCommands = commandChecks
|
|
45
|
+
.filter((check) => check.exists)
|
|
46
|
+
.map((check) => check.command);
|
|
47
|
+
|
|
48
|
+
return existingCommands[0];
|
|
32
49
|
}
|
|
33
50
|
|
|
34
51
|
async function installVSCodeExtensions(
|
|
@@ -42,14 +59,16 @@ async function installVSCodeExtensions(
|
|
|
42
59
|
return;
|
|
43
60
|
}
|
|
44
61
|
|
|
45
|
-
const extensions = getExtensionsFromJSON(projectPath);
|
|
62
|
+
const extensions = await getExtensionsFromJSON(projectPath);
|
|
46
63
|
for (const extensionName of extensions) {
|
|
47
64
|
// eslint-disable-next-line no-await-in-loop
|
|
48
65
|
await $`${vsCodeCommand} --install-extension ${extensionName}`;
|
|
49
66
|
}
|
|
50
67
|
}
|
|
51
68
|
|
|
52
|
-
function getExtensionsFromJSON(
|
|
69
|
+
async function getExtensionsFromJSON(
|
|
70
|
+
projectPath: string,
|
|
71
|
+
): Promise<readonly string[]> {
|
|
53
72
|
const extensionsJSONPath = path.join(
|
|
54
73
|
projectPath,
|
|
55
74
|
".vscode",
|
|
@@ -60,7 +79,7 @@ function getExtensionsFromJSON(projectPath: string): readonly string[] {
|
|
|
60
79
|
return [];
|
|
61
80
|
}
|
|
62
81
|
|
|
63
|
-
const extensionsJSON = getJSONC(extensionsJSONPath);
|
|
82
|
+
const extensionsJSON = await getJSONC(extensionsJSONPath);
|
|
64
83
|
|
|
65
84
|
const { recommendations } = extensionsJSON;
|
|
66
85
|
if (!Array.isArray(recommendations)) {
|
package/src/git.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
-
import { commandExists,
|
|
3
|
-
import { $ } from "execa";
|
|
2
|
+
import { $, commandExists, isFileAsync, readFileAsync } from "complete-node";
|
|
4
3
|
import path from "node:path";
|
|
5
4
|
import yaml from "yaml";
|
|
6
5
|
import { HOME_DIR, PROJECT_NAME, PROJECT_VERSION } from "./constants.js";
|
|
@@ -11,8 +10,9 @@ import { getInputString, getInputYesNo, promptLog } from "./prompt.js";
|
|
|
11
10
|
* If the GitHub CLI is installed, we can derive the user's GitHub username from their YAML
|
|
12
11
|
* configuration.
|
|
13
12
|
*/
|
|
14
|
-
export function getGitHubUsername(): string | undefined {
|
|
15
|
-
|
|
13
|
+
export async function getGitHubUsername(): Promise<string | undefined> {
|
|
14
|
+
const ghExists = await commandExists("gh");
|
|
15
|
+
if (!ghExists) {
|
|
16
16
|
return undefined;
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -21,11 +21,12 @@ export function getGitHubUsername(): string | undefined {
|
|
|
21
21
|
return undefined;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
const hostsPathExists = await isFileAsync(githubCLIHostsPath);
|
|
25
|
+
if (!hostsPathExists) {
|
|
25
26
|
return undefined;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
const configYAMLRaw =
|
|
29
|
+
const configYAMLRaw = await readFileAsync(githubCLIHostsPath);
|
|
29
30
|
const configYAML = yaml.parse(configYAMLRaw) as GitHubCLIHostsYAML;
|
|
30
31
|
|
|
31
32
|
const githubCom = configYAML["github.com"];
|
|
@@ -71,14 +72,15 @@ export async function promptGitHubRepoOrGitRemoteURL(
|
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
// We do not need to prompt the user if they do not have Git installed.
|
|
74
|
-
|
|
75
|
+
const gitExists = await commandExists("git");
|
|
76
|
+
if (!gitExists) {
|
|
75
77
|
promptLog(
|
|
76
78
|
'Git does not seem to be installed. (The "git" command is not in the path.) Skipping Git-related things.',
|
|
77
79
|
);
|
|
78
80
|
return undefined;
|
|
79
81
|
}
|
|
80
82
|
|
|
81
|
-
const gitHubUsername = getGitHubUsername();
|
|
83
|
+
const gitHubUsername = await getGitHubUsername();
|
|
82
84
|
if (gitHubUsername !== undefined) {
|
|
83
85
|
const { exitCode } = await $`gh repo view ${projectName}`;
|
|
84
86
|
const gitHubRepoExists = exitCode === 0;
|
|
@@ -153,7 +155,8 @@ export async function initGitRepository(
|
|
|
153
155
|
projectPath: string,
|
|
154
156
|
gitRemoteURL: string | undefined,
|
|
155
157
|
): Promise<void> {
|
|
156
|
-
|
|
158
|
+
const gitExists = await commandExists("git");
|
|
159
|
+
if (!gitExists) {
|
|
157
160
|
return;
|
|
158
161
|
}
|
|
159
162
|
|
package/src/main.ts
CHANGED
|
@@ -7,13 +7,10 @@ import { NukeCommand } from "./commands/NukeCommand.js";
|
|
|
7
7
|
import { PublishCommand } from "./commands/PublishCommand.js";
|
|
8
8
|
import { UpdateCommand } from "./commands/UpdateCommand.js";
|
|
9
9
|
import { PROJECT_NAME, PROJECT_VERSION } from "./constants.js";
|
|
10
|
-
import { validateNodeVersion } from "./validateNoteVersion.js";
|
|
11
10
|
|
|
12
11
|
await main();
|
|
13
12
|
|
|
14
13
|
async function main(): Promise<void> {
|
|
15
|
-
validateNodeVersion();
|
|
16
|
-
|
|
17
14
|
const [_node, _app, ...args] = process.argv;
|
|
18
15
|
|
|
19
16
|
const cli = new Cli({
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import { parseSemanticVersion } from "complete-common";
|
|
3
|
-
import { PROJECT_NAME } from "./constants.js";
|
|
4
|
-
// 20.11 is the minimum version that supports `import.meta.dirname`.
|
|
5
|
-
const REQUIRED_NODE_JS_MAJOR_VERSION = 20;
|
|
6
|
-
const REQUIRED_NODE_JS_MINOR_VERSION = 11;
|
|
7
|
-
export function validateNodeVersion() {
|
|
8
|
-
const { version } = process;
|
|
9
|
-
const semanticVersion = parseSemanticVersion(version);
|
|
10
|
-
if (semanticVersion === undefined) {
|
|
11
|
-
throw new Error(`Failed to parse the Node version: ${version}`);
|
|
12
|
-
}
|
|
13
|
-
const { majorVersion, minorVersion } = semanticVersion;
|
|
14
|
-
if (majorVersion > REQUIRED_NODE_JS_MAJOR_VERSION) {
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
if (majorVersion === REQUIRED_NODE_JS_MAJOR_VERSION &&
|
|
18
|
-
minorVersion >= REQUIRED_NODE_JS_MINOR_VERSION) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
console.error(`Your Node.js version is: ${chalk.red(version)}`);
|
|
22
|
-
console.error(`${PROJECT_NAME} requires a Node.js version of ${chalk.red(`${REQUIRED_NODE_JS_MAJOR_VERSION}.${REQUIRED_NODE_JS_MINOR_VERSION}.0`)} or greater.`);
|
|
23
|
-
console.error(`Please upgrade your version of Node.js before using ${PROJECT_NAME}.`);
|
|
24
|
-
process.exit(1);
|
|
25
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import { parseSemanticVersion } from "complete-common";
|
|
3
|
-
import { PROJECT_NAME } from "./constants.js";
|
|
4
|
-
|
|
5
|
-
// 20.11 is the minimum version that supports `import.meta.dirname`.
|
|
6
|
-
const REQUIRED_NODE_JS_MAJOR_VERSION = 20;
|
|
7
|
-
const REQUIRED_NODE_JS_MINOR_VERSION = 11;
|
|
8
|
-
|
|
9
|
-
export function validateNodeVersion(): void {
|
|
10
|
-
const { version } = process;
|
|
11
|
-
|
|
12
|
-
const semanticVersion = parseSemanticVersion(version);
|
|
13
|
-
if (semanticVersion === undefined) {
|
|
14
|
-
throw new Error(`Failed to parse the Node version: ${version}`);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const { majorVersion, minorVersion } = semanticVersion;
|
|
18
|
-
if (majorVersion > REQUIRED_NODE_JS_MAJOR_VERSION) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (
|
|
23
|
-
majorVersion === REQUIRED_NODE_JS_MAJOR_VERSION &&
|
|
24
|
-
minorVersion >= REQUIRED_NODE_JS_MINOR_VERSION
|
|
25
|
-
) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
console.error(`Your Node.js version is: ${chalk.red(version)}`);
|
|
30
|
-
console.error(
|
|
31
|
-
`${PROJECT_NAME} requires a Node.js version of ${chalk.red(
|
|
32
|
-
`${REQUIRED_NODE_JS_MAJOR_VERSION}.${REQUIRED_NODE_JS_MINOR_VERSION}.0`,
|
|
33
|
-
)} or greater.`,
|
|
34
|
-
);
|
|
35
|
-
console.error(
|
|
36
|
-
`Please upgrade your version of Node.js before using ${PROJECT_NAME}.`,
|
|
37
|
-
);
|
|
38
|
-
process.exit(1);
|
|
39
|
-
}
|