@cluerise/tools 3.0.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/README.md +52 -0
- package/dist/bin/cluenar-tools.sh +10 -0
- package/dist/configs/.editorconfig +10 -0
- package/dist/configs/.eslintignore +47 -0
- package/dist/configs/.eslintrc.cjs +114 -0
- package/dist/configs/.nvmrc +1 -0
- package/dist/configs/.prettierignore +37 -0
- package/dist/configs/_gitignore +23 -0
- package/dist/configs/_npmrc +1 -0
- package/dist/configs/commitlint.config.ts +31 -0
- package/dist/configs/hooks/commit-msg +1 -0
- package/dist/configs/hooks/post-commit +1 -0
- package/dist/configs/hooks/pre-commit +1 -0
- package/dist/configs/hooks/prepare-commit-msg +1 -0
- package/dist/configs/lint-staged.config.js +31 -0
- package/dist/configs/prettier.config.js +13 -0
- package/dist/configs/release.config.js +119 -0
- package/dist/configs/tsconfig.json +27 -0
- package/dist/scripts/check-heroku-node-version/main.js +138 -0
- package/dist/scripts/create-commit-message/main.js +149 -0
- package/dist/scripts/format-commit-message/main.js +130 -0
- package/dist/scripts/init/main.js +386 -0
- package/dist/scripts/lint/main.js +161 -0
- package/dist/scripts/release/main.js +230 -0
- package/dist/scripts/update-node-versions/main.js +162 -0
- package/package.json +45 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import FileSystem from "fs/promises";
|
|
2
|
+
import { z, ZodError } from "zod";
|
|
3
|
+
import ChildProcess from "child_process";
|
|
4
|
+
import "eslint";
|
|
5
|
+
import "glob";
|
|
6
|
+
import "prettier";
|
|
7
|
+
import loadCommitlintConfig from "@commitlint/load";
|
|
8
|
+
const enginesSchema = z.object({
|
|
9
|
+
node: z.string()
|
|
10
|
+
});
|
|
11
|
+
const repositoryObjectSchema = z.object({
|
|
12
|
+
type: z.string(),
|
|
13
|
+
url: z.string(),
|
|
14
|
+
directory: z.ostring()
|
|
15
|
+
});
|
|
16
|
+
const repositorySchema = z.union([z.string(), repositoryObjectSchema]);
|
|
17
|
+
z.object({
|
|
18
|
+
name: z.string(),
|
|
19
|
+
version: z.string(),
|
|
20
|
+
description: z.string(),
|
|
21
|
+
engines: enginesSchema.optional(),
|
|
22
|
+
repository: repositorySchema.optional()
|
|
23
|
+
});
|
|
24
|
+
const runMain = (main2) => {
|
|
25
|
+
main2(process.argv.slice(2)).then((exitCode) => {
|
|
26
|
+
process.exit(exitCode);
|
|
27
|
+
}).catch((error) => {
|
|
28
|
+
console.error(error);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
const capitalize = (value) => {
|
|
33
|
+
const [firstLetter] = value;
|
|
34
|
+
if (!firstLetter) {
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
return `${firstLetter.toUpperCase()}${value.slice(1)}`;
|
|
38
|
+
};
|
|
39
|
+
const StringUtils = {
|
|
40
|
+
capitalize
|
|
41
|
+
};
|
|
42
|
+
const getBranchName = () => ChildProcess.execSync("git symbolic-ref --short HEAD").toString().trim();
|
|
43
|
+
const isRebasing = () => {
|
|
44
|
+
try {
|
|
45
|
+
ChildProcess.execSync("ls `git rev-parse --git-dir` | grep rebase");
|
|
46
|
+
return true;
|
|
47
|
+
} catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const GitCommands = {
|
|
52
|
+
getBranchName,
|
|
53
|
+
isRebasing
|
|
54
|
+
};
|
|
55
|
+
z.union([z.literal("all"), z.literal("code")]);
|
|
56
|
+
const stringifySemanticCommitMessagePrefix = ({ type, scope }) => `${type}${scope ? `(${scope})` : ""}`;
|
|
57
|
+
const startsWithSemanticCommitMessagePrefix = (message, prefix) => message.startsWith(stringifySemanticCommitMessagePrefix(prefix));
|
|
58
|
+
const createSemanticCommitMessage = (prefix, message) => {
|
|
59
|
+
const [subject, ...comments] = message.split("\n#");
|
|
60
|
+
let commitMessage = stringifySemanticCommitMessagePrefix(prefix) + ": ";
|
|
61
|
+
if (subject) {
|
|
62
|
+
commitMessage += StringUtils.capitalize(subject);
|
|
63
|
+
}
|
|
64
|
+
if (comments.length > 0) {
|
|
65
|
+
commitMessage += "\n\n#" + comments.join("\n#");
|
|
66
|
+
}
|
|
67
|
+
return commitMessage;
|
|
68
|
+
};
|
|
69
|
+
const isValidEnumValue = async (ruleName, value) => {
|
|
70
|
+
const { rules } = await loadCommitlintConfig();
|
|
71
|
+
const rule = rules[ruleName];
|
|
72
|
+
if (!rule) {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
const [_severity, _condition, values] = rule;
|
|
76
|
+
if (!values) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
return values.includes(value);
|
|
80
|
+
};
|
|
81
|
+
const isValidType = (type) => isValidEnumValue("type-enum", type);
|
|
82
|
+
const isValidScope = (scope) => isValidEnumValue("scope-enum", scope);
|
|
83
|
+
const CommitLintConfig = {
|
|
84
|
+
isValidType,
|
|
85
|
+
isValidScope
|
|
86
|
+
};
|
|
87
|
+
const parseSemanticBranchName = async (name) => {
|
|
88
|
+
const [typeValue, scopeValue] = name.split("-");
|
|
89
|
+
if (!typeValue || !await CommitLintConfig.isValidType(typeValue)) {
|
|
90
|
+
throw new Error("Invalid commit type in branch name");
|
|
91
|
+
}
|
|
92
|
+
const type = typeValue.toLowerCase();
|
|
93
|
+
const scope = scopeValue && await CommitLintConfig.isValidScope(scopeValue) ? scopeValue.toLowerCase() : null;
|
|
94
|
+
return {
|
|
95
|
+
type,
|
|
96
|
+
scope
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
const parseSemanticCommitMessage = (message) => {
|
|
100
|
+
const firstColonPosition = message.search(":");
|
|
101
|
+
const prefix = message.slice(0, firstColonPosition).trim();
|
|
102
|
+
const content = message.slice(firstColonPosition + 1).trim();
|
|
103
|
+
return { prefix, content };
|
|
104
|
+
};
|
|
105
|
+
const formatSemanticCommitMessage = (message) => {
|
|
106
|
+
const { prefix, content } = parseSemanticCommitMessage(message);
|
|
107
|
+
if (!prefix || !content) {
|
|
108
|
+
return message;
|
|
109
|
+
}
|
|
110
|
+
return `${prefix}: ${StringUtils.capitalize(content)}`;
|
|
111
|
+
};
|
|
112
|
+
const CommitLintCommands = {
|
|
113
|
+
createSemanticCommitMessage,
|
|
114
|
+
parseSemanticBranchName,
|
|
115
|
+
formatSemanticCommitMessage,
|
|
116
|
+
startsWithSemanticCommitMessagePrefix
|
|
117
|
+
};
|
|
118
|
+
const commitMessagePathArgSchema = z.string();
|
|
119
|
+
const parseCreateCommitMessageArgs = ([commitMessagePathArg]) => {
|
|
120
|
+
const commitMessagePath = commitMessagePathArgSchema.parse(commitMessagePathArg);
|
|
121
|
+
return {
|
|
122
|
+
commitMessagePath
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
const main = async (args) => {
|
|
126
|
+
try {
|
|
127
|
+
if (GitCommands.isRebasing()) {
|
|
128
|
+
return 0;
|
|
129
|
+
}
|
|
130
|
+
const { commitMessagePath } = parseCreateCommitMessageArgs(args);
|
|
131
|
+
const commitMessage = (await FileSystem.readFile(commitMessagePath)).toString();
|
|
132
|
+
const branchName = GitCommands.getBranchName();
|
|
133
|
+
const commitMessagePrefix = await CommitLintCommands.parseSemanticBranchName(branchName);
|
|
134
|
+
if (!CommitLintCommands.startsWithSemanticCommitMessagePrefix(commitMessage, commitMessagePrefix)) {
|
|
135
|
+
const nextCommitMessage = CommitLintCommands.createSemanticCommitMessage(commitMessagePrefix, commitMessage);
|
|
136
|
+
await FileSystem.writeFile(commitMessagePath, nextCommitMessage);
|
|
137
|
+
}
|
|
138
|
+
} catch (error) {
|
|
139
|
+
if (error instanceof ZodError) {
|
|
140
|
+
console.warn("Invalid commit message path");
|
|
141
|
+
}
|
|
142
|
+
if (error instanceof Error) {
|
|
143
|
+
console.warn(error.message);
|
|
144
|
+
}
|
|
145
|
+
console.warn(error);
|
|
146
|
+
}
|
|
147
|
+
return 0;
|
|
148
|
+
};
|
|
149
|
+
runMain(main);
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import FileSystem from "fs/promises";
|
|
2
|
+
import { z, ZodError } from "zod";
|
|
3
|
+
import "eslint";
|
|
4
|
+
import "glob";
|
|
5
|
+
import "prettier";
|
|
6
|
+
import loadCommitlintConfig from "@commitlint/load";
|
|
7
|
+
const enginesSchema = z.object({
|
|
8
|
+
node: z.string()
|
|
9
|
+
});
|
|
10
|
+
const repositoryObjectSchema = z.object({
|
|
11
|
+
type: z.string(),
|
|
12
|
+
url: z.string(),
|
|
13
|
+
directory: z.ostring()
|
|
14
|
+
});
|
|
15
|
+
const repositorySchema = z.union([z.string(), repositoryObjectSchema]);
|
|
16
|
+
z.object({
|
|
17
|
+
name: z.string(),
|
|
18
|
+
version: z.string(),
|
|
19
|
+
description: z.string(),
|
|
20
|
+
engines: enginesSchema.optional(),
|
|
21
|
+
repository: repositorySchema.optional()
|
|
22
|
+
});
|
|
23
|
+
const runMain = (main2) => {
|
|
24
|
+
main2(process.argv.slice(2)).then((exitCode) => {
|
|
25
|
+
process.exit(exitCode);
|
|
26
|
+
}).catch((error) => {
|
|
27
|
+
console.error(error);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
const capitalize = (value) => {
|
|
32
|
+
const [firstLetter] = value;
|
|
33
|
+
if (!firstLetter) {
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
return `${firstLetter.toUpperCase()}${value.slice(1)}`;
|
|
37
|
+
};
|
|
38
|
+
const StringUtils = {
|
|
39
|
+
capitalize
|
|
40
|
+
};
|
|
41
|
+
z.union([z.literal("all"), z.literal("code")]);
|
|
42
|
+
const stringifySemanticCommitMessagePrefix = ({ type, scope }) => `${type}${scope ? `(${scope})` : ""}`;
|
|
43
|
+
const startsWithSemanticCommitMessagePrefix = (message, prefix) => message.startsWith(stringifySemanticCommitMessagePrefix(prefix));
|
|
44
|
+
const createSemanticCommitMessage = (prefix, message) => {
|
|
45
|
+
const [subject, ...comments] = message.split("\n#");
|
|
46
|
+
let commitMessage = stringifySemanticCommitMessagePrefix(prefix) + ": ";
|
|
47
|
+
if (subject) {
|
|
48
|
+
commitMessage += StringUtils.capitalize(subject);
|
|
49
|
+
}
|
|
50
|
+
if (comments.length > 0) {
|
|
51
|
+
commitMessage += "\n\n#" + comments.join("\n#");
|
|
52
|
+
}
|
|
53
|
+
return commitMessage;
|
|
54
|
+
};
|
|
55
|
+
const isValidEnumValue = async (ruleName, value) => {
|
|
56
|
+
const { rules } = await loadCommitlintConfig();
|
|
57
|
+
const rule = rules[ruleName];
|
|
58
|
+
if (!rule) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
const [_severity, _condition, values] = rule;
|
|
62
|
+
if (!values) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
return values.includes(value);
|
|
66
|
+
};
|
|
67
|
+
const isValidType = (type) => isValidEnumValue("type-enum", type);
|
|
68
|
+
const isValidScope = (scope) => isValidEnumValue("scope-enum", scope);
|
|
69
|
+
const CommitLintConfig = {
|
|
70
|
+
isValidType,
|
|
71
|
+
isValidScope
|
|
72
|
+
};
|
|
73
|
+
const parseSemanticBranchName = async (name) => {
|
|
74
|
+
const [typeValue, scopeValue] = name.split("-");
|
|
75
|
+
if (!typeValue || !await CommitLintConfig.isValidType(typeValue)) {
|
|
76
|
+
throw new Error("Invalid commit type in branch name");
|
|
77
|
+
}
|
|
78
|
+
const type = typeValue.toLowerCase();
|
|
79
|
+
const scope = scopeValue && await CommitLintConfig.isValidScope(scopeValue) ? scopeValue.toLowerCase() : null;
|
|
80
|
+
return {
|
|
81
|
+
type,
|
|
82
|
+
scope
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
const parseSemanticCommitMessage = (message) => {
|
|
86
|
+
const firstColonPosition = message.search(":");
|
|
87
|
+
const prefix = message.slice(0, firstColonPosition).trim();
|
|
88
|
+
const content = message.slice(firstColonPosition + 1).trim();
|
|
89
|
+
return { prefix, content };
|
|
90
|
+
};
|
|
91
|
+
const formatSemanticCommitMessage = (message) => {
|
|
92
|
+
const { prefix, content } = parseSemanticCommitMessage(message);
|
|
93
|
+
if (!prefix || !content) {
|
|
94
|
+
return message;
|
|
95
|
+
}
|
|
96
|
+
return `${prefix}: ${StringUtils.capitalize(content)}`;
|
|
97
|
+
};
|
|
98
|
+
const CommitLintCommands = {
|
|
99
|
+
createSemanticCommitMessage,
|
|
100
|
+
parseSemanticBranchName,
|
|
101
|
+
formatSemanticCommitMessage,
|
|
102
|
+
startsWithSemanticCommitMessagePrefix
|
|
103
|
+
};
|
|
104
|
+
const commitMessagePathArgSchema = z.string();
|
|
105
|
+
const parseFormatCommitMessageArgs = ([commitMessagePathArg]) => {
|
|
106
|
+
const commitMessagePath = commitMessagePathArgSchema.parse(commitMessagePathArg);
|
|
107
|
+
return {
|
|
108
|
+
commitMessagePath
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
const main = async (args) => {
|
|
112
|
+
try {
|
|
113
|
+
const { commitMessagePath } = parseFormatCommitMessageArgs(args);
|
|
114
|
+
const commitMessage = (await FileSystem.readFile(commitMessagePath)).toString();
|
|
115
|
+
const formattedCommitMessage = CommitLintCommands.formatSemanticCommitMessage(commitMessage);
|
|
116
|
+
if (formattedCommitMessage !== commitMessage) {
|
|
117
|
+
await FileSystem.writeFile(commitMessagePath, formattedCommitMessage);
|
|
118
|
+
}
|
|
119
|
+
} catch (error) {
|
|
120
|
+
if (error instanceof ZodError) {
|
|
121
|
+
console.warn("Invalid commit message path");
|
|
122
|
+
}
|
|
123
|
+
if (error instanceof Error) {
|
|
124
|
+
console.warn(error.message);
|
|
125
|
+
}
|
|
126
|
+
console.warn(error);
|
|
127
|
+
}
|
|
128
|
+
return 0;
|
|
129
|
+
};
|
|
130
|
+
runMain(main);
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { z, ZodError } from "zod";
|
|
2
|
+
import FileSystem from "fs/promises";
|
|
3
|
+
import Path from "path";
|
|
4
|
+
import ChildProcess from "child_process";
|
|
5
|
+
import { ESLint } from "eslint";
|
|
6
|
+
import { glob } from "glob";
|
|
7
|
+
import * as Prettier from "prettier";
|
|
8
|
+
import "@commitlint/load";
|
|
9
|
+
class ParseGitRepositoryError extends Error {
|
|
10
|
+
}
|
|
11
|
+
const gitProviderOrigins = {
|
|
12
|
+
github: "https://github.com"
|
|
13
|
+
};
|
|
14
|
+
const gitProviderNames = Object.keys(gitProviderOrigins);
|
|
15
|
+
const isGitProviderName = (name) => gitProviderNames.includes(name);
|
|
16
|
+
const parseRepositoryUrl = (urlString) => {
|
|
17
|
+
const urlValue = urlString.includes(":") ? urlString : `https://${urlString}`;
|
|
18
|
+
const url = new URL(urlValue);
|
|
19
|
+
const scheme = url.protocol.slice(0, -1);
|
|
20
|
+
if (isGitProviderName(scheme)) {
|
|
21
|
+
const [owner, repositoryName] = url.pathname.split("/");
|
|
22
|
+
if (!owner || !repositoryName) {
|
|
23
|
+
throw new ParseGitRepositoryError("Unknown owner or repositoryName");
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
origin: gitProviderOrigins[scheme],
|
|
27
|
+
owner,
|
|
28
|
+
repositoryName
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if (scheme === "https") {
|
|
32
|
+
const [, owner, repositoryName] = url.pathname.split("/");
|
|
33
|
+
if (!owner || !repositoryName) {
|
|
34
|
+
throw new ParseGitRepositoryError("Unknown owner or repositoryName");
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
origin: url.origin,
|
|
38
|
+
owner,
|
|
39
|
+
repositoryName: repositoryName.endsWith(".git") ? repositoryName.slice(0, -4) : repositoryName
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
throw new ParseGitRepositoryError("Unsupported repository URL");
|
|
43
|
+
};
|
|
44
|
+
const parsePackageJsonRepository = (repository) => {
|
|
45
|
+
if (typeof repository === "string") {
|
|
46
|
+
return parseRepositoryUrl(repository);
|
|
47
|
+
}
|
|
48
|
+
return parseRepositoryUrl(repository.url);
|
|
49
|
+
};
|
|
50
|
+
const enginesSchema = z.object({
|
|
51
|
+
node: z.string()
|
|
52
|
+
});
|
|
53
|
+
const repositoryObjectSchema = z.object({
|
|
54
|
+
type: z.string(),
|
|
55
|
+
url: z.string(),
|
|
56
|
+
directory: z.ostring()
|
|
57
|
+
});
|
|
58
|
+
const repositorySchema = z.union([z.string(), repositoryObjectSchema]);
|
|
59
|
+
const packageJsonSchema = z.object({
|
|
60
|
+
name: z.string(),
|
|
61
|
+
version: z.string(),
|
|
62
|
+
description: z.string(),
|
|
63
|
+
engines: enginesSchema.optional(),
|
|
64
|
+
repository: repositorySchema.optional()
|
|
65
|
+
});
|
|
66
|
+
const readPackageJson = async () => {
|
|
67
|
+
const packageJsonData = await FileSystem.readFile("package.json", { encoding: "utf8" });
|
|
68
|
+
const packageJson = JSON.parse(packageJsonData);
|
|
69
|
+
const parseResult = packageJsonSchema.safeParse(packageJson);
|
|
70
|
+
if (!parseResult.success) {
|
|
71
|
+
throw parseResult.error;
|
|
72
|
+
}
|
|
73
|
+
return packageJson;
|
|
74
|
+
};
|
|
75
|
+
const CoreCommands = {
|
|
76
|
+
readPackageJson,
|
|
77
|
+
parsePackageJsonRepository
|
|
78
|
+
};
|
|
79
|
+
const runMain = (main2) => {
|
|
80
|
+
main2(process.argv.slice(2)).then((exitCode) => {
|
|
81
|
+
process.exit(exitCode);
|
|
82
|
+
}).catch((error) => {
|
|
83
|
+
console.error(error);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
const createResultMessage = (exitCode) => {
|
|
88
|
+
if (exitCode === null) {
|
|
89
|
+
return "Done";
|
|
90
|
+
}
|
|
91
|
+
return exitCode === 0 ? "OK" : "Failed";
|
|
92
|
+
};
|
|
93
|
+
const createStatusConsole = (command) => ({
|
|
94
|
+
printBegin: (arg) => console.info(`${command} ${arg}...`),
|
|
95
|
+
printEnd: (arg, exitCode = null) => console.info(`${command} ${arg}... ${createResultMessage(exitCode)}`)
|
|
96
|
+
});
|
|
97
|
+
const packageName = "@cluerise/tools";
|
|
98
|
+
const rootAppDirectory = `./node_modules/${packageName}`;
|
|
99
|
+
const toolsConfigPackage = `${packageName}/dist/configs`;
|
|
100
|
+
const toolsConfigDirectory = `${rootAppDirectory}/dist/configs`;
|
|
101
|
+
const AppConfig = {
|
|
102
|
+
toolsConfigPackage,
|
|
103
|
+
toolsConfigDirectory
|
|
104
|
+
};
|
|
105
|
+
const copyFile = async (sourceDirectory, filePath, destinationFilePath) => {
|
|
106
|
+
const sourcePath = Path.resolve(sourceDirectory, filePath);
|
|
107
|
+
const destinationPath = Path.resolve(process.cwd(), destinationFilePath ?? filePath);
|
|
108
|
+
await FileSystem.mkdir(Path.dirname(destinationPath), { recursive: true });
|
|
109
|
+
return FileSystem.copyFile(sourcePath, destinationPath);
|
|
110
|
+
};
|
|
111
|
+
const createFile = async (path, content) => {
|
|
112
|
+
const destinationPath = Path.resolve(process.cwd(), path);
|
|
113
|
+
await FileSystem.mkdir(Path.dirname(destinationPath), { recursive: true });
|
|
114
|
+
return FileSystem.writeFile(destinationPath, content);
|
|
115
|
+
};
|
|
116
|
+
const ConfigCommands = {
|
|
117
|
+
copyFile,
|
|
118
|
+
createFile
|
|
119
|
+
};
|
|
120
|
+
const commitlintConfigName = "commitlint.config";
|
|
121
|
+
const commitlintConfigPath = `${commitlintConfigName}.ts`;
|
|
122
|
+
const initCommitlint = async ({ configPackage }) => {
|
|
123
|
+
const configContent = `export { default } from '${configPackage}/${commitlintConfigName}';
|
|
124
|
+
`;
|
|
125
|
+
await ConfigCommands.createFile(commitlintConfigPath, configContent);
|
|
126
|
+
};
|
|
127
|
+
const editorConfigPath = ".editorconfig";
|
|
128
|
+
const initEditorConfig = async ({ configDirectory }) => {
|
|
129
|
+
await ConfigCommands.copyFile(configDirectory, editorConfigPath);
|
|
130
|
+
};
|
|
131
|
+
const eslintConfigPath = ".eslintrc.cjs";
|
|
132
|
+
const eslintIgnorePath = ".eslintignore";
|
|
133
|
+
const initEslint = async ({ configDirectory }) => {
|
|
134
|
+
const configContent = `module.exports = {
|
|
135
|
+
extends: '${configDirectory}/${eslintConfigPath}'
|
|
136
|
+
};
|
|
137
|
+
`;
|
|
138
|
+
await ConfigCommands.createFile(eslintConfigPath, configContent);
|
|
139
|
+
await ConfigCommands.copyFile(configDirectory, eslintIgnorePath);
|
|
140
|
+
};
|
|
141
|
+
const sourceGitignorePath = "_gitignore";
|
|
142
|
+
const destinationGitignorePath = ".gitignore";
|
|
143
|
+
const gitHookDirectory = "hooks";
|
|
144
|
+
const gitHookPaths = [
|
|
145
|
+
Path.join(gitHookDirectory, "commit-msg"),
|
|
146
|
+
Path.join(gitHookDirectory, "post-commit"),
|
|
147
|
+
Path.join(gitHookDirectory, "pre-commit"),
|
|
148
|
+
Path.join(gitHookDirectory, "prepare-commit-msg")
|
|
149
|
+
];
|
|
150
|
+
const initGit = async ({ configDirectory }) => {
|
|
151
|
+
await ConfigCommands.copyFile(configDirectory, sourceGitignorePath, destinationGitignorePath);
|
|
152
|
+
await Promise.all(gitHookPaths.map((gitHookPath) => ConfigCommands.copyFile(configDirectory, gitHookPath)));
|
|
153
|
+
};
|
|
154
|
+
const lintStagedConfigPath = "lint-staged.config.js";
|
|
155
|
+
const initLintStaged = async ({ configPackage }) => {
|
|
156
|
+
const configContent = `export { default } from '${configPackage}/${lintStagedConfigPath}';
|
|
157
|
+
`;
|
|
158
|
+
await ConfigCommands.createFile(lintStagedConfigPath, configContent);
|
|
159
|
+
};
|
|
160
|
+
const sourceNpmrcPath = "_npmrc";
|
|
161
|
+
const destinationNpmrcPath = ".npmrc";
|
|
162
|
+
const initNpm = async ({ configDirectory }) => {
|
|
163
|
+
await ConfigCommands.copyFile(configDirectory, sourceNpmrcPath, destinationNpmrcPath);
|
|
164
|
+
};
|
|
165
|
+
const nvmrcPath = ".nvmrc";
|
|
166
|
+
const initNvm = async ({ configDirectory }) => {
|
|
167
|
+
await ConfigCommands.copyFile(configDirectory, nvmrcPath);
|
|
168
|
+
};
|
|
169
|
+
const prettierConfigPath = "prettier.config.js";
|
|
170
|
+
const initPrettier = async ({ configPackage }) => {
|
|
171
|
+
const configContent = `export { default } from '${configPackage}/${prettierConfigPath}';
|
|
172
|
+
`;
|
|
173
|
+
await ConfigCommands.createFile(prettierConfigPath, configContent);
|
|
174
|
+
};
|
|
175
|
+
const releaseConfigPath = "release.config.js";
|
|
176
|
+
const defaultReleaseConfigParams = {
|
|
177
|
+
host: "<host>",
|
|
178
|
+
owner: "<owner>",
|
|
179
|
+
repository: "<repository>"
|
|
180
|
+
};
|
|
181
|
+
const getReleaseConfigParams = async () => {
|
|
182
|
+
try {
|
|
183
|
+
const { repository } = await CoreCommands.readPackageJson();
|
|
184
|
+
if (!repository) {
|
|
185
|
+
return defaultReleaseConfigParams;
|
|
186
|
+
}
|
|
187
|
+
const { origin, owner, repositoryName } = CoreCommands.parsePackageJsonRepository(repository);
|
|
188
|
+
return {
|
|
189
|
+
host: origin,
|
|
190
|
+
owner,
|
|
191
|
+
repository: repositoryName
|
|
192
|
+
};
|
|
193
|
+
} catch {
|
|
194
|
+
return defaultReleaseConfigParams;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
const initRelease = async ({ configPackage }) => {
|
|
198
|
+
const releaseConfigParams = await getReleaseConfigParams();
|
|
199
|
+
const configContent = `import { createReleaseConfig } from '${configPackage}/${releaseConfigPath}';
|
|
200
|
+
|
|
201
|
+
export default createReleaseConfig(${JSON.stringify(releaseConfigParams, null, 2)});
|
|
202
|
+
`;
|
|
203
|
+
await ConfigCommands.createFile(releaseConfigPath, configContent);
|
|
204
|
+
};
|
|
205
|
+
const typescriptConfigPath = "tsconfig.json";
|
|
206
|
+
const initTypescript = async ({ configDirectory }) => {
|
|
207
|
+
const configContent = `{
|
|
208
|
+
"extends": "${configDirectory}/${typescriptConfigPath}",
|
|
209
|
+
"compilerOptions": {
|
|
210
|
+
"baseUrl": "./"
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
`;
|
|
214
|
+
await ConfigCommands.createFile(typescriptConfigPath, configContent);
|
|
215
|
+
};
|
|
216
|
+
const vscodeSettingsPath = Path.join(".vscode", "settings.json");
|
|
217
|
+
const initVscode = async () => {
|
|
218
|
+
const configContent = `{
|
|
219
|
+
"prettier.ignorePath": "node_modules/@cluerise/tools/dist/configs/.prettierignore",
|
|
220
|
+
"typescript.tsdk": "node_modules/typescript/lib"
|
|
221
|
+
}
|
|
222
|
+
`;
|
|
223
|
+
await ConfigCommands.createFile(vscodeSettingsPath, configContent);
|
|
224
|
+
};
|
|
225
|
+
const toolInitializers = {
|
|
226
|
+
commitlint: initCommitlint,
|
|
227
|
+
editorconfig: initEditorConfig,
|
|
228
|
+
eslint: initEslint,
|
|
229
|
+
git: initGit,
|
|
230
|
+
"lint-staged": initLintStaged,
|
|
231
|
+
npm: initNpm,
|
|
232
|
+
nvm: initNvm,
|
|
233
|
+
prettier: initPrettier,
|
|
234
|
+
release: initRelease,
|
|
235
|
+
typescript: initTypescript,
|
|
236
|
+
vscode: initVscode
|
|
237
|
+
};
|
|
238
|
+
const toolInitializerNames = Object.keys(toolInitializers);
|
|
239
|
+
const toolNameSchema = z.union([
|
|
240
|
+
z.literal("commitlint"),
|
|
241
|
+
z.literal("editorconfig"),
|
|
242
|
+
z.literal("eslint"),
|
|
243
|
+
z.literal("git"),
|
|
244
|
+
z.literal("lint-staged"),
|
|
245
|
+
z.literal("npm"),
|
|
246
|
+
z.literal("nvm"),
|
|
247
|
+
z.literal("prettier"),
|
|
248
|
+
z.literal("release"),
|
|
249
|
+
z.literal("typescript"),
|
|
250
|
+
z.literal("vscode")
|
|
251
|
+
]);
|
|
252
|
+
const initializingConsole = createStatusConsole("Initializing");
|
|
253
|
+
const initTool = async (name, params) => {
|
|
254
|
+
const toolInitializer = toolInitializers[name];
|
|
255
|
+
if (!toolInitializer) {
|
|
256
|
+
throw new Error(`Tool "${name}" is not supported.`);
|
|
257
|
+
}
|
|
258
|
+
initializingConsole.printBegin(name);
|
|
259
|
+
await toolInitializer(params);
|
|
260
|
+
initializingConsole.printEnd(name);
|
|
261
|
+
};
|
|
262
|
+
const initAllTools = async (params) => {
|
|
263
|
+
for (const name of toolInitializerNames) {
|
|
264
|
+
await initTool(name, params);
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
const InitCommands = {
|
|
268
|
+
initAllTools,
|
|
269
|
+
initTool
|
|
270
|
+
};
|
|
271
|
+
const lintCommit = (args) => {
|
|
272
|
+
const { status } = ChildProcess.spawnSync("commitlint", args, { stdio: "inherit" });
|
|
273
|
+
return status ?? 0;
|
|
274
|
+
};
|
|
275
|
+
z.union([z.literal("all"), z.literal("code")]);
|
|
276
|
+
const scopePatterns = {
|
|
277
|
+
all: ["**"],
|
|
278
|
+
code: ["src/**"]
|
|
279
|
+
};
|
|
280
|
+
const scopeShortcuts = Object.keys(scopePatterns);
|
|
281
|
+
const isScopeShortcut = (scope) => scopeShortcuts.includes(scope);
|
|
282
|
+
const resolveScope = (scope) => {
|
|
283
|
+
if (Array.isArray(scope)) {
|
|
284
|
+
return scope;
|
|
285
|
+
}
|
|
286
|
+
if (isScopeShortcut(scope)) {
|
|
287
|
+
return scopePatterns[scope];
|
|
288
|
+
}
|
|
289
|
+
return [scope];
|
|
290
|
+
};
|
|
291
|
+
const formatWithPrettier = async (patterns) => {
|
|
292
|
+
const eslint = new ESLint();
|
|
293
|
+
const configPath = await Prettier.resolveConfigFile();
|
|
294
|
+
if (!configPath) {
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
const config = await Prettier.resolveConfig(configPath);
|
|
298
|
+
if (!config) {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
const paths = await glob(patterns, {
|
|
302
|
+
nodir: true,
|
|
303
|
+
ignore: "node_modules/**"
|
|
304
|
+
});
|
|
305
|
+
await Promise.all(
|
|
306
|
+
paths.map(async (path) => {
|
|
307
|
+
if (await eslint.isPathIgnored(path)) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
const prevContent = (await FileSystem.readFile(path)).toString();
|
|
311
|
+
const nextContent = await Prettier.format(prevContent, {
|
|
312
|
+
...config,
|
|
313
|
+
filepath: path
|
|
314
|
+
});
|
|
315
|
+
await FileSystem.writeFile(path, nextContent);
|
|
316
|
+
})
|
|
317
|
+
);
|
|
318
|
+
};
|
|
319
|
+
const lintFiles = async (scope, options) => {
|
|
320
|
+
const patterns = resolveScope(scope);
|
|
321
|
+
if (options == null ? void 0 : options.fix) {
|
|
322
|
+
await formatWithPrettier(patterns);
|
|
323
|
+
}
|
|
324
|
+
const eslint = new ESLint({
|
|
325
|
+
fix: options == null ? void 0 : options.fix
|
|
326
|
+
});
|
|
327
|
+
const results = await eslint.lintFiles(patterns);
|
|
328
|
+
const problemCount = results.reduce((sum, result) => sum + result.errorCount + result.warningCount, 0);
|
|
329
|
+
if (options == null ? void 0 : options.fix) {
|
|
330
|
+
await ESLint.outputFixes(results);
|
|
331
|
+
}
|
|
332
|
+
if (problemCount > 0) {
|
|
333
|
+
const formatter = await eslint.loadFormatter("stylish");
|
|
334
|
+
const resultText = formatter.format(results);
|
|
335
|
+
console.error(resultText);
|
|
336
|
+
const errorMessage = `Linting failed with ${problemCount} problem${problemCount === 1 ? "" : "s"}.`;
|
|
337
|
+
throw new Error(errorMessage);
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
const lintStaged = (args) => {
|
|
341
|
+
const { status } = ChildProcess.spawnSync("lint-staged", args, { stdio: "inherit" });
|
|
342
|
+
return status ?? 0;
|
|
343
|
+
};
|
|
344
|
+
const LintCommands = {
|
|
345
|
+
lintFiles,
|
|
346
|
+
lintCommit,
|
|
347
|
+
lintStaged
|
|
348
|
+
};
|
|
349
|
+
const toolNameArgSchema = z.union([z.literal("all"), toolNameSchema]);
|
|
350
|
+
const parseInitArgs = ([nameArg]) => {
|
|
351
|
+
const name = toolNameArgSchema.parse(nameArg);
|
|
352
|
+
return {
|
|
353
|
+
name
|
|
354
|
+
};
|
|
355
|
+
};
|
|
356
|
+
const toolInitializerParams = {
|
|
357
|
+
configDirectory: AppConfig.toolsConfigDirectory,
|
|
358
|
+
configPackage: AppConfig.toolsConfigPackage
|
|
359
|
+
};
|
|
360
|
+
const main = async (args) => {
|
|
361
|
+
try {
|
|
362
|
+
const { name } = parseInitArgs(args);
|
|
363
|
+
if (name === "all") {
|
|
364
|
+
await InitCommands.initAllTools(toolInitializerParams);
|
|
365
|
+
} else {
|
|
366
|
+
await InitCommands.initTool(name, toolInitializerParams);
|
|
367
|
+
}
|
|
368
|
+
await LintCommands.lintFiles("all", { fix: true });
|
|
369
|
+
return 0;
|
|
370
|
+
} catch (error) {
|
|
371
|
+
if (error instanceof ZodError) {
|
|
372
|
+
const firstIssue = error.issues[0];
|
|
373
|
+
if ((firstIssue == null ? void 0 : firstIssue.code) === "invalid_union") {
|
|
374
|
+
console.error("Invalid tool name");
|
|
375
|
+
return 1;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
if (error instanceof Error) {
|
|
379
|
+
console.error(error.message);
|
|
380
|
+
return 1;
|
|
381
|
+
}
|
|
382
|
+
console.error(error);
|
|
383
|
+
return 1;
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
runMain(main);
|