better-commits 1.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/dist/index.js +405 -0
- package/dist/init.js +137 -0
- package/dist/utils.js +119 -0
- package/dist/zod-state.js +133 -0
- package/package.json +40 -0
- package/readme.md +156 -0
- package/src/index.ts +283 -0
- package/src/init.ts +21 -0
- package/src/utils.ts +59 -0
- package/src/zod-state.ts +67 -0
- package/tsconfig.json +14 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/index.ts
|
|
27
|
+
var p = __toESM(require("@clack/prompts"));
|
|
28
|
+
var import_picocolors2 = __toESM(require("picocolors"));
|
|
29
|
+
var import_simple_git = require("simple-git");
|
|
30
|
+
var import_fs = __toESM(require("fs"));
|
|
31
|
+
var import_child_process = require("child_process");
|
|
32
|
+
var import_zod_validation_error = require("zod-validation-error");
|
|
33
|
+
|
|
34
|
+
// src/zod-state.ts
|
|
35
|
+
var import_zod2 = require("zod");
|
|
36
|
+
|
|
37
|
+
// src/utils.ts
|
|
38
|
+
var import_os = require("os");
|
|
39
|
+
var import_zod = require("zod");
|
|
40
|
+
var import_picocolors = __toESM(require("picocolors"));
|
|
41
|
+
var CONFIG_FILE_NAME = ".better-commits.json";
|
|
42
|
+
var SPACE_TO_SELECT = `${import_picocolors.default.dim("(<space> to select)")}`;
|
|
43
|
+
var OPTIONAL_PROMPT = `${import_picocolors.default.dim("(optional)")}`;
|
|
44
|
+
var REGEX_SLASH_TAG = new RegExp(/\/(\w+-\d+)/);
|
|
45
|
+
var REGEX_START_TAG = new RegExp(/^(\w+-\d+)/);
|
|
46
|
+
var REGEX_SLASH_NUM = new RegExp(/\/(\d+)/);
|
|
47
|
+
var REGEX_START_NUM = new RegExp(/^(\d+)/);
|
|
48
|
+
var DEFAULT_TYPE_OPTIONS = [
|
|
49
|
+
{ value: "feat", label: "feat" },
|
|
50
|
+
{ value: "fix", label: "fix" },
|
|
51
|
+
{ value: "docs", label: "docs" },
|
|
52
|
+
{ value: "refactor", label: "refactor" },
|
|
53
|
+
{ value: "perf", label: "perf" },
|
|
54
|
+
{ value: "test", label: "test" },
|
|
55
|
+
{ value: "", label: "none" }
|
|
56
|
+
];
|
|
57
|
+
var DEFAULT_SCOPE_OPTIONS = [
|
|
58
|
+
{ value: "app", label: "app" },
|
|
59
|
+
{ value: "shared", label: "shared" },
|
|
60
|
+
{ value: "server", label: "server" },
|
|
61
|
+
{ value: "tools", label: "tools" },
|
|
62
|
+
{ value: "", label: "none" }
|
|
63
|
+
];
|
|
64
|
+
var COMMIT_FOOTER_OPTIONS = [
|
|
65
|
+
{ value: "closes", label: "closes <issue/ticket>", hint: "Attempts to infer ticket from branch" },
|
|
66
|
+
{ value: "breaking-change", label: "breaking change", hint: "Add breaking change" },
|
|
67
|
+
{ value: "deprecated", label: "deprecated", hint: "Add deprecated change" }
|
|
68
|
+
];
|
|
69
|
+
var Z_FOOTER_OPTIONS = import_zod.z.enum(["closes", "breaking-change", "deprecated"]);
|
|
70
|
+
var FOOTER_OPTION_VALUES = ["closes", "breaking-change", "deprecated"];
|
|
71
|
+
function get_default_config_path() {
|
|
72
|
+
return (0, import_os.homedir)() + "/" + CONFIG_FILE_NAME;
|
|
73
|
+
}
|
|
74
|
+
function check_missing_stage(stats) {
|
|
75
|
+
return stats.files.filter((f) => f.index.trim() === "" || f.index === "?").map((f) => f.path);
|
|
76
|
+
}
|
|
77
|
+
function addNewLine(arr, i) {
|
|
78
|
+
return i === arr.length - 1 ? "" : "\n";
|
|
79
|
+
}
|
|
80
|
+
function clean_commit_title(title) {
|
|
81
|
+
const title_trimmed = title.trim();
|
|
82
|
+
const remove_period = title_trimmed.endsWith(".");
|
|
83
|
+
if (remove_period) {
|
|
84
|
+
return title_trimmed.substring(0, title_trimmed.length - 1).trim();
|
|
85
|
+
}
|
|
86
|
+
return title.trim();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// src/zod-state.ts
|
|
90
|
+
var Config = import_zod2.z.object({
|
|
91
|
+
check_status: import_zod2.z.boolean().default(true),
|
|
92
|
+
commit_type: import_zod2.z.object({
|
|
93
|
+
enable: import_zod2.z.boolean().default(true),
|
|
94
|
+
initial_value: import_zod2.z.string().default("feat"),
|
|
95
|
+
options: import_zod2.z.array(import_zod2.z.object({
|
|
96
|
+
value: import_zod2.z.string(),
|
|
97
|
+
label: import_zod2.z.string().optional(),
|
|
98
|
+
hint: import_zod2.z.string().optional()
|
|
99
|
+
})).default(DEFAULT_TYPE_OPTIONS)
|
|
100
|
+
}).default({}).refine((val) => {
|
|
101
|
+
const options = val.options.map((v) => v.value);
|
|
102
|
+
return options.includes(val.initial_value);
|
|
103
|
+
}, (val) => ({ message: `Type: initial_value "${val.initial_value}" must exist in options` })),
|
|
104
|
+
commit_scope: import_zod2.z.object({
|
|
105
|
+
enable: import_zod2.z.boolean().default(true),
|
|
106
|
+
initial_value: import_zod2.z.string().default("app"),
|
|
107
|
+
options: import_zod2.z.array(import_zod2.z.object({
|
|
108
|
+
value: import_zod2.z.string(),
|
|
109
|
+
label: import_zod2.z.string().optional(),
|
|
110
|
+
hint: import_zod2.z.string().optional()
|
|
111
|
+
})).default(DEFAULT_SCOPE_OPTIONS)
|
|
112
|
+
}).default({}).refine((val) => {
|
|
113
|
+
const options = val.options.map((v) => v.value);
|
|
114
|
+
return options.includes(val.initial_value);
|
|
115
|
+
}, (val) => ({ message: `Scope: initial_value "${val.initial_value}" must exist in options` })),
|
|
116
|
+
check_ticket: import_zod2.z.object({
|
|
117
|
+
infer_ticket: import_zod2.z.boolean().default(true),
|
|
118
|
+
confirm_ticket: import_zod2.z.boolean().default(true),
|
|
119
|
+
add_to_title: import_zod2.z.boolean().default(true)
|
|
120
|
+
}).default({}),
|
|
121
|
+
commit_title: import_zod2.z.object({
|
|
122
|
+
max_size: import_zod2.z.number().positive().default(70)
|
|
123
|
+
}).default({}),
|
|
124
|
+
commit_body: import_zod2.z.object({
|
|
125
|
+
enable: import_zod2.z.boolean().default(true),
|
|
126
|
+
required: import_zod2.z.boolean().default(false)
|
|
127
|
+
}).default({}),
|
|
128
|
+
commit_footer: import_zod2.z.object({
|
|
129
|
+
enable: import_zod2.z.boolean().default(true),
|
|
130
|
+
initial_value: import_zod2.z.array(Z_FOOTER_OPTIONS).default([]),
|
|
131
|
+
options: import_zod2.z.array(Z_FOOTER_OPTIONS).default(FOOTER_OPTION_VALUES)
|
|
132
|
+
}).default({}),
|
|
133
|
+
breaking_change: import_zod2.z.object({
|
|
134
|
+
add_exclamation_to_title: import_zod2.z.boolean().default(true)
|
|
135
|
+
}).default({}),
|
|
136
|
+
confirm_commit: import_zod2.z.boolean().default(true)
|
|
137
|
+
}).default({});
|
|
138
|
+
var CommitState = import_zod2.z.object({
|
|
139
|
+
type: import_zod2.z.string().default(""),
|
|
140
|
+
scope: import_zod2.z.string().default(""),
|
|
141
|
+
title: import_zod2.z.string().default(""),
|
|
142
|
+
body: import_zod2.z.string().default(""),
|
|
143
|
+
closes: import_zod2.z.string().default(""),
|
|
144
|
+
ticket: import_zod2.z.string().default(""),
|
|
145
|
+
breaking_title: import_zod2.z.string().default(""),
|
|
146
|
+
breaking_body: import_zod2.z.string().default(""),
|
|
147
|
+
deprecates: import_zod2.z.string().default(""),
|
|
148
|
+
deprecates_title: import_zod2.z.string().default(""),
|
|
149
|
+
deprecates_body: import_zod2.z.string().default("")
|
|
150
|
+
}).default({});
|
|
151
|
+
|
|
152
|
+
// src/index.ts
|
|
153
|
+
main(load_setup());
|
|
154
|
+
function load_setup() {
|
|
155
|
+
console.clear();
|
|
156
|
+
p.intro(`${import_picocolors2.default.bgCyan(import_picocolors2.default.black(" better-commits "))}`);
|
|
157
|
+
const root = (0, import_child_process.execSync)("git rev-parse --show-toplevel").toString().trim();
|
|
158
|
+
const root_path = `${root}/${CONFIG_FILE_NAME}`;
|
|
159
|
+
if (import_fs.default.existsSync(root_path)) {
|
|
160
|
+
p.log.step("Found repository config");
|
|
161
|
+
return read_config_from_path(root_path);
|
|
162
|
+
}
|
|
163
|
+
const home_path = get_default_config_path();
|
|
164
|
+
if (import_fs.default.existsSync(home_path)) {
|
|
165
|
+
p.log.step("Found global config");
|
|
166
|
+
return read_config_from_path(home_path);
|
|
167
|
+
}
|
|
168
|
+
const default_config = Config.parse({});
|
|
169
|
+
p.log.step("Config not found. Generating default .better-commit.json at $HOME");
|
|
170
|
+
import_fs.default.writeFileSync(home_path, JSON.stringify(default_config, null, " "));
|
|
171
|
+
return default_config;
|
|
172
|
+
}
|
|
173
|
+
function read_config_from_path(config_path) {
|
|
174
|
+
let res = null;
|
|
175
|
+
try {
|
|
176
|
+
res = JSON.parse(import_fs.default.readFileSync(config_path, "utf8"));
|
|
177
|
+
} catch (err) {
|
|
178
|
+
p.log.error("Invalid JSON file. Exiting.\n" + err);
|
|
179
|
+
process.exit(0);
|
|
180
|
+
}
|
|
181
|
+
return validate_config(res);
|
|
182
|
+
}
|
|
183
|
+
function validate_config(config) {
|
|
184
|
+
try {
|
|
185
|
+
return Config.parse(config);
|
|
186
|
+
} catch (err) {
|
|
187
|
+
console.log((0, import_zod_validation_error.fromZodError)(err).message);
|
|
188
|
+
process.exit(0);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
async function main(config) {
|
|
192
|
+
let commit_state = CommitState.parse({});
|
|
193
|
+
let git_status = await (0, import_simple_git.simpleGit)().status();
|
|
194
|
+
if (config.check_status) {
|
|
195
|
+
p.log.step(import_picocolors2.default.black(import_picocolors2.default.bgGreen(" Checking Git Status ")));
|
|
196
|
+
const missing_files = check_missing_stage(git_status);
|
|
197
|
+
const staged_files = git_status.staged.reduce((acc, curr, i) => import_picocolors2.default.green(acc + curr + addNewLine(git_status.staged, i)), "");
|
|
198
|
+
p.log.success("Changes to be committed:\n" + staged_files);
|
|
199
|
+
if (missing_files.length) {
|
|
200
|
+
const unstaged_files = missing_files.reduce((acc, curr, i) => import_picocolors2.default.red(acc + curr + addNewLine(missing_files, i)), "");
|
|
201
|
+
p.log.error("Changes not staged for commit:\n" + unstaged_files);
|
|
202
|
+
const selected_for_staging = await p.multiselect({
|
|
203
|
+
message: `Some files have not been staged, would you like to add them now? ${SPACE_TO_SELECT}`,
|
|
204
|
+
options: [{ value: ".", label: "." }, ...missing_files.map((v) => ({ value: v, label: v }))],
|
|
205
|
+
required: false
|
|
206
|
+
});
|
|
207
|
+
if (p.isCancel(selected_for_staging))
|
|
208
|
+
process.exit(0);
|
|
209
|
+
await (0, import_simple_git.simpleGit)().add(selected_for_staging);
|
|
210
|
+
git_status = await (0, import_simple_git.simpleGit)().status();
|
|
211
|
+
if (selected_for_staging?.length) {
|
|
212
|
+
p.log.success(import_picocolors2.default.green("Changes successfully staged"));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (!git_status.staged.length) {
|
|
217
|
+
p.log.error(import_picocolors2.default.red('no changes added to commit (use "git add" and/or "git commit -a")'));
|
|
218
|
+
process.exit(0);
|
|
219
|
+
}
|
|
220
|
+
if (config.commit_type.enable) {
|
|
221
|
+
const commit_type = await p.select(
|
|
222
|
+
{
|
|
223
|
+
message: `Select a commit type`,
|
|
224
|
+
initialValue: config.commit_type.initial_value,
|
|
225
|
+
options: config.commit_type.options
|
|
226
|
+
}
|
|
227
|
+
);
|
|
228
|
+
if (p.isCancel(commit_type))
|
|
229
|
+
process.exit(0);
|
|
230
|
+
commit_state.type = commit_type;
|
|
231
|
+
}
|
|
232
|
+
if (config.commit_scope.enable) {
|
|
233
|
+
const commit_scope = await p.select({
|
|
234
|
+
message: "Select a commit scope",
|
|
235
|
+
initialValue: config.commit_scope.initial_value,
|
|
236
|
+
options: config.commit_scope.options
|
|
237
|
+
});
|
|
238
|
+
if (p.isCancel(commit_scope))
|
|
239
|
+
process.exit(0);
|
|
240
|
+
commit_state.scope = commit_scope;
|
|
241
|
+
}
|
|
242
|
+
if (config.check_ticket.infer_ticket) {
|
|
243
|
+
try {
|
|
244
|
+
const branch = (0, import_child_process.execSync)("git rev-parse --abbrev-ref HEAD", { stdio: "pipe" }).toString();
|
|
245
|
+
const found = [branch.match(REGEX_SLASH_TAG), branch.match(REGEX_SLASH_NUM), branch.match(REGEX_START_TAG), branch.match(REGEX_START_NUM)].filter((v) => v != null).map((v) => v && v.length >= 2 ? v[1] : "");
|
|
246
|
+
commit_state.ticket = found.length ? found[0] : "";
|
|
247
|
+
} catch (err) {
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (config.check_ticket.confirm_ticket) {
|
|
251
|
+
const user_commit_ticket = await p.text({
|
|
252
|
+
message: commit_state.ticket ? "Ticket / issue infered from branch (confirm / edit)" : `Add ticket / issue ${OPTIONAL_PROMPT}`,
|
|
253
|
+
initialValue: commit_state.ticket
|
|
254
|
+
});
|
|
255
|
+
if (p.isCancel(user_commit_ticket))
|
|
256
|
+
process.exit(0);
|
|
257
|
+
commit_state.ticket = user_commit_ticket ?? "";
|
|
258
|
+
}
|
|
259
|
+
const commit_title = await p.text(
|
|
260
|
+
{
|
|
261
|
+
message: "Write a brief title describing the commit",
|
|
262
|
+
placeholder: "",
|
|
263
|
+
validate: (value) => {
|
|
264
|
+
if (!value)
|
|
265
|
+
return "Please enter a title";
|
|
266
|
+
const commit_scope_size = commit_state.scope ? commit_state.scope.length + 2 : 0;
|
|
267
|
+
const commit_type_size = commit_state.type.length;
|
|
268
|
+
const commit_ticket_size = config.check_ticket.add_to_title ? commit_state.ticket.length : 0;
|
|
269
|
+
if (commit_scope_size + commit_type_size + commit_ticket_size + value.length > config.commit_title.max_size)
|
|
270
|
+
return `Exceeded max length. Title max [${config.commit_title.max_size}]`;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
if (p.isCancel(commit_title))
|
|
275
|
+
process.exit(0);
|
|
276
|
+
commit_state.title = clean_commit_title(commit_title);
|
|
277
|
+
if (config.commit_body.enable) {
|
|
278
|
+
const commit_body = await p.text({
|
|
279
|
+
message: `Write a detailed description of the changes ${OPTIONAL_PROMPT}`,
|
|
280
|
+
placeholder: "",
|
|
281
|
+
validate: (val) => {
|
|
282
|
+
if (config.commit_body.required && !val)
|
|
283
|
+
return "Please enter a description";
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
if (p.isCancel(commit_body))
|
|
287
|
+
process.exit(0);
|
|
288
|
+
commit_state.body = commit_body;
|
|
289
|
+
}
|
|
290
|
+
if (config.commit_footer.enable) {
|
|
291
|
+
const commit_footer = await p.multiselect({
|
|
292
|
+
message: `Select optional footers ${SPACE_TO_SELECT}`,
|
|
293
|
+
initialValues: config.commit_footer.initial_value,
|
|
294
|
+
options: COMMIT_FOOTER_OPTIONS,
|
|
295
|
+
required: false
|
|
296
|
+
});
|
|
297
|
+
if (commit_footer?.includes("breaking-change")) {
|
|
298
|
+
const breaking_changes_title = await p.text({
|
|
299
|
+
message: "Breaking changes: Write a short title / summary",
|
|
300
|
+
placeholder: "",
|
|
301
|
+
validate: (value) => {
|
|
302
|
+
if (!value)
|
|
303
|
+
return "Please enter a title / summary";
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
const breaking_changes_body = await p.text({
|
|
307
|
+
message: `Breaking Changes: Write a description & migration instructions ${OPTIONAL_PROMPT}`,
|
|
308
|
+
placeholder: ""
|
|
309
|
+
});
|
|
310
|
+
commit_state.breaking_title = breaking_changes_title;
|
|
311
|
+
commit_state.breaking_body = breaking_changes_body;
|
|
312
|
+
}
|
|
313
|
+
if (commit_footer?.includes("deprecated")) {
|
|
314
|
+
const deprecated_title = await p.text({
|
|
315
|
+
message: "Deprecated: Write a short title / summary",
|
|
316
|
+
placeholder: "",
|
|
317
|
+
validate: (value) => {
|
|
318
|
+
if (!value)
|
|
319
|
+
return "Please enter a title / summary";
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
const deprecated_body = await p.text({
|
|
323
|
+
message: `Deprecated: Write a description ${OPTIONAL_PROMPT}`,
|
|
324
|
+
placeholder: ""
|
|
325
|
+
});
|
|
326
|
+
commit_state.deprecates_body = deprecated_body;
|
|
327
|
+
commit_state.deprecates_title = deprecated_title;
|
|
328
|
+
}
|
|
329
|
+
if (commit_footer?.includes("closes")) {
|
|
330
|
+
commit_state.closes = "Closes:";
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
let continue_commit = true;
|
|
334
|
+
p.note(build_commit_string(commit_state, config, true), "Commit Preview");
|
|
335
|
+
if (config.confirm_commit) {
|
|
336
|
+
continue_commit = await p.confirm({ message: "Confirm Commit?" });
|
|
337
|
+
if (p.isCancel(continue_commit))
|
|
338
|
+
process.exit(0);
|
|
339
|
+
}
|
|
340
|
+
if (continue_commit)
|
|
341
|
+
(0, import_simple_git.simpleGit)().commit(build_commit_string(commit_state, config, false));
|
|
342
|
+
}
|
|
343
|
+
function build_commit_string(commit_state, config, colorize = false) {
|
|
344
|
+
let commit_string = "";
|
|
345
|
+
if (commit_state.type) {
|
|
346
|
+
commit_string += colorize ? import_picocolors2.default.blue(commit_state.type) : commit_state.type;
|
|
347
|
+
}
|
|
348
|
+
if (commit_state.scope) {
|
|
349
|
+
const scope = colorize ? import_picocolors2.default.cyan(commit_state.scope) : commit_state.scope;
|
|
350
|
+
commit_string += `(${scope})`;
|
|
351
|
+
}
|
|
352
|
+
if (commit_state.breaking_title && config.breaking_change.add_exclamation_to_title) {
|
|
353
|
+
commit_string += colorize ? import_picocolors2.default.red("!") : "!";
|
|
354
|
+
}
|
|
355
|
+
if (commit_state.scope || commit_state.type) {
|
|
356
|
+
commit_string += ": ";
|
|
357
|
+
}
|
|
358
|
+
if (commit_state.ticket) {
|
|
359
|
+
commit_string += colorize ? import_picocolors2.default.magenta(commit_state.ticket) + " " : commit_state.ticket + " ";
|
|
360
|
+
}
|
|
361
|
+
if (commit_state.title) {
|
|
362
|
+
commit_string += colorize ? import_picocolors2.default.reset(commit_state.title) : commit_state.title;
|
|
363
|
+
}
|
|
364
|
+
if (commit_state.body) {
|
|
365
|
+
const temp = commit_state.body.split("\\n");
|
|
366
|
+
const res = temp.map((v) => colorize ? import_picocolors2.default.reset(v.trim()) : v.trim()).join("\n");
|
|
367
|
+
commit_string += colorize ? `
|
|
368
|
+
|
|
369
|
+
${res}` : `
|
|
370
|
+
|
|
371
|
+
${res}`;
|
|
372
|
+
}
|
|
373
|
+
if (commit_state.breaking_title) {
|
|
374
|
+
const title = colorize ? import_picocolors2.default.red(`BREAKING CHANGE: ${commit_state.breaking_title}`) : `BREAKING CHANGE: ${commit_state.breaking_title}`;
|
|
375
|
+
commit_string += `
|
|
376
|
+
|
|
377
|
+
${title}`;
|
|
378
|
+
}
|
|
379
|
+
if (commit_state.breaking_body) {
|
|
380
|
+
const body = colorize ? import_picocolors2.default.red(commit_state.breaking_body) : commit_state.breaking_body;
|
|
381
|
+
commit_string += `
|
|
382
|
+
|
|
383
|
+
${body}`;
|
|
384
|
+
}
|
|
385
|
+
if (commit_state.deprecates_title) {
|
|
386
|
+
const title = colorize ? import_picocolors2.default.yellow(`DEPRECATED: ${commit_state.deprecates_title}`) : `DEPRECATED: ${commit_state.deprecates_title}`;
|
|
387
|
+
commit_string += `
|
|
388
|
+
|
|
389
|
+
${title}`;
|
|
390
|
+
}
|
|
391
|
+
if (commit_state.deprecates_body) {
|
|
392
|
+
const body = colorize ? import_picocolors2.default.yellow(commit_state.deprecates_body) : commit_state.deprecates_body;
|
|
393
|
+
commit_string += `
|
|
394
|
+
|
|
395
|
+
${body}`;
|
|
396
|
+
}
|
|
397
|
+
if (commit_state.closes && commit_state.ticket) {
|
|
398
|
+
commit_string += colorize ? `
|
|
399
|
+
|
|
400
|
+
${import_picocolors2.default.reset(commit_state.closes)} ${import_picocolors2.default.magenta(commit_state.ticket)}` : `
|
|
401
|
+
|
|
402
|
+
${commit_state.closes} ${commit_state.ticket}`;
|
|
403
|
+
}
|
|
404
|
+
return commit_string;
|
|
405
|
+
}
|
package/dist/init.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/zod-state.ts
|
|
27
|
+
var import_zod2 = require("zod");
|
|
28
|
+
|
|
29
|
+
// src/utils.ts
|
|
30
|
+
var import_zod = require("zod");
|
|
31
|
+
var import_picocolors = __toESM(require("picocolors"));
|
|
32
|
+
var CONFIG_FILE_NAME = ".better-commits.json";
|
|
33
|
+
var SPACE_TO_SELECT = `${import_picocolors.default.dim("(<space> to select)")}`;
|
|
34
|
+
var OPTIONAL_PROMPT = `${import_picocolors.default.dim("(optional)")}`;
|
|
35
|
+
var REGEX_SLASH_TAG = new RegExp(/\/(\w+-\d+)/);
|
|
36
|
+
var REGEX_START_TAG = new RegExp(/^(\w+-\d+)/);
|
|
37
|
+
var REGEX_SLASH_NUM = new RegExp(/\/(\d+)/);
|
|
38
|
+
var REGEX_START_NUM = new RegExp(/^(\d+)/);
|
|
39
|
+
var DEFAULT_TYPE_OPTIONS = [
|
|
40
|
+
{ value: "feat", label: "feat" },
|
|
41
|
+
{ value: "fix", label: "fix" },
|
|
42
|
+
{ value: "docs", label: "docs" },
|
|
43
|
+
{ value: "refactor", label: "refactor" },
|
|
44
|
+
{ value: "perf", label: "perf" },
|
|
45
|
+
{ value: "test", label: "test" },
|
|
46
|
+
{ value: "", label: "none" }
|
|
47
|
+
];
|
|
48
|
+
var DEFAULT_SCOPE_OPTIONS = [
|
|
49
|
+
{ value: "app", label: "app" },
|
|
50
|
+
{ value: "shared", label: "shared" },
|
|
51
|
+
{ value: "server", label: "server" },
|
|
52
|
+
{ value: "tools", label: "tools" },
|
|
53
|
+
{ value: "", label: "none" }
|
|
54
|
+
];
|
|
55
|
+
var Z_FOOTER_OPTIONS = import_zod.z.enum(["closes", "breaking-change", "deprecated"]);
|
|
56
|
+
var FOOTER_OPTION_VALUES = ["closes", "breaking-change", "deprecated"];
|
|
57
|
+
|
|
58
|
+
// src/zod-state.ts
|
|
59
|
+
var Config = import_zod2.z.object({
|
|
60
|
+
check_status: import_zod2.z.boolean().default(true),
|
|
61
|
+
commit_type: import_zod2.z.object({
|
|
62
|
+
enable: import_zod2.z.boolean().default(true),
|
|
63
|
+
initial_value: import_zod2.z.string().default("feat"),
|
|
64
|
+
options: import_zod2.z.array(import_zod2.z.object({
|
|
65
|
+
value: import_zod2.z.string(),
|
|
66
|
+
label: import_zod2.z.string().optional(),
|
|
67
|
+
hint: import_zod2.z.string().optional()
|
|
68
|
+
})).default(DEFAULT_TYPE_OPTIONS)
|
|
69
|
+
}).default({}).refine((val) => {
|
|
70
|
+
const options = val.options.map((v) => v.value);
|
|
71
|
+
return options.includes(val.initial_value);
|
|
72
|
+
}, (val) => ({ message: `Type: initial_value "${val.initial_value}" must exist in options` })),
|
|
73
|
+
commit_scope: import_zod2.z.object({
|
|
74
|
+
enable: import_zod2.z.boolean().default(true),
|
|
75
|
+
initial_value: import_zod2.z.string().default("app"),
|
|
76
|
+
options: import_zod2.z.array(import_zod2.z.object({
|
|
77
|
+
value: import_zod2.z.string(),
|
|
78
|
+
label: import_zod2.z.string().optional(),
|
|
79
|
+
hint: import_zod2.z.string().optional()
|
|
80
|
+
})).default(DEFAULT_SCOPE_OPTIONS)
|
|
81
|
+
}).default({}).refine((val) => {
|
|
82
|
+
const options = val.options.map((v) => v.value);
|
|
83
|
+
return options.includes(val.initial_value);
|
|
84
|
+
}, (val) => ({ message: `Scope: initial_value "${val.initial_value}" must exist in options` })),
|
|
85
|
+
check_ticket: import_zod2.z.object({
|
|
86
|
+
infer_ticket: import_zod2.z.boolean().default(true),
|
|
87
|
+
confirm_ticket: import_zod2.z.boolean().default(true),
|
|
88
|
+
add_to_title: import_zod2.z.boolean().default(true)
|
|
89
|
+
}).default({}),
|
|
90
|
+
commit_title: import_zod2.z.object({
|
|
91
|
+
max_size: import_zod2.z.number().positive().default(70)
|
|
92
|
+
}).default({}),
|
|
93
|
+
commit_body: import_zod2.z.object({
|
|
94
|
+
enable: import_zod2.z.boolean().default(true),
|
|
95
|
+
required: import_zod2.z.boolean().default(false)
|
|
96
|
+
}).default({}),
|
|
97
|
+
commit_footer: import_zod2.z.object({
|
|
98
|
+
enable: import_zod2.z.boolean().default(true),
|
|
99
|
+
initial_value: import_zod2.z.array(Z_FOOTER_OPTIONS).default([]),
|
|
100
|
+
options: import_zod2.z.array(Z_FOOTER_OPTIONS).default(FOOTER_OPTION_VALUES)
|
|
101
|
+
}).default({}),
|
|
102
|
+
breaking_change: import_zod2.z.object({
|
|
103
|
+
add_exclamation_to_title: import_zod2.z.boolean().default(true)
|
|
104
|
+
}).default({}),
|
|
105
|
+
confirm_commit: import_zod2.z.boolean().default(true)
|
|
106
|
+
}).default({});
|
|
107
|
+
var CommitState = import_zod2.z.object({
|
|
108
|
+
type: import_zod2.z.string().default(""),
|
|
109
|
+
scope: import_zod2.z.string().default(""),
|
|
110
|
+
title: import_zod2.z.string().default(""),
|
|
111
|
+
body: import_zod2.z.string().default(""),
|
|
112
|
+
closes: import_zod2.z.string().default(""),
|
|
113
|
+
ticket: import_zod2.z.string().default(""),
|
|
114
|
+
breaking_title: import_zod2.z.string().default(""),
|
|
115
|
+
breaking_body: import_zod2.z.string().default(""),
|
|
116
|
+
deprecates: import_zod2.z.string().default(""),
|
|
117
|
+
deprecates_title: import_zod2.z.string().default(""),
|
|
118
|
+
deprecates_body: import_zod2.z.string().default("")
|
|
119
|
+
}).default({});
|
|
120
|
+
|
|
121
|
+
// src/init.ts
|
|
122
|
+
var import_picocolors2 = __toESM(require("picocolors"));
|
|
123
|
+
var import_fs = __toESM(require("fs"));
|
|
124
|
+
var import_child_process = require("child_process");
|
|
125
|
+
var p = __toESM(require("@clack/prompts"));
|
|
126
|
+
try {
|
|
127
|
+
console.clear();
|
|
128
|
+
p.intro(`${import_picocolors2.default.bgCyan(import_picocolors2.default.black(" better-commits-init "))}`);
|
|
129
|
+
const root = (0, import_child_process.execSync)("git rev-parse --show-toplevel").toString().trim();
|
|
130
|
+
const root_path = `${root}/${CONFIG_FILE_NAME}`;
|
|
131
|
+
const default_config = Config.parse({});
|
|
132
|
+
import_fs.default.writeFileSync(root_path, JSON.stringify(default_config, null, " "));
|
|
133
|
+
p.log.success(`${import_picocolors2.default.green("Successfully created .better-commits.json")}`);
|
|
134
|
+
p.outro(`Run ${import_picocolors2.default.bgBlack(import_picocolors2.default.white("better-commits"))} to start the CLI`);
|
|
135
|
+
} catch (err) {
|
|
136
|
+
p.log.error(`${import_picocolors2.default.red("Could not determine git root folder. better-commits-init must be used in a git repository")}`);
|
|
137
|
+
}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/utils.ts
|
|
31
|
+
var utils_exports = {};
|
|
32
|
+
__export(utils_exports, {
|
|
33
|
+
COMMIT_FOOTER_OPTIONS: () => COMMIT_FOOTER_OPTIONS,
|
|
34
|
+
CONFIG_FILE_NAME: () => CONFIG_FILE_NAME,
|
|
35
|
+
DEFAULT_SCOPE_OPTIONS: () => DEFAULT_SCOPE_OPTIONS,
|
|
36
|
+
DEFAULT_TYPE_OPTIONS: () => DEFAULT_TYPE_OPTIONS,
|
|
37
|
+
FOOTER_OPTION_VALUES: () => FOOTER_OPTION_VALUES,
|
|
38
|
+
OPTIONAL_PROMPT: () => OPTIONAL_PROMPT,
|
|
39
|
+
REGEX_SLASH_NUM: () => REGEX_SLASH_NUM,
|
|
40
|
+
REGEX_SLASH_TAG: () => REGEX_SLASH_TAG,
|
|
41
|
+
REGEX_START_NUM: () => REGEX_START_NUM,
|
|
42
|
+
REGEX_START_TAG: () => REGEX_START_TAG,
|
|
43
|
+
SPACE_TO_SELECT: () => SPACE_TO_SELECT,
|
|
44
|
+
Z_FOOTER_OPTIONS: () => Z_FOOTER_OPTIONS,
|
|
45
|
+
addNewLine: () => addNewLine,
|
|
46
|
+
check_missing_stage: () => check_missing_stage,
|
|
47
|
+
clean_commit_title: () => clean_commit_title,
|
|
48
|
+
get_default_config_path: () => get_default_config_path
|
|
49
|
+
});
|
|
50
|
+
module.exports = __toCommonJS(utils_exports);
|
|
51
|
+
var import_os = require("os");
|
|
52
|
+
var import_zod = require("zod");
|
|
53
|
+
var import_picocolors = __toESM(require("picocolors"));
|
|
54
|
+
var CONFIG_FILE_NAME = ".better-commits.json";
|
|
55
|
+
var SPACE_TO_SELECT = `${import_picocolors.default.dim("(<space> to select)")}`;
|
|
56
|
+
var OPTIONAL_PROMPT = `${import_picocolors.default.dim("(optional)")}`;
|
|
57
|
+
var REGEX_SLASH_TAG = new RegExp(/\/(\w+-\d+)/);
|
|
58
|
+
var REGEX_START_TAG = new RegExp(/^(\w+-\d+)/);
|
|
59
|
+
var REGEX_SLASH_NUM = new RegExp(/\/(\d+)/);
|
|
60
|
+
var REGEX_START_NUM = new RegExp(/^(\d+)/);
|
|
61
|
+
var DEFAULT_TYPE_OPTIONS = [
|
|
62
|
+
{ value: "feat", label: "feat" },
|
|
63
|
+
{ value: "fix", label: "fix" },
|
|
64
|
+
{ value: "docs", label: "docs" },
|
|
65
|
+
{ value: "refactor", label: "refactor" },
|
|
66
|
+
{ value: "perf", label: "perf" },
|
|
67
|
+
{ value: "test", label: "test" },
|
|
68
|
+
{ value: "", label: "none" }
|
|
69
|
+
];
|
|
70
|
+
var DEFAULT_SCOPE_OPTIONS = [
|
|
71
|
+
{ value: "app", label: "app" },
|
|
72
|
+
{ value: "shared", label: "shared" },
|
|
73
|
+
{ value: "server", label: "server" },
|
|
74
|
+
{ value: "tools", label: "tools" },
|
|
75
|
+
{ value: "", label: "none" }
|
|
76
|
+
];
|
|
77
|
+
var COMMIT_FOOTER_OPTIONS = [
|
|
78
|
+
{ value: "closes", label: "closes <issue/ticket>", hint: "Attempts to infer ticket from branch" },
|
|
79
|
+
{ value: "breaking-change", label: "breaking change", hint: "Add breaking change" },
|
|
80
|
+
{ value: "deprecated", label: "deprecated", hint: "Add deprecated change" }
|
|
81
|
+
];
|
|
82
|
+
var Z_FOOTER_OPTIONS = import_zod.z.enum(["closes", "breaking-change", "deprecated"]);
|
|
83
|
+
var FOOTER_OPTION_VALUES = ["closes", "breaking-change", "deprecated"];
|
|
84
|
+
function get_default_config_path() {
|
|
85
|
+
return (0, import_os.homedir)() + "/" + CONFIG_FILE_NAME;
|
|
86
|
+
}
|
|
87
|
+
function check_missing_stage(stats) {
|
|
88
|
+
return stats.files.filter((f) => f.index.trim() === "" || f.index === "?").map((f) => f.path);
|
|
89
|
+
}
|
|
90
|
+
function addNewLine(arr, i) {
|
|
91
|
+
return i === arr.length - 1 ? "" : "\n";
|
|
92
|
+
}
|
|
93
|
+
function clean_commit_title(title) {
|
|
94
|
+
const title_trimmed = title.trim();
|
|
95
|
+
const remove_period = title_trimmed.endsWith(".");
|
|
96
|
+
if (remove_period) {
|
|
97
|
+
return title_trimmed.substring(0, title_trimmed.length - 1).trim();
|
|
98
|
+
}
|
|
99
|
+
return title.trim();
|
|
100
|
+
}
|
|
101
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
102
|
+
0 && (module.exports = {
|
|
103
|
+
COMMIT_FOOTER_OPTIONS,
|
|
104
|
+
CONFIG_FILE_NAME,
|
|
105
|
+
DEFAULT_SCOPE_OPTIONS,
|
|
106
|
+
DEFAULT_TYPE_OPTIONS,
|
|
107
|
+
FOOTER_OPTION_VALUES,
|
|
108
|
+
OPTIONAL_PROMPT,
|
|
109
|
+
REGEX_SLASH_NUM,
|
|
110
|
+
REGEX_SLASH_TAG,
|
|
111
|
+
REGEX_START_NUM,
|
|
112
|
+
REGEX_START_TAG,
|
|
113
|
+
SPACE_TO_SELECT,
|
|
114
|
+
Z_FOOTER_OPTIONS,
|
|
115
|
+
addNewLine,
|
|
116
|
+
check_missing_stage,
|
|
117
|
+
clean_commit_title,
|
|
118
|
+
get_default_config_path
|
|
119
|
+
});
|