@hallaxius/forge 0.1.2 → 0.1.4
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 +160 -158
- package/bin/forge.js +2 -2
- package/dist/cli.js +31602 -9895
- package/package.json +75 -72
- package/src/cli.ts +80 -78
- package/src/commands/account.ts +80 -0
- package/src/commands/alias.ts +66 -66
- package/src/commands/branch.ts +46 -46
- package/src/commands/ci.ts +28 -0
- package/src/commands/clone.ts +100 -100
- package/src/commands/commit.ts +88 -93
- package/src/commands/config.ts +47 -48
- package/src/commands/diff.ts +26 -26
- package/src/commands/fetch.ts +20 -20
- package/src/commands/help.ts +58 -58
- package/src/commands/init.ts +32 -37
- package/src/commands/issue.ts +63 -0
- package/src/commands/log.ts +29 -29
- package/src/commands/merge.ts +37 -37
- package/src/commands/pr.ts +65 -0
- package/src/commands/push.ts +35 -35
- package/src/commands/release.ts +26 -0
- package/src/commands/remote.ts +107 -107
- package/src/commands/reset.ts +30 -30
- package/src/commands/setup.ts +93 -95
- package/src/commands/stash.ts +44 -44
- package/src/commands/status.ts +74 -74
- package/src/commands/sync.ts +20 -20
- package/src/commands/tag.ts +41 -41
- package/src/commands/undo.ts +27 -27
- package/src/commands/version.ts +12 -12
- package/src/constants/colors.ts +7 -7
- package/src/constants/commit-types.ts +24 -24
- package/src/constants/messages.ts +13 -23
- package/src/lib/auth.ts +172 -95
- package/src/lib/config.ts +108 -99
- package/src/lib/git.ts +543 -382
- package/src/lib/github.ts +202 -0
- package/src/lib/logger.ts +18 -31
- package/src/lib/ui.ts +122 -156
- package/src/lib/validators.ts +16 -27
- package/src/templates/commit-types.json +9 -9
- package/src/utils/files.ts +21 -21
- package/src/utils/strings.ts +19 -19
- package/src/version.const.ts +1 -1
- package/src/commands/archive.ts +0 -35
- package/src/commands/bisect.ts +0 -102
- package/src/commands/cherry-pick.ts +0 -57
- package/src/commands/clean.ts +0 -76
- package/src/commands/worktree.ts +0 -92
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { Octokit } from "@octokit/rest";
|
|
3
|
+
import { currentBranch, getConfig } from "isomorphic-git";
|
|
4
|
+
import { resolveToken } from "./auth.js";
|
|
5
|
+
|
|
6
|
+
function parseRemoteUrl(remoteUrl: string): { owner: string; repo: string } {
|
|
7
|
+
const match = remoteUrl.match(
|
|
8
|
+
/github\.com[:/]([\w.-]+)\/([\w.-]+?)(?:\.git)?$/,
|
|
9
|
+
);
|
|
10
|
+
if (!match)
|
|
11
|
+
throw new Error(
|
|
12
|
+
`Could not determine GitHub repo from remote URL: ${remoteUrl}`,
|
|
13
|
+
);
|
|
14
|
+
return { owner: match[1], repo: match[2] };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function createClient(): Promise<Octokit> {
|
|
18
|
+
const token = await resolveToken();
|
|
19
|
+
return new Octokit({ auth: token });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function getRepoInfo(): Promise<{ owner: string; repo: string }> {
|
|
23
|
+
const dir = process.cwd();
|
|
24
|
+
const remoteUrl = await getConfig({ fs, dir, path: "remote.origin.url" });
|
|
25
|
+
if (!remoteUrl)
|
|
26
|
+
throw new Error(
|
|
27
|
+
"No remote 'origin' configured. Set up a GitHub remote first.",
|
|
28
|
+
);
|
|
29
|
+
return parseRemoteUrl(remoteUrl);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function createPR(
|
|
33
|
+
title: string,
|
|
34
|
+
body: string,
|
|
35
|
+
head: string,
|
|
36
|
+
base: string = "main",
|
|
37
|
+
): Promise<{ number: number; url: string }> {
|
|
38
|
+
const octokit = await createClient();
|
|
39
|
+
const { owner, repo } = await getRepoInfo();
|
|
40
|
+
const { data } = await octokit.pulls.create({
|
|
41
|
+
owner,
|
|
42
|
+
repo,
|
|
43
|
+
title,
|
|
44
|
+
body,
|
|
45
|
+
head,
|
|
46
|
+
base,
|
|
47
|
+
});
|
|
48
|
+
return { number: data.number, url: data.html_url };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function listPRs(
|
|
52
|
+
state: "open" | "closed" | "all" = "open",
|
|
53
|
+
): Promise<
|
|
54
|
+
{
|
|
55
|
+
number: number;
|
|
56
|
+
title: string;
|
|
57
|
+
state: string;
|
|
58
|
+
url: string;
|
|
59
|
+
author: string;
|
|
60
|
+
}[]
|
|
61
|
+
> {
|
|
62
|
+
const octokit = await createClient();
|
|
63
|
+
const { owner, repo } = await getRepoInfo();
|
|
64
|
+
const { data } = await octokit.pulls.list({
|
|
65
|
+
owner,
|
|
66
|
+
repo,
|
|
67
|
+
state,
|
|
68
|
+
per_page: 20,
|
|
69
|
+
});
|
|
70
|
+
return data.map((pr) => ({
|
|
71
|
+
number: pr.number,
|
|
72
|
+
title: pr.title,
|
|
73
|
+
state: pr.state,
|
|
74
|
+
url: pr.html_url,
|
|
75
|
+
author: pr.user?.login || "",
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function createIssue(
|
|
80
|
+
title: string,
|
|
81
|
+
body: string,
|
|
82
|
+
labels: string[] = [],
|
|
83
|
+
): Promise<{ number: number; url: string }> {
|
|
84
|
+
const octokit = await createClient();
|
|
85
|
+
const { owner, repo } = await getRepoInfo();
|
|
86
|
+
const { data } = await octokit.issues.create({
|
|
87
|
+
owner,
|
|
88
|
+
repo,
|
|
89
|
+
title,
|
|
90
|
+
body,
|
|
91
|
+
labels,
|
|
92
|
+
});
|
|
93
|
+
return { number: data.number, url: data.html_url };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function listIssues(
|
|
97
|
+
state: "open" | "closed" | "all" = "open",
|
|
98
|
+
): Promise<
|
|
99
|
+
{
|
|
100
|
+
number: number;
|
|
101
|
+
title: string;
|
|
102
|
+
state: string;
|
|
103
|
+
url: string;
|
|
104
|
+
author: string;
|
|
105
|
+
}[]
|
|
106
|
+
> {
|
|
107
|
+
const octokit = await createClient();
|
|
108
|
+
const { owner, repo } = await getRepoInfo();
|
|
109
|
+
const { data } = await octokit.issues.list({
|
|
110
|
+
owner,
|
|
111
|
+
repo,
|
|
112
|
+
state,
|
|
113
|
+
per_page: 20,
|
|
114
|
+
});
|
|
115
|
+
return data.map((issue) => ({
|
|
116
|
+
number: issue.number,
|
|
117
|
+
title: issue.title,
|
|
118
|
+
state: issue.state,
|
|
119
|
+
url: issue.html_url,
|
|
120
|
+
author: issue.user?.login || "",
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function createRelease(
|
|
125
|
+
tag: string,
|
|
126
|
+
name: string,
|
|
127
|
+
body: string,
|
|
128
|
+
): Promise<{ url: string }> {
|
|
129
|
+
const octokit = await createClient();
|
|
130
|
+
const { owner, repo } = await getRepoInfo();
|
|
131
|
+
const { data } = await octokit.repos.createRelease({
|
|
132
|
+
owner,
|
|
133
|
+
repo,
|
|
134
|
+
tag_name: tag,
|
|
135
|
+
name,
|
|
136
|
+
body,
|
|
137
|
+
});
|
|
138
|
+
return { url: data.html_url };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface AccountInfo {
|
|
142
|
+
login: string;
|
|
143
|
+
name: string | null;
|
|
144
|
+
email: string | null;
|
|
145
|
+
avatarUrl: string;
|
|
146
|
+
profileUrl: string;
|
|
147
|
+
publicRepos: number;
|
|
148
|
+
publicGists: number;
|
|
149
|
+
followers: number;
|
|
150
|
+
following: number;
|
|
151
|
+
createdAt: string;
|
|
152
|
+
plan: string | null;
|
|
153
|
+
bio: string | null;
|
|
154
|
+
company: string | null;
|
|
155
|
+
location: string | null;
|
|
156
|
+
twitter: string | null;
|
|
157
|
+
blog: string | null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export async function getAccountInfo(): Promise<AccountInfo> {
|
|
161
|
+
const octokit = await createClient();
|
|
162
|
+
const { data } = await octokit.users.getAuthenticated();
|
|
163
|
+
return {
|
|
164
|
+
login: data.login,
|
|
165
|
+
name: data.name ?? null,
|
|
166
|
+
email: data.email ?? null,
|
|
167
|
+
avatarUrl: data.avatar_url,
|
|
168
|
+
profileUrl: data.html_url,
|
|
169
|
+
publicRepos: data.public_repos,
|
|
170
|
+
publicGists: data.public_gists,
|
|
171
|
+
followers: data.followers,
|
|
172
|
+
following: data.following,
|
|
173
|
+
createdAt: data.created_at,
|
|
174
|
+
plan: data.plan?.name ?? null,
|
|
175
|
+
bio: data.bio ?? null,
|
|
176
|
+
company: data.company ?? null,
|
|
177
|
+
location: data.location ?? null,
|
|
178
|
+
twitter: data.twitter_username ?? null,
|
|
179
|
+
blog: data.blog ?? null,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export async function getCIStatus(): Promise<
|
|
184
|
+
{ branch: string; name: string; conclusion: string; url: string }[]
|
|
185
|
+
> {
|
|
186
|
+
const octokit = await createClient();
|
|
187
|
+
const { owner, repo } = await getRepoInfo();
|
|
188
|
+
const dir = process.cwd();
|
|
189
|
+
const branch = (await currentBranch({ fs, dir })) || "HEAD";
|
|
190
|
+
const { data } = await octokit.checks.listForRef({
|
|
191
|
+
owner,
|
|
192
|
+
repo,
|
|
193
|
+
ref: branch,
|
|
194
|
+
per_page: 10,
|
|
195
|
+
});
|
|
196
|
+
return data.check_runs.map((run) => ({
|
|
197
|
+
branch,
|
|
198
|
+
name: run.name,
|
|
199
|
+
conclusion: run.conclusion || "pending",
|
|
200
|
+
url: run.html_url,
|
|
201
|
+
}));
|
|
202
|
+
}
|
package/src/lib/logger.ts
CHANGED
|
@@ -1,31 +1,18 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import { colors } from "../constants/colors.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function highlight(msg: string): void {
|
|
22
|
-
console.log(chalk.hex(colors.highlight)(`${icons.highlight} ${msg}`));
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function text(msg: string): void {
|
|
26
|
-
console.log(msg);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function newline(): void {
|
|
30
|
-
console.log();
|
|
31
|
-
}
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { colors } from "../constants/colors.js";
|
|
3
|
+
|
|
4
|
+
export function error(msg: string): void {
|
|
5
|
+
console.error(chalk.hex(colors.error)(msg));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function warning(msg: string): void {
|
|
9
|
+
console.warn(chalk.hex(colors.warning)(`warning: ${msg}`));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function text(msg: string): void {
|
|
13
|
+
console.log(msg);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function newline(): void {
|
|
17
|
+
console.log();
|
|
18
|
+
}
|
package/src/lib/ui.ts
CHANGED
|
@@ -1,156 +1,122 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
function
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
return value;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export async function password(
|
|
129
|
-
message: string,
|
|
130
|
-
mask: string = "*",
|
|
131
|
-
): Promise<string> {
|
|
132
|
-
const { value } = await prompt([
|
|
133
|
-
{
|
|
134
|
-
type: "password",
|
|
135
|
-
name: "value",
|
|
136
|
-
message,
|
|
137
|
-
mask,
|
|
138
|
-
},
|
|
139
|
-
]);
|
|
140
|
-
return value;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export async function checkbox(
|
|
144
|
-
message: string,
|
|
145
|
-
choices: { name: string; value: string; checked?: boolean }[],
|
|
146
|
-
): Promise<string[]> {
|
|
147
|
-
const { value } = await prompt([
|
|
148
|
-
{
|
|
149
|
-
type: "checkbox",
|
|
150
|
-
name: "value",
|
|
151
|
-
message,
|
|
152
|
-
choices,
|
|
153
|
-
},
|
|
154
|
-
]);
|
|
155
|
-
return value;
|
|
156
|
-
}
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
|
|
4
|
+
const { prompt } = inquirer;
|
|
5
|
+
|
|
6
|
+
function stripAnsi(str: string): string {
|
|
7
|
+
return str.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function padEnd(str: string, len: number): string {
|
|
11
|
+
const visibleLen = stripAnsi(str).length;
|
|
12
|
+
const diff = len - visibleLen;
|
|
13
|
+
return diff > 0 ? str + " ".repeat(diff) : str;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function createTable(headers: string[], rows: string[][]): string {
|
|
17
|
+
const colWidths: number[] = headers.map((h, i) => {
|
|
18
|
+
const maxRow = Math.max(...rows.map((r) => stripAnsi(r[i] || "").length));
|
|
19
|
+
return Math.max(stripAnsi(h).length, maxRow);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const headerRow = headers.map((h, i) => padEnd(h, colWidths[i])).join(" ");
|
|
23
|
+
const dataRows = rows.map((row) =>
|
|
24
|
+
row.map((cell, i) => padEnd(cell, colWidths[i])).join(" "),
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
return [headerRow, ...dataRows].join("\n");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function withSpinner<T>(
|
|
31
|
+
text: string,
|
|
32
|
+
fn: () => Promise<T>,
|
|
33
|
+
): Promise<T> {
|
|
34
|
+
const spinner = ora({
|
|
35
|
+
text,
|
|
36
|
+
color: "cyan",
|
|
37
|
+
}).start();
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const result = await fn();
|
|
41
|
+
spinner.succeed();
|
|
42
|
+
return result;
|
|
43
|
+
} catch (err) {
|
|
44
|
+
spinner.fail();
|
|
45
|
+
throw err;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function confirm(
|
|
50
|
+
msg: string,
|
|
51
|
+
defaultValue: boolean = true,
|
|
52
|
+
): Promise<boolean> {
|
|
53
|
+
const { value } = await prompt([
|
|
54
|
+
{
|
|
55
|
+
type: "confirm",
|
|
56
|
+
name: "value",
|
|
57
|
+
message: msg,
|
|
58
|
+
default: defaultValue,
|
|
59
|
+
},
|
|
60
|
+
]);
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function select<T>(
|
|
65
|
+
message: string,
|
|
66
|
+
choices: { name: string; value: T }[],
|
|
67
|
+
): Promise<T> {
|
|
68
|
+
const { value } = await prompt([
|
|
69
|
+
{
|
|
70
|
+
type: "list",
|
|
71
|
+
name: "value",
|
|
72
|
+
message,
|
|
73
|
+
choices,
|
|
74
|
+
},
|
|
75
|
+
]);
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function input(
|
|
80
|
+
message: string,
|
|
81
|
+
defaultValue?: string,
|
|
82
|
+
): Promise<string> {
|
|
83
|
+
const { value } = await prompt([
|
|
84
|
+
{
|
|
85
|
+
type: "input",
|
|
86
|
+
name: "value",
|
|
87
|
+
message,
|
|
88
|
+
default: defaultValue,
|
|
89
|
+
},
|
|
90
|
+
]);
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export async function password(
|
|
95
|
+
message: string,
|
|
96
|
+
mask: string = "*",
|
|
97
|
+
): Promise<string> {
|
|
98
|
+
const { value } = await prompt([
|
|
99
|
+
{
|
|
100
|
+
type: "password",
|
|
101
|
+
name: "value",
|
|
102
|
+
message,
|
|
103
|
+
mask,
|
|
104
|
+
},
|
|
105
|
+
]);
|
|
106
|
+
return value;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export async function checkbox(
|
|
110
|
+
message: string,
|
|
111
|
+
choices: { name: string; value: string; checked?: boolean }[],
|
|
112
|
+
): Promise<string[]> {
|
|
113
|
+
const { value } = await prompt([
|
|
114
|
+
{
|
|
115
|
+
type: "checkbox",
|
|
116
|
+
name: "value",
|
|
117
|
+
message,
|
|
118
|
+
choices,
|
|
119
|
+
},
|
|
120
|
+
]);
|
|
121
|
+
return value;
|
|
122
|
+
}
|
package/src/lib/validators.ts
CHANGED
|
@@ -1,27 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return true;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export async function validateGitInstalled(): Promise<boolean> {
|
|
21
|
-
try {
|
|
22
|
-
execSync("git --version", { stdio: "ignore" });
|
|
23
|
-
return true;
|
|
24
|
-
} catch {
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
1
|
+
export function validateEmail(email: string): boolean {
|
|
2
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
3
|
+
return emailRegex.test(email);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function validateGitHubToken(token: string): boolean {
|
|
7
|
+
const tokenRegex = /^(ghp_|gho_|ghu_|ghs_|ghr_|github_pat_)[a-zA-Z0-9]{4,}$/;
|
|
8
|
+
return tokenRegex.test(token);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function validateNotEmpty(input: string): boolean | string {
|
|
12
|
+
if (input.length === 0) {
|
|
13
|
+
return "Value cannot be empty";
|
|
14
|
+
}
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
[
|
|
2
|
-
{ "value": "feat", "description": "A new feature" },
|
|
3
|
-
{ "value": "fix", "description": "A bug fix" },
|
|
4
|
-
{ "value": "docs", "description": "Documentation only changes" },
|
|
5
|
-
{ "value": "style", "description": "Code style changes (formatting, etc)" },
|
|
6
|
-
{ "value": "refactor", "description": "Code refactoring" },
|
|
7
|
-
{ "value": "test", "description": "Adding or fixing tests" },
|
|
8
|
-
{ "value": "chore", "description": "Build process or tool changes" }
|
|
9
|
-
]
|
|
1
|
+
[
|
|
2
|
+
{ "value": "feat", "description": "A new feature" },
|
|
3
|
+
{ "value": "fix", "description": "A bug fix" },
|
|
4
|
+
{ "value": "docs", "description": "Documentation only changes" },
|
|
5
|
+
{ "value": "style", "description": "Code style changes (formatting, etc)" },
|
|
6
|
+
{ "value": "refactor", "description": "Code refactoring" },
|
|
7
|
+
{ "value": "test", "description": "Adding or fixing tests" },
|
|
8
|
+
{ "value": "chore", "description": "Build process or tool changes" }
|
|
9
|
+
]
|
package/src/utils/files.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
-
import { dirname } from "node:path";
|
|
4
|
-
|
|
5
|
-
export async function ensureDir(dirPath: string): Promise<void> {
|
|
6
|
-
if (!existsSync(dirPath)) {
|
|
7
|
-
await mkdir(dirPath, { recursive: true });
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export async function readJSON(path: string): Promise<any> {
|
|
12
|
-
const content = await readFile(path, "utf-8");
|
|
13
|
-
return JSON.parse(content);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export async function writeJSON(path: string, data: any): Promise<void> {
|
|
17
|
-
const directory = dirname(path);
|
|
18
|
-
await ensureDir(directory);
|
|
19
|
-
const content = JSON.stringify(data, null, 2);
|
|
20
|
-
await writeFile(path, content, "utf-8");
|
|
21
|
-
}
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
|
|
5
|
+
export async function ensureDir(dirPath: string): Promise<void> {
|
|
6
|
+
if (!existsSync(dirPath)) {
|
|
7
|
+
await mkdir(dirPath, { recursive: true });
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function readJSON(path: string): Promise<any> {
|
|
12
|
+
const content = await readFile(path, "utf-8");
|
|
13
|
+
return JSON.parse(content);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function writeJSON(path: string, data: any): Promise<void> {
|
|
17
|
+
const directory = dirname(path);
|
|
18
|
+
await ensureDir(directory);
|
|
19
|
+
const content = JSON.stringify(data, null, 2);
|
|
20
|
+
await writeFile(path, content, "utf-8");
|
|
21
|
+
}
|
package/src/utils/strings.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
export function capitalize(str: string): string {
|
|
2
|
-
if (str.length === 0) return str;
|
|
3
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export function truncate(str: string, maxLength: number): string {
|
|
7
|
-
if (str.length <= maxLength) return str;
|
|
8
|
-
return `${str.slice(0, maxLength - 3)}...`;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function formatTimestamp(date: Date): string {
|
|
12
|
-
const year = date.getFullYear();
|
|
13
|
-
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
14
|
-
const day = String(date.getDate()).padStart(2, "0");
|
|
15
|
-
const hours = String(date.getHours()).padStart(2, "0");
|
|
16
|
-
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
17
|
-
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
18
|
-
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
19
|
-
}
|
|
1
|
+
export function capitalize(str: string): string {
|
|
2
|
+
if (str.length === 0) return str;
|
|
3
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function truncate(str: string, maxLength: number): string {
|
|
7
|
+
if (str.length <= maxLength) return str;
|
|
8
|
+
return `${str.slice(0, maxLength - 3)}...`;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function formatTimestamp(date: Date): string {
|
|
12
|
+
const year = date.getFullYear();
|
|
13
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
14
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
15
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
16
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
17
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
18
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
19
|
+
}
|
package/src/version.const.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated by build script. DO NOT EDIT.
|
|
2
|
-
export const VERSION = "0.1.
|
|
2
|
+
export const VERSION = "0.1.4";
|