better-commits 1.23.2 โ†’ 1.24.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.
Files changed (68) hide show
  1. package/dist/branch.js +19 -19
  2. package/dist/index.js +31 -53
  3. package/dist/init.js +1 -1
  4. package/dist/messages-ZJeoTfy2.js +1 -0
  5. package/dist/utils-CeUs4BjU.js +259 -0
  6. package/package.json +18 -12
  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
@@ -0,0 +1,259 @@
1
+ import*as e from"@clack/prompts";import*as t from"valibot";import{ValiError as n,parse as r}from"valibot";import{execSync as i}from"child_process";import a from"fs";import{homedir as o}from"os";import{parse as s}from"jsonc-parser";import c from"picocolors";import{parse as l}from"@bomb.sh/args";const u=`custom`,d=[`closes`,`trailer`,`breaking-change`,`deprecated`,`custom`],f=t.picklist([`branch`,`worktree`]),p=t.picklist([`closes`,`trailer`,`breaking-change`,`deprecated`,`custom`]),m=t.picklist([`user`,`version`,`type`,`scope`,`ticket`,`description`]);t.picklist([`branch_user`,`branch_version`,`branch_type`,`branch_scope`,`branch_ticket`,`branch_description`]);const h=[`user`,`version`,`type`,`ticket`,`scope`,`description`],g=[{value:`app`,label:`app`},{value:`shared`,label:`shared`},{value:`server`,label:`server`},{value:`tools`,label:`tools`},{value:``,label:`none`}],_=t.pipe(t.optional(t.object({enable:t.optional(t.boolean(),!0),initial_value:t.optional(t.string(),`feat`),max_items:t.optional(t.pipe(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`),autocomplete:t.optional(t.boolean(),!0),options:t.optional(t.array(t.object({value:t.string(),label:t.optional(t.string()),hint:t.optional(t.string()),emoji:t.optional(t.pipe(t.string(),t.emoji())),trailer:t.optional(t.string())})),[{value:`feat`,label:`feat`,hint:`A new feature`,emoji:`๐ŸŒŸ`,trailer:`Changelog: feature`},{value:`fix`,label:`fix`,hint:`A bug fix`,emoji:`๐Ÿ›`,trailer:`Changelog: fix`},{value:`docs`,label:`docs`,hint:`Documentation only changes`,emoji:`๐Ÿ“š`,trailer:`Changelog: documentation`},{value:`refactor`,label:`refactor`,hint:`A code change that neither fixes a bug nor adds a feature`,emoji:`๐Ÿ”จ`,trailer:`Changelog: refactor`},{value:`perf`,label:`perf`,hint:`A code change that improves performance`,emoji:`๐Ÿš€`,trailer:`Changelog: performance`},{value:`test`,label:`test`,hint:`Adding missing tests or correcting existing tests`,emoji:`๐Ÿšจ`,trailer:`Changelog: test`},{value:`build`,label:`build`,hint:`Changes that affect the build system or external dependencies`,emoji:`๐Ÿšง`,trailer:`Changelog: build`},{value:`ci`,label:`ci`,hint:`Changes to our CI configuration files and scripts`,emoji:`๐Ÿค–`,trailer:`Changelog: ci`},{value:`chore`,label:`chore`,hint:`Other changes that do not modify src or test files`,emoji:`๐Ÿงน`,trailer:`Changelog: chore`},{value:``,label:`none`}])}),{}),t.rawCheck(({dataset:e,addIssue:t})=>{e.typed&&!e.value.options.some(t=>t.value===e.value.initial_value)&&t({message:`Type: initial_value "${e.value.initial_value}" must exist in options`})}),t.transform(e=>({...e,options:e.options.map(t=>({...t,label:t.emoji&&e.append_emoji_to_label?`${t.emoji} ${t.label}`:t.label}))}))),v=t.pipe(t.optional(t.object({enable:t.optional(t.boolean(),!0),custom_scope:t.optional(t.boolean(),!1),max_items:t.optional(t.pipe(t.number(),t.minValue(1)),20),initial_value:t.optional(t.string(),`app`),infer_scope_from_branch:t.optional(t.boolean(),!0),autocomplete:t.optional(t.boolean(),!0),options:t.optional(t.array(t.object({value:t.string(),label:t.optional(t.string()),hint:t.optional(t.string())})),g)}),{}),t.rawCheck(({dataset:e,addIssue:t})=>{if(!e.typed)return;let n=e.value.options.map(e=>e.value);e.value.custom_scope&&n.push(u),n.includes(e.value.initial_value)||t({message:`Scope: initial_value "${e.value.initial_value}" must exist in options`})}),t.transform(e=>{let t=e.options.map(e=>e.value);return e.custom_scope&&!t.includes(`custom`)?{...e,options:[...e.options,{label:u,value:u,hint:`Write a custom scope`}]}:e})),y=t.object({check_status:t.optional(t.boolean(),!0),check_status_autocomplete:t.optional(t.boolean(),!0),commit_type:_,commit_scope:v,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.pipe(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(p),[]),options:t.optional(t.array(p),d)}),{}),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([`/`,`-`,`_`]),`/`),autocomplete:t.optional(t.boolean(),!0)}),{}),branch_scope:t.optional(t.object({enable:t.optional(t.boolean(),!0),separator:t.optional(t.picklist([`/`,`-`,`_`]),`-`),autocomplete:t.optional(t.boolean(),!0)}),{}),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.pipe(t.number(),t.minValue(1)),70),separator:t.optional(t.picklist([``,`/`,`-`,`_`]),``)}),{}),branch_action_default:t.optional(f,`branch`),branch_order:t.optional(t.array(m),h),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())}),{})}),b={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(),``)},x=t.optional(t.object(b),{}),S={user:t.optional(t.string(),``),type:t.optional(t.string(),``),scope:t.optional(t.string(),``),ticket:t.optional(t.string(),``),description:t.optional(t.string(),``),version:t.optional(t.string(),``),checkout:t.optional(f,`branch`)},C=t.optional(t.object(S),{}),w=[`type`,`scope`,`title`,`body`,`ticket`,`closes`,`trailer`,`breaking-title`,`breaking-body`,`deprecates-title`,`deprecates-body`,`custom-footer`],T=[`git-dir`,`work-tree`],E=[`interactive`,`dry-run`,`help`,`version`],D=new class{#e;constructor(e){this.#e=e}get git_args(){return this.#e.git_args}get interactive(){return!this.#e.no_interactive}get dry_run(){return this.#e.dry_run}get help(){return this.#e.help}get version(){return this.#e.version}get commit_state(){return this.#e.commit_state}}(O(process.argv.slice(2)));function O(e){let t=l(e,{alias:{h:`help`,v:`version`},boolean:E,string:[...w,...T]}),n={};return w.forEach(e=>{let r=t[e],i=k(e,r);if(i!==void 0){let t=e.replace(`-`,`_`);n[t]=i}}),{help:t.help===!0,version:t.version===!0,git_args:A(t[`git-dir`],t[`work-tree`]),no_interactive:t.interactive===!1,dry_run:t[`dry-run`]===!0,commit_state:n}}function k(e,t){if(t===void 0)return;if(e!==`closes`)return t;let n=t.trim().toLowerCase();if(n!==`false`&&(t===``||n))return`Closes:`}function A(e,t){return`${e?`--git-dir=${e}`:``} ${t?`--work-tree=${t}`:``}`.trim()}const j=`{
2
+ // Run interactive \`git status\` before composing a commit
3
+ "check_status": true,
4
+ "check_status_autocomplete": true,
5
+
6
+ /* COMMIT FIELDS */
7
+ "commit_type": {
8
+ "enable": true,
9
+
10
+ // Default selected type from options
11
+ "initial_value": "feat",
12
+
13
+ "max_items": 20,
14
+
15
+ // Infer type from the current branch name: user/TYPE/my-branch
16
+ "infer_type_from_branch": true,
17
+
18
+ // Include emoji in prompt label
19
+ "append_emoji_to_label": false,
20
+
21
+ // Include emoji from prompt label in commit message
22
+ "append_emoji_to_commit": false,
23
+
24
+ // "Start" | "After-Colon"
25
+ "emoji_commit_position": "Start",
26
+
27
+ "autocomplete": true,
28
+
29
+ "options": [
30
+ {
31
+ "value": "feat",
32
+ "label": "feat",
33
+ "hint": "A new feature",
34
+ "emoji": "๐ŸŒŸ",
35
+ "trailer": "Changelog: feature"
36
+ },
37
+ {
38
+ "value": "fix",
39
+ "label": "fix",
40
+ "hint": "A bug fix",
41
+ "emoji": "๐Ÿ›",
42
+ "trailer": "Changelog: fix"
43
+ },
44
+ {
45
+ "value": "docs",
46
+ "label": "docs",
47
+ "hint": "Documentation only changes",
48
+ "emoji": "๐Ÿ“š",
49
+ "trailer": "Changelog: documentation"
50
+ },
51
+ {
52
+ "value": "refactor",
53
+ "label": "refactor",
54
+ "hint": "A code change that neither fixes a bug nor adds a feature",
55
+ "emoji": "๐Ÿ”จ",
56
+ "trailer": "Changelog: refactor"
57
+ },
58
+ {
59
+ "value": "perf",
60
+ "label": "perf",
61
+ "hint": "A code change that improves performance",
62
+ "emoji": "๐Ÿš€",
63
+ "trailer": "Changelog: performance"
64
+ },
65
+ {
66
+ "value": "test",
67
+ "label": "test",
68
+ "hint": "Adding missing tests or correcting existing tests",
69
+ "emoji": "๐Ÿšจ",
70
+ "trailer": "Changelog: test"
71
+ },
72
+ {
73
+ "value": "build",
74
+ "label": "build",
75
+ "hint": "Changes that affect the build system or external dependencies",
76
+ "emoji": "๐Ÿšง",
77
+ "trailer": "Changelog: build"
78
+ },
79
+ {
80
+ "value": "ci",
81
+ "label": "ci",
82
+ "hint": "Changes to our CI configuration files and scripts",
83
+ "emoji": "๐Ÿค–",
84
+ "trailer": "Changelog: ci"
85
+ },
86
+ {
87
+ "value": "chore",
88
+ "label": "chore",
89
+ "hint": "Other changes that do not modify src or test files",
90
+ "emoji": "๐Ÿงน",
91
+ "trailer": "Changelog: chore"
92
+ },
93
+ {
94
+ "value": "",
95
+ "label": "none"
96
+ }
97
+ ]
98
+ },
99
+
100
+ "commit_scope": {
101
+ "enable": true,
102
+
103
+ // If true, users can type a scope not listed in options
104
+ "custom_scope": false,
105
+
106
+ // Default selected scope from options
107
+ "initial_value": "app",
108
+
109
+ // Infer scope from the current branch name: user/type/ticket-SCOPE-my-branch
110
+ "infer_scope_from_branch": true,
111
+
112
+ "max_items": 20,
113
+ "autocomplete": true,
114
+ "options": [
115
+ { "value": "app", "label": "app" },
116
+ { "value": "shared", "label": "shared" },
117
+ { "value": "server", "label": "server" },
118
+ { "value": "tools", "label": "tools" },
119
+ { "value": "", "label": "none" }
120
+ ]
121
+ },
122
+
123
+ "check_ticket": {
124
+ // Infer ticket / issue from the branch name - user/type/TICKET-my-branch
125
+ "infer_ticket": true,
126
+
127
+ // Prompt for confirmation / edit before using an inferred ticket
128
+ "confirm_ticket": true,
129
+
130
+ // Add the ticket to the commit title - feat(app): TICKET my commit title
131
+ "add_to_title": true,
132
+
133
+ // Deprecated, prefer \`prepend_hashtag\`
134
+ "append_hashtag": false,
135
+
136
+ // "Never" | "Prompt" | "Always" - 12345 --> #12345
137
+ "prepend_hashtag": "Never",
138
+
139
+ // Wrap the ticket in the commit title: "" | "[]" | "()" | "{}"
140
+ "surround": "",
141
+
142
+ // "start" | "end" | "before-colon" | "beginning"
143
+ "title_position": "start"
144
+ },
145
+
146
+ "commit_title": {
147
+ // Includes total size of title + type + scope + ticket
148
+ "max_size": 70
149
+ },
150
+
151
+ "commit_body": {
152
+ "enable": true,
153
+ "required": false,
154
+
155
+ // Split sentences into multiple lines automatically
156
+ "split_by_period": false
157
+ },
158
+
159
+ "commit_footer": {
160
+ "enable": true,
161
+ "initial_value": [],
162
+
163
+ // "closes", "trailer", "breaking-change", "deprecated", "custom"
164
+ "options": ["closes", "trailer", "breaking-change", "deprecated", "custom"]
165
+ },
166
+
167
+ "breaking_change": {
168
+ // Adds \`!\` to the commit title when a breaking change is selected
169
+ "add_exclamation_to_title": true
170
+ },
171
+
172
+ // Confirm / edit with $GIT_EDITOR or $EDITOR
173
+ "confirm_with_editor": false,
174
+
175
+ // Show a final confirmation prompt before running git commit
176
+ "confirm_commit": true,
177
+
178
+ // Reuse the last known value from a previous canceled or failed commit
179
+ "cache_last_value": true,
180
+
181
+ // Pretty-print the final commit preview before execution
182
+ "print_commit_output": true,
183
+
184
+ /* BRANCH FIELDS */
185
+ // Optional shell commands to run before / after creating branches or worktrees
186
+ "branch_pre_commands": [],
187
+ "branch_post_commands": [],
188
+ "worktree_pre_commands": [],
189
+ "worktree_post_commands": [],
190
+
191
+ "branch_user": {
192
+ "enable": true,
193
+ "required": false,
194
+
195
+ // "/" | "-" | "_" - user/feat/my-branch
196
+ "separator": "/"
197
+ },
198
+
199
+ "branch_type": {
200
+ "enable": true,
201
+ "separator": "/",
202
+ "autocomplete": true,
203
+ },
204
+
205
+ "branch_scope": {
206
+ "enable": true,
207
+ "separator": "-",
208
+ "autocomplete": true,
209
+ },
210
+
211
+ "branch_ticket": {
212
+ "enable": true,
213
+ "required": false,
214
+ "separator": "-"
215
+ },
216
+
217
+ "branch_version": {
218
+ "enable": false,
219
+ "required": false,
220
+ "separator": "/"
221
+ },
222
+
223
+ "branch_description": {
224
+ // Maximum length for the description segment of the branch name
225
+ "max_length": 70,
226
+
227
+ // Allowed values: "" | "/" | "-" | "_"
228
+ "separator": ""
229
+ },
230
+
231
+ // "branch" | "worktree"
232
+ "branch_action_default": "branch",
233
+
234
+ // Order of values in the final branch name
235
+ "branch_order": ["user", "version", "type", "ticket", "scope", "description"],
236
+
237
+ // Deprecated, prefer \`worktrees.enable\`
238
+ "enable_worktrees": true,
239
+
240
+ "worktrees": {
241
+ // If false, always create a branch instead of prompting for a worktree
242
+ "enable": true,
243
+
244
+ // Directory where worktrees are created
245
+ "base_path": "..",
246
+
247
+ // Available template variables include:
248
+ // {{repo_name}}, {{branch_description}}, {{user}}, {{type}}, {{scope}}, {{ticket}}, {{version}}
249
+ "folder_template": "{{repo_name}}-{{ticket}}-{{branch_description}}"
250
+ },
251
+
252
+ /* OTHER FIELDS */
253
+ "overrides": {
254
+ // Useful on Windows or for shells with different multiline behavior
255
+ "shell": "/bin/sh"
256
+ }
257
+ }
258
+ `,M=[`.better-commits.jsonc`,`.better-commits.json`],N=M[0],P=[{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`}],F=[{value:`branch`,label:`Branch`},{value:`worktree`,label:`Worktree`}],I={get:()=>``,set:(e,t)=>{},clear:()=>{}};function L(t=` better-commits `,n=D.git_args){console.clear(),e.intro(`${c.bgCyan(c.black(t))}`);let i=null,o=V();a.existsSync(o)&&(i=R(o));let s=H(B(n));if(s){e.log.step(`Reading from Repository Config`);let t=R(s);return{config:i?{...t,overrides:i.overrides.shell?i.overrides:t.overrides,confirm_with_editor:i.confirm_with_editor,cache_last_value:i.cache_last_value}:t,config_source:`repository`}}if(i)return e.log.step(`Reading from Global Config`),{config:i,config_source:`global`};let l=r(y,{});return e.log.step(`Config not found. Generating default ${N} at $HOME`),a.writeFileSync(o,j),{config:l,config_source:`none`}}function R(t){let n=null;try{n=s(a.readFileSync(t,`utf8`))}catch(n){e.log.error(`Invalid JSON/JSONC config file at ${t}. Exiting.\n`+n),process.exit(0)}return z(n)}function z(t){try{return r(y,t)}catch(t){if(t instanceof n){let n=(t.issues[0].path??[]).map(e=>e.key).filter(e=>typeof e==`string`||typeof e==`number`).join(`.`);e.log.error(`Invalid Configuration: ${c.red(n)}\n`+t.message)}process.exit(0)}}function B(t=D.git_args){let n=`.`;try{n=i(`git ${t} rev-parse --show-toplevel`).toString().trim()}catch{e.log.warn(`Could not find git root. If in a --bare repository, ignore this warning.`)}return n}function V(){return U(o())??o()+`/`+N}function H(e){return U(e)}function U(e){for(let t of M){let n=`${e}/${t}`;if(a.existsSync(n))return n}return null}function W(){try{return JSON.parse(a.readFileSync(new URL(`../package.json`,import.meta.url),`utf8`)).version??`unknown`}catch{return`unknown`}}function G(e,t){return t===e.length-1?``:`
259
+ `}function K(e){let t=e.trim();return t.endsWith(`.`)?t.substring(0,t.length-1).trim():e.trim()}function q(t,n){try{return t.get(n)??``}catch{e.log.warn(`Could not access ${n} from cache. Check that "~/.config" exists. Set "cache_last_value" to false to disable.`)}return``}function J(t,n,r){try{t.set(n,r)}catch{e.log.warn(`Could not access ${n} from cache. Check that "~/.config" exists. Set "cache_last_value" to false to disable.`)}}export{b as _,G as a,W as c,L as d,J as f,C as g,S as h,I as i,H as l,D as m,P as n,K as o,j as p,N as r,B as s,F as t,q as u,x as v,u as y};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "better-commits",
3
3
  "private": false,
4
- "version": "1.23.2",
4
+ "version": "1.24.0",
5
5
  "description": "A CLI for creating better commits following the conventional commits specification",
6
6
  "author": "Erik Verduin (https://github.com/everduin94)",
7
7
  "type": "module",
@@ -13,6 +13,14 @@
13
13
  "commit"
14
14
  ],
15
15
  "main": "dist/index.js",
16
+ "engines": {
17
+ "node": ">=20.19.0"
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "LICENSE",
22
+ "readme.md"
23
+ ],
16
24
  "bin": {
17
25
  "better-commits-init": "./dist/init.js",
18
26
  "better-commits": "./dist/index.js",
@@ -29,7 +37,7 @@
29
37
  "@bomb.sh/args": "^0.3.1",
30
38
  "@clack/core": "^1.2.0",
31
39
  "@clack/prompts": "^1.2.0",
32
- "configstore": "^5.0.1",
40
+ "configstore": "^8.0.0",
33
41
  "jsonc-parser": "^3.3.1",
34
42
  "picocolors": "^1.0.0",
35
43
  "valibot": "^1.3.1"
@@ -38,21 +46,19 @@
38
46
  "start": "tsx ./src/index.ts",
39
47
  "branch": "tsx ./src/branch.ts",
40
48
  "init": "tsx ./src/init.ts",
41
- "build": "tsup",
49
+ "build": "tsdown",
42
50
  "commit": "tsx ./src/index.ts",
43
- "test": "vitest run"
51
+ "test": "vitest run",
52
+ "knip": "knip"
44
53
  },
45
54
  "devDependencies": {
46
55
  "@semantic-release/git": "^10.0.1",
47
- "@semantic-release/npm": "^13.1.3",
48
- "@types/configstore": "^6.0.0",
49
- "@types/node": "^24.10.1",
50
- "jiti": "^1.17.0",
51
- "prettier": "3.2.5",
52
- "semantic-release": "^25.0.2",
53
- "tsup": "^8.0.2",
56
+ "@types/node": "^24.12.4",
57
+ "knip": "^6.15.0",
58
+ "semantic-release": "^25.0.3",
59
+ "tsdown": "^0.21.10",
54
60
  "tsx": "^3.12.3",
55
- "typescript": "^5.4.5",
61
+ "typescript": "^5.9.3",
56
62
  "vitest": "^3.2.4"
57
63
  },
58
64
  "release": {
package/readme.md CHANGED
@@ -3,7 +3,7 @@
3
3
  ![bc-gradient](https://github.com/Everduin94/better-commits/assets/14320878/2f94e6ea-a40f-4f3e-b0b2-5cc7d83a9a7d)
4
4
 
5
5
  [![better commits is enabled](https://img.shields.io/badge/better--commits-enabled?style=for-the-badge&logo=git&color=a6e3a1&logoColor=D9E0EE&labelColor=302D41)](https://github.com/Everduin94/better-commits)
6
- [![downloads](https://img.shields.io/npm/dt/better-commits.svg?style=for-the-badge&logo=npm&color=74c7ec&logoColor=D9E0EE&labelColor=302D41)](https://www.npmjs.com/package/better-commits)
6
+ [![downloads](https://img.shields.io/npm/dt/better-commits.svg?style=for-the-badge&logo=npm&color=74c7ec&logoColor=D9E0EE&labelColor=302D41)](https://npmx.dev/package/better-commits)
7
7
  [![discord](https://img.shields.io/badge/discord-join--discord?style=for-the-badge&logo=discord&color=cba6f7&logoColor=D9E0EE&labelColor=302D41)](https://discord.gg/grHVnZwYup)
8
8
 
9
9
  </h3>
@@ -12,7 +12,7 @@
12
12
  A CLI for writing better commits, following the conventional commits specification.
13
13
  </p>
14
14
 
15
- <video src="https://github.com/Everduin94/better-commits/assets/14320878/8fb15d46-17c4-4e5d-80d9-79abe0a2a00a"></video>
15
+ <video src="https://github.com/Everduin94/better-commits/assets/14320878/8fb15d46-17c4-4e5d-80d9-79abe0a2a00a"></video>
16
16
 
17
17
  ## โœจ Features
18
18
 
@@ -36,6 +36,8 @@ As a side-effect of formatting messages
36
36
 
37
37
  ## ๐Ÿ“ฆ Installation
38
38
 
39
+ > Requires Node.js 20 or newer.
40
+
39
41
  ```sh
40
42
  npm install -g better-commits
41
43
  ```
@@ -1,52 +0,0 @@
1
- {
2
- "commit_type": {
3
- "append_emoji_to_label": true,
4
- "append_emoji_to_commit": false
5
- },
6
- "commit_body": {
7
- "split_by_period": true
8
- },
9
- "commit_scope": {
10
- "enable": true,
11
- "initial_value": "commit",
12
- "options": [
13
- {
14
- "value": "commit",
15
- "label": "commit"
16
- },
17
- {
18
- "value": "branch",
19
- "label": "branch"
20
- },
21
- {
22
- "value": "init",
23
- "label": "init"
24
- },
25
- {
26
- "value": "util",
27
- "label": "util"
28
- },
29
- {
30
- "value": "build",
31
- "label": "build"
32
- },
33
- {
34
- "value": "help",
35
- "label": "help"
36
- },
37
- {
38
- "value": "",
39
- "label": "none"
40
- }
41
- ]
42
- },
43
- "check_ticket": {
44
- "prepend_hashtag": "Always"
45
- },
46
- "branch_pre_commands": [
47
- "git stash",
48
- "git checkout main",
49
- "git pull -r origin main",
50
- "npm install"
51
- ]
52
- }
@@ -1,34 +0,0 @@
1
- name: Publish to NPM
2
-
3
- on:
4
- push:
5
- branches:
6
- - main
7
-
8
- jobs:
9
- publish:
10
- name: Publish
11
- runs-on: ubuntu-latest
12
- permissions:
13
- contents: write
14
- issues: write
15
- pull-requests: write
16
- id-token: write
17
- steps:
18
- - name: Checkout
19
- uses: actions/checkout@v4
20
- with:
21
- fetch-depth: 0
22
- - name: Setup Node.js
23
- uses: actions/setup-node@v4
24
- with:
25
- node-version: "lts/*"
26
- registry-url: "https://registry.npmjs.org"
27
- - name: Install dependencies
28
- run: npm ci
29
- - name: Build package
30
- run: npm run build
31
- - name: Release
32
- env:
33
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
34
- run: npx semantic-release
@@ -1,27 +0,0 @@
1
- name: Test
2
-
3
- on:
4
- pull_request:
5
- push:
6
- branches:
7
- - main
8
-
9
- jobs:
10
- test:
11
- name: npm test
12
- runs-on: ubuntu-latest
13
- steps:
14
- - name: Checkout
15
- uses: actions/checkout@v4
16
-
17
- - name: Setup Node.js
18
- uses: actions/setup-node@v4
19
- with:
20
- node-version: "lts/*"
21
- cache: npm
22
-
23
- - name: Install dependencies
24
- run: npm ci
25
-
26
- - name: Run tests
27
- run: npm run test
package/.prettierignore DELETED
@@ -1,5 +0,0 @@
1
- # Ignore artifacts:
2
- build
3
- coverage
4
- node_modules
5
- dist
package/.prettierrc DELETED
@@ -1 +0,0 @@
1
- {}
@@ -1 +0,0 @@
1
- import{a as _,b as u,d as l,f as p}from"./chunk-B7AGSPP3.js";import*as s from"valibot";function g(t,n){let r=t.scope?t.scope.length+2:0,e=t.type?.length??0,i=n.include_ticket?t.ticket?.length??0:0,o=t.title?.length??0;return r+e+i+o}function a(t){return t.map(r=>r===""?'"" (none)':`"${r}"`).join(", ")}function G(t){let n=t.commit_type.options.map(e=>e.value),r=t.commit_scope.options.map(e=>e.value);return s.pipe(s.object(u),s.rawCheck(({dataset:e,addIssue:i})=>{if(!e.typed)return;let o=e.value.type?`"${e.value.type}"`:"(empty)";e.value.type&&!n.includes(e.value.type)&&i({message:`Invalid --type ${o}. Valid types: ${a(n)}.`})}),s.rawCheck(({dataset:e,addIssue:i})=>{if(!e.typed)return;let o=e.value.scope?`"${e.value.scope}"`:"(empty)";e.value.scope&&!t.commit_scope.custom_scope&&!r.includes(e.value.scope)&&i({message:`Invalid --scope ${o}. Valid scopes: ${a(r)}.`})}),s.rawCheck(({dataset:e,addIssue:i})=>{!e.typed||e.value.title.trim()||i({message:"Missing --title. Provide a non-empty commit title."})}),s.rawCheck(({dataset:e,addIssue:i})=>{if(!e.typed)return;let o=g(e.value,{include_ticket:t.check_ticket.add_to_title});o>t.commit_title.max_size&&i({message:`Title exceeds max width. Current size is ${o}, max is ${t.commit_title.max_size} (includes type, scope, and ticket when enabled).`})}),s.rawCheck(({dataset:e,addIssue:i})=>{e.typed&&t.commit_body.required&&!e.value.body.trim()&&i({message:"Missing --body. commit_body.required is enabled in config."})}),s.rawCheck(({dataset:e,addIssue:i})=>{e.typed&&e.value.closes&&!e.value.ticket&&i({message:'Invalid footer values: --closes requires --ticket (for example: --ticket "ABC-123").'})}),s.rawCheck(({dataset:e,addIssue:i})=>{e.typed&&e.value.breaking_body&&!e.value.breaking_title&&i({message:"Invalid breaking change values: --breaking-body requires --breaking-title."})}),s.rawCheck(({dataset:e,addIssue:i})=>{e.typed&&e.value.deprecates_body&&!e.value.deprecates_title&&i({message:"Invalid deprecation values: --deprecates-body requires --deprecates-title."})}))}function N(t){let n=t.commit_type.options.map(e=>e.value),r=t.commit_scope.options.map(e=>e.value);return s.pipe(s.object(l),s.rawCheck(({dataset:e,addIssue:i})=>{if(!e.typed)return;let o=e.value.type?`"${e.value.type}"`:"(empty)";e.value.type&&!n.includes(e.value.type)&&i({message:`Invalid --type ${o}. Valid types: ${a(n)}.`})}),s.rawCheck(({dataset:e,addIssue:i})=>{if(!e.typed)return;let o=e.value.scope?`"${e.value.scope}"`:"(empty)";e.value.scope&&!t.commit_scope.custom_scope&&!r.includes(e.value.scope)&&i({message:`Invalid --scope ${o}. Valid scopes: ${a(r)}.`})}),s.rawCheck(({dataset:e,addIssue:i})=>{!e.typed||e.value.description.trim()||i({message:"Missing --description. Provide a non-empty branch description."})}),s.rawCheck(({dataset:e,addIssue:i})=>{if(!e.typed)return;let o=e.value.description.trim();o.length>t.branch_description.max_length&&i({message:`Description exceeds max length. Current length is ${o.length}, max is ${t.branch_description.max_length}.`})}),s.rawCheck(({dataset:e,addIssue:i})=>{e.typed&&t.branch_user.required&&!e.value.user.trim()&&i({message:"Missing --user. branch_user.required is enabled in config."})}),s.rawCheck(({dataset:e,addIssue:i})=>{e.typed&&t.branch_ticket.required&&!e.value.ticket.trim()&&i({message:"Missing --ticket. branch_ticket.required is enabled in config."})}),s.rawCheck(({dataset:e,addIssue:i})=>{e.typed&&t.branch_version.required&&!e.value.version.trim()&&i({message:"Missing --branch-version. branch_version.required is enabled in config."})}))}import{execSync as h}from"child_process";var v=/\/(\w+-\d+)/,y=/^(\w+-\d+)/,k=/^([A-Z]+-[\[a-zA-Z\]\d]+)_/,b=/\/([A-Z]+-[\[a-zA-Z\]\d]+)_/,$=/\/(\d+)/,C=/^(\d+)/;function V(t){if(p.interactive)return;let n={ticket:"",type:"",scope:""};if(t.check_ticket.infer_ticket){let e=w({append_hashtag:t.check_ticket.append_hashtag,prepend_hashtag:t.check_ticket.prepend_hashtag},p.git_args);n.ticket=e}let r=x(t.commit_type.options,p.git_args);if(n.type=r,t.commit_scope.enable&&t.commit_scope.infer_scope_from_branch){let e=E(t.commit_scope.options,p.git_args);n.scope=e}return n}function x(t,n){let r=m(n);return r?T(r,t.map(e=>e.value)):""}function w(t,n){let r=m(n);return r?S(r,t):""}function E(t,n){let r=m(n);return r?z(r,t):""}function S(t,n){let r=[t.match(k),t.match(b),t.match(v),t.match($),t.match(y),t.match(C)].filter(e=>e!=null).map(e=>e&&e.length>=2?e[1]:"");return!r.length||!r[0]?"":n.append_hashtag||n.prepend_hashtag==="Always"?`#${r[0]}`:r[0]}function T(t,n){return n.find(e=>{let i=new RegExp(`^${e}-`),o=new RegExp(`-${e}-`),d=new RegExp(`${e}/`);return[t.match(i),t.match(o),t.match(d)].filter(f=>f!=null).length>0})??""}function A(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function z(t,n){return n.map(i=>i.value).filter(i=>i&&i!==_).sort((i,o)=>o.length-i.length).find(i=>new RegExp(`(?:^|[/_-])${A(i)}(?=$|[/_-])`).test(t))??""}function m(t){try{return h(`git ${t} branch --show-current`,{stdio:"pipe"}).toString().trim()}catch{return""}}import c from"picocolors";function D(t){return`${t} ${c.dim("\xB7 restored from cache")}`}function L(t){return`${t} ${c.dim("\xB7 inferred from branch")}`}function B(t){return`${t} ${c.dim("\xB7 optional")}`}function K(t){return`${t} ${c.dim("\xB7 <space> to select")}`}function Y(t){return`${t} ${c.dim("\xB7 <space> to select \xB7 <a> to select all")}`}function F(t){return`${t} ${c.dim("\xB7 dry run - changes will not be committed")}`}export{g as a,G as b,N as c,V as d,x as e,w as f,E as g,D as h,L as i,B as j,K as k,Y as l,F as m};