better-commits 1.16.0 → 1.17.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/branch.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #! /usr/bin/env node
2
- import{d as u,e as d,h,i as f,q as b,r as g}from"./chunk-KYIWYSZF.js";import*as t from"@clack/prompts";import{execSync as m}from"child_process";import w from"configstore";import a from"picocolors";import{chdir as y}from"process";import{parse as C}from"valibot";x(g(" better-branch "));async function x(e){let i=C(u,{}),o="branch";if(e.enable_worktrees){let r=await t.select({message:"Checkout a branch or create a worktree?",initialValue:e.branch_action_default,options:b});t.isCancel(r)&&process.exit(),o=r}if(e.branch_user.enable){let r=O(),n=e.branch_user.required,c=await t.text({message:`Type your git username ${n?"":h} ${f}`.trim(),placeholder:"",initialValue:r,validate:k=>{if(n&&!k)return"Please enter a username"}});t.isCancel(c)&&process.exit(0),i.user=c?.replace(/\s+/g,"-")?.toLowerCase()??"",S(i.user)}if(e.branch_type.enable){let r=e.commit_type.initial_value,n=await t.select({message:"Select a branch type",initialValue:r,options:e.commit_type.options});t.isCancel(n)&&process.exit(0),i.type=n}if(e.branch_ticket.enable){let r=e.branch_ticket.required,n=await t.text({message:`Type ticket / issue number ${r?"":h}`.trim(),placeholder:"",validate:c=>{if(r&&!c)return"Please enter a ticket / issue"}});t.isCancel(n)&&process.exit(0),i.ticket=n}if(e.branch_version.enable){let r=e.branch_version.required,n=await t.text({message:`Type version number ${r?"":h}`.trim(),placeholder:"",validate:c=>{if(r&&!c)return"Please enter a version"}});t.isCancel(n)&&process.exit(0),i.version=n}let s=e.branch_description.max_length,_=await t.text({message:"Type a short description",placeholder:"",validate:r=>{if(!r)return"Please enter a description";if(r.length>s)return`Exceeded max length. Description max [${s}]`}});t.isCancel(_)&&process.exit(0),i.description=_?.replace(/\s+/g,"-")?.toLowerCase()??"",(o==="worktree"?e.worktree_pre_commands:e.branch_pre_commands).forEach(r=>{try{m(r,{stdio:"inherit"})}catch(n){t.log.error("Something went wrong when executing pre-commands: "+n),process.exit(0)}});let p=$(i,e),l=v(p);if(o==="branch")try{m(`git ${d.git_args} checkout ${l} ${p}`,{stdio:"inherit"}),t.log.info(`Switched to a new branch '${a.bgGreen(" "+a.black(p)+" ")}'`)}catch{process.exit(0)}else try{let n=`${i.ticket?`${i.ticket}-`:""}${i.description}`;m(`git worktree add ${n} ${l} ${p}`,{stdio:"inherit"}),t.log.info(`Created a new worktree ${a.bgGreen(+" "+a.black(n)+" ")}, checked out branch ${a.bgGreen(" "+a.black(p)+" ")}`),t.log.info(a.bgMagenta(a.black(` cd ${n} `))+" to navigate to your new worktree"),y(n)}catch{process.exit(0)}(o==="worktree"?e.worktree_post_commands:e.branch_post_commands).forEach(r=>{try{m(r,{stdio:"inherit"})}catch(n){t.log.error("Something went wrong when executing post-commands: "+n),process.exit(0)}})}function $(e,i){let o="";return i.branch_order.forEach(s=>{let _=`branch_${s}`;e[s]&&(o+=e[s]+i[_].separator)}),o.endsWith("-")||o.endsWith("/")||o.endsWith("_")?o.slice(0,-1).trim():o.trim()}function O(){try{return new w("better-commits").get("username")??""}catch{t.log.warn('There was an issue accessing username from cache. Check that the folder "~/.config" exists')}return""}function v(e){let i="";try{m(`git show-ref ${e}`,{encoding:"utf-8"}),t.log.warning(a.yellow(`${e} already exists! Checking out existing branch.`))}catch{i="-b"}return i}function S(e){try{new w("better-commits").set("username",e)}catch{}}
2
+ import{d as u,e as d,h,i as f,q as b,s as g}from"./chunk-7K2QIDID.js";import*as t from"@clack/prompts";import{execSync as m}from"child_process";import w from"configstore";import a from"picocolors";import{chdir as y}from"process";import{parse as C}from"valibot";x(g(" better-branch "));async function x(e){let i=C(u,{}),o="branch";if(e.enable_worktrees){let r=await t.select({message:"Checkout a branch or create a worktree?",initialValue:e.branch_action_default,options:b});t.isCancel(r)&&process.exit(),o=r}if(e.branch_user.enable){let r=O(),n=e.branch_user.required,c=await t.text({message:`Type your git username ${n?"":h} ${f}`.trim(),placeholder:"",initialValue:r,validate:k=>{if(n&&!k)return"Please enter a username"}});t.isCancel(c)&&process.exit(0),i.user=c?.replace(/\s+/g,"-")?.toLowerCase()??"",S(i.user)}if(e.branch_type.enable){let r=e.commit_type.initial_value,n=await t.select({message:"Select a branch type",initialValue:r,options:e.commit_type.options});t.isCancel(n)&&process.exit(0),i.type=n}if(e.branch_ticket.enable){let r=e.branch_ticket.required,n=await t.text({message:`Type ticket / issue number ${r?"":h}`.trim(),placeholder:"",validate:c=>{if(r&&!c)return"Please enter a ticket / issue"}});t.isCancel(n)&&process.exit(0),i.ticket=n}if(e.branch_version.enable){let r=e.branch_version.required,n=await t.text({message:`Type version number ${r?"":h}`.trim(),placeholder:"",validate:c=>{if(r&&!c)return"Please enter a version"}});t.isCancel(n)&&process.exit(0),i.version=n}let s=e.branch_description.max_length,_=await t.text({message:"Type a short description",placeholder:"",validate:r=>{if(!r)return"Please enter a description";if(r.length>s)return`Exceeded max length. Description max [${s}]`}});t.isCancel(_)&&process.exit(0),i.description=_?.replace(/\s+/g,"-")?.toLowerCase()??"",(o==="worktree"?e.worktree_pre_commands:e.branch_pre_commands).forEach(r=>{try{m(r,{stdio:"inherit"})}catch(n){t.log.error("Something went wrong when executing pre-commands: "+n),process.exit(0)}});let p=$(i,e),l=v(p);if(o==="branch")try{m(`git ${d.git_args} checkout ${l} ${p}`,{stdio:"inherit"}),t.log.info(`Switched to a new branch '${a.bgGreen(" "+a.black(p)+" ")}'`)}catch{process.exit(0)}else try{let n=`${i.ticket?`${i.ticket}-`:""}${i.description}`;m(`git worktree add ${n} ${l} ${p}`,{stdio:"inherit"}),t.log.info(`Created a new worktree ${a.bgGreen(+" "+a.black(n)+" ")}, checked out branch ${a.bgGreen(" "+a.black(p)+" ")}`),t.log.info(a.bgMagenta(a.black(` cd ${n} `))+" to navigate to your new worktree"),y(n)}catch{process.exit(0)}(o==="worktree"?e.worktree_post_commands:e.branch_post_commands).forEach(r=>{try{m(r,{stdio:"inherit"})}catch(n){t.log.error("Something went wrong when executing post-commands: "+n),process.exit(0)}})}function $(e,i){let o="";return i.branch_order.forEach(s=>{let _=`branch_${s}`;e[s]&&(o+=e[s]+i[_].separator)}),o.endsWith("-")||o.endsWith("/")||o.endsWith("_")?o.slice(0,-1).trim():o.trim()}function O(){try{return new w("better-commits").get("username")??""}catch{t.log.warn('There was an issue accessing username from cache. Check that the folder "~/.config" exists')}return""}function v(e){let i="";try{m(`git show-ref ${e}`,{encoding:"utf-8"}),t.log.warning(a.yellow(`${e} already exists! Checking out existing branch.`))}catch{i="-b"}return i}function S(e){try{new w("better-commits").set("username",e)}catch{}}
@@ -0,0 +1,4 @@
1
+ import*as p from"valibot";var c="custom",f=["closes","trailer","breaking-change","deprecated","custom"],h=p.picklist(["branch","worktree"]),g=p.picklist(["closes","trailer","breaking-change","deprecated","custom"]),d=p.picklist(["user","version","type","ticket","description"]),$=p.picklist(["branch_user","branch_version","branch_type","branch_ticket","branch_description"]),O=["user","version","type","ticket","description"],x=[{value:"app",label:"app"},{value:"shared",label:"shared"},{value:"server",label:"server"},{value:"tools",label:"tools"},{value:"",label:"none"}],C=[{value:"feat",label:"feat",hint:"A new feature",emoji:"\u{1F31F}",trailer:"Changelog: feature"},{value:"fix",label:"fix",hint:"A bug fix",emoji:"\u{1F41B}",trailer:"Changelog: fix"},{value:"docs",label:"docs",hint:"Documentation only changes",emoji:"\u{1F4DA}",trailer:"Changelog: documentation"},{value:"refactor",label:"refactor",hint:"A code change that neither fixes a bug nor adds a feature",emoji:"\u{1F528}",trailer:"Changelog: refactor"},{value:"perf",label:"perf",hint:"A code change that improves performance",emoji:"\u{1F680}",trailer:"Changelog: performance"},{value:"test",label:"test",hint:"Adding missing tests or correcting existing tests",emoji:"\u{1F6A8}",trailer:"Changelog: test"},{value:"build",label:"build",hint:"Changes that affect the build system or external dependencies",emoji:"\u{1F6A7}",trailer:"Changelog: build"},{value:"ci",label:"ci",hint:"Changes to our CI configuration files and scripts",emoji:"\u{1F916}",trailer:"Changelog: ci"},{value:"chore",label:"chore",hint:"Other changes that do not modify src or test files",emoji:"\u{1F9F9}",trailer:"Changelog: chore"},{value:"",label:"none"}];import*as t from"valibot";var m=t.object({check_status:t.optional(t.boolean(),!0),commit_type:t.transform(t.optional(t.object({enable:t.optional(t.boolean(),!0),initial_value:t.optional(t.string(),"feat"),max_items:t.optional(t.number([t.minValue(1)]),20),infer_type_from_branch:t.optional(t.boolean(),!0),append_emoji_to_label:t.optional(t.boolean(),!1),append_emoji_to_commit:t.optional(t.boolean(),!1),emoji_commit_position:t.optional(t.picklist(["Start","After-Colon"]),"Start"),options:t.optional(t.array(t.object({value:t.string(),label:t.optional(t.string()),hint:t.optional(t.string()),emoji:t.optional(t.string([t.emoji()]),void 0),trailer:t.optional(t.string())})),C)},[t.custom(e=>e.options.map(o=>o.value).includes(e.initial_value),e=>`Type: initial_value "${e.input.initial_value}" must exist in options`)]),{}),e=>{let o=e.options.map(n=>({...n,label:n.emoji&&e.append_emoji_to_label?`${n.emoji} ${n.label}`:n.label}))??[];return{...e,options:o}}),commit_scope:t.transform(t.optional(t.object({enable:t.optional(t.boolean(),!0),custom_scope:t.optional(t.boolean(),!1),max_items:t.optional(t.number([t.minValue(1)]),20),initial_value:t.optional(t.string(),"app"),options:t.optional(t.array(t.object({value:t.string(),label:t.optional(t.string()),hint:t.optional(t.string())})),x)},[t.custom(e=>{let o=e.options.map(n=>n.value);return e.custom_scope&&o.push(c),o.includes(e.initial_value)},e=>`Scope: initial_value "${e.input.initial_value}" must exist in options`)]),{}),e=>{let o=e.options.map(n=>n.value);return e.custom_scope&&!o.includes(c)?{...e,options:[...e.options,{label:c,value:c,hint:"Write a custom scope"}]}:e}),check_ticket:t.optional(t.object({infer_ticket:t.optional(t.boolean(),!0),confirm_ticket:t.optional(t.boolean(),!0),add_to_title:t.optional(t.boolean(),!0),append_hashtag:t.optional(t.boolean(),!1),prepend_hashtag:t.optional(t.picklist(["Never","Always","Prompt"]),"Never"),surround:t.optional(t.picklist(["","()","[]","{}"]),""),title_position:t.optional(t.picklist(["start","end","before-colon","beginning"]),"start")}),{}),commit_title:t.optional(t.object({max_size:t.optional(t.number([t.minValue(1)]),70)}),{}),commit_body:t.optional(t.object({enable:t.optional(t.boolean(),!0),required:t.optional(t.boolean(),!1)}),{}),commit_footer:t.optional(t.object({enable:t.optional(t.boolean(),!0),initial_value:t.optional(t.array(g),[]),options:t.optional(t.array(g),f)}),{}),breaking_change:t.optional(t.object({add_exclamation_to_title:t.optional(t.boolean(),!1)}),{}),cache_last_value:t.optional(t.boolean(),!0),confirm_with_editor:t.optional(t.boolean(),!1),confirm_commit:t.optional(t.boolean(),!0),print_commit_output:t.optional(t.boolean(),!0),branch_pre_commands:t.optional(t.array(t.string()),[]),branch_post_commands:t.optional(t.array(t.string()),[]),worktree_pre_commands:t.optional(t.array(t.string()),[]),worktree_post_commands:t.optional(t.array(t.string()),[]),branch_user:t.optional(t.object({enable:t.optional(t.boolean(),!0),required:t.optional(t.boolean(),!1),separator:t.optional(t.picklist(["/","-","_"]),"/")}),{}),branch_type:t.optional(t.object({enable:t.optional(t.boolean(),!0),separator:t.optional(t.picklist(["/","-","_"]),"/")}),{}),branch_version:t.optional(t.object({enable:t.optional(t.boolean(),!1),required:t.optional(t.boolean(),!1),separator:t.optional(t.picklist(["/","-","_"]),"/")}),{}),branch_ticket:t.optional(t.object({enable:t.optional(t.boolean(),!0),required:t.optional(t.boolean(),!1),separator:t.optional(t.picklist(["/","-","_"]),"-")}),{}),branch_description:t.optional(t.object({max_length:t.optional(t.number([t.minValue(1)]),70),separator:t.optional(t.picklist(["","/","-","_"]),"")}),{}),branch_action_default:t.optional(h,"branch"),branch_order:t.optional(t.array(d),O),enable_worktrees:t.optional(t.boolean(),!0),overrides:t.optional(t.object({shell:t.optional(t.string())}),{})}),H=t.optional(t.object({type:t.optional(t.string(),""),scope:t.optional(t.string(),""),title:t.optional(t.string(),""),body:t.optional(t.string(),""),closes:t.optional(t.string(),""),ticket:t.optional(t.string(),""),breaking_title:t.optional(t.string(),""),breaking_body:t.optional(t.string(),""),deprecates:t.optional(t.string(),""),deprecates_title:t.optional(t.string(),""),deprecates_body:t.optional(t.string(),""),custom_footer:t.optional(t.string(),""),trailer:t.optional(t.string(),"")}),{}),D=t.optional(t.object({user:t.optional(t.string(),""),type:t.optional(t.string(),""),ticket:t.optional(t.string(),""),description:t.optional(t.string(),""),version:t.optional(t.string(),"")}),{});var b=class{#t="";constructor(){}get git_args(){return this.#t}set git_args(o){this.#t=o}},_=new b;import*as i from"@clack/prompts";import{execSync as S}from"child_process";import u from"fs";import{homedir as R}from"os";import a from"picocolors";import{ValiError as N,parse as y}from"valibot";import{argv as E}from"process";var T=".better-commits.json",K=`${a.dim("(<space> to select)")}`,Q=`${a.dim("(<space> to select, <a> to select all)")}`,tt=`${a.dim("(optional)")}`,ot=`${a.dim("(value will be saved)")}`,et=new RegExp(/\/(\w+-\d+)/),nt=new RegExp(/^(\w+-\d+)/),it=new RegExp(/^([A-Z]+-[\[a-zA-Z\]\d]+)_/),rt=new RegExp(/\/([A-Z]+-[\[a-zA-Z\]\d]+)_/),at=new RegExp(/\/(\d+)/),lt=new RegExp(/^(\d+)/),st=[{value:"closes",label:"closes <issue/ticket>",hint:"Attempts to infer ticket from branch"},{value:"trailer",label:"trailer",hint:"Appends trailer based on commit type"},{value:"breaking-change",label:"breaking change",hint:"Add breaking change"},{value:"deprecated",label:"deprecated",hint:"Add deprecated change"},{value:"custom",label:"custom",hint:"Add a custom footer"}],pt=[{value:"branch",label:"Branch"},{value:"worktree",label:"Worktree"}],ct={get:()=>"",set:(e,o)=>{},clear:()=>{}};function vt(e=" better-commits "){console.clear(),i.intro(`${a.bgCyan(a.black(e))}`),P();let o=null,n=I();u.existsSync(n)&&(i.log.step("Found global config"),o=A(n));let l=`${w()}/${T}`;if(u.existsSync(l)){i.log.step("Found repository config");let s=A(l);return o?{...s,overrides:o.overrides.shell?o.overrides:s.overrides,confirm_with_editor:o.confirm_with_editor,cache_last_value:o.cache_last_value}:s}if(o)return o;let v=y(m,{});return i.log.step("Config not found. Generating default .better-commit.json at $HOME"),u.writeFileSync(n,JSON.stringify(v,null,4)),v}function A(e){let o=null;try{o=JSON.parse(u.readFileSync(e,"utf8"))}catch(n){i.log.error(`Invalid JSON file. Exiting.
2
+ `+n),process.exit(0)}return j(o)}function j(e){try{return y(m,e)}catch(o){if(o instanceof N){let r=(o.issues[0].path??[]).map(l=>l.key).join(".");i.log.error(`Invalid Configuration: ${a.red(r)}
3
+ `+o.message)}process.exit(0)}}function _t(e){let o="";try{o=S(`git ${_.git_args} branch --show-current`,{stdio:"pipe"}).toString()}catch{return""}return e.find(r=>{let l=new RegExp(`^${r}-`),v=new RegExp(`-${r}-`),s=new RegExp(`${r}/`);return[o.match(l),o.match(v),o.match(s)].filter(k=>k!=null)?.length})??""}function w(){let e=".";try{e=S(`git ${_.git_args} rev-parse --show-toplevel`).toString().trim()}catch{i.log.warn("Could not find git root. If in a --bare repository, ignore this warning.")}return e}function I(){return R()+"/"+T}function ut(e,o){return o===e.length-1?"":`
4
+ `}function gt(e){let o=e.trim();return o.endsWith(".")?o.substring(0,o.length-1).trim():e.trim()}function P(){_.git_args=`${E[2]??""} ${E[3]??""}`.trim()}function mt(e,o){try{return e.get(o)??""}catch{i.log.warn(`Could not access ${o} from cache. Check that "~/.config" exists. Set "cache_last_value" to false to disable.`)}return""}function bt(e,o,n){try{e.set(o,n)}catch{i.log.warn(`Could not access ${o} from cache. Check that "~/.config" exists. Set "cache_last_value" to false to disable.`)}}export{c as a,m as b,H as c,D as d,_ as e,T as f,K as g,tt as h,ot as i,et as j,nt as k,it as l,rt as m,at as n,lt as o,st as p,pt as q,ct as r,vt as s,_t as t,w as u,ut as v,gt as w,mt as x,bt as y};
package/dist/index.js CHANGED
@@ -1,31 +1,31 @@
1
1
  #! /usr/bin/env node
2
- import{a as S,c as A,e as g,g as y,h as k,j as T,k as O,l as R,m as v,n as P,o as G,p as j,r as N,s as D,t as I,u as $,v as W}from"./chunk-KYIWYSZF.js";import*as s from"@clack/prompts";import c from"picocolors";import{execSync as E}from"child_process";import{chdir as X}from"process";import{parse as F}from"valibot";import{execSync as L}from"child_process";import*as b from"@clack/prompts";import x from"picocolors";var M=["M","T","R","D","A","C"];function C(){let e="";try{e=L(`git ${g.git_args} status --porcelain`,{stdio:"pipe"}).toString()}catch(_){return b.log.error(x.red("Failed to git status"+_)),{index:[],work_tree:[]}}let i=e.split(`
3
- `),a=[],d=[];return i.forEach(_=>{let o=_.trimEnd();if(!o)return;let t=o.substring(2).trim(),r=o.charAt(0).trim(),n=o.charAt(1).trim();(r==="?"||n==="?")&&a.push(t),M.includes(r)&&d.push(t),M.includes(n)&&a.push(t)}),{index:d,work_tree:a}}function V(e){let i=e.join(" ");if(i)try{L(`git ${g.git_args} add ${i}`,{stdio:"pipe"}).toString(),b.log.success(x.green("Changes successfully staged"))}catch{b.log.error(x.red("Failed to stage changes"))}}H(N());async function H(e){let i=F(A,{});if(X(I()),e.check_status){let{index:t,work_tree:r}=C();s.log.step(c.black(c.bgGreen(" Checking Git Status ")));let n=t.reduce((u,h,l)=>c.green(u+h+$(t,l)),"");if(s.log.success(`Changes to be committed:
4
- `+n),r.length){let u=r.reduce((l,m,f)=>c.red(l+m+$(r,f)),"");s.log.error(`Changes not staged for commit:
5
- `+u);let h=await s.multiselect({message:`Some files have not been staged, would you like to add them now? ${y}`,options:[{value:".",label:"."},...r.map(l=>({value:l,label:l}))],required:!1});s.isCancel(h)&&process.exit(0),V(h)}C().index.length||(s.log.error(c.red('no changes added to commit (use "git add" and/or "git commit -a")')),process.exit(0))}let a=e.commit_type.options.reduce((t,r)=>({...t,[r.value]:{emoji:r.emoji??"",trailer:r.trailer??""}}),{});if(e.commit_type.enable){let t="Select a commit type",r=e.commit_type.initial_value;if(e.commit_type.infer_type_from_branch){let p=e.commit_type.options.map(h=>h.value),u=D(p);u&&(t=`Commit type inferred from branch ${c.dim("(confirm / edit)")}`,r=u)}let n=await s.select({message:t,initialValue:r,maxItems:e.commit_type.max_items,options:e.commit_type.options});s.isCancel(n)&&process.exit(0),i.trailer=a[n].trailer,i.type=e.commit_type.append_emoji_to_commit&&e.commit_type.emoji_commit_position==="Start"?`${a[n].emoji} ${n}`.trim():n}if(e.commit_scope.enable){let t=await s.select({message:"Select a commit scope",initialValue:e.commit_scope.initial_value,maxItems:e.commit_scope.max_items,options:e.commit_scope.options});s.isCancel(t)&&process.exit(0),t===S&&e.commit_scope.custom_scope&&(t=await s.text({message:"Write a custom scope",placeholder:""}),s.isCancel(t)&&process.exit(0)),i.scope=t}if(e.check_ticket.infer_ticket)try{let t=E(`git ${g.git_args} branch --show-current`,{stdio:"pipe"}).toString(),r=[t.match(R),t.match(v),t.match(T),t.match(P),t.match(O),t.match(G)].filter(n=>n!=null).map(n=>n&&n.length>=2?n[1]:"");r.length&&r[0]&&(i.ticket=e.check_ticket.append_hashtag||e.check_ticket.prepend_hashtag==="Prompt"?"#"+r[0]:r[0])}catch{}if(e.check_ticket.confirm_ticket){let t=await s.text({message:i.ticket?`Ticket / issue inferred from branch ${c.dim("(confirm / edit)")}`:`Add ticket / issue ${k}`,placeholder:"",initialValue:i.ticket});s.isCancel(t)&&process.exit(0),i.ticket=t??""}e.check_ticket.prepend_hashtag==="Always"&&i.ticket&&!i.ticket.startsWith("#")&&(i.ticket="#"+i.ticket);let d=await s.text({message:"Write a brief title describing the commit",placeholder:"",validate:t=>{if(!t)return"Please enter a title";let r=i.scope?i.scope.length+2:0,n=i.type.length,p=e.check_ticket.add_to_title?i.ticket.length:0;if(r+n+p+t.length>e.commit_title.max_size)return`Exceeded max length. Title max [${e.commit_title.max_size}]`}});s.isCancel(d)&&process.exit(0);let _=d;if(e.commit_type.append_emoji_to_commit&&e.commit_type.emoji_commit_position==="After-Colon"&&(_=`${a[i.type].emoji} ${d}`),i.title=W(_),e.commit_body.enable){let t=await s.text({message:`Write a detailed description of the changes ${k}`,placeholder:"",validate:r=>{if(e.commit_body.required&&!r)return"Please enter a description"}});s.isCancel(t)&&process.exit(0),i.body=t??""}if(e.commit_footer.enable){let t=await s.multiselect({message:`Select optional footers ${y}`,initialValues:e.commit_footer.initial_value,options:j,required:!1});if(s.isCancel(t)&&process.exit(0),t.includes("breaking-change")){let r=await s.text({message:"Breaking changes: Write a short title / summary",placeholder:"",validate:p=>{if(!p)return"Please enter a title / summary"}});s.isCancel(r)&&process.exit(0);let n=await s.text({message:`Breaking Changes: Write a description & migration instructions ${k}`,placeholder:""});s.isCancel(n)&&process.exit(0),i.breaking_title=r,i.breaking_body=n}if(t.includes("deprecated")){let r=await s.text({message:"Deprecated: Write a short title / summary",placeholder:"",validate:p=>{if(!p)return"Please enter a title / summary"}});s.isCancel(r)&&process.exit(0);let n=await s.text({message:`Deprecated: Write a description ${k}`,placeholder:""});s.isCancel(n)&&process.exit(0),i.deprecates_body=n,i.deprecates_title=r}if(t.includes("closes")&&(i.closes="Closes:"),t.includes("custom")){let r=await s.text({message:"Write a custom footer",placeholder:""});s.isCancel(r)&&process.exit(0),i.custom_footer=r}t.includes("trailer")||(i.trailer="")}if(e.confirm_with_editor){let t=e.overrides.shell?{shell:e.overrides.shell,stdio:"inherit"}:{stdio:"inherit"},r=i.trailer?`--trailer="${i.trailer}"`:"";E(`git ${g.git_args} commit -m "${w(i,e,!1,!0,!1)}" ${r} --edit`,t),process.exit(0)}let o=!0;s.note(w(i,e,!0,!1,!0),"Commit Preview"),e.confirm_commit&&(o=await s.confirm({message:"Confirm Commit?"}),s.isCancel(o)&&process.exit(0)),o||(s.log.info("Exiting without commit"),process.exit(0));try{let t=e.overrides.shell?{shell:e.overrides.shell}:{},r=i.trailer?`--trailer="${i.trailer}"`:"",n=E(`git ${g.git_args} commit -m "${w(i,e,!1,!0,!1)}" ${r}`,t).toString().trim();e.print_commit_output&&s.log.info(n)}catch(t){s.log.error("Something went wrong when committing: "+t)}}function w(e,i,a=!1,d=!1,_=!1){let o="";if(e.type&&(o+=a?c.blue(e.type):e.type),e.scope){let l=a?c.cyan(e.scope):e.scope;o+=`(${l})`}let t=e.ticket,r=i.check_ticket.surround;if(e.ticket&&r){let l=r.charAt(0),m=r.charAt(1);t=`${l}${e.ticket}${m}`}let n=i.check_ticket.title_position==="beginning";t&&i.check_ticket.add_to_title&&n&&(o=`${a?c.magenta(t):t} ${o}`);let p=i.check_ticket.title_position==="before-colon";if(t&&i.check_ticket.add_to_title&&p){let l=e.scope||e.type&&!i.check_ticket.surround?" ":"";o+=a?c.magenta(l+t):l+t}e.breaking_title&&i.breaking_change.add_exclamation_to_title&&(o+=a?c.red("!"):"!"),(e.scope||e.type||t&&p)&&(o+=": ");let u=i.check_ticket.title_position==="start",h=i.check_ticket.title_position==="end";if(t&&i.check_ticket.add_to_title&&u&&(o+=a?c.magenta(t)+" ":t+" "),e.title&&(o+=a?c.reset(e.title):e.title),t&&i.check_ticket.add_to_title&&h&&(o+=" "+(a?c.magenta(t):t)),e.body){let m=e.body.split("\\n").map(f=>a?c.reset(f.trim()):f.trim()).join(`
6
- `);o+=a?`
2
+ import{a as A,c as T,e as g,g as x,h as b,j as R,k as v,l as P,m as j,n as G,o as N,p as D,r as I,s as W,t as M,u as V,v as C,w as H,x as k,y}from"./chunk-7K2QIDID.js";import*as s from"@clack/prompts";import c from"picocolors";import{execSync as w}from"child_process";import{chdir as B}from"process";import{parse as q}from"valibot";import{execSync as X}from"child_process";import*as $ from"@clack/prompts";import E from"picocolors";var L=["M","T","R","D","A","C"];function S(){let e="";try{e=X(`git ${g.git_args} status --porcelain`,{stdio:"pipe"}).toString()}catch(u){return $.log.error(E.red("Failed to git status"+u)),{index:[],work_tree:[]}}let t=e.split(`
3
+ `),o=[],h=[];return t.forEach(u=>{let a=u.trimEnd();if(!a)return;let p=a.substring(2).trim(),i=a.charAt(0).trim(),r=a.charAt(1).trim();(i==="?"||r==="?")&&o.push(p),L.includes(i)&&h.push(p),L.includes(r)&&o.push(p)}),{index:h,work_tree:o}}function F(e){let t=e.join(" ");if(t)try{X(`git ${g.git_args} add ${t}`,{stdio:"pipe"}).toString(),$.log.success(E.green("Changes successfully staged"))}catch{$.log.error(E.red("Failed to stage changes"))}}import K from"configstore";Y(W());async function Y(e){let t=q(T,{});B(V());let o=e.cache_last_value?new K("better-commits"):I;if(e.check_status){let{index:i,work_tree:r}=S();s.log.step(c.black(c.bgGreen(" Checking Git Status ")));let n=i.reduce((d,l,m)=>c.green(d+l+C(i,m)),"");if(s.log.success(`Changes to be committed:
4
+ `+n),r.length){let d=r.reduce((m,f,U)=>c.red(m+f+C(r,U)),"");s.log.error(`Changes not staged for commit:
5
+ `+d);let l=await s.multiselect({message:`Some files have not been staged, would you like to add them now? ${x}`,options:[{value:".",label:"."},...r.map(m=>({value:m,label:m}))],required:!1});s.isCancel(l)&&process.exit(0),F(l)}S().index.length||(s.log.error(c.red('no changes added to commit (use "git add" and/or "git commit -a")')),process.exit(0))}let h=e.commit_type.options.reduce((i,r)=>({...i,[r.value]:{emoji:r.emoji??"",trailer:r.trailer??""}}),{});if(e.commit_type.enable){let i="Select a commit type",r=e.commit_type.initial_value;if(e.commit_type.infer_type_from_branch){let _=e.commit_type.options.map(l=>l.value),d=M(_);d&&(i=`Commit type inferred from branch ${c.dim("(confirm / edit)")}`,r=d)}let n=await s.select({message:i,initialValue:k(o,"commit_type")||r,maxItems:e.commit_type.max_items,options:e.commit_type.options});s.isCancel(n)&&process.exit(0),y(o,"commit_type",n),t.trailer=h[n].trailer,t.type=e.commit_type.append_emoji_to_commit&&e.commit_type.emoji_commit_position==="Start"?`${h[n].emoji} ${n}`.trim():n}if(e.commit_scope.enable){let i=await s.select({message:"Select a commit scope",initialValue:k(o,"commit_scope")||e.commit_scope.initial_value,maxItems:e.commit_scope.max_items,options:e.commit_scope.options});s.isCancel(i)&&process.exit(0),y(o,"commit_scope",i),i===A&&e.commit_scope.custom_scope&&(i=await s.text({message:"Write a custom scope",placeholder:""}),s.isCancel(i)&&process.exit(0)),t.scope=i}if(e.check_ticket.infer_ticket)try{let i=w(`git ${g.git_args} branch --show-current`,{stdio:"pipe"}).toString(),r=[i.match(P),i.match(j),i.match(R),i.match(G),i.match(v),i.match(N)].filter(n=>n!=null).map(n=>n&&n.length>=2?n[1]:"");r.length&&r[0]&&(t.ticket=e.check_ticket.append_hashtag||e.check_ticket.prepend_hashtag==="Prompt"?"#"+r[0]:r[0])}catch{}if(e.check_ticket.confirm_ticket){let i=await s.text({message:t.ticket?`Ticket / issue inferred from branch ${c.dim("(confirm / edit)")}`:`Add ticket / issue ${b}`,placeholder:"",initialValue:k(o,"commit_ticket")||t.ticket});s.isCancel(i)&&process.exit(0),y(o,"commit_ticket",i),t.ticket=i??""}e.check_ticket.prepend_hashtag==="Always"&&t.ticket&&!t.ticket.startsWith("#")&&(t.ticket="#"+t.ticket);let u=await s.text({message:"Write a brief title describing the commit",initialValue:k(o,"commit_title")||"",placeholder:"",validate:i=>{if(!i)return"Please enter a title";let r=t.scope?t.scope.length+2:0,n=t.type.length,_=e.check_ticket.add_to_title?t.ticket.length:0;if(r+n+_+i.length>e.commit_title.max_size)return`Exceeded max length. Title max [${e.commit_title.max_size}]`}});s.isCancel(u)&&process.exit(0),y(o,"commit_title",u);let a=u;if(e.commit_type.append_emoji_to_commit&&e.commit_type.emoji_commit_position==="After-Colon"&&(a=`${h[t.type].emoji} ${u}`),t.title=H(a),e.commit_body.enable){let i=await s.text({message:`Write a detailed description of the changes ${b}`,initialValue:k(o,"commit_body")||"",placeholder:"",validate:r=>{if(e.commit_body.required&&!r)return"Please enter a description"}});s.isCancel(i)&&process.exit(0),y(o,"commit_body",i),t.body=i??""}if(e.commit_footer.enable){let i=k(o,"commit_footer").split(","),r=await s.multiselect({message:`Select optional footers ${x}`,initialValues:i||e.commit_footer.initial_value,options:D,required:!1});if(s.isCancel(r)&&process.exit(0),y(o,"commit_footer",r.join(",")),r.includes("breaking-change")){let n=await s.text({message:"Breaking changes: Write a short title / summary",placeholder:"",validate:d=>{if(!d)return"Please enter a title / summary"}});s.isCancel(n)&&process.exit(0);let _=await s.text({message:`Breaking Changes: Write a description & migration instructions ${b}`,placeholder:""});s.isCancel(_)&&process.exit(0),t.breaking_title=n,t.breaking_body=_}if(r.includes("deprecated")){let n=await s.text({message:"Deprecated: Write a short title / summary",placeholder:"",validate:d=>{if(!d)return"Please enter a title / summary"}});s.isCancel(n)&&process.exit(0);let _=await s.text({message:`Deprecated: Write a description ${b}`,placeholder:""});s.isCancel(_)&&process.exit(0),t.deprecates_body=_,t.deprecates_title=n}if(r.includes("closes")&&(t.closes="Closes:"),r.includes("custom")){let n=await s.text({message:"Write a custom footer",placeholder:""});s.isCancel(n)&&process.exit(0),t.custom_footer=n}r.includes("trailer")||(t.trailer="")}if(e.confirm_with_editor){let i=e.overrides.shell?{shell:e.overrides.shell,stdio:"inherit"}:{stdio:"inherit"},r=t.trailer?`--trailer="${t.trailer}"`:"";w(`git ${g.git_args} commit -m "${O(t,e,!1,!0,!1)}" ${r} --edit`,i),process.exit(0)}let p=!0;e.print_commit_output&&s.note(O(t,e,!0,!1,!0),"Commit Preview"),e.confirm_commit&&(p=await s.confirm({message:"Confirm Commit?"}),s.isCancel(p)&&process.exit(0)),p||(s.log.info("Exiting without commit"),process.exit(0));try{s.log.info("Committing changes...");let i=e.overrides.shell?{shell:e.overrides.shell,stdio:"inherit"}:{stdio:"inherit"},r=t.trailer?`--trailer="${t.trailer}"`:"";w(`git ${g.git_args} commit -m "${O(t,e,!1,!0,!1)}" ${r}`,i)}catch(i){s.log.error("Something went wrong when committing: "+i)}s.log.success("Commit Complete"),o.clear()}function O(e,t,o=!1,h=!1,u=!1){let a="";if(e.type&&(a+=o?c.blue(e.type):e.type),e.scope){let l=o?c.cyan(e.scope):e.scope;a+=`(${l})`}let p=e.ticket,i=t.check_ticket.surround;if(e.ticket&&i){let l=i.charAt(0),m=i.charAt(1);p=`${l}${e.ticket}${m}`}let r=t.check_ticket.title_position==="beginning";p&&t.check_ticket.add_to_title&&r&&(a=`${o?c.magenta(p):p} ${a}`);let n=t.check_ticket.title_position==="before-colon";if(p&&t.check_ticket.add_to_title&&n){let l=e.scope||e.type&&!t.check_ticket.surround?" ":"";a+=o?c.magenta(l+p):l+p}e.breaking_title&&t.breaking_change.add_exclamation_to_title&&(a+=o?c.red("!"):"!"),(e.scope||e.type||p&&n)&&(a+=": ");let _=t.check_ticket.title_position==="start",d=t.check_ticket.title_position==="end";if(p&&t.check_ticket.add_to_title&&_&&(a+=o?c.magenta(p)+" ":p+" "),e.title&&(a+=o?c.reset(e.title):e.title),p&&t.check_ticket.add_to_title&&d&&(a+=" "+(o?c.magenta(p):p)),e.body){let m=e.body.split("\\n").map(f=>o?c.reset(f.trim()):f.trim()).join(`
6
+ `);a+=o?`
7
7
 
8
8
  ${m}`:`
9
9
 
10
- ${m}`}if(e.breaking_title){let l=a?c.red(`BREAKING CHANGE: ${e.breaking_title}`):`BREAKING CHANGE: ${e.breaking_title}`;o+=`
10
+ ${m}`}if(e.breaking_title){let l=o?c.red(`BREAKING CHANGE: ${e.breaking_title}`):`BREAKING CHANGE: ${e.breaking_title}`;a+=`
11
11
 
12
- ${l}`}if(e.breaking_body){let l=a?c.red(e.breaking_body):e.breaking_body;o+=`
12
+ ${l}`}if(e.breaking_body){let l=o?c.red(e.breaking_body):e.breaking_body;a+=`
13
13
 
14
- ${l}`}if(e.deprecates_title){let l=a?c.yellow(`DEPRECATED: ${e.deprecates_title}`):`DEPRECATED: ${e.deprecates_title}`;o+=`
14
+ ${l}`}if(e.deprecates_title){let l=o?c.yellow(`DEPRECATED: ${e.deprecates_title}`):`DEPRECATED: ${e.deprecates_title}`;a+=`
15
15
 
16
- ${l}`}if(e.deprecates_body){let l=a?c.yellow(e.deprecates_body):e.deprecates_body;o+=`
16
+ ${l}`}if(e.deprecates_body){let l=o?c.yellow(e.deprecates_body):e.deprecates_body;a+=`
17
17
 
18
- ${l}`}if(e.custom_footer){let m=e.custom_footer.split("\\n").map(f=>a?c.reset(f.trim()):f.trim()).join(`
19
- `);o+=a?`
18
+ ${l}`}if(e.custom_footer){let m=e.custom_footer.split("\\n").map(f=>o?c.reset(f.trim()):f.trim()).join(`
19
+ `);a+=o?`
20
20
 
21
21
  ${m}`:`
22
22
 
23
- ${m}`}return e.closes&&e.ticket&&(o+=a?`
23
+ ${m}`}return e.closes&&e.ticket&&(a+=o?`
24
24
 
25
25
  ${c.reset(e.closes)} ${c.magenta(e.ticket)}`:`
26
26
 
27
- ${e.closes} ${e.ticket}`),_&&e.trailer&&(o+=a?`
27
+ ${e.closes} ${e.ticket}`),u&&e.trailer&&(a+=o?`
28
28
 
29
29
  ${c.dim(e.trailer)}`:`
30
30
 
31
- ${e.trailer}`),d&&(o=o.replaceAll('"','\\"')),o}export{H as main};
31
+ ${e.trailer}`),h&&(a=a.replaceAll('"','\\"')),a}export{Y as main};
package/dist/init.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #! /usr/bin/env node
2
- import{b as r,f as e,t as i}from"./chunk-KYIWYSZF.js";import*as t from"@clack/prompts";import c from"fs";import o from"picocolors";import{parse as l}from"valibot";try{console.clear(),t.intro(`${o.bgCyan(o.black(" better-commits-init "))}`);let s=`${i()}/${e}`,m=l(r,{});c.writeFileSync(s,JSON.stringify(m,null,4)),t.log.success(`${o.green("Successfully created .better-commits.json")}`),t.outro(`Run ${o.bgBlack(o.white("better-commits"))} to start the CLI`)}catch{t.log.error(`${o.red("Could not determine git root folder. better-commits-init must be used in a git repository")}`)}
2
+ import{b as r,f as e,u as i}from"./chunk-7K2QIDID.js";import*as t from"@clack/prompts";import c from"fs";import o from"picocolors";import{parse as l}from"valibot";try{console.clear(),t.intro(`${o.bgCyan(o.black(" better-commits-init "))}`);let s=`${i()}/${e}`,m=l(r,{});c.writeFileSync(s,JSON.stringify(m,null,4)),t.log.success(`${o.green("Successfully created .better-commits.json")}`),t.outro(`Run ${o.bgBlack(o.white("better-commits"))} to start the CLI`)}catch{t.log.error(`${o.red("Could not determine git root folder. better-commits-init must be used in a git repository")}`)}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "better-commits",
3
3
  "private": false,
4
- "version": "1.16.0",
4
+ "version": "1.17.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",
package/readme.md CHANGED
@@ -91,7 +91,7 @@ Better-commits (& better-branch) are highly flexible with sane defaults. These o
91
91
  "commit_type": {
92
92
  "enable": true,
93
93
  "initial_value": "feat",
94
- "max_items": Infinity,
94
+ "max_items": 20,
95
95
  "infer_type_from_branch": true,
96
96
  "append_emoji_to_label": false,
97
97
  "append_emoji_to_commit": false,
@@ -170,7 +170,7 @@ Better-commits (& better-branch) are highly flexible with sane defaults. These o
170
170
  "enable": true,
171
171
  "custom_scope": false,
172
172
  "initial_value": "app",
173
- "max_items": Infinity
173
+ "max_items": 20
174
174
  "options": [
175
175
  {
176
176
  "value": "app",
@@ -219,6 +219,7 @@ Better-commits (& better-branch) are highly flexible with sane defaults. These o
219
219
  "add_exclamation_to_title": true
220
220
  },
221
221
  "confirm_commit": true,
222
+ "cache_last_value": true,
222
223
  "confirm_with_editor": false,
223
224
  "print_commit_output": true,
224
225
  "branch_pre_commands": [],
@@ -316,6 +317,7 @@ Expand to see explanations and possible values
316
317
  | `breaking_change.add_exclamation_to_title` | If true adds exclamation mark to title for breaking changes |
317
318
  | `confirm_commit` | If true manually confirm commit at end |
318
319
  | `confirm_with_editor` | Confirm / Edit commit with $GIT_EDITOR / $EDITOR |
320
+ | `cache_last_value` | Reuse last prompt value after cancel |
319
321
  | `print_commit_output` | If true pretty print commit preview |
320
322
  | `overrides.shell` | Override default shell, useful for windows users |
321
323
 
package/src/index.ts CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  import * as p from "@clack/prompts";
4
4
  import color from "picocolors";
5
- import { execSync } from "child_process";
5
+ import { StdioOptions, execSync } from "child_process";
6
6
  import { chdir } from "process";
7
7
  import { Output, parse } from "valibot";
8
8
  import { CommitState, Config } from "./valibot-state";
@@ -21,16 +21,23 @@ import {
21
21
  get_git_root,
22
22
  REGEX_SLASH_UND,
23
23
  REGEX_START_UND,
24
+ get_value_from_cache,
25
+ set_value_cache,
26
+ NOOP_PROMPT_CACHE,
24
27
  } from "./utils";
25
28
  import { git_add, git_status } from "./git";
26
29
  import { CUSTOM_SCOPE_KEY, V_FOOTER_OPTIONS } from "./valibot-consts";
27
30
  import { flags } from "./args";
31
+ import Configstore from "configstore";
28
32
 
29
33
  main(load_setup());
30
34
 
31
35
  export async function main(config: Output<typeof Config>) {
32
36
  let commit_state = parse(CommitState, {});
33
37
  chdir(get_git_root());
38
+ const prompt_cache = config.cache_last_value
39
+ ? new Configstore("better-commits")
40
+ : NOOP_PROMPT_CACHE;
34
41
 
35
42
  if (config.check_status) {
36
43
  let { index, work_tree } = git_status();
@@ -94,11 +101,13 @@ export async function main(config: Output<typeof Config>) {
94
101
  }
95
102
  const commit_type = await p.select({
96
103
  message,
97
- initialValue: initial_value,
104
+ initialValue:
105
+ get_value_from_cache(prompt_cache, "commit_type") || initial_value,
98
106
  maxItems: config.commit_type.max_items,
99
107
  options: config.commit_type.options,
100
108
  });
101
109
  if (p.isCancel(commit_type)) process.exit(0);
110
+ set_value_cache(prompt_cache, "commit_type", commit_type);
102
111
  commit_state.trailer = value_to_data[commit_type].trailer;
103
112
  commit_state.type =
104
113
  config.commit_type.append_emoji_to_commit &&
@@ -110,11 +119,15 @@ export async function main(config: Output<typeof Config>) {
110
119
  if (config.commit_scope.enable) {
111
120
  let commit_scope = await p.select({
112
121
  message: "Select a commit scope",
113
- initialValue: config.commit_scope.initial_value,
122
+ initialValue:
123
+ get_value_from_cache(prompt_cache, "commit_scope") ||
124
+ config.commit_scope.initial_value,
114
125
  maxItems: config.commit_scope.max_items,
115
126
  options: config.commit_scope.options,
116
127
  });
117
128
  if (p.isCancel(commit_scope)) process.exit(0);
129
+ set_value_cache(prompt_cache, "commit_scope", commit_scope);
130
+
118
131
  if (commit_scope === CUSTOM_SCOPE_KEY && config.commit_scope.custom_scope) {
119
132
  commit_scope = await p.text({
120
133
  message: "Write a custom scope",
@@ -158,9 +171,12 @@ export async function main(config: Output<typeof Config>) {
158
171
  ? `Ticket / issue inferred from branch ${color.dim("(confirm / edit)")}`
159
172
  : `Add ticket / issue ${OPTIONAL_PROMPT}`,
160
173
  placeholder: "",
161
- initialValue: commit_state.ticket,
174
+ initialValue:
175
+ get_value_from_cache(prompt_cache, "commit_ticket") ||
176
+ commit_state.ticket,
162
177
  });
163
178
  if (p.isCancel(user_commit_ticket)) process.exit(0);
179
+ set_value_cache(prompt_cache, "commit_ticket", user_commit_ticket);
164
180
  commit_state.ticket = user_commit_ticket ?? "";
165
181
  }
166
182
 
@@ -174,6 +190,7 @@ export async function main(config: Output<typeof Config>) {
174
190
 
175
191
  const commit_title = await p.text({
176
192
  message: "Write a brief title describing the commit",
193
+ initialValue: get_value_from_cache(prompt_cache, "commit_title") || "",
177
194
  placeholder: "",
178
195
  validate: (value) => {
179
196
  if (!value) return "Please enter a title";
@@ -195,6 +212,8 @@ export async function main(config: Output<typeof Config>) {
195
212
  },
196
213
  });
197
214
  if (p.isCancel(commit_title)) process.exit(0);
215
+ set_value_cache(prompt_cache, "commit_title", commit_title);
216
+
198
217
  let commit_title_with_emoji = commit_title;
199
218
  if (
200
219
  config.commit_type.append_emoji_to_commit &&
@@ -206,6 +225,7 @@ export async function main(config: Output<typeof Config>) {
206
225
  if (config.commit_body.enable) {
207
226
  const commit_body = await p.text({
208
227
  message: `Write a detailed description of the changes ${OPTIONAL_PROMPT}`,
228
+ initialValue: get_value_from_cache(prompt_cache, "commit_body") || "",
209
229
  placeholder: "",
210
230
  validate: (val) => {
211
231
  if (config.commit_body.required && !val)
@@ -213,13 +233,18 @@ export async function main(config: Output<typeof Config>) {
213
233
  },
214
234
  });
215
235
  if (p.isCancel(commit_body)) process.exit(0);
236
+ set_value_cache(prompt_cache, "commit_body", commit_body);
216
237
  commit_state.body = commit_body ?? "";
217
238
  }
218
239
 
219
240
  if (config.commit_footer.enable) {
241
+ const cache_footer = get_value_from_cache(
242
+ prompt_cache,
243
+ "commit_footer",
244
+ ).split(",");
220
245
  const commit_footer = await p.multiselect({
221
246
  message: `Select optional footers ${SPACE_TO_SELECT}`,
222
- initialValues: config.commit_footer.initial_value,
247
+ initialValues: cache_footer || config.commit_footer.initial_value,
223
248
  options: COMMIT_FOOTER_OPTIONS as {
224
249
  value: Output<typeof V_FOOTER_OPTIONS>;
225
250
  label: string;
@@ -228,6 +253,7 @@ export async function main(config: Output<typeof Config>) {
228
253
  required: false,
229
254
  });
230
255
  if (p.isCancel(commit_footer)) process.exit(0);
256
+ set_value_cache(prompt_cache, "commit_footer", commit_footer.join(","));
231
257
 
232
258
  if (commit_footer.includes("breaking-change")) {
233
259
  const breaking_changes_title = await p.text({
@@ -285,8 +311,8 @@ export async function main(config: Output<typeof Config>) {
285
311
 
286
312
  if (config.confirm_with_editor) {
287
313
  const options = config.overrides.shell
288
- ? { shell: config.overrides.shell, stdio: "inherit" }
289
- : { stdio: "inherit" };
314
+ ? { shell: config.overrides.shell, stdio: "inherit" as StdioOptions }
315
+ : { stdio: "inherit" as StdioOptions };
290
316
  const trailer = commit_state.trailer
291
317
  ? `--trailer="${commit_state.trailer}"`
292
318
  : "";
@@ -298,10 +324,12 @@ export async function main(config: Output<typeof Config>) {
298
324
  }
299
325
 
300
326
  let continue_commit = true;
301
- p.note(
302
- build_commit_string(commit_state, config, true, false, true),
303
- "Commit Preview",
304
- );
327
+ if (config.print_commit_output) {
328
+ p.note(
329
+ build_commit_string(commit_state, config, true, false, true),
330
+ "Commit Preview",
331
+ );
332
+ }
305
333
  if (config.confirm_commit) {
306
334
  continue_commit = (await p.confirm({
307
335
  message: "Confirm Commit?",
@@ -315,22 +343,22 @@ export async function main(config: Output<typeof Config>) {
315
343
  }
316
344
 
317
345
  try {
346
+ p.log.info("Committing changes...");
318
347
  const options = config.overrides.shell
319
- ? { shell: config.overrides.shell }
320
- : {};
348
+ ? { shell: config.overrides.shell, stdio: "inherit" as StdioOptions }
349
+ : { stdio: "inherit" as StdioOptions };
321
350
  const trailer = commit_state.trailer
322
351
  ? `--trailer="${commit_state.trailer}"`
323
352
  : "";
324
- const output = execSync(
353
+ execSync(
325
354
  `git ${flags.git_args} commit -m "${build_commit_string(commit_state, config, false, true, false)}" ${trailer}`,
326
355
  options,
327
- )
328
- .toString()
329
- .trim();
330
- if (config.print_commit_output) p.log.info(output);
356
+ );
331
357
  } catch (err) {
332
358
  p.log.error("Something went wrong when committing: " + err);
333
359
  }
360
+ p.log.success("Commit Complete");
361
+ prompt_cache.clear();
334
362
  }
335
363
 
336
364
  function build_commit_string(
package/src/utils.ts CHANGED
@@ -8,6 +8,7 @@ import { Config } from "./valibot-state";
8
8
  import { V_BRANCH_ACTIONS } from "./valibot-consts";
9
9
  import { argv } from "process";
10
10
  import { flags } from "./args";
11
+ import Configstore from "configstore";
11
12
 
12
13
  export const CONFIG_FILE_NAME = ".better-commits.json";
13
14
  export const SPACE_TO_SELECT = `${color.dim("(<space> to select)")}`;
@@ -56,6 +57,12 @@ export const BRANCH_ACTION_OPTIONS: {
56
57
  { value: "worktree", label: "Worktree" },
57
58
  ];
58
59
 
60
+ export const NOOP_PROMPT_CACHE = {
61
+ get: () => "",
62
+ set: (key: string, value: string) => {},
63
+ clear: () => {},
64
+ } as unknown as Configstore;
65
+
59
66
  /* LOAD */
60
67
  export function load_setup(
61
68
  cli_name = " better-commits ",
@@ -84,6 +91,7 @@ export function load_setup(
84
91
  ? global_config.overrides
85
92
  : repo_config.overrides,
86
93
  confirm_with_editor: global_config.confirm_with_editor,
94
+ cache_last_value: global_config.cache_last_value,
87
95
  }
88
96
  : repo_config;
89
97
  }
@@ -187,3 +195,32 @@ export function clean_commit_title(title: string): string {
187
195
  function set_non_configuration_arguments() {
188
196
  flags.git_args = `${argv[2] ?? ""} ${argv[3] ?? ""}`.trim();
189
197
  }
198
+
199
+ export function get_value_from_cache(
200
+ config_store: Configstore,
201
+ key: string,
202
+ ): string {
203
+ try {
204
+ return config_store.get(key) ?? "";
205
+ } catch (err) {
206
+ p.log.warn(
207
+ `Could not access ${key} from cache. Check that "~/.config" exists. Set "cache_last_value" to false to disable.`,
208
+ );
209
+ }
210
+
211
+ return "";
212
+ }
213
+
214
+ export function set_value_cache(
215
+ config_store: Configstore,
216
+ key: string,
217
+ value: string,
218
+ ): void {
219
+ try {
220
+ config_store.set(key, value);
221
+ } catch (err) {
222
+ p.log.warn(
223
+ `Could not access ${key} from cache. Check that "~/.config" exists. Set "cache_last_value" to false to disable.`,
224
+ );
225
+ }
226
+ }
@@ -162,6 +162,7 @@ export const Config = v.object({
162
162
  }),
163
163
  {},
164
164
  ),
165
+ cache_last_value: v.optional(v.boolean(), true),
165
166
  confirm_with_editor: v.optional(v.boolean(), false),
166
167
  confirm_commit: v.optional(v.boolean(), true),
167
168
  print_commit_output: v.optional(v.boolean(), true),
@@ -1,4 +0,0 @@
1
- import*as p from"valibot";var c="custom",f=["closes","trailer","breaking-change","deprecated","custom"],d=p.picklist(["branch","worktree"]),g=p.picklist(["closes","trailer","breaking-change","deprecated","custom"]),h=p.picklist(["user","version","type","ticket","description"]),L=p.picklist(["branch_user","branch_version","branch_type","branch_ticket","branch_description"]),O=["user","version","type","ticket","description"],x=[{value:"app",label:"app"},{value:"shared",label:"shared"},{value:"server",label:"server"},{value:"tools",label:"tools"},{value:"",label:"none"}],E=[{value:"feat",label:"feat",hint:"A new feature",emoji:"\u{1F31F}",trailer:"Changelog: feature"},{value:"fix",label:"fix",hint:"A bug fix",emoji:"\u{1F41B}",trailer:"Changelog: fix"},{value:"docs",label:"docs",hint:"Documentation only changes",emoji:"\u{1F4DA}",trailer:"Changelog: documentation"},{value:"refactor",label:"refactor",hint:"A code change that neither fixes a bug nor adds a feature",emoji:"\u{1F528}",trailer:"Changelog: refactor"},{value:"perf",label:"perf",hint:"A code change that improves performance",emoji:"\u{1F680}",trailer:"Changelog: performance"},{value:"test",label:"test",hint:"Adding missing tests or correcting existing tests",emoji:"\u{1F6A8}",trailer:"Changelog: test"},{value:"build",label:"build",hint:"Changes that affect the build system or external dependencies",emoji:"\u{1F6A7}",trailer:"Changelog: build"},{value:"ci",label:"ci",hint:"Changes to our CI configuration files and scripts",emoji:"\u{1F916}",trailer:"Changelog: ci"},{value:"chore",label:"chore",hint:"Other changes that do not modify src or test files",emoji:"\u{1F9F9}",trailer:"Changelog: chore"},{value:"",label:"none"}];import*as t from"valibot";var m=t.object({check_status:t.optional(t.boolean(),!0),commit_type:t.transform(t.optional(t.object({enable:t.optional(t.boolean(),!0),initial_value:t.optional(t.string(),"feat"),max_items:t.optional(t.number([t.minValue(1)]),20),infer_type_from_branch:t.optional(t.boolean(),!0),append_emoji_to_label:t.optional(t.boolean(),!1),append_emoji_to_commit:t.optional(t.boolean(),!1),emoji_commit_position:t.optional(t.picklist(["Start","After-Colon"]),"Start"),options:t.optional(t.array(t.object({value:t.string(),label:t.optional(t.string()),hint:t.optional(t.string()),emoji:t.optional(t.string([t.emoji()]),void 0),trailer:t.optional(t.string())})),E)},[t.custom(e=>e.options.map(o=>o.value).includes(e.initial_value),e=>`Type: initial_value "${e.input.initial_value}" must exist in options`)]),{}),e=>{let o=e.options.map(n=>({...n,label:n.emoji&&e.append_emoji_to_label?`${n.emoji} ${n.label}`:n.label}))??[];return{...e,options:o}}),commit_scope:t.transform(t.optional(t.object({enable:t.optional(t.boolean(),!0),custom_scope:t.optional(t.boolean(),!1),max_items:t.optional(t.number([t.minValue(1)]),20),initial_value:t.optional(t.string(),"app"),options:t.optional(t.array(t.object({value:t.string(),label:t.optional(t.string()),hint:t.optional(t.string())})),x)},[t.custom(e=>{let o=e.options.map(n=>n.value);return e.custom_scope&&o.push(c),o.includes(e.initial_value)},e=>`Scope: initial_value "${e.input.initial_value}" must exist in options`)]),{}),e=>{let o=e.options.map(n=>n.value);return e.custom_scope&&!o.includes(c)?{...e,options:[...e.options,{label:c,value:c,hint:"Write a custom scope"}]}:e}),check_ticket:t.optional(t.object({infer_ticket:t.optional(t.boolean(),!0),confirm_ticket:t.optional(t.boolean(),!0),add_to_title:t.optional(t.boolean(),!0),append_hashtag:t.optional(t.boolean(),!1),prepend_hashtag:t.optional(t.picklist(["Never","Always","Prompt"]),"Never"),surround:t.optional(t.picklist(["","()","[]","{}"]),""),title_position:t.optional(t.picklist(["start","end","before-colon","beginning"]),"start")}),{}),commit_title:t.optional(t.object({max_size:t.optional(t.number([t.minValue(1)]),70)}),{}),commit_body:t.optional(t.object({enable:t.optional(t.boolean(),!0),required:t.optional(t.boolean(),!1)}),{}),commit_footer:t.optional(t.object({enable:t.optional(t.boolean(),!0),initial_value:t.optional(t.array(g),[]),options:t.optional(t.array(g),f)}),{}),breaking_change:t.optional(t.object({add_exclamation_to_title:t.optional(t.boolean(),!1)}),{}),confirm_with_editor:t.optional(t.boolean(),!1),confirm_commit:t.optional(t.boolean(),!0),print_commit_output:t.optional(t.boolean(),!0),branch_pre_commands:t.optional(t.array(t.string()),[]),branch_post_commands:t.optional(t.array(t.string()),[]),worktree_pre_commands:t.optional(t.array(t.string()),[]),worktree_post_commands:t.optional(t.array(t.string()),[]),branch_user:t.optional(t.object({enable:t.optional(t.boolean(),!0),required:t.optional(t.boolean(),!1),separator:t.optional(t.picklist(["/","-","_"]),"/")}),{}),branch_type:t.optional(t.object({enable:t.optional(t.boolean(),!0),separator:t.optional(t.picklist(["/","-","_"]),"/")}),{}),branch_version:t.optional(t.object({enable:t.optional(t.boolean(),!1),required:t.optional(t.boolean(),!1),separator:t.optional(t.picklist(["/","-","_"]),"/")}),{}),branch_ticket:t.optional(t.object({enable:t.optional(t.boolean(),!0),required:t.optional(t.boolean(),!1),separator:t.optional(t.picklist(["/","-","_"]),"-")}),{}),branch_description:t.optional(t.object({max_length:t.optional(t.number([t.minValue(1)]),70),separator:t.optional(t.picklist(["","/","-","_"]),"")}),{}),branch_action_default:t.optional(d,"branch"),branch_order:t.optional(t.array(h),O),enable_worktrees:t.optional(t.boolean(),!0),overrides:t.optional(t.object({shell:t.optional(t.string())}),{})}),H=t.optional(t.object({type:t.optional(t.string(),""),scope:t.optional(t.string(),""),title:t.optional(t.string(),""),body:t.optional(t.string(),""),closes:t.optional(t.string(),""),ticket:t.optional(t.string(),""),breaking_title:t.optional(t.string(),""),breaking_body:t.optional(t.string(),""),deprecates:t.optional(t.string(),""),deprecates_title:t.optional(t.string(),""),deprecates_body:t.optional(t.string(),""),custom_footer:t.optional(t.string(),""),trailer:t.optional(t.string(),"")}),{}),D=t.optional(t.object({user:t.optional(t.string(),""),type:t.optional(t.string(),""),ticket:t.optional(t.string(),""),description:t.optional(t.string(),""),version:t.optional(t.string(),"")}),{});var b=class{#t="";constructor(){}get git_args(){return this.#t}set git_args(o){this.#t=o}},_=new b;import*as i from"@clack/prompts";import{execSync as C}from"child_process";import u from"fs";import{homedir as R}from"os";import a from"picocolors";import{ValiError as N,parse as y}from"valibot";import{argv as A}from"process";var T=".better-commits.json",K=`${a.dim("(<space> to select)")}`,Q=`${a.dim("(<space> to select, <a> to select all)")}`,tt=`${a.dim("(optional)")}`,ot=`${a.dim("(value will be saved)")}`,et=new RegExp(/\/(\w+-\d+)/),nt=new RegExp(/^(\w+-\d+)/),it=new RegExp(/^([A-Z]+-[\[a-zA-Z\]\d]+)_/),rt=new RegExp(/\/([A-Z]+-[\[a-zA-Z\]\d]+)_/),at=new RegExp(/\/(\d+)/),lt=new RegExp(/^(\d+)/),st=[{value:"closes",label:"closes <issue/ticket>",hint:"Attempts to infer ticket from branch"},{value:"trailer",label:"trailer",hint:"Appends trailer based on commit type"},{value:"breaking-change",label:"breaking change",hint:"Add breaking change"},{value:"deprecated",label:"deprecated",hint:"Add deprecated change"},{value:"custom",label:"custom",hint:"Add a custom footer"}],pt=[{value:"branch",label:"Branch"},{value:"worktree",label:"Worktree"}];function ct(e=" better-commits "){console.clear(),i.intro(`${a.bgCyan(a.black(e))}`),P();let o=null,n=I();u.existsSync(n)&&(i.log.step("Found global config"),o=S(n));let l=`${w()}/${T}`;if(u.existsSync(l)){i.log.step("Found repository config");let s=S(l);return o?{...s,overrides:o.overrides.shell?o.overrides:s.overrides,confirm_with_editor:o.confirm_with_editor}:s}if(o)return o;let v=y(m,{});return i.log.step("Config not found. Generating default .better-commit.json at $HOME"),u.writeFileSync(n,JSON.stringify(v,null,4)),v}function S(e){let o=null;try{o=JSON.parse(u.readFileSync(e,"utf8"))}catch(n){i.log.error(`Invalid JSON file. Exiting.
2
- `+n),process.exit(0)}return j(o)}function j(e){try{return y(m,e)}catch(o){if(o instanceof N){let r=(o.issues[0].path??[]).map(l=>l.key).join(".");i.log.error(`Invalid Configuration: ${a.red(r)}
3
- `+o.message)}process.exit(0)}}function vt(e){let o="";try{o=C(`git ${_.git_args} branch --show-current`,{stdio:"pipe"}).toString()}catch{return""}return e.find(r=>{let l=new RegExp(`^${r}-`),v=new RegExp(`-${r}-`),s=new RegExp(`${r}/`);return[o.match(l),o.match(v),o.match(s)].filter(k=>k!=null)?.length})??""}function w(){let e=".";try{e=C(`git ${_.git_args} rev-parse --show-toplevel`).toString().trim()}catch{i.log.warn("Could not find git root. If in a --bare repository, ignore this warning.")}return e}function I(){return R()+"/"+T}function _t(e,o){return o===e.length-1?"":`
4
- `}function ut(e){let o=e.trim();return o.endsWith(".")?o.substring(0,o.length-1).trim():e.trim()}function P(){_.git_args=`${A[2]??""} ${A[3]??""}`.trim()}export{c as a,m as b,H as c,D as d,_ as e,T as f,K as g,tt as h,ot as i,et as j,nt as k,it as l,rt as m,at as n,lt as o,st as p,pt as q,ct as r,vt as s,w as t,_t as u,ut as v};