better-commits 1.19.0 → 1.20.0-cli-flags
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/.better-commits.json +4 -0
- package/.github/workflows/test.yml +27 -0
- package/.opencode/package-lock.json +115 -0
- package/.opencode/plans/cli-args.md +182 -0
- package/.svelte-kit/ambient.d.ts +289 -0
- package/.svelte-kit/generated/client/app.js +28 -0
- package/.svelte-kit/generated/client/matchers.js +1 -0
- package/.svelte-kit/generated/client/nodes/0.js +1 -0
- package/.svelte-kit/generated/client/nodes/1.js +1 -0
- package/.svelte-kit/tsconfig.json +49 -0
- package/0001-feat-branch-124-update-worktrees-feature.patch +316 -0
- package/dist/branch.js +27 -1
- package/dist/chunk-OFJCRS3N.js +4 -0
- package/dist/chunk-SIF4LZUS.js +1 -0
- package/dist/index.js +44 -19
- package/dist/init.js +1 -1
- package/docs/ai-skills.yaml +48 -0
- package/docs/clack.md +143 -0
- package/docs/valibot.md +228 -0
- package/package.json +12 -9
- package/readme.md +18 -2
- package/src/args.test.ts +102 -0
- package/src/args.ts +101 -7
- package/src/branch-args.test.ts +72 -0
- package/src/branch-args.ts +106 -0
- package/src/branch-help.ts +114 -0
- package/src/branch.ts +67 -238
- package/src/help.ts +131 -0
- package/src/index.test.ts +7 -0
- package/src/index.ts +73 -492
- package/src/prompts/branch-checkout.prompt.ts +36 -0
- package/src/prompts/branch-confirm.prompt.ts +134 -0
- package/src/prompts/branch-description.prompt.ts +37 -0
- package/src/prompts/branch-runnable.ts +13 -0
- package/src/prompts/branch-ticket.prompt.ts +41 -0
- package/src/prompts/branch-type.prompt.ts +43 -0
- package/src/prompts/branch-user.prompt.ts +50 -0
- package/src/prompts/branch-version.prompt.ts +41 -0
- package/src/prompts/commit-body.prompt.ts +57 -0
- package/src/prompts/commit-confirm.prompt.ts +119 -0
- package/src/prompts/commit-footer.prompt.ts +195 -0
- package/src/prompts/commit-scope.prompt.ts +73 -0
- package/src/prompts/commit-status.prompt.ts +75 -0
- package/src/prompts/commit-ticket.prompt.ts +82 -0
- package/src/prompts/commit-title.prompt.ts +98 -0
- package/src/prompts/commit-type.prompt.ts +93 -0
- package/src/prompts/runnable.ts +13 -0
- package/src/utils/build-branch.test.ts +141 -0
- package/src/utils/build-branch.ts +46 -0
- package/src/utils/build-commit-string.test.ts +253 -0
- package/src/utils/build-commit-string.ts +158 -0
- package/src/utils/commit-title-size.ts +24 -0
- package/src/utils/infer.test.ts +83 -0
- package/src/utils/infer.ts +114 -0
- package/src/utils/messages.ts +25 -0
- package/src/utils/no-interactive-branch-validation.test.ts +170 -0
- package/src/utils/no-interactive-validation.test.ts +174 -0
- package/src/utils/no-interactive-validation.ts +190 -0
- package/src/utils.ts +59 -66
- package/src/valibot-consts.ts +2 -2
- package/src/valibot-state.test.ts +48 -0
- package/src/valibot-state.ts +133 -130
- package/tsconfig.json +3 -2
- package/vitest.config.ts +8 -0
- package/dist/chunk-K2RPF2JY.js +0 -4
package/src/utils.ts
CHANGED
|
@@ -3,10 +3,9 @@ import { execSync } from "child_process";
|
|
|
3
3
|
import fs from "fs";
|
|
4
4
|
import { homedir } from "os";
|
|
5
5
|
import color from "picocolors";
|
|
6
|
-
import {
|
|
6
|
+
import { InferOutput, ValiError, parse } from "valibot";
|
|
7
7
|
import { Config } from "./valibot-state";
|
|
8
8
|
import { V_BRANCH_ACTIONS } from "./valibot-consts";
|
|
9
|
-
import { argv } from "process";
|
|
10
9
|
import { flags } from "./args";
|
|
11
10
|
import Configstore from "configstore";
|
|
12
11
|
|
|
@@ -16,19 +15,6 @@ export const A_FOR_ALL = `${color.dim(
|
|
|
16
15
|
"(<space> to select, <a> to select all)",
|
|
17
16
|
)}`;
|
|
18
17
|
export const OPTIONAL_PROMPT = `${color.dim("(optional)")}`;
|
|
19
|
-
export const CACHE_PROMPT = `${color.dim("(value will be saved)")}`;
|
|
20
|
-
export const REGEX_SLASH_TAG = new RegExp(/\/(\w+-\d+)/);
|
|
21
|
-
export const REGEX_START_TAG = new RegExp(/^(\w+-\d+)/);
|
|
22
|
-
export const REGEX_START_UND = new RegExp(/^([A-Z]+-[\[a-zA-Z\]\d]+)_/);
|
|
23
|
-
export const REGEX_SLASH_UND = new RegExp(/\/([A-Z]+-[\[a-zA-Z\]\d]+)_/);
|
|
24
|
-
|
|
25
|
-
// TODO: This might conflict with version from better-branch
|
|
26
|
-
// - Maybe negative lookup against .
|
|
27
|
-
// - Maybe check the order
|
|
28
|
-
// - Maybe use order to split and check values
|
|
29
|
-
export const REGEX_SLASH_NUM = new RegExp(/\/(\d+)/);
|
|
30
|
-
export const REGEX_START_NUM = new RegExp(/^(\d+)/);
|
|
31
|
-
|
|
32
18
|
export const COMMIT_FOOTER_OPTIONS = [
|
|
33
19
|
{
|
|
34
20
|
value: "closes",
|
|
@@ -49,7 +35,7 @@ export const COMMIT_FOOTER_OPTIONS = [
|
|
|
49
35
|
{ value: "custom", label: "custom", hint: "Add a custom footer" },
|
|
50
36
|
];
|
|
51
37
|
export const BRANCH_ACTION_OPTIONS: {
|
|
52
|
-
value:
|
|
38
|
+
value: InferOutput<typeof V_BRANCH_ACTIONS>;
|
|
53
39
|
label: string;
|
|
54
40
|
hint?: string;
|
|
55
41
|
}[] = [
|
|
@@ -63,47 +49,64 @@ export const NOOP_PROMPT_CACHE = {
|
|
|
63
49
|
clear: () => {},
|
|
64
50
|
} as unknown as Configstore;
|
|
65
51
|
|
|
52
|
+
export type ConfigSource = "repository" | "global" | "none";
|
|
53
|
+
|
|
54
|
+
export type LoadedSetup = {
|
|
55
|
+
config: InferOutput<typeof Config>;
|
|
56
|
+
config_source: ConfigSource;
|
|
57
|
+
};
|
|
58
|
+
|
|
66
59
|
/* LOAD */
|
|
67
60
|
export function load_setup(
|
|
68
61
|
cli_name = " better-commits ",
|
|
69
|
-
|
|
62
|
+
git_args = flags.git_args,
|
|
63
|
+
): LoadedSetup {
|
|
70
64
|
console.clear();
|
|
71
65
|
p.intro(`${color.bgCyan(color.black(cli_name))}`);
|
|
72
66
|
|
|
73
|
-
set_non_configuration_arguments();
|
|
74
|
-
|
|
75
67
|
let global_config = null;
|
|
76
68
|
const home_path = get_default_config_path();
|
|
77
69
|
if (fs.existsSync(home_path)) {
|
|
78
|
-
p.log.step("Found global config");
|
|
79
70
|
global_config = read_config_from_path(home_path);
|
|
80
71
|
}
|
|
81
72
|
|
|
82
|
-
const root = get_git_root();
|
|
73
|
+
const root = get_git_root(git_args);
|
|
83
74
|
const root_path = `${root}/${CONFIG_FILE_NAME}`;
|
|
84
75
|
if (fs.existsSync(root_path)) {
|
|
85
|
-
p.log.step("
|
|
76
|
+
p.log.step("Reading from Repository Config");
|
|
86
77
|
const repo_config = read_config_from_path(root_path);
|
|
87
|
-
return
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
78
|
+
return {
|
|
79
|
+
config: global_config
|
|
80
|
+
? {
|
|
81
|
+
...repo_config,
|
|
82
|
+
overrides: global_config.overrides.shell
|
|
83
|
+
? global_config.overrides
|
|
84
|
+
: repo_config.overrides,
|
|
85
|
+
confirm_with_editor: global_config.confirm_with_editor,
|
|
86
|
+
cache_last_value: global_config.cache_last_value,
|
|
87
|
+
}
|
|
88
|
+
: repo_config,
|
|
89
|
+
config_source: "repository",
|
|
90
|
+
};
|
|
97
91
|
}
|
|
98
92
|
|
|
99
|
-
if (global_config)
|
|
93
|
+
if (global_config) {
|
|
94
|
+
p.log.step("Reading from Global Config");
|
|
95
|
+
return {
|
|
96
|
+
config: global_config,
|
|
97
|
+
config_source: "global",
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
100
|
|
|
101
101
|
const default_config = parse(Config, {});
|
|
102
102
|
p.log.step(
|
|
103
103
|
"Config not found. Generating default .better-commit.json at $HOME",
|
|
104
104
|
);
|
|
105
105
|
fs.writeFileSync(home_path, JSON.stringify(default_config, null, 4));
|
|
106
|
-
return
|
|
106
|
+
return {
|
|
107
|
+
config: default_config,
|
|
108
|
+
config_source: "none",
|
|
109
|
+
};
|
|
107
110
|
}
|
|
108
111
|
|
|
109
112
|
function read_config_from_path(config_path: string) {
|
|
@@ -118,13 +121,19 @@ function read_config_from_path(config_path: string) {
|
|
|
118
121
|
return validate_config(res);
|
|
119
122
|
}
|
|
120
123
|
|
|
121
|
-
function validate_config(config:
|
|
124
|
+
function validate_config(config: unknown): InferOutput<typeof Config> {
|
|
122
125
|
try {
|
|
123
126
|
return parse(Config, config);
|
|
124
127
|
} catch (err: any) {
|
|
125
128
|
if (err instanceof ValiError) {
|
|
126
129
|
const first_issue_path = err.issues[0].path ?? [];
|
|
127
|
-
const dot_path = first_issue_path
|
|
130
|
+
const dot_path = first_issue_path
|
|
131
|
+
.map((item: { key?: unknown }) => item.key)
|
|
132
|
+
.filter(
|
|
133
|
+
(key: unknown): key is string | number =>
|
|
134
|
+
typeof key === "string" || typeof key === "number",
|
|
135
|
+
)
|
|
136
|
+
.join(".");
|
|
128
137
|
p.log.error(
|
|
129
138
|
`Invalid Configuration: ${color.red(dot_path)}\n` + err.message,
|
|
130
139
|
);
|
|
@@ -134,37 +143,13 @@ function validate_config(config: Output<typeof Config>): Output<typeof Config> {
|
|
|
134
143
|
}
|
|
135
144
|
/* END LOAD */
|
|
136
145
|
|
|
137
|
-
export function infer_type_from_branch(types: string[]): string {
|
|
138
|
-
let branch = "";
|
|
139
|
-
try {
|
|
140
|
-
branch = execSync(`git ${flags.git_args} branch --show-current`, {
|
|
141
|
-
stdio: "pipe",
|
|
142
|
-
}).toString();
|
|
143
|
-
} catch (err) {
|
|
144
|
-
return "";
|
|
145
|
-
}
|
|
146
|
-
const found = types.find((t) => {
|
|
147
|
-
const start_dash = new RegExp(`^${t}-`);
|
|
148
|
-
const between_dash = new RegExp(`-${t}-`);
|
|
149
|
-
const before_slash = new RegExp(`${t}\/`);
|
|
150
|
-
const re = [
|
|
151
|
-
branch.match(start_dash),
|
|
152
|
-
branch.match(between_dash),
|
|
153
|
-
branch.match(before_slash),
|
|
154
|
-
].filter((v) => v != null);
|
|
155
|
-
return re?.length;
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
return found ?? "";
|
|
159
|
-
}
|
|
160
|
-
|
|
161
146
|
/*
|
|
162
147
|
rev-parse will fail in a --bare repository root
|
|
163
148
|
*/
|
|
164
|
-
export function get_git_root(): string {
|
|
149
|
+
export function get_git_root(git_args = flags.git_args): string {
|
|
165
150
|
let path = ".";
|
|
166
151
|
try {
|
|
167
|
-
path = execSync(`git ${
|
|
152
|
+
path = execSync(`git ${git_args} rev-parse --show-toplevel`)
|
|
168
153
|
.toString()
|
|
169
154
|
.trim();
|
|
170
155
|
} catch (err) {
|
|
@@ -179,6 +164,18 @@ export function get_default_config_path(): string {
|
|
|
179
164
|
return homedir() + "/" + CONFIG_FILE_NAME;
|
|
180
165
|
}
|
|
181
166
|
|
|
167
|
+
export function get_package_version(): string {
|
|
168
|
+
try {
|
|
169
|
+
const package_json = JSON.parse(
|
|
170
|
+
fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"),
|
|
171
|
+
) as { version?: string };
|
|
172
|
+
|
|
173
|
+
return package_json.version ?? "unknown";
|
|
174
|
+
} catch {
|
|
175
|
+
return "unknown";
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
182
179
|
export function addNewLine(arr: string[], i: number) {
|
|
183
180
|
return i === arr.length - 1 ? "" : "\n";
|
|
184
181
|
}
|
|
@@ -192,10 +189,6 @@ export function clean_commit_title(title: string): string {
|
|
|
192
189
|
return title.trim();
|
|
193
190
|
}
|
|
194
191
|
|
|
195
|
-
function set_non_configuration_arguments() {
|
|
196
|
-
flags.git_args = `${argv[2] ?? ""} ${argv[3] ?? ""}`.trim();
|
|
197
|
-
}
|
|
198
|
-
|
|
199
192
|
export function get_value_from_cache(
|
|
200
193
|
config_store: Configstore,
|
|
201
194
|
key: string,
|
package/src/valibot-consts.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as v from "valibot";
|
|
2
2
|
|
|
3
3
|
export const CUSTOM_SCOPE_KEY: "custom" = "custom";
|
|
4
|
-
export const FOOTER_OPTION_VALUES: v.
|
|
4
|
+
export const FOOTER_OPTION_VALUES: v.InferOutput<typeof V_FOOTER_OPTIONS>[] = [
|
|
5
5
|
"closes",
|
|
6
6
|
"trailer",
|
|
7
7
|
"breaking-change",
|
|
@@ -30,7 +30,7 @@ export const V_BRANCH_CONFIG_FIELDS = v.picklist([
|
|
|
30
30
|
"branch_ticket",
|
|
31
31
|
"branch_description",
|
|
32
32
|
]);
|
|
33
|
-
export const BRANCH_ORDER_DEFAULTS: v.
|
|
33
|
+
export const BRANCH_ORDER_DEFAULTS: v.InferOutput<typeof V_BRANCH_FIELDS>[] = [
|
|
34
34
|
"user",
|
|
35
35
|
"version",
|
|
36
36
|
"type",
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { ValiError, parse } from "valibot";
|
|
3
|
+
import { Config } from "./valibot-state";
|
|
4
|
+
|
|
5
|
+
describe("Config", () => {
|
|
6
|
+
it("parses a defaulted config from empty input", () => {
|
|
7
|
+
const config = parse(Config, {});
|
|
8
|
+
|
|
9
|
+
expect(config.commit_type.initial_value).toBe("feat");
|
|
10
|
+
expect(config.commit_scope.initial_value).toBe("app");
|
|
11
|
+
expect(config.commit_type.options.length).toBeGreaterThan(0);
|
|
12
|
+
expect(config.commit_scope.options.length).toBeGreaterThan(0);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("adds the custom scope option when custom_scope is enabled", () => {
|
|
16
|
+
const config = parse(Config, {
|
|
17
|
+
commit_scope: {
|
|
18
|
+
custom_scope: true,
|
|
19
|
+
initial_value: "custom",
|
|
20
|
+
options: [{ value: "app", label: "app" }],
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
expect(config.commit_scope.options.map((option) => option.value)).toContain(
|
|
25
|
+
"custom",
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("rejects commit_type.initial_value values outside options", () => {
|
|
30
|
+
expect(() =>
|
|
31
|
+
parse(Config, {
|
|
32
|
+
commit_type: {
|
|
33
|
+
initial_value: "unknown",
|
|
34
|
+
options: [{ value: "feat", label: "feat" }],
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
37
|
+
).toThrowError(ValiError);
|
|
38
|
+
|
|
39
|
+
expect(() =>
|
|
40
|
+
parse(Config, {
|
|
41
|
+
commit_type: {
|
|
42
|
+
initial_value: "unknown",
|
|
43
|
+
options: [{ value: "feat", label: "feat" }],
|
|
44
|
+
},
|
|
45
|
+
}),
|
|
46
|
+
).toThrow(/must exist in options/);
|
|
47
|
+
});
|
|
48
|
+
});
|
package/src/valibot-state.ts
CHANGED
|
@@ -10,113 +10,114 @@ import {
|
|
|
10
10
|
V_FOOTER_OPTIONS,
|
|
11
11
|
} from "./valibot-consts";
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
v.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
v.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}),
|
|
38
|
-
),
|
|
39
|
-
DEFAULT_TYPE_OPTIONS,
|
|
40
|
-
),
|
|
41
|
-
},
|
|
42
|
-
[
|
|
43
|
-
v.custom(
|
|
44
|
-
(val) =>
|
|
45
|
-
val.options.map((v) => v.value).includes(val.initial_value),
|
|
46
|
-
(val) => {
|
|
47
|
-
const input = val.input as { initial_value: string };
|
|
48
|
-
return `Type: initial_value "${input.initial_value}" must exist in options`;
|
|
49
|
-
},
|
|
50
|
-
),
|
|
51
|
-
],
|
|
13
|
+
const CommitTypeConfig = v.pipe(
|
|
14
|
+
v.optional(
|
|
15
|
+
v.object({
|
|
16
|
+
enable: v.optional(v.boolean(), true),
|
|
17
|
+
initial_value: v.optional(v.string(), "feat"),
|
|
18
|
+
max_items: v.optional(v.pipe(v.number(), v.minValue(1)), 20),
|
|
19
|
+
infer_type_from_branch: v.optional(v.boolean(), true),
|
|
20
|
+
append_emoji_to_label: v.optional(v.boolean(), false),
|
|
21
|
+
append_emoji_to_commit: v.optional(v.boolean(), false),
|
|
22
|
+
emoji_commit_position: v.optional(
|
|
23
|
+
v.picklist(["Start", "After-Colon"]),
|
|
24
|
+
"Start",
|
|
25
|
+
),
|
|
26
|
+
options: v.optional(
|
|
27
|
+
v.array(
|
|
28
|
+
v.object({
|
|
29
|
+
value: v.string(),
|
|
30
|
+
label: v.optional(v.string()),
|
|
31
|
+
hint: v.optional(v.string()),
|
|
32
|
+
emoji: v.optional(v.pipe(v.string(), v.emoji())),
|
|
33
|
+
trailer: v.optional(v.string()),
|
|
34
|
+
}),
|
|
35
|
+
),
|
|
36
|
+
DEFAULT_TYPE_OPTIONS,
|
|
52
37
|
),
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
(val) => {
|
|
56
|
-
const options =
|
|
57
|
-
val.options.map((v) => ({
|
|
58
|
-
...v,
|
|
59
|
-
label:
|
|
60
|
-
v.emoji && val.append_emoji_to_label
|
|
61
|
-
? `${v.emoji} ${v.label}`
|
|
62
|
-
: v.label,
|
|
63
|
-
})) ?? [];
|
|
64
|
-
return { ...val, options };
|
|
65
|
-
},
|
|
38
|
+
}),
|
|
39
|
+
{},
|
|
66
40
|
),
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
41
|
+
v.rawCheck(({ dataset, addIssue }) => {
|
|
42
|
+
if (
|
|
43
|
+
dataset.typed &&
|
|
44
|
+
!dataset.value.options.some(
|
|
45
|
+
(option) => option.value === dataset.value.initial_value,
|
|
46
|
+
)
|
|
47
|
+
) {
|
|
48
|
+
addIssue({
|
|
49
|
+
message: `Type: initial_value "${dataset.value.initial_value}" must exist in options`,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}),
|
|
53
|
+
v.transform((value) => ({
|
|
54
|
+
...value,
|
|
55
|
+
options: value.options.map((option) => ({
|
|
56
|
+
...option,
|
|
57
|
+
label:
|
|
58
|
+
option.emoji && value.append_emoji_to_label
|
|
59
|
+
? `${option.emoji} ${option.label}`
|
|
60
|
+
: option.label,
|
|
61
|
+
})),
|
|
62
|
+
})),
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const CommitScopeConfig = v.pipe(
|
|
66
|
+
v.optional(
|
|
67
|
+
v.object({
|
|
68
|
+
enable: v.optional(v.boolean(), true),
|
|
69
|
+
custom_scope: v.optional(v.boolean(), false),
|
|
70
|
+
max_items: v.optional(v.pipe(v.number(), v.minValue(1)), 20),
|
|
71
|
+
initial_value: v.optional(v.string(), "app"),
|
|
72
|
+
options: v.optional(
|
|
73
|
+
v.array(
|
|
74
|
+
v.object({
|
|
75
|
+
value: v.string(),
|
|
76
|
+
label: v.optional(v.string()),
|
|
77
|
+
hint: v.optional(v.string()),
|
|
78
|
+
}),
|
|
79
|
+
),
|
|
80
|
+
DEFAULT_SCOPE_OPTIONS,
|
|
99
81
|
),
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
(val) => {
|
|
103
|
-
const options = val.options.map((v) => v.value);
|
|
104
|
-
if (val.custom_scope && !options.includes(CUSTOM_SCOPE_KEY)) {
|
|
105
|
-
return {
|
|
106
|
-
...val,
|
|
107
|
-
options: [
|
|
108
|
-
...val.options,
|
|
109
|
-
{
|
|
110
|
-
label: CUSTOM_SCOPE_KEY,
|
|
111
|
-
value: CUSTOM_SCOPE_KEY,
|
|
112
|
-
hint: "Write a custom scope",
|
|
113
|
-
},
|
|
114
|
-
],
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
return val;
|
|
118
|
-
},
|
|
82
|
+
}),
|
|
83
|
+
{},
|
|
119
84
|
),
|
|
85
|
+
v.rawCheck(({ dataset, addIssue }) => {
|
|
86
|
+
if (!dataset.typed) return;
|
|
87
|
+
|
|
88
|
+
const option_values = dataset.value.options.map((option) => option.value);
|
|
89
|
+
if (dataset.value.custom_scope) option_values.push(CUSTOM_SCOPE_KEY);
|
|
90
|
+
|
|
91
|
+
if (!option_values.includes(dataset.value.initial_value)) {
|
|
92
|
+
addIssue({
|
|
93
|
+
message: `Scope: initial_value "${dataset.value.initial_value}" must exist in options`,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}),
|
|
97
|
+
v.transform((value) => {
|
|
98
|
+
const option_values = value.options.map((option) => option.value);
|
|
99
|
+
if (value.custom_scope && !option_values.includes(CUSTOM_SCOPE_KEY)) {
|
|
100
|
+
return {
|
|
101
|
+
...value,
|
|
102
|
+
options: [
|
|
103
|
+
...value.options,
|
|
104
|
+
{
|
|
105
|
+
label: CUSTOM_SCOPE_KEY,
|
|
106
|
+
value: CUSTOM_SCOPE_KEY,
|
|
107
|
+
hint: "Write a custom scope",
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return value;
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
export const Config = v.object({
|
|
118
|
+
check_status: v.optional(v.boolean(), true),
|
|
119
|
+
commit_type: CommitTypeConfig,
|
|
120
|
+
commit_scope: CommitScopeConfig,
|
|
120
121
|
check_ticket: v.optional(
|
|
121
122
|
v.object({
|
|
122
123
|
infer_ticket: v.optional(v.boolean(), true),
|
|
@@ -137,7 +138,7 @@ export const Config = v.object({
|
|
|
137
138
|
),
|
|
138
139
|
commit_title: v.optional(
|
|
139
140
|
v.object({
|
|
140
|
-
max_size: v.optional(v.number(
|
|
141
|
+
max_size: v.optional(v.pipe(v.number(), v.minValue(1)), 70),
|
|
141
142
|
}),
|
|
142
143
|
{},
|
|
143
144
|
),
|
|
@@ -204,7 +205,7 @@ export const Config = v.object({
|
|
|
204
205
|
),
|
|
205
206
|
branch_description: v.optional(
|
|
206
207
|
v.object({
|
|
207
|
-
max_length: v.optional(v.number(
|
|
208
|
+
max_length: v.optional(v.pipe(v.number(), v.minValue(1)), 70),
|
|
208
209
|
separator: v.optional(v.picklist(["", "/", "-", "_"]), ""),
|
|
209
210
|
}),
|
|
210
211
|
{},
|
|
@@ -231,32 +232,34 @@ export const Config = v.object({
|
|
|
231
232
|
),
|
|
232
233
|
});
|
|
233
234
|
|
|
234
|
-
export const
|
|
235
|
-
v.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
235
|
+
export const COMMIT_STATE_ENTRIES = {
|
|
236
|
+
type: v.optional(v.string(), ""),
|
|
237
|
+
scope: v.optional(v.string(), ""),
|
|
238
|
+
title: v.optional(v.string(), ""),
|
|
239
|
+
body: v.optional(v.string(), ""),
|
|
240
|
+
closes: v.optional(v.string(), ""),
|
|
241
|
+
ticket: v.optional(v.string(), ""),
|
|
242
|
+
breaking_title: v.optional(v.string(), ""),
|
|
243
|
+
breaking_body: v.optional(v.string(), ""),
|
|
244
|
+
deprecates: v.optional(v.string(), ""),
|
|
245
|
+
deprecates_title: v.optional(v.string(), ""),
|
|
246
|
+
deprecates_body: v.optional(v.string(), ""),
|
|
247
|
+
custom_footer: v.optional(v.string(), ""),
|
|
248
|
+
trailer: v.optional(v.string(), ""),
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
export const CommitState = v.optional(v.object(COMMIT_STATE_ENTRIES), {});
|
|
252
|
+
|
|
253
|
+
export const BRANCH_STATE_ENTRIES = {
|
|
254
|
+
user: v.optional(v.string(), ""),
|
|
255
|
+
type: v.optional(v.string(), ""),
|
|
256
|
+
ticket: v.optional(v.string(), ""),
|
|
257
|
+
description: v.optional(v.string(), ""),
|
|
258
|
+
version: v.optional(v.string(), ""),
|
|
259
|
+
checkout: v.optional(V_BRANCH_ACTIONS, "branch"),
|
|
260
|
+
};
|
|
252
261
|
|
|
253
262
|
export const BranchState = v.optional(
|
|
254
|
-
v.object(
|
|
255
|
-
user: v.optional(v.string(), ""),
|
|
256
|
-
type: v.optional(v.string(), ""),
|
|
257
|
-
ticket: v.optional(v.string(), ""),
|
|
258
|
-
description: v.optional(v.string(), ""),
|
|
259
|
-
version: v.optional(v.string(), ""),
|
|
260
|
-
}),
|
|
263
|
+
v.object(BRANCH_STATE_ENTRIES),
|
|
261
264
|
{},
|
|
262
265
|
);
|
package/tsconfig.json
CHANGED
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
"module": "ESNext",
|
|
4
4
|
"target": "ESNext",
|
|
5
5
|
"declaration": true,
|
|
6
|
-
"moduleResolution": "
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
7
|
"emitDeclarationOnly": true,
|
|
8
8
|
"strict": true,
|
|
9
9
|
"esModuleInterop": true,
|
|
10
10
|
"forceConsistentCasingInFileNames": true,
|
|
11
11
|
"allowJs": true,
|
|
12
12
|
"types": ["node"]
|
|
13
|
-
}
|
|
13
|
+
},
|
|
14
|
+
"exclude": ["dist", "node_modules", ".svelte-kit", ".opencode"]
|
|
14
15
|
}
|
package/vitest.config.ts
ADDED
package/dist/chunk-K2RPF2JY.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import*as p from"valibot";var c="custom",f=["closes","trailer","breaking-change","deprecated","custom"],h=p.picklist(["branch","worktree"]),g=p.picklist(["closes","trailer","breaking-change","deprecated","custom"]),d=p.picklist(["user","version","type","ticket","description"]),$=p.picklist(["branch_user","branch_version","branch_type","branch_ticket","branch_description"]),O=["user","version","type","ticket","description"],x=[{value:"app",label:"app"},{value:"shared",label:"shared"},{value:"server",label:"server"},{value:"tools",label:"tools"},{value:"",label:"none"}],C=[{value:"feat",label:"feat",hint:"A new feature",emoji:"\u{1F31F}",trailer:"Changelog: feature"},{value:"fix",label:"fix",hint:"A bug fix",emoji:"\u{1F41B}",trailer:"Changelog: fix"},{value:"docs",label:"docs",hint:"Documentation only changes",emoji:"\u{1F4DA}",trailer:"Changelog: documentation"},{value:"refactor",label:"refactor",hint:"A code change that neither fixes a bug nor adds a feature",emoji:"\u{1F528}",trailer:"Changelog: refactor"},{value:"perf",label:"perf",hint:"A code change that improves performance",emoji:"\u{1F680}",trailer:"Changelog: performance"},{value:"test",label:"test",hint:"Adding missing tests or correcting existing tests",emoji:"\u{1F6A8}",trailer:"Changelog: test"},{value:"build",label:"build",hint:"Changes that affect the build system or external dependencies",emoji:"\u{1F6A7}",trailer:"Changelog: build"},{value:"ci",label:"ci",hint:"Changes to our CI configuration files and scripts",emoji:"\u{1F916}",trailer:"Changelog: ci"},{value:"chore",label:"chore",hint:"Other changes that do not modify src or test files",emoji:"\u{1F9F9}",trailer:"Changelog: chore"},{value:"",label:"none"}];import*as t from"valibot";var m=t.object({check_status:t.optional(t.boolean(),!0),commit_type:t.transform(t.optional(t.object({enable:t.optional(t.boolean(),!0),initial_value:t.optional(t.string(),"feat"),max_items:t.optional(t.number([t.minValue(1)]),20),infer_type_from_branch:t.optional(t.boolean(),!0),append_emoji_to_label:t.optional(t.boolean(),!1),append_emoji_to_commit:t.optional(t.boolean(),!1),emoji_commit_position:t.optional(t.picklist(["Start","After-Colon"]),"Start"),options:t.optional(t.array(t.object({value:t.string(),label:t.optional(t.string()),hint:t.optional(t.string()),emoji:t.optional(t.string([t.emoji()]),void 0),trailer:t.optional(t.string())})),C)},[t.custom(e=>e.options.map(o=>o.value).includes(e.initial_value),e=>`Type: initial_value "${e.input.initial_value}" must exist in options`)]),{}),e=>{let o=e.options.map(n=>({...n,label:n.emoji&&e.append_emoji_to_label?`${n.emoji} ${n.label}`:n.label}))??[];return{...e,options:o}}),commit_scope:t.transform(t.optional(t.object({enable:t.optional(t.boolean(),!0),custom_scope:t.optional(t.boolean(),!1),max_items:t.optional(t.number([t.minValue(1)]),20),initial_value:t.optional(t.string(),"app"),options:t.optional(t.array(t.object({value:t.string(),label:t.optional(t.string()),hint:t.optional(t.string())})),x)},[t.custom(e=>{let o=e.options.map(n=>n.value);return e.custom_scope&&o.push(c),o.includes(e.initial_value)},e=>`Scope: initial_value "${e.input.initial_value}" must exist in options`)]),{}),e=>{let o=e.options.map(n=>n.value);return e.custom_scope&&!o.includes(c)?{...e,options:[...e.options,{label:c,value:c,hint:"Write a custom scope"}]}:e}),check_ticket:t.optional(t.object({infer_ticket:t.optional(t.boolean(),!0),confirm_ticket:t.optional(t.boolean(),!0),add_to_title:t.optional(t.boolean(),!0),append_hashtag:t.optional(t.boolean(),!1),prepend_hashtag:t.optional(t.picklist(["Never","Always","Prompt"]),"Never"),surround:t.optional(t.picklist(["","()","[]","{}"]),""),title_position:t.optional(t.picklist(["start","end","before-colon","beginning"]),"start")}),{}),commit_title:t.optional(t.object({max_size:t.optional(t.number([t.minValue(1)]),70)}),{}),commit_body:t.optional(t.object({enable:t.optional(t.boolean(),!0),required:t.optional(t.boolean(),!1),split_by_period:t.optional(t.boolean(),!1)}),{}),commit_footer:t.optional(t.object({enable:t.optional(t.boolean(),!0),initial_value:t.optional(t.array(g),[]),options:t.optional(t.array(g),f)}),{}),breaking_change:t.optional(t.object({add_exclamation_to_title:t.optional(t.boolean(),!0)}),{}),cache_last_value:t.optional(t.boolean(),!0),confirm_with_editor:t.optional(t.boolean(),!1),confirm_commit:t.optional(t.boolean(),!0),print_commit_output:t.optional(t.boolean(),!0),branch_pre_commands:t.optional(t.array(t.string()),[]),branch_post_commands:t.optional(t.array(t.string()),[]),worktree_pre_commands:t.optional(t.array(t.string()),[]),worktree_post_commands:t.optional(t.array(t.string()),[]),branch_user:t.optional(t.object({enable:t.optional(t.boolean(),!0),required:t.optional(t.boolean(),!1),separator:t.optional(t.picklist(["/","-","_"]),"/")}),{}),branch_type:t.optional(t.object({enable:t.optional(t.boolean(),!0),separator:t.optional(t.picklist(["/","-","_"]),"/")}),{}),branch_version:t.optional(t.object({enable:t.optional(t.boolean(),!1),required:t.optional(t.boolean(),!1),separator:t.optional(t.picklist(["/","-","_"]),"/")}),{}),branch_ticket:t.optional(t.object({enable:t.optional(t.boolean(),!0),required:t.optional(t.boolean(),!1),separator:t.optional(t.picklist(["/","-","_"]),"-")}),{}),branch_description:t.optional(t.object({max_length:t.optional(t.number([t.minValue(1)]),70),separator:t.optional(t.picklist(["","/","-","_"]),"")}),{}),branch_action_default:t.optional(h,"branch"),branch_order:t.optional(t.array(d),O),enable_worktrees:t.optional(t.boolean(),!0),worktrees:t.optional(t.object({enable:t.optional(t.boolean(),!0),base_path:t.optional(t.string(),".."),folder_template:t.optional(t.string(),"{{repo_name}}-{{ticket}}-{{branch_description}}")}),{}),overrides:t.optional(t.object({shell:t.optional(t.string())}),{})}),H=t.optional(t.object({type:t.optional(t.string(),""),scope:t.optional(t.string(),""),title:t.optional(t.string(),""),body:t.optional(t.string(),""),closes:t.optional(t.string(),""),ticket:t.optional(t.string(),""),breaking_title:t.optional(t.string(),""),breaking_body:t.optional(t.string(),""),deprecates:t.optional(t.string(),""),deprecates_title:t.optional(t.string(),""),deprecates_body:t.optional(t.string(),""),custom_footer:t.optional(t.string(),""),trailer:t.optional(t.string(),"")}),{}),D=t.optional(t.object({user:t.optional(t.string(),""),type:t.optional(t.string(),""),ticket:t.optional(t.string(),""),description:t.optional(t.string(),""),version:t.optional(t.string(),"")}),{});var b=class{#t="";constructor(){}get git_args(){return this.#t}set git_args(o){this.#t=o}},_=new b;import*as i from"@clack/prompts";import{execSync as S}from"child_process";import u from"fs";import{homedir as R}from"os";import a from"picocolors";import{ValiError as N,parse as y}from"valibot";import{argv as E}from"process";var T=".better-commits.json",K=`${a.dim("(<space> to select)")}`,Q=`${a.dim("(<space> to select, <a> to select all)")}`,tt=`${a.dim("(optional)")}`,ot=`${a.dim("(value will be saved)")}`,et=new RegExp(/\/(\w+-\d+)/),nt=new RegExp(/^(\w+-\d+)/),it=new RegExp(/^([A-Z]+-[\[a-zA-Z\]\d]+)_/),rt=new RegExp(/\/([A-Z]+-[\[a-zA-Z\]\d]+)_/),at=new RegExp(/\/(\d+)/),lt=new RegExp(/^(\d+)/),st=[{value:"closes",label:"closes <issue/ticket>",hint:"Attempts to infer ticket from branch"},{value:"trailer",label:"trailer",hint:"Appends trailer based on commit type"},{value:"breaking-change",label:"breaking change",hint:"Add breaking change"},{value:"deprecated",label:"deprecated",hint:"Add deprecated change"},{value:"custom",label:"custom",hint:"Add a custom footer"}],pt=[{value:"branch",label:"Branch"},{value:"worktree",label:"Worktree"}],ct={get:()=>"",set:(e,o)=>{},clear:()=>{}};function vt(e=" better-commits "){console.clear(),i.intro(`${a.bgCyan(a.black(e))}`),P();let o=null,n=I();u.existsSync(n)&&(i.log.step("Found global config"),o=A(n));let l=`${w()}/${T}`;if(u.existsSync(l)){i.log.step("Found repository config");let s=A(l);return o?{...s,overrides:o.overrides.shell?o.overrides:s.overrides,confirm_with_editor:o.confirm_with_editor,cache_last_value:o.cache_last_value}:s}if(o)return o;let v=y(m,{});return i.log.step("Config not found. Generating default .better-commit.json at $HOME"),u.writeFileSync(n,JSON.stringify(v,null,4)),v}function A(e){let o=null;try{o=JSON.parse(u.readFileSync(e,"utf8"))}catch(n){i.log.error(`Invalid JSON file. Exiting.
|
|
2
|
-
`+n),process.exit(0)}return j(o)}function j(e){try{return y(m,e)}catch(o){if(o instanceof N){let r=(o.issues[0].path??[]).map(l=>l.key).join(".");i.log.error(`Invalid Configuration: ${a.red(r)}
|
|
3
|
-
`+o.message)}process.exit(0)}}function _t(e){let o="";try{o=S(`git ${_.git_args} branch --show-current`,{stdio:"pipe"}).toString()}catch{return""}return e.find(r=>{let l=new RegExp(`^${r}-`),v=new RegExp(`-${r}-`),s=new RegExp(`${r}/`);return[o.match(l),o.match(v),o.match(s)].filter(k=>k!=null)?.length})??""}function w(){let e=".";try{e=S(`git ${_.git_args} rev-parse --show-toplevel`).toString().trim()}catch{i.log.warn("Could not find git root. If in a --bare repository, ignore this warning.")}return e}function I(){return R()+"/"+T}function ut(e,o){return o===e.length-1?"":`
|
|
4
|
-
`}function gt(e){let o=e.trim();return o.endsWith(".")?o.substring(0,o.length-1).trim():e.trim()}function P(){_.git_args=`${E[2]??""} ${E[3]??""}`.trim()}function mt(e,o){try{return e.get(o)??""}catch{i.log.warn(`Could not access ${o} from cache. Check that "~/.config" exists. Set "cache_last_value" to false to disable.`)}return""}function bt(e,o,n){try{e.set(o,n)}catch{i.log.warn(`Could not access ${o} from cache. Check that "~/.config" exists. Set "cache_last_value" to false to disable.`)}}export{c as a,m as b,H as c,D as d,_ as e,T as f,K as g,tt as h,ot as i,et as j,nt as k,it as l,rt as m,at as n,lt as o,st as p,pt as q,ct as r,vt as s,_t as t,w as u,ut as v,gt as w,mt as x,bt as y};
|