better-commits 1.23.2 → 1.23.3

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.
Files changed (68) hide show
  1. package/dist/branch.js +628 -19
  2. package/dist/chunk-GAAS3VS3.js +922 -0
  3. package/dist/chunk-H5CLUQIL.js +313 -0
  4. package/dist/index.js +1122 -41
  5. package/dist/init.js +44 -1
  6. package/package.json +12 -4
  7. package/readme.md +4 -2
  8. package/.better-commits.json +0 -52
  9. package/.github/workflows/publish.yml +0 -34
  10. package/.github/workflows/test.yml +0 -27
  11. package/.prettierignore +0 -5
  12. package/.prettierrc +0 -1
  13. package/dist/chunk-43H72S6V.js +0 -1
  14. package/dist/chunk-B7AGSPP3.js +0 -261
  15. package/src/args.test.ts +0 -128
  16. package/src/args.ts +0 -125
  17. package/src/branch-args.test.ts +0 -75
  18. package/src/branch-args.ts +0 -107
  19. package/src/branch-help.ts +0 -125
  20. package/src/branch.ts +0 -97
  21. package/src/default-config-template.ts +0 -258
  22. package/src/git.test.ts +0 -64
  23. package/src/git.ts +0 -72
  24. package/src/help.ts +0 -138
  25. package/src/index.test.ts +0 -7
  26. package/src/index.ts +0 -101
  27. package/src/init.test.ts +0 -123
  28. package/src/init.ts +0 -46
  29. package/src/prompts/autocomplete-multiselect.test.ts +0 -129
  30. package/src/prompts/autocomplete-multiselect.ts +0 -249
  31. package/src/prompts/branch-checkout.prompt.ts +0 -36
  32. package/src/prompts/branch-confirm.prompt.test.ts +0 -89
  33. package/src/prompts/branch-confirm.prompt.ts +0 -149
  34. package/src/prompts/branch-description.prompt.ts +0 -37
  35. package/src/prompts/branch-runnable.ts +0 -13
  36. package/src/prompts/branch-scope.prompt.ts +0 -59
  37. package/src/prompts/branch-ticket.prompt.ts +0 -41
  38. package/src/prompts/branch-type.prompt.ts +0 -46
  39. package/src/prompts/branch-user.prompt.ts +0 -50
  40. package/src/prompts/branch-version.prompt.ts +0 -41
  41. package/src/prompts/commit-body.prompt.ts +0 -51
  42. package/src/prompts/commit-confirm.prompt.ts +0 -123
  43. package/src/prompts/commit-footer.prompt.ts +0 -195
  44. package/src/prompts/commit-scope.prompt.ts +0 -91
  45. package/src/prompts/commit-status.prompt.ts +0 -66
  46. package/src/prompts/commit-ticket.prompt.ts +0 -82
  47. package/src/prompts/commit-title.prompt.ts +0 -98
  48. package/src/prompts/commit-type.prompt.ts +0 -96
  49. package/src/prompts/runnable.ts +0 -13
  50. package/src/utils/build-branch.test.ts +0 -159
  51. package/src/utils/build-branch.ts +0 -48
  52. package/src/utils/build-commit-string.test.ts +0 -273
  53. package/src/utils/build-commit-string.ts +0 -163
  54. package/src/utils/commit-title-size.ts +0 -24
  55. package/src/utils/infer.test.ts +0 -174
  56. package/src/utils/infer.ts +0 -160
  57. package/src/utils/messages.ts +0 -25
  58. package/src/utils/no-interactive-branch-validation.test.ts +0 -193
  59. package/src/utils/no-interactive-validation.test.ts +0 -174
  60. package/src/utils/no-interactive-validation.ts +0 -213
  61. package/src/utils.test.ts +0 -164
  62. package/src/utils.ts +0 -235
  63. package/src/valibot-consts.ts +0 -117
  64. package/src/valibot-state.test.ts +0 -57
  65. package/src/valibot-state.ts +0 -276
  66. package/tsconfig.json +0 -15
  67. package/tsup.config.ts +0 -12
  68. package/vitest.config.ts +0 -8
package/dist/branch.js CHANGED
@@ -1,28 +1,637 @@
1
1
  #! /usr/bin/env node
2
- import{c as q,e as j,f as U,g as W,j as g}from"./chunk-43H72S6V.js";import{a as F,e as E,j as G,k as L,l as V,m as f,o as l,r as D,s as H}from"./chunk-B7AGSPP3.js";import gt from"configstore";import{chdir as ut}from"process";import{ValiError as _t,parse as J}from"valibot";var a=class{constructor(t,e,n){this.config=t;this.branch_state=e;this.prompt_cache=n}};import*as b from"@clack/prompts";var d=class extends a{async run(){if(this.#e){let t=await b.select({message:this.#t,initialValue:this.#r,options:G});b.isCancel(t)&&process.exit(),this.#n(t)}}get#t(){return"Checkout a branch or create a worktree?"}get#e(){return this.config.worktrees.enable}get#r(){return this.branch_state.checkout||this.config.branch_action_default}#n(t){this.branch_state.checkout=t}};import*as v from"@clack/prompts";var y=class extends a{async run(){if(!this.#t)return;let t=await v.text({message:this.#r,placeholder:"",initialValue:this.#n,validate:e=>this.#i(e)});v.isCancel(t)&&process.exit(0),this.#o(t??"")}get#t(){return this.config.branch_user.enable}get#e(){return this.config.branch_user.required}get#r(){return this.#e?"Type your git username":g("Type your git username")}get#n(){return this.branch_state.user||D(this.prompt_cache,"username")}#i(t){if(this.#e&&!t)return"Please enter a username"}#o(t){this.branch_state.user=t.replace(/\s+/g,"-").toLowerCase(),H(this.prompt_cache,"username",this.branch_state.user)}};import*as u from"@clack/prompts";var k=class extends a{async run(){if(!this.#t)return;let e=await(this.config.branch_type.autocomplete?u.autocomplete:u.select)({message:this.#e,initialValue:this.#r,options:this.#n});u.isCancel(e)&&process.exit(0),this.#i(e)}get#t(){return this.config.branch_type.enable}get#e(){return"Select a branch type"}get#r(){return this.branch_state.type||this.config.commit_type.initial_value}get#n(){return this.config.commit_type.options}#i(t){this.branch_state.type=t}};import*as p from"@clack/prompts";var w=class extends a{async run(){if(!this.#t)return;let e=await(this.config.branch_scope.autocomplete?p.autocomplete:p.select)({message:this.#e,initialValue:this.#r,options:this.#n});p.isCancel(e)&&process.exit(0),await this.#o(e)}get#t(){return this.config.branch_scope.enable}get#e(){return"Select a branch scope"}get#r(){return this.branch_state.scope||this.config.commit_scope.initial_value}get#n(){return this.config.commit_scope.options}get#i(){return this.config.commit_scope.custom_scope}async#o(t){let e=t;if(e===F&&this.#i){let n=await p.text({message:"Write a custom scope",placeholder:""});p.isCancel(n)&&process.exit(0),e=n??""}this.branch_state.scope=e}};import*as C from"@clack/prompts";var x=class extends a{async run(){if(!this.#t)return;let t=await C.text({message:this.#r,placeholder:"",validate:e=>this.#n(e),initialValue:this.branch_state.ticket});C.isCancel(t)&&process.exit(0),this.#i(t??"")}get#t(){return this.config.branch_ticket.enable}get#e(){return this.config.branch_ticket.required}get#r(){return this.#e?"Type ticket / issue number":g("Type ticket / issue number")}#n(t){if(this.#e&&!t)return"Please enter a ticket / issue"}#i(t){this.branch_state.ticket=t}};import*as S from"@clack/prompts";var $=class extends a{async run(){if(!this.#t)return;let t=await S.text({message:this.#r,placeholder:"",validate:e=>this.#n(e),initialValue:this.branch_state.version});S.isCancel(t)&&process.exit(0),this.#i(t??"")}get#t(){return this.config.branch_version.enable}get#e(){return this.config.branch_version.required}get#r(){return this.#e?"Type version number":g("Type version number")}#n(t){if(this.#e&&!t)return"Please enter a version"}#i(t){this.branch_state.version=t}};import*as O from"@clack/prompts";var I=class extends a{async run(){let t=await O.text({message:this.#t,placeholder:"",validate:e=>this.#r(e),initialValue:this.branch_state.description});O.isCancel(t)&&process.exit(0),this.#n(t??"")}get#t(){return"Type a short description"}get#e(){return this.config.branch_description.max_length}#r(t){if(!t)return"Please enter a description";if(t.length>this.#e)return`Exceeded max length. Description max [${this.#e}]`}#n(t){this.branch_state.description=t.replace(/\s+/g,"-").toLowerCase()}};import*as m from"@clack/prompts";import{execSync as B}from"child_process";import h from"picocolors";import{chdir as at}from"process";import{parse as rt}from"@bomb.sh/args";var M=["user","type","scope","description","ticket","branch-version","checkout"],nt=["git-dir","work-tree"],it=["interactive","dry-run","help","version"],T=class{#t;constructor(t){this.#t=t}get interactive(){return!this.#t.no_interactive}get dry_run(){return this.#t.dry_run}get help(){return this.#t.help}get version(){return this.#t.version}get git_args(){return this.#t.git_args}get branch_state(){return this.#t.branch_state}},o=new T(ot(process.argv.slice(2)));function ot(r){let t=rt(r,{alias:{h:"help",v:"version"},boolean:it,string:[...M,...nt]}),e={};return M.forEach(n=>{let i=t[n];if(i){let s=n==="branch-version"?"version":n.replace("-","_");s==="checkout"?e[s]=i??"branch":e[s]=i}}),{help:t.help===!0,version:t.version===!0,git_args:st(t["git-dir"],t["work-tree"]),no_interactive:t.interactive===!1,dry_run:t["dry-run"]===!0,branch_state:e}}function st(r,t){return`${r?`--git-dir=${r}`:""} ${t?`--work-tree=${t}`:""}`.trim()}function K(r,t){let e="";return t.branch_order.forEach(n=>{let i=`branch_${n}`;r[n]&&(e+=r[n]+t[i].separator)}),e.endsWith("-")||e.endsWith("/")||e.endsWith("_")?e.slice(0,-1).trim():e.trim()}function Y(r,t,e){let n=e.split("/").pop()||"repo",i=t.worktrees.folder_template;i=i.replace("{{repo_name}}",n).replace("{{branch_description}}",r.description).replace("{{user}}",r.user||"").replace("{{type}}",r.type||"").replace("{{scope}}",r.scope||"").replace("{{ticket}}",r.ticket||"").replace("{{version}}",r.version||""),i=i.replace(/\s/g,"").replace(/--+/g,"-").replace(/^-+|-+$/g,"");let s=t.worktrees.base_path;return`${s}${s.endsWith("/")?"":"/"}${i}`}var _=class extends a{async run(){this.#i(),this.#o(),this.#c()}get#t(){return this.branch_state.checkout==="worktree"}get#e(){return this.#t?this.config.worktree_pre_commands:this.config.branch_pre_commands}get#r(){return this.#t?this.config.worktree_post_commands:this.config.branch_post_commands}get#n(){return K(this.branch_state,this.config)}#i(){this.#a(this.#e,"Something went wrong when executing pre-commands: ")}#o(){let t=this.#n,e=this.#p(t);if(!this.#t){let n=`git ${o.git_args} checkout ${e} ${t}`;if(o.dry_run){this.#s(n);return}try{B(n,{stdio:"inherit"}),m.log.info(`Switched to a new branch '${h.bgGreen(" "+h.black(t)+" ")}'`)}catch{process.exit(0)}return}try{let n=Y(this.branch_state,this.config,f(o.git_args)),i=`git ${o.git_args} worktree add ${n} ${e} ${t}`;if(o.dry_run){this.#s(i);return}B(i,{stdio:"inherit"}),m.log.info(`Created a new worktree ${h.bgGreen(" "+h.black(n)+" ")}, checked out branch ${h.bgGreen(" "+h.black(t)+" ")}`),m.log.info(h.bgMagenta(h.black(` cd ${n} `))+" to navigate to your new worktree"),at(n)}catch{process.exit(0)}}#c(){this.#a(this.#r,"Something went wrong when executing post-commands: ")}#a(t,e){t.forEach(n=>{if(o.dry_run){this.#s(n);return}try{B(n,{stdio:"inherit"})}catch(i){m.log.error(e+i),process.exit(0)}})}#s(t){m.log.info(`Dry run: ${t}`)}#p(t){let e="";try{B(`git ${o.git_args} show-ref ${t}`,{encoding:"utf-8"}),m.log.warning(h.yellow(`${t} already exists! Checking out existing branch.`))}catch{e="-b"}return e}};import{execSync as ct}from"child_process";import c from"picocolors";var pt={"--interactive":"Run in interactive prompt mode (default behavior).","--dry-run":"Print branch commands without creating a branch or worktree.","--help":"Show help information and exit."},ht={"--user":"Set branch username segment.","--type":"Set branch type (for example feat, fix, docs).","--scope":"Set branch scope segment.","--description":"Set branch description segment.","--ticket":"Set branch ticket/issue segment.","--branch-version":"Set branch version segment.","--checkout":"Choose branch or worktree checkout mode."},mt={"--git-dir":"Set the path to the .git directory.","--work-tree":"Set the path to the working tree root."};function A(r){let n=" ";return Object.entries(r).map(([i,s])=>{let P=Math.max(2,26-i.length);return`${n}${i}${" ".repeat(P)}${s}`}).join(`
3
- `)}function z(r,t){let e=l(),n="(none)";try{n=ct(`git ${o.git_args} branch --show-current`,{stdio:"pipe"}).toString().trim()||"(none)"}catch{}let i=j(r.commit_type.options,o.git_args)||"Unknown",s=r.check_ticket.infer_ticket?U({append_hashtag:r.check_ticket.append_hashtag,prepend_hashtag:r.check_ticket.prepend_hashtag},o.git_args)||"Unknown":"Infer Disabled",P=r.commit_scope.infer_scope_from_branch?W(r.commit_scope.options,o.git_args)||"Unknown":"Infer Disabled",Q=r.commit_type.options.map(N=>N.value).join(", ").trim(),X=r.commit_scope.options.map(N=>N.value).join(", ").trim(),Z=A(pt),tt=A(mt),et=A(ht);console.log(`
4
- ${c.green("\uF489 better-branch")} ${c.gray("v"+e)}
2
+ import {
3
+ create_strict_branch_state,
4
+ infer_scope_from_git,
5
+ infer_ticket_from_git,
6
+ infer_type_from_git,
7
+ optional_message
8
+ } from "./chunk-H5CLUQIL.js";
9
+ import {
10
+ BRANCH_ACTION_OPTIONS,
11
+ BranchState,
12
+ CUSTOM_SCOPE_KEY,
13
+ NOOP_PROMPT_CACHE,
14
+ get_git_root,
15
+ get_package_version,
16
+ get_value_from_cache,
17
+ load_setup,
18
+ set_value_cache
19
+ } from "./chunk-GAAS3VS3.js";
5
20
 
6
- ${c.gray("BRANCH")}
7
- ${n}
8
- ${c.gray("Type")} ${c.blue(i)} ${c.gray("\xB7")} ${c.gray("Scope")} ${c.cyan(P)} ${c.gray("\xB7")} ${c.gray("Ticket")} ${c.magenta(s)}
21
+ // src/branch.ts
22
+ import Configstore from "configstore";
23
+ import { chdir as chdir2 } from "process";
24
+ import { ValiError, parse as parse2 } from "valibot";
9
25
 
10
- ${c.gray("CONFIGURATION")}
11
- ${t}
26
+ // src/prompts/branch-runnable.ts
27
+ var BranchRunnable = class {
28
+ constructor(config2, branch_state, prompt_cache) {
29
+ this.config = config2;
30
+ this.branch_state = branch_state;
31
+ this.prompt_cache = prompt_cache;
32
+ }
33
+ };
12
34
 
13
- ${c.gray("Types")}
14
- ${Q}
35
+ // src/prompts/branch-checkout.prompt.ts
36
+ import * as p from "@clack/prompts";
37
+ var BranchCheckoutPrompt = class extends BranchRunnable {
38
+ async run() {
39
+ if (this.#is_enabled) {
40
+ const branch_or_worktree = await p.select({
41
+ message: this.#message,
42
+ initialValue: this.#initival_values,
43
+ options: BRANCH_ACTION_OPTIONS
44
+ });
45
+ if (p.isCancel(branch_or_worktree))
46
+ process.exit();
47
+ this.#post_run_effects(branch_or_worktree);
48
+ }
49
+ }
50
+ get #message() {
51
+ return `Checkout a branch or create a worktree?`;
52
+ }
53
+ get #is_enabled() {
54
+ return this.config.worktrees.enable;
55
+ }
56
+ get #initival_values() {
57
+ return this.branch_state.checkout || this.config.branch_action_default;
58
+ }
59
+ #post_run_effects(value) {
60
+ this.branch_state.checkout = value;
61
+ }
62
+ };
15
63
 
16
- ${c.gray("Scopes")}
17
- ${X}
64
+ // src/prompts/branch-user.prompt.ts
65
+ import * as p2 from "@clack/prompts";
66
+ var BranchUserPrompt = class extends BranchRunnable {
67
+ async run() {
68
+ if (!this.#is_enabled)
69
+ return;
70
+ const user_name = await p2.text({
71
+ message: this.#message,
72
+ placeholder: "",
73
+ initialValue: this.#initial_value,
74
+ validate: (value) => this.#validate(value)
75
+ });
76
+ if (p2.isCancel(user_name))
77
+ process.exit(0);
78
+ this.#run_post_effects(user_name ?? "");
79
+ }
80
+ get #is_enabled() {
81
+ return this.config.branch_user.enable;
82
+ }
83
+ get #is_required() {
84
+ return this.config.branch_user.required;
85
+ }
86
+ get #message() {
87
+ return this.#is_required ? "Type your git username" : optional_message("Type your git username");
88
+ }
89
+ get #initial_value() {
90
+ return this.branch_state.user || get_value_from_cache(this.prompt_cache, "username");
91
+ }
92
+ #validate(value) {
93
+ if (this.#is_required && !value)
94
+ return "Please enter a username";
95
+ }
96
+ #run_post_effects(prompt_result) {
97
+ this.branch_state.user = prompt_result.replace(/\s+/g, "-").toLowerCase();
98
+ set_value_cache(this.prompt_cache, "username", this.branch_state.user);
99
+ }
100
+ };
18
101
 
19
- ${c.gray("CLI FLAGS")}
20
- ${Z}
102
+ // src/prompts/branch-type.prompt.ts
103
+ import * as p3 from "@clack/prompts";
104
+ var BranchTypePrompt = class extends BranchRunnable {
105
+ async run() {
106
+ if (!this.#is_enabled)
107
+ return;
108
+ const prompt_type = this.config.branch_type.autocomplete ? p3.autocomplete : p3.select;
109
+ const branch_type = await prompt_type({
110
+ message: this.#message,
111
+ initialValue: this.#initial_value,
112
+ options: this.#options
113
+ });
114
+ if (p3.isCancel(branch_type))
115
+ process.exit(0);
116
+ this.#run_post_effects(branch_type);
117
+ }
118
+ get #is_enabled() {
119
+ return this.config.branch_type.enable;
120
+ }
121
+ get #message() {
122
+ return "Select a branch type";
123
+ }
124
+ get #initial_value() {
125
+ return this.branch_state.type || this.config.commit_type.initial_value;
126
+ }
127
+ get #options() {
128
+ return this.config.commit_type.options;
129
+ }
130
+ #run_post_effects(prompt_result) {
131
+ this.branch_state.type = prompt_result;
132
+ }
133
+ };
21
134
 
22
- ${c.gray("Branch Flags")}
23
- ${et}
135
+ // src/prompts/branch-scope.prompt.ts
136
+ import * as p4 from "@clack/prompts";
137
+ var BranchScopePrompt = class extends BranchRunnable {
138
+ async run() {
139
+ if (!this.#is_enabled)
140
+ return;
141
+ const prompt_type = this.config.branch_scope.autocomplete ? p4.autocomplete : p4.select;
142
+ const branch_scope = await prompt_type({
143
+ message: this.#message,
144
+ initialValue: this.#initial_value,
145
+ options: this.#options
146
+ });
147
+ if (p4.isCancel(branch_scope))
148
+ process.exit(0);
149
+ await this.#run_post_effects(branch_scope);
150
+ }
151
+ get #is_enabled() {
152
+ return this.config.branch_scope.enable;
153
+ }
154
+ get #message() {
155
+ return "Select a branch scope";
156
+ }
157
+ get #initial_value() {
158
+ return this.branch_state.scope || this.config.commit_scope.initial_value;
159
+ }
160
+ get #options() {
161
+ return this.config.commit_scope.options;
162
+ }
163
+ get #custom_scope_enabled() {
164
+ return this.config.commit_scope.custom_scope;
165
+ }
166
+ async #run_post_effects(prompt_result) {
167
+ let branch_scope_value = prompt_result;
168
+ if (branch_scope_value === CUSTOM_SCOPE_KEY && this.#custom_scope_enabled) {
169
+ const branch_scope = await p4.text({
170
+ message: "Write a custom scope",
171
+ placeholder: ""
172
+ });
173
+ if (p4.isCancel(branch_scope))
174
+ process.exit(0);
175
+ branch_scope_value = branch_scope ?? "";
176
+ }
177
+ this.branch_state.scope = branch_scope_value;
178
+ }
179
+ };
24
180
 
25
- ${c.gray("Git Flags (Advanced)")}
26
- ${tt}
181
+ // src/prompts/branch-ticket.prompt.ts
182
+ import * as p5 from "@clack/prompts";
183
+ var BranchTicketPrompt = class extends BranchRunnable {
184
+ async run() {
185
+ if (!this.#is_enabled)
186
+ return;
187
+ const ticket = await p5.text({
188
+ message: this.#message,
189
+ placeholder: "",
190
+ validate: (value) => this.#validate(value),
191
+ initialValue: this.branch_state.ticket
192
+ });
193
+ if (p5.isCancel(ticket))
194
+ process.exit(0);
195
+ this.#run_post_effects(ticket ?? "");
196
+ }
197
+ get #is_enabled() {
198
+ return this.config.branch_ticket.enable;
199
+ }
200
+ get #is_required() {
201
+ return this.config.branch_ticket.required;
202
+ }
203
+ get #message() {
204
+ return this.#is_required ? "Type ticket / issue number" : optional_message("Type ticket / issue number");
205
+ }
206
+ #validate(value) {
207
+ if (this.#is_required && !value)
208
+ return "Please enter a ticket / issue";
209
+ }
210
+ #run_post_effects(prompt_result) {
211
+ this.branch_state.ticket = prompt_result;
212
+ }
213
+ };
27
214
 
28
- `)}import*as R from"@clack/prompts";var ft=[d,y,k,x,w,$,I,_],{config:lt,config_source:dt}=V(" better-branch ",o.git_args);bt(lt,dt);async function bt(r,t){if(ut(f(o.git_args)),o.version){let s=l();R.log.step("Better Commits v"+s);return}if(o.help){z(r,t);return}let e=J(E,o.branch_state);if(!o.interactive)try{J(q(r),e)}catch(s){s instanceof _t?R.log.error(`Invalid branch input: ${s.message}`):R.log.error(`Failed to validate branch input: ${s}`),process.exit(0)}let n=r.cache_last_value?new gt("better-commits"):L,i=o.interactive?ft:[_];for(let s of i)await new s(r,e,n).run()}
215
+ // src/prompts/branch-version.prompt.ts
216
+ import * as p6 from "@clack/prompts";
217
+ var BranchVersionPrompt = class extends BranchRunnable {
218
+ async run() {
219
+ if (!this.#is_enabled)
220
+ return;
221
+ const version = await p6.text({
222
+ message: this.#message,
223
+ placeholder: "",
224
+ validate: (value) => this.#validate(value),
225
+ initialValue: this.branch_state.version
226
+ });
227
+ if (p6.isCancel(version))
228
+ process.exit(0);
229
+ this.#run_post_effects(version ?? "");
230
+ }
231
+ get #is_enabled() {
232
+ return this.config.branch_version.enable;
233
+ }
234
+ get #is_required() {
235
+ return this.config.branch_version.required;
236
+ }
237
+ get #message() {
238
+ return this.#is_required ? "Type version number" : optional_message("Type version number");
239
+ }
240
+ #validate(value) {
241
+ if (this.#is_required && !value)
242
+ return "Please enter a version";
243
+ }
244
+ #run_post_effects(prompt_result) {
245
+ this.branch_state.version = prompt_result;
246
+ }
247
+ };
248
+
249
+ // src/prompts/branch-description.prompt.ts
250
+ import * as p7 from "@clack/prompts";
251
+ var BranchDescriptionPrompt = class extends BranchRunnable {
252
+ async run() {
253
+ const description = await p7.text({
254
+ message: this.#message,
255
+ placeholder: "",
256
+ validate: (value) => this.#validate(value),
257
+ initialValue: this.branch_state.description
258
+ });
259
+ if (p7.isCancel(description))
260
+ process.exit(0);
261
+ this.#run_post_effects(description ?? "");
262
+ }
263
+ get #message() {
264
+ return "Type a short description";
265
+ }
266
+ get #max_length() {
267
+ return this.config.branch_description.max_length;
268
+ }
269
+ #validate(value) {
270
+ if (!value)
271
+ return "Please enter a description";
272
+ if (value.length > this.#max_length) {
273
+ return `Exceeded max length. Description max [${this.#max_length}]`;
274
+ }
275
+ }
276
+ #run_post_effects(prompt_result) {
277
+ this.branch_state.description = prompt_result.replace(/\s+/g, "-").toLowerCase();
278
+ }
279
+ };
280
+
281
+ // src/prompts/branch-confirm.prompt.ts
282
+ import * as p8 from "@clack/prompts";
283
+ import { execSync } from "child_process";
284
+ import color from "picocolors";
285
+ import { chdir } from "process";
286
+
287
+ // src/branch-args.ts
288
+ import { parse } from "@bomb.sh/args";
289
+ var BRANCH_OPTIONS = [
290
+ "user",
291
+ "type",
292
+ "scope",
293
+ "description",
294
+ "ticket",
295
+ "branch-version",
296
+ "checkout"
297
+ ];
298
+ var GIT_OPTIONS = ["git-dir", "work-tree"];
299
+ var BOOLEAN_FLAGS = [
300
+ "interactive",
301
+ "dry-run",
302
+ "help",
303
+ "version"
304
+ ];
305
+ var BranchFlags = class {
306
+ #runtime;
307
+ constructor(runtime) {
308
+ this.#runtime = runtime;
309
+ }
310
+ get interactive() {
311
+ return !this.#runtime.no_interactive;
312
+ }
313
+ get dry_run() {
314
+ return this.#runtime.dry_run;
315
+ }
316
+ get help() {
317
+ return this.#runtime.help;
318
+ }
319
+ get version() {
320
+ return this.#runtime.version;
321
+ }
322
+ get git_args() {
323
+ return this.#runtime.git_args;
324
+ }
325
+ get branch_state() {
326
+ return this.#runtime.branch_state;
327
+ }
328
+ };
329
+ var branch_flags = new BranchFlags(
330
+ parse_branch_runtime_flags(process.argv.slice(2))
331
+ );
332
+ function parse_branch_runtime_flags(argv) {
333
+ const parsed = parse(argv, {
334
+ alias: { h: "help", v: "version" },
335
+ boolean: BOOLEAN_FLAGS,
336
+ string: [...BRANCH_OPTIONS, ...GIT_OPTIONS]
337
+ });
338
+ const branch_state = {};
339
+ BRANCH_OPTIONS.forEach((value) => {
340
+ const cli_value = parsed[value];
341
+ if (cli_value) {
342
+ const str = value === "branch-version" ? "version" : value.replace("-", "_");
343
+ if (str === "checkout")
344
+ branch_state[str] = cli_value ?? "branch";
345
+ else if (str === "description")
346
+ branch_state[str] = cli_value.replace(/\s+/g, "-").toLowerCase();
347
+ else
348
+ branch_state[str] = cli_value;
349
+ }
350
+ });
351
+ return {
352
+ help: parsed["help"] === true,
353
+ version: parsed["version"] === true,
354
+ git_args: get_git_args(parsed["git-dir"], parsed["work-tree"]),
355
+ no_interactive: parsed["interactive"] === false,
356
+ dry_run: parsed["dry-run"] === true,
357
+ branch_state
358
+ };
359
+ }
360
+ function get_git_args(git_dir, work_tree) {
361
+ return `${git_dir ? `--git-dir=${git_dir}` : ""} ${work_tree ? `--work-tree=${work_tree}` : ""}`.trim();
362
+ }
363
+
364
+ // src/utils/build-branch.ts
365
+ function build_branch(branch, config2) {
366
+ let res = "";
367
+ config2.branch_order.forEach((b) => {
368
+ const config_key = `branch_${b}`;
369
+ if (branch[b])
370
+ res += branch[b] + config2[config_key].separator;
371
+ });
372
+ if (res.endsWith("-") || res.endsWith("/") || res.endsWith("_")) {
373
+ return res.slice(0, -1).trim();
374
+ }
375
+ return res.trim();
376
+ }
377
+ function build_worktree_path(branch_state, config2, git_root) {
378
+ const repo_name = git_root.split("/").pop() || "repo";
379
+ let worktree_name = config2.worktrees.folder_template;
380
+ worktree_name = worktree_name.replace("{{repo_name}}", repo_name).replace("{{branch_description}}", branch_state.description).replace("{{user}}", branch_state.user || "").replace("{{type}}", branch_state.type || "").replace("{{scope}}", branch_state.scope || "").replace("{{ticket}}", branch_state.ticket || "").replace("{{version}}", branch_state.version || "");
381
+ worktree_name = worktree_name.replace(/\s/g, "").replace(/--+/g, "-").replace(/^-+|-+$/g, "");
382
+ const base_path = config2.worktrees.base_path;
383
+ return `${base_path}${base_path.endsWith("/") ? "" : "/"}${worktree_name}`;
384
+ }
385
+
386
+ // src/prompts/branch-confirm.prompt.ts
387
+ var BranchConfirmPrompt = class extends BranchRunnable {
388
+ async run() {
389
+ this.#run_pre_commands();
390
+ this.#run_checkout();
391
+ this.#run_post_commands();
392
+ }
393
+ get #is_worktree() {
394
+ return this.branch_state.checkout === "worktree";
395
+ }
396
+ get #pre_commands() {
397
+ return this.#is_worktree ? this.config.worktree_pre_commands : this.config.branch_pre_commands;
398
+ }
399
+ get #post_commands() {
400
+ return this.#is_worktree ? this.config.worktree_post_commands : this.config.branch_post_commands;
401
+ }
402
+ get #branch_name() {
403
+ return build_branch(this.branch_state, this.config);
404
+ }
405
+ #run_pre_commands() {
406
+ this.#run_commands(
407
+ this.#pre_commands,
408
+ "Something went wrong when executing pre-commands: "
409
+ );
410
+ }
411
+ #run_checkout() {
412
+ const branch_name = this.#branch_name;
413
+ const branch_flag = this.#verify_branch_name(branch_name);
414
+ if (!this.#is_worktree) {
415
+ const command = `git ${branch_flags.git_args} checkout ${branch_flag} ${branch_name}`;
416
+ if (branch_flags.dry_run) {
417
+ this.#log_dry_run_command(command);
418
+ return;
419
+ }
420
+ try {
421
+ execSync(command, {
422
+ stdio: "inherit"
423
+ });
424
+ p8.log.info(
425
+ `Switched to a new branch '${color.bgGreen(
426
+ " " + color.black(branch_name) + " "
427
+ )}'`
428
+ );
429
+ } catch (err) {
430
+ process.exit(0);
431
+ }
432
+ return;
433
+ }
434
+ try {
435
+ const worktree_name = build_worktree_path(
436
+ this.branch_state,
437
+ this.config,
438
+ get_git_root(branch_flags.git_args)
439
+ );
440
+ const command = `git ${branch_flags.git_args} worktree add ${worktree_name} ${branch_flag} ${branch_name}`;
441
+ if (branch_flags.dry_run) {
442
+ this.#log_dry_run_command(command);
443
+ return;
444
+ }
445
+ execSync(command, {
446
+ stdio: "inherit"
447
+ });
448
+ p8.log.info(
449
+ `Created a new worktree ${color.bgGreen(
450
+ " " + color.black(worktree_name) + " "
451
+ )}, checked out branch ${color.bgGreen(
452
+ " " + color.black(branch_name) + " "
453
+ )}`
454
+ );
455
+ p8.log.info(
456
+ color.bgMagenta(color.black(` cd ${worktree_name} `)) + " to navigate to your new worktree"
457
+ );
458
+ chdir(worktree_name);
459
+ } catch (err) {
460
+ process.exit(0);
461
+ }
462
+ }
463
+ #run_post_commands() {
464
+ this.#run_commands(
465
+ this.#post_commands,
466
+ "Something went wrong when executing post-commands: "
467
+ );
468
+ }
469
+ #run_commands(commands, error_message) {
470
+ commands.forEach((command) => {
471
+ if (branch_flags.dry_run) {
472
+ this.#log_dry_run_command(command);
473
+ return;
474
+ }
475
+ try {
476
+ execSync(command, { stdio: "inherit" });
477
+ } catch (err) {
478
+ p8.log.error(error_message + err);
479
+ process.exit(0);
480
+ }
481
+ });
482
+ }
483
+ #log_dry_run_command(command) {
484
+ p8.log.info(`Dry run: ${command}`);
485
+ }
486
+ #verify_branch_name(branch_name) {
487
+ let branch_flag = "";
488
+ try {
489
+ execSync(`git ${branch_flags.git_args} show-ref ${branch_name}`, {
490
+ encoding: "utf-8"
491
+ });
492
+ p8.log.warning(
493
+ color.yellow(
494
+ `${branch_name} already exists! Checking out existing branch.`
495
+ )
496
+ );
497
+ } catch (err) {
498
+ branch_flag = "-b";
499
+ }
500
+ return branch_flag;
501
+ }
502
+ };
503
+
504
+ // src/branch-help.ts
505
+ import { execSync as execSync2 } from "child_process";
506
+ import color2 from "picocolors";
507
+ var CLI_FLAG_DEFINITIONS = {
508
+ "--interactive": "Run in interactive prompt mode (default behavior).",
509
+ "--dry-run": "Print branch commands without creating a branch or worktree.",
510
+ "--help": "Show help information and exit."
511
+ };
512
+ var BRANCH_FLAG_DEFINITIONS = {
513
+ "--user": "Set branch username segment.",
514
+ "--type": "Set branch type (for example feat, fix, docs).",
515
+ "--scope": "Set branch scope segment.",
516
+ "--description": "Set branch description segment.",
517
+ "--ticket": "Set branch ticket/issue segment.",
518
+ "--branch-version": "Set branch version segment.",
519
+ "--checkout": "Choose branch or worktree checkout mode."
520
+ };
521
+ var GIT_FLAG_DEFINITIONS = {
522
+ "--git-dir": "Set the path to the .git directory.",
523
+ "--work-tree": "Set the path to the working tree root."
524
+ };
525
+ function to_definition_lines(definitions) {
526
+ const description_column = 26;
527
+ const minimum_spacing = 2;
528
+ const indent = " ";
529
+ return Object.entries(definitions).map(([name, description]) => {
530
+ const spaces = Math.max(
531
+ minimum_spacing,
532
+ description_column - name.length
533
+ );
534
+ return `${indent}${name}${" ".repeat(spaces)}${description}`;
535
+ }).join("\n");
536
+ }
537
+ function print_help_text(config2, config_source2) {
538
+ const version = get_package_version();
539
+ let branch = "(none)";
540
+ try {
541
+ branch = execSync2(`git ${branch_flags.git_args} branch --show-current`, {
542
+ stdio: "pipe"
543
+ }).toString().trim() || "(none)";
544
+ } catch {
545
+ }
546
+ const inferred_type = infer_type_from_git(config2.commit_type.options, branch_flags.git_args) || "Unknown";
547
+ const inferred_ticket = config2.check_ticket.infer_ticket ? infer_ticket_from_git(
548
+ {
549
+ append_hashtag: config2.check_ticket.append_hashtag,
550
+ prepend_hashtag: config2.check_ticket.prepend_hashtag
551
+ },
552
+ branch_flags.git_args
553
+ ) || "Unknown" : "Infer Disabled";
554
+ const inferred_scope = config2.commit_scope.infer_scope_from_branch ? infer_scope_from_git(
555
+ config2.commit_scope.options,
556
+ branch_flags.git_args
557
+ ) || "Unknown" : "Infer Disabled";
558
+ const types = config2.commit_type.options.map((option) => option.value).join(", ").trim();
559
+ const scopes = config2.commit_scope.options.map((option) => option.value).join(", ").trim();
560
+ const cli_flags = to_definition_lines(CLI_FLAG_DEFINITIONS);
561
+ const git_flags = to_definition_lines(GIT_FLAG_DEFINITIONS);
562
+ const branch_flags_help = to_definition_lines(BRANCH_FLAG_DEFINITIONS);
563
+ console.log(`
564
+ ${color2.green("\uF489 better-branch")} ${color2.gray("v" + version)}
565
+
566
+ ${color2.gray("BRANCH")}
567
+ ${branch}
568
+ ${color2.gray("Type")} ${color2.blue(inferred_type)} ${color2.gray("\xB7")} ${color2.gray("Scope")} ${color2.cyan(inferred_scope)} ${color2.gray("\xB7")} ${color2.gray("Ticket")} ${color2.magenta(inferred_ticket)}
569
+
570
+ ${color2.gray("CONFIGURATION")}
571
+ ${config_source2}
572
+
573
+ ${color2.gray("Types")}
574
+ ${types}
575
+
576
+ ${color2.gray("Scopes")}
577
+ ${scopes}
578
+
579
+ ${color2.gray("CLI FLAGS")}
580
+ ${cli_flags}
581
+
582
+ ${color2.gray("Branch Flags")}
583
+ ${branch_flags_help}
584
+
585
+ ${color2.gray("Git Flags (Advanced)")}
586
+ ${git_flags}
587
+
588
+ `);
589
+ }
590
+
591
+ // src/branch.ts
592
+ import * as p9 from "@clack/prompts";
593
+ var promptCtors = [
594
+ BranchCheckoutPrompt,
595
+ BranchUserPrompt,
596
+ BranchTypePrompt,
597
+ BranchTicketPrompt,
598
+ BranchScopePrompt,
599
+ BranchVersionPrompt,
600
+ BranchDescriptionPrompt,
601
+ BranchConfirmPrompt
602
+ ];
603
+ var { config, config_source } = load_setup(
604
+ " better-branch ",
605
+ branch_flags.git_args
606
+ );
607
+ main(config, config_source);
608
+ async function main(config2, config_source2) {
609
+ chdir2(get_git_root(branch_flags.git_args));
610
+ if (branch_flags.version) {
611
+ const version = get_package_version();
612
+ p9.log.step("Better Commits v" + version);
613
+ return;
614
+ }
615
+ if (branch_flags.help) {
616
+ print_help_text(config2, config_source2);
617
+ return;
618
+ }
619
+ const branch_state = parse2(BranchState, branch_flags.branch_state);
620
+ if (!branch_flags.interactive) {
621
+ try {
622
+ parse2(create_strict_branch_state(config2), branch_state);
623
+ } catch (err) {
624
+ if (err instanceof ValiError) {
625
+ p9.log.error(`Invalid branch input: ${err.message}`);
626
+ } else {
627
+ p9.log.error(`Failed to validate branch input: ${err}`);
628
+ }
629
+ process.exit(0);
630
+ }
631
+ }
632
+ const prompt_cache = config2.cache_last_value ? new Configstore("better-commits") : NOOP_PROMPT_CACHE;
633
+ const prompts_to_run = branch_flags.interactive ? promptCtors : [BranchConfirmPrompt];
634
+ for (const Prompt of prompts_to_run) {
635
+ await new Prompt(config2, branch_state, prompt_cache).run();
636
+ }
637
+ }