bob-core 1.4.0 → 2.0.0-beta.10

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 (66) hide show
  1. package/README.md +316 -175
  2. package/dist/cjs/index.js +18 -6
  3. package/dist/cjs/package-D82wayAe.cjs +1 -0
  4. package/dist/cjs/src/Cli.d.ts +21 -12
  5. package/dist/cjs/src/Command.d.ts +51 -35
  6. package/dist/cjs/src/CommandIO.d.ts +21 -1
  7. package/dist/cjs/src/CommandParser.d.ts +92 -44
  8. package/dist/cjs/src/CommandRegistry.d.ts +12 -7
  9. package/dist/cjs/src/CommandSignatureParser.d.ts +40 -0
  10. package/dist/cjs/src/CommandWithSignature.d.ts +28 -0
  11. package/dist/cjs/src/ExceptionHandler.d.ts +3 -0
  12. package/dist/cjs/src/Logger.d.ts +16 -0
  13. package/dist/cjs/src/commands/HelpCommand.d.ts +1 -3
  14. package/dist/cjs/src/contracts/CommandOption.d.ts +4 -5
  15. package/dist/cjs/src/contracts/LoggerContract.d.ts +13 -0
  16. package/dist/cjs/src/contracts/index.d.ts +1 -0
  17. package/dist/cjs/src/errors/BadCommandOption.d.ts +2 -1
  18. package/dist/cjs/src/errors/BadCommandParameter.d.ts +2 -1
  19. package/dist/cjs/src/errors/BobError.d.ts +2 -1
  20. package/dist/cjs/src/errors/CommandNotFoundError.d.ts +2 -1
  21. package/dist/cjs/src/errors/InvalidOption.d.ts +5 -4
  22. package/dist/cjs/src/errors/MissingRequiredArgumentValue.d.ts +4 -4
  23. package/dist/cjs/src/errors/MissingRequiredOptionValue.d.ts +7 -0
  24. package/dist/cjs/src/errors/index.d.ts +4 -0
  25. package/dist/cjs/src/index.d.ts +8 -1
  26. package/dist/cjs/src/lib/optionHelpers.d.ts +5 -0
  27. package/dist/cjs/src/lib/types.d.ts +33 -0
  28. package/dist/cjs/src/lib/valueConverter.d.ts +10 -0
  29. package/dist/cjs/src/options/HelpOption.d.ts +3 -1
  30. package/dist/cjs/src/testFixtures.d.ts +11 -0
  31. package/dist/esm/index.js +1108 -475
  32. package/dist/esm/package-O5nP1XlU.js +31 -0
  33. package/dist/esm/src/Cli.d.ts +21 -12
  34. package/dist/esm/src/Command.d.ts +51 -35
  35. package/dist/esm/src/CommandIO.d.ts +21 -1
  36. package/dist/esm/src/CommandParser.d.ts +92 -44
  37. package/dist/esm/src/CommandRegistry.d.ts +12 -7
  38. package/dist/esm/src/CommandSignatureParser.d.ts +40 -0
  39. package/dist/esm/src/CommandWithSignature.d.ts +28 -0
  40. package/dist/esm/src/ExceptionHandler.d.ts +3 -0
  41. package/dist/esm/src/Logger.d.ts +16 -0
  42. package/dist/esm/src/commands/HelpCommand.d.ts +1 -3
  43. package/dist/esm/src/contracts/CommandOption.d.ts +4 -5
  44. package/dist/esm/src/contracts/LoggerContract.d.ts +13 -0
  45. package/dist/esm/src/contracts/index.d.ts +1 -0
  46. package/dist/esm/src/errors/BadCommandOption.d.ts +2 -1
  47. package/dist/esm/src/errors/BadCommandParameter.d.ts +2 -1
  48. package/dist/esm/src/errors/BobError.d.ts +2 -1
  49. package/dist/esm/src/errors/CommandNotFoundError.d.ts +2 -1
  50. package/dist/esm/src/errors/InvalidOption.d.ts +5 -4
  51. package/dist/esm/src/errors/MissingRequiredArgumentValue.d.ts +4 -4
  52. package/dist/esm/src/errors/MissingRequiredOptionValue.d.ts +7 -0
  53. package/dist/esm/src/errors/index.d.ts +4 -0
  54. package/dist/esm/src/index.d.ts +8 -1
  55. package/dist/esm/src/lib/optionHelpers.d.ts +5 -0
  56. package/dist/esm/src/lib/types.d.ts +33 -0
  57. package/dist/esm/src/lib/valueConverter.d.ts +10 -0
  58. package/dist/esm/src/options/HelpOption.d.ts +3 -1
  59. package/dist/esm/src/testFixtures.d.ts +11 -0
  60. package/package.json +17 -4
  61. package/dist/cjs/package-6sByjm31.cjs +0 -1
  62. package/dist/cjs/src/errors/MissingSignatureArgument.d.ts +0 -8
  63. package/dist/cjs/src/errors/MissingSignatureOption.d.ts +0 -8
  64. package/dist/esm/package-eljsfLkU.js +0 -31
  65. package/dist/esm/src/errors/MissingSignatureArgument.d.ts +0 -8
  66. package/dist/esm/src/errors/MissingSignatureOption.d.ts +0 -8
package/dist/cjs/index.js CHANGED
@@ -1,9 +1,21 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const A=require("minimist"),o=require("chalk"),f=require("prompts"),x=require("node:fs"),$=require("path"),V=require("string-similarity");function b(l){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(l){for(const t in l)if(t!=="default"){const n=Object.getOwnPropertyDescriptor(l,t);Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>l[t]})}}return e.default=l,Object.freeze(e)}const E=b(x),j=b(V);class p extends Error{}class S extends p{constructor(e){super(`Argument "${e.name}" is required.`),this.paramSignature=e}pretty(){const e=console.log;e(o`{white.bgRed ERROR } Argument {bold.yellow ${this.paramSignature.name}} is required.`)}}class y extends p{constructor(e,t){super(`Missing ${e} in the command signature`),this.option=e,this.optionsSignature=t}pretty(){const e=console.log;if(this.optionsSignature.length){e(o`{yellow Available options}:`);for(const t of this.optionsSignature){const n=t.type?o`{white (${t.type})}`:"",s=" ".repeat(20-t.name.length);e(o` {green ${t.name}} ${s} ${t.help??"\b"} ${n}`)}e("")}e(o`{white.bgRed ERROR } Option {bold.yellow ${this.option}} is missing in the signature.`)}}class w extends p{constructor(e,t){super(`Missing ${e} in the command signature`),this.argument=e,this.argumentSignatures=t}pretty(){const e=console.log;if(this.argumentSignatures.length){e(o`\n{yellow Available arguments}:`);for(const t of this.argumentSignatures){const n=t.type?o`{white (${t.type})}`:"",s=" ".repeat(20-t.name.length);e(o` {green ${t.name}} ${s} ${t.help??"\b"} ${n}`)}e("")}e(o`{white.bgRed ERROR } Argument {bold.yellow ${this.argument}} is missing in the signature.`)}}class k extends p{constructor(e,t){super(`Invalid option ${e} in not recognized`),this.option=e,this.optionsSignature=t}pretty(){const e=console.log;if(this.optionsSignature.length>0){e(o`\n{yellow Available options}:`);for(const t of this.optionsSignature){const n=t.type?o`{white (${t.type})}`:"",s=`--${t.name}${t.alias?.map(i=>`, -${i}`).join("")??""}`,r=" ".repeat(30-s.length);e(o` {green ${s}} ${r} ${t.help??"\b"} ${n}`)}e("")}e(o`{white.bgRed ERROR } Option {bold.yellow ${this.option}} is not recognized.`)}}class F{constructor(e,t,n,s,...r){this.io=e,this.signature=t,this.helperDefinitions=n,this.defaultCommandOptions=s;const[i,...u]=t.split(/\{(.*?)\}/g).map(c=>c.trim()).filter(Boolean),{_:a,...m}=A(r);this.command=i,this.parseSignature(u),this.parseDefaultOptions(),this.handleArguments(a),this.handleOptions(m)}command;arguments={};options={};argumentsSignature={};optionSignatures={};optionAliases={};option(e){if(!this.optionSignatures[e])throw new y(e,Object.values(this.optionSignatures));return this.options[e]}setOption(e,t){if(!this.optionSignatures[e])throw new y(e,Object.values(this.optionSignatures));this.options[e]=t}optionHelp(e){if(!this.optionSignatures[e])throw new y(e,Object.values(this.optionSignatures));return this.optionSignatures[e].help}argument(e){if(!this.argumentsSignature[e])throw new w(e,Object.values(this.argumentsSignature));return this.arguments[e]}setArgument(e,t){if(!this.argumentsSignature[e])throw new w(e,Object.values(this.argumentsSignature));this.arguments[e]=t}argumentHelp(e){if(!this.argumentsSignature[e])throw new w(e,Object.values(this.argumentsSignature));return this.argumentsSignature[e].help}getArgumentSignatures(){return this.argumentsSignature}getOptionSignatures(){return this.optionSignatures}getParamValue(e,t){return t.type==="boolean"?e==="true"||e==="1"?!0:e==="false"||e==="0"?!1:!!e:t.type==="array"?e?Array.isArray(e)?e:[e]:[]:e??t.defaultValue}handleArguments(e){for(const[t,n]of Object.entries(this.arguments)){const s=this.argumentsSignature[t];if(s.variadic)this.arguments[t]=e;else{const r=e.shift();this.arguments[t]=this.getParamValue(r,s)}}}handleOptions(e){for(const[t,n]of Object.entries(e)){const s=this.optionAliases[t],r=this.optionSignatures[t]??this.optionSignatures[s];if(!r)throw new k(t,Object.values(this.optionSignatures));this.options[t]=this.getParamValue(n,r);for(const i of r.alias??[])e[i]&&(this.options[r.name]=e[i])}}parseSignature(e){for(const t of e){const n=this.parseParamSignature(t);if(n.isOption){this.options[n.name]=n.defaultValue??null,this.optionSignatures[n.name]=n;for(const s of n.alias??[])this.optionAliases[s]=n.name}else this.arguments[n.name]=n.defaultValue??null,this.argumentsSignature[n.name]=n}}parseDefaultOptions(){if(this.defaultCommandOptions.length){for(const e of this.defaultCommandOptions)if(this.optionSignatures[e.option]={name:e.option,type:e.defaultValue==null?"string":typeof e.defaultValue=="boolean"?"boolean":Array.isArray(e.defaultValue)?"array":"string",optional:!0,alias:e.alias,variadic:!1,help:e.description,defaultValue:e.defaultValue??null,isOption:!0},this.options[e.option]=e.defaultValue,e.alias)for(const t of e.alias)this.optionAliases[t]=e.option}}parseParamSignature(e){const t={name:e,optional:!1,type:"string",help:void 0,defaultValue:null,variadic:!1,isOption:!1};if(t.name.includes(":")){const[n,s]=t.name.split(":");t.name=n.trim(),t.help=s.trim()}if(t.name.includes("=")){const[n,s]=t.name.split("=");t.name=n.trim(),t.defaultValue=s.trim(),t.optional=!0,t.defaultValue.length?t.defaultValue==="true"?(t.defaultValue=!0,t.type="boolean"):t.defaultValue==="false"&&(t.defaultValue=!1,t.type="boolean"):t.defaultValue=null}else t.name.startsWith("--")&&(t.optional=!0,t.defaultValue=!1,t.type="boolean");if(t.name.includes("|")){const[n,...s]=t.name.split("|");t.name=n.trim(),t.alias=s.map(r=>r.trim())}return t.name.startsWith("--")&&(t.isOption=!0,t.name=t.name.slice(2)),t.defaultValue==="*"&&(t.defaultValue=[],t.type="array"),t.name.endsWith("?")&&(t.optional=!0,t.name=t.name.slice(0,-1)),t.name.endsWith("*")&&(t.type="array",t.variadic=!0,t.defaultValue=[],t.name=t.name.slice(0,-1)),t.help=t.help??this.helperDefinitions[t.name]??this.helperDefinitions[`--${t.name}`],t}async validate(){for(const[e,t]of Object.entries(this.arguments)){const n=this.argumentsSignature[e];if(!t&&!n.optional){let s=null;switch(n.type){case"string":let r=o`{yellow.bold ${n.name}} is required`;n.help&&(r+=o`: {gray (${n.help})}`),r+=`
2
- `,s=await this.io.askForInput(r,n.defaultValue,{validate:i=>i?.trim()?.length?!0:`${n.name} cannot be empty`});break}if(s)this.setArgument(e,s);else throw new S(n)}if(!t?.length&&n.variadic&&!n.optional)throw new S(n)}}}function C(l){return new Array(l+5).join(" ")}class O{option="help";alias=["h"];defaultValue=!1;description=o`Display help for the given command. When no command is given display help for the {green list} command`;async handler(){const e=console.log,t=Object.values(this.parser.getArgumentSignatures()),n=Object.values(this.parser.getOptionSignatures()).map(a=>({...a,optionWithAlias:`--${a.name}${a.alias?.map(m=>`, -${m}`).join("")??""}`})),s=t.filter(a=>!a.optional);e(o`{yellow Description}:`),e(o` ${this.description}\n`),e(o`{yellow Usage}:`),e(o` ${this.command} ${s.length>0?s.map(a=>`<${a.name}>`).join(" "):"\b"} [options]`);const r=Math.max(...n.map(a=>a.optionWithAlias.length))??0,i=Math.max(...t.map(a=>a.name.length))??0,u=i>r?i:r;if(t.length>0){e(o`\n{yellow Arguments}:`);for(const a of t){const m=C(u-a.name.length);let c=o` {green ${a.name}} ${m} ${a.help??"\b"}`;if(a.defaultValue!==void 0&&a.optional){const h=a.type==="array"?JSON.stringify(a.defaultValue):a.defaultValue;c+=o` {yellow [default: ${h}]}`}a.variadic&&(c+=o` {white (variadic)}`),e(c)}}if(n.length>0){e(o`\n{yellow Options}:`);for(const a of n){const m=C(u-a.optionWithAlias.length);let c=o`{green ${a.optionWithAlias}} ${m} ${a.help??"\b"}`;if(a.type&&(c+=o` {white (${a.type})}`),a.defaultValue!==void 0&&a.optional){const h=a.type==="array"?JSON.stringify(a.defaultValue):a.defaultValue;c+=o` {yellow [default: ${h}]}`}e(c)}}if(this.commandsExamples.length>0){e(o`\n{yellow Examples}:`);let a=process.argv[0].split("/").pop();a==="node"&&(a+=" "+process.argv[1].split("/").pop());for(const[m,c]of this.commandsExamples.entries())m>0&&e(""),e(` ${c.description}
3
- `),e(o` {green ${a} ${c.command}}`)}return-1}}class v{async askForConfirmation(e="Do you want to continue?",t){return(await f({type:"confirm",name:"value",message:e,initial:t??!1})).value}async askForInput(e,t,n){return(await f({type:"text",name:"value",message:e,initial:t,...n}))?.value??null}async askForToggle(e,t,n){return(await f({type:"toggle",name:"value",message:e,initial:t,...n}))?.value??null}async askForSelect(e,t,n){if(t.length===0)throw new Error("No options provided");const s=[];for(const i of t)typeof i=="string"?s.push({title:i,value:i}):s.push(i);return(await f({type:"select",name:"value",message:e,choices:s,...n}))?.value??null}newLoader(e="",t=["⠙","⠘","⠰","⠴","⠤","⠦","⠆","⠃","⠋","⠉"],n=100){let s=e,r=null,i=0;const u=setInterval(function(){r&&(process.stdout.write(new TextEncoder().encode("\r"+" ".repeat(r.length+5)+"\r")),r=null),process.stdout.write(new TextEncoder().encode("\r"+t[i++]+" "+s)),i=i%t.length},n),a=()=>{clearInterval(u),process.stdout.write(new TextEncoder().encode("\r"+" ".repeat(s.length+5)+"\r"))};return{[Symbol.dispose]:a,[Symbol.asyncDispose]:a,updateText:m=>{r=s,s=m},stop:a}}}class R{ctx;helperDefinitions={};commandsExamples=[];parser;io;get CommandParserClass(){return F}get CommandIOClass(){return v}defaultOptions(){return[new O]}get command(){return this.parser?this.parser.command:this.signature.split(" ")[0]}async run(e,...t){this.ctx=e;const n=this.defaultOptions();this.io=new this.CommandIOClass,this.parser=new this.CommandParserClass(this.io,this.signature,this.helperDefinitions,n,...t);for(const r of n)if(this.parser.option(r.option)){const i=await r.handler.call(this);if(i&&i!==0)return i}await this.parser.validate();const s=this.preHandle?await this.preHandle():null;return s&&s!==0?s:await this.handle()??0}setOption(e,t){this.parser.setOption(e,t)}setArgument(e,t){this.parser.setArgument(e,t)}option(e,t=null){return this.parser.option(e)??t}optionBoolean(e,t=!1){return this.parser.option(e)??t}optionArray(e,t=[]){const n=this.parser.option(e);if(!Array.isArray(n))throw new Error(`Option ${e} is not an array`);return n.length?n:t}optionNumber(e,t=null){const n=this.parser.option(e);return n?typeof n=="number"?n:parseInt(n):t}argument(e,t=null){return this.parser.argument(e)??t}argumentArray(e,t=[]){const n=this.parser.argument(e);if(!Array.isArray(n))throw new Error(`Argument ${e} is not an array`);return n?.length?n:t}argumentBoolean(e,t=!1){return this.parser.argument(e)??t}argumentNumber(e,t=null){const n=this.parser.argument(e);return n?typeof n=="number"?n:parseInt(n):t}async askForConfirmation(...e){return this.io.askForConfirmation(...e)}async askForInput(...e){return this.io.askForInput(...e)}async askForSelect(...e){return this.io.askForSelect(...e)}newLoader(...e){return this.io.newLoader(...e)}}class H extends p{constructor(e){super(`Command "${e}" not found.`),this.command=e}pretty(){const e=console.log;e(o`{bgRed ERROR } Command {yellow ${this.command}} not found.`)}}class I{commands={};io;get commandSuffix(){return"Command"}get CommandIOClass(){return v}constructor(){this.io=new this.CommandIOClass}getAvailableCommands(){return Object.keys(this.commands)}getCommands(){return Object.values(this.commands)}commandResolver=async e=>{const t=(await import(e)).default;let n;return t?.default?n=new t.default:n=new t,n};setCommandResolver(e){this.commandResolver=e}registerCommand(e,t=!1){const n=e.signature.split(" ")[0];if(!n)throw new Error("Command signature is invalid, it must have a command name.");if(!t&&this.commands[n])throw new Error(`Command ${n} already registered.`);this.commands[n]=e}async loadCommandsPath(e){for await(const t of this.listCommandsFiles(e))try{const n=await this.commandResolver(t);this.registerCommand(n)}catch(n){throw new Error(`Command ${t} failed to load. ${n}`)}}async runCommand(e,t,...n){const s=typeof t=="string"?this.commands[t]:t,r=typeof t=="string"?t:s.command;if(!s){const i=await this.suggestCommand(r);return i?await this.runCommand(e,i,...n):1}return await s.run(e,...n)}async suggestCommand(e){const t=this.getAvailableCommands(),{bestMatch:n,bestMatchIndex:s,ratings:r}=j.findBestMatch(e,t),i=r.filter(u=>u.rating>.3).map(u=>u.target);if(n.rating>0&&i.length<=1||n.rating>.7&&i.length>1){const u=t[s];return await this.askRunSimilarCommand(e,u)?u:null}if(i.length){console.log(o`{bgRed ERROR } Command {yellow ${e}} not found.\n`);const u=await this.io.askForSelect(o`{green Did you mean to run one of these commands instead?}`,i);if(u)return u}throw new H(e)}async askRunSimilarCommand(e,t){return console.log(o`{bgRed ERROR } Command {yellow ${e}} not found.\n`),this.io.askForConfirmation(o`{green Do you want to run {yellow ${t}} instead?} `)}async*listCommandsFiles(e){const t=E.readdirSync(e,{withFileTypes:!0});for(const n of t){const s=$.resolve(e,n.name);if(n.isDirectory())yield*this.listCommandsFiles($.resolve(e,n.name));else{if(!s.endsWith(`${this.commandSuffix}.ts`)&&!s.endsWith(`${this.commandSuffix}.js`))continue;yield s}}}}class D extends R{constructor(e){super(),this.opts=e}signature="help";description="Show help";async handle(){const e=this.opts.commandRegistry.getCommands(),t=this.opts.cliName??"Bob CLI",n=this.opts.cliVersion??"0.0.0",s=(await Promise.resolve().then(()=>require("./package-6sByjm31.cjs")))?.default?.version??"0.0.0";console.log(o`${t} {green ${n}} (core: {yellow ${s}})
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const v=require("prompts"),se=require("minimist"),ie=require("node:fs"),D=require("path"),oe=require("string-similarity");function Q(r){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const t in r)if(t!=="default"){const n=Object.getOwnPropertyDescriptor(r,t);Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>r[t]})}}return e.default=r,Object.freeze(e)}const ae=Q(ie),le=Q(oe);class I{logger;constructor(e){this.logger=e}log(...e){this.logger.log(...e)}info(...e){this.logger.info(...e)}warn(...e){this.logger.warn(...e)}error(...e){this.logger.error(...e)}debug(...e){this.logger.debug(...e)}async askForConfirmation(e="Do you want to continue?",t){return(await v({type:"confirm",name:"value",message:e,initial:t??!1})).value}async askForInput(e,t,n){return(await v({type:"text",name:"value",message:e,initial:t,...n}))?.value??null}async askForDate(e,t,n){return(await v({type:"date",name:"value",message:e,initial:t,...n}))?.value??null}async askForList(e,t,n){return(await v({type:"list",name:"value",message:e,initial:t,...n}))?.value??null}async askForToggle(e,t,n){return(await v({type:"toggle",name:"value",message:e,initial:t,...n}))?.value??null}async askForSelect(e,t,n){if(t.length===0)throw new Error("No options provided");const s=[];for(const o of t)typeof o=="string"?s.push({title:o,value:o}):s.push(o);return(await v({type:"select",name:"value",message:e,choices:s,...n}))?.value??null}newLoader(e="",t=["⠙","⠘","⠰","⠴","⠤","⠦","⠆","⠃","⠋","⠉"],n=100){let s=e,i=null,o=0;const u=setInterval(function(){i&&(process.stdout.write(new TextEncoder().encode("\r"+" ".repeat(i.length+5)+"\r")),i=null),process.stdout.write(new TextEncoder().encode("\r"+t[o++]+" "+s)),o=o%t.length},n),m=()=>{clearInterval(u),process.stdout.write(new TextEncoder().encode("\r"+" ".repeat(s.length+5)+"\r"))};return{[Symbol.dispose]:m,[Symbol.asyncDispose]:m,updateText:h=>{i=s,s=h},stop:m}}}const k=10,V=(r=0)=>e=>`\x1B[${e+r}m`,H=(r=0)=>e=>`\x1B[${38+r};5;${e}m`,W=(r=0)=>(e,t,n)=>`\x1B[${38+r};2;${e};${t};${n}m`,c={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],overline:[53,55],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],gray:[90,39],grey:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgGray:[100,49],bgGrey:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]}};Object.keys(c.modifier);const ue=Object.keys(c.color),me=Object.keys(c.bgColor);[...ue,...me];function de(){const r=new Map;for(const[e,t]of Object.entries(c)){for(const[n,s]of Object.entries(t))c[n]={open:`\x1B[${s[0]}m`,close:`\x1B[${s[1]}m`},t[n]=c[n],r.set(s[0],s[1]);Object.defineProperty(c,e,{value:t,enumerable:!1})}return Object.defineProperty(c,"codes",{value:r,enumerable:!1}),c.color.close="\x1B[39m",c.bgColor.close="\x1B[49m",c.color.ansi=V(),c.color.ansi256=H(),c.color.ansi16m=W(),c.bgColor.ansi=V(k),c.bgColor.ansi256=H(k),c.bgColor.ansi16m=W(k),Object.defineProperties(c,{rgbToAnsi256:{value(e,t,n){return e===t&&t===n?e<8?16:e>248?231:Math.round((e-8)/247*24)+232:16+36*Math.round(e/255*5)+6*Math.round(t/255*5)+Math.round(n/255*5)},enumerable:!1},hexToRgb:{value(e){const t=/[a-f\d]{6}|[a-f\d]{3}/i.exec(e.toString(16));if(!t)return[0,0,0];let[n]=t;n.length===3&&(n=[...n].map(i=>i+i).join(""));const s=Number.parseInt(n,16);return[s>>16&255,s>>8&255,s&255]},enumerable:!1},hexToAnsi256:{value:e=>c.rgbToAnsi256(...c.hexToRgb(e)),enumerable:!1},ansi256ToAnsi:{value(e){if(e<8)return 30+e;if(e<16)return 90+(e-8);let t,n,s;if(e>=232)t=((e-232)*10+8)/255,n=t,s=t;else{e-=16;const u=e%36;t=Math.floor(e/36)/5,n=Math.floor(u/6)/5,s=u%6/5}const i=Math.max(t,n,s)*2;if(i===0)return 30;let o=30+(Math.round(s)<<2|Math.round(n)<<1|Math.round(t));return i===2&&(o+=60),o},enumerable:!1},rgbToAnsi:{value:(e,t,n)=>c.ansi256ToAnsi(c.rgbToAnsi256(e,t,n)),enumerable:!1},hexToAnsi:{value:e=>c.ansi256ToAnsi(c.hexToAnsi256(e)),enumerable:!1}}),c}const f=de(),_=(()=>{if(!("navigator"in globalThis))return 0;if(globalThis.navigator.userAgentData){const r=navigator.userAgentData.brands.find(({brand:e})=>e==="Chromium");if(r&&r.version>93)return 3}return/\b(Chrome|Chromium)\//.test(globalThis.navigator.userAgent)?1:0})(),G=_!==0&&{level:_},ce={stdout:G,stderr:G};function he(r,e,t){let n=r.indexOf(e);if(n===-1)return r;const s=e.length;let i=0,o="";do o+=r.slice(i,n)+e+t,i=n+s,n=r.indexOf(e,i);while(n!==-1);return o+=r.slice(i),o}function pe(r,e,t,n){let s=0,i="";do{const o=r[n-1]==="\r";i+=r.slice(s,o?n-1:n)+e+(o?`\r
2
+ `:`
3
+ `)+t,s=n+1,n=r.indexOf(`
4
+ `,s)}while(n!==-1);return i+=r.slice(s),i}const{stdout:U,stderr:Y}=ce,P=Symbol("GENERATOR"),C=Symbol("STYLER"),$=Symbol("IS_EMPTY"),z=["ansi","ansi","ansi256","ansi16m"],O=Object.create(null),ge=(r,e={})=>{if(e.level&&!(Number.isInteger(e.level)&&e.level>=0&&e.level<=3))throw new Error("The `level` option should be an integer from 0 to 3");const t=U?U.level:0;r.level=e.level===void 0?t:e.level},fe=r=>{const e=(...t)=>t.join(" ");return ge(e,r),Object.setPrototypeOf(e,x.prototype),e};function x(r){return fe(r)}Object.setPrototypeOf(x.prototype,Function.prototype);for(const[r,e]of Object.entries(f))O[r]={get(){const t=E(this,j(e.open,e.close,this[C]),this[$]);return Object.defineProperty(this,r,{value:t}),t}};O.visible={get(){const r=E(this,this[C],!0);return Object.defineProperty(this,"visible",{value:r}),r}};const T=(r,e,t,...n)=>r==="rgb"?e==="ansi16m"?f[t].ansi16m(...n):e==="ansi256"?f[t].ansi256(f.rgbToAnsi256(...n)):f[t].ansi(f.rgbToAnsi(...n)):r==="hex"?T("rgb",e,t,...f.hexToRgb(...n)):f[t][r](...n),ye=["rgb","hex","ansi256"];for(const r of ye){O[r]={get(){const{level:t}=this;return function(...n){const s=j(T(r,z[t],"color",...n),f.color.close,this[C]);return E(this,s,this[$])}}};const e="bg"+r[0].toUpperCase()+r.slice(1);O[e]={get(){const{level:t}=this;return function(...n){const s=j(T(r,z[t],"bgColor",...n),f.bgColor.close,this[C]);return E(this,s,this[$])}}}}const be=Object.defineProperties(()=>{},{...O,level:{enumerable:!0,get(){return this[P].level},set(r){this[P].level=r}}}),j=(r,e,t)=>{let n,s;return t===void 0?(n=r,s=e):(n=t.openAll+r,s=e+t.closeAll),{open:r,close:e,openAll:n,closeAll:s,parent:t}},E=(r,e,t)=>{const n=(...s)=>we(n,s.length===1?""+s[0]:s.join(" "));return Object.setPrototypeOf(n,be),n[P]=r,n[C]=e,n[$]=t,n},we=(r,e)=>{if(r.level<=0||!e)return r[$]?"":e;let t=r[C];if(t===void 0)return e;const{openAll:n,closeAll:s}=t;if(e.includes("\x1B"))for(;t!==void 0;)e=he(e,t.close,t.open),t=t.parent;const i=e.indexOf(`
5
+ `);return i!==-1&&(e=pe(e,s,n,i)),n+e+s};Object.defineProperties(x.prototype,O);const a=x();x({level:Y?Y.level:0});class b extends Error{}function J(r){if(r==="string"||r==="number")return null;if(r==="boolean")return!1;if(Array.isArray(r)&&r.length===1){if(r[0]==="string")return[];if(r[0]==="number")return[]}throw new Error("Invalid option type: "+r)}function K(r){return!Array.isArray(r)&&typeof r=="object"&&r.type?r.default!==void 0?r.default:J(r.type):J(r)}function y(r){return typeof r=="string"||Array.isArray(r)?{alias:[],default:K(r),description:"",required:!1,secret:!1,type:r,variadic:!1}:{alias:r.alias?Array.isArray(r.alias)?r.alias:[r.alias]:[],default:r.default??K(r.type),description:r.description??"",required:r.required??!1,secret:r.secret??!1,type:r.type,variadic:r.variadic??!1}}class S extends b{constructor(e,t={}){super(`Invalid option ${e} in not recognized`),this.option=e,this.optionsSchema=t}pretty(e){const t=Object.entries(this.optionsSchema);if(t.length>0){e.log(`
6
+ ${a.yellow("Available options")}:`);for(const[n,s]of t){const i=y(s),o=typeof i.alias=="string"?[i.alias]:i.alias,u=Array.isArray(i.type)?`[${i.type[0]}]`:i.type,m=`--${n}${o.length>0?o.map(l=>`, -${l}`).join(""):""}`,h=" ".repeat(30-m.length);e.log(` ${a.green(m)} ${h} ${i.description||"\b"} ${a.white(`(${u})`)}`)}e.log("")}e.log(`${a.white.bgRed(" ERROR ")} Option ${a.bold.yellow(this.option)} is not recognized.`)}}class B extends b{constructor(e){super(`Argument "${e}" is required.`),this.argument=e}pretty(e){e.log(`${a.white.bgRed(" ERROR ")} Argument ${a.bold.yellow(this.argument)} is required.`)}}class X extends b{constructor(e){super(`Argument "${e}" is required.`),this.option=e}pretty(e){e.log(`${a.white.bgRed(" ERROR ")} Option ${a.bold.yellow(this.option)} is required.`)}}class ve extends b{constructor(e){let t=`Argument "${e.param}" value is invalid.`;e.reason?t+=` Reason: ${e.reason}`:t+=` Value: "${e.value}"`,super(t),this.param=e}pretty(e){e.log(` ${a.white.bgRed(" ERROR ")} Argument ${a.bold.yellow(this.param.param)} value is invalid. `),(this.param.value||this.param.reason)&&e.log(""),this.param.value&&e.log(` ${a.blue("Value")}: ${this.param.value}`),this.param.reason&&e.log(` ${a.yellow("Reason")}: ${this.param.reason}`)}}class F extends b{constructor(e){let t=`Option "${e.option}" value is invalid.`;e.reason?t+=` Reason: ${e.reason}`:t+=` Value: "${e.value}"`,super(t),this.param=e}pretty(e){e.log(` ${a.white.bgRed(" ERROR ")} Option ${a.bold.yellow(this.param.option)} value is invalid. `),(this.param.value||this.param.reason)&&e.log(""),this.param.value&&e.log(` ${a.blue("Value")}: ${this.param.value}`),this.param.reason&&e.log(` ${a.yellow("Reason")}: ${this.param.reason}`)}}class Z extends b{constructor(e){super(`Command "${e}" not found.`),this.command=e}pretty(e){e.log(`${a.bgRed(" ERROR ")} Command ${a.yellow(this.command)} not found.`)}}function A(r,e,t,n){if(r==null)return n??null;if(e==="string")return String(r);if(e==="number"){const s=Number(r);if(isNaN(s))throw new F({option:t,reason:`Expected a number, got "${r}"`});return s}if(e==="boolean")return typeof r=="boolean"?r:r==="true"||r==="1"?!0:r==="false"||r==="0"?!1:!!r;if(Array.isArray(e)){const s=e[0],i=Array.isArray(r)?r:[r];if(s==="string")return i.map(o=>String(o));if(s==="number")return i.map(o=>{const u=Number(o);if(isNaN(u))throw new F({option:t,reason:`Expected array of numbers, got "${o}" in array`});return u})}return r}class M{options;parsedOptions=null;arguments;parsedArguments=null;io;shouldPromptForMissingOptions=!0;constructor(e){this.options=e.options,this.arguments=e.arguments,this.io=e.io}init(e){const{_:t,...n}=se(e);return this.validateUnknownOptions(n),this.parsedOptions=this.handleOptions(n),this.parsedArguments=this.handleArguments(t),{options:this.parsedOptions,arguments:this.parsedArguments}}async validate(){for(const e in this.options)if(y(this.options[e]).required&&(this.parsedOptions?.[e]===void 0||this.parsedOptions?.[e]===null))throw new X(e);for(const e in this.arguments){const t=y(this.arguments[e]),n=this.parsedArguments?.[e];if(t.required&&n==null){if(this.shouldPromptForMissingOptions){const s=await this.promptForArgument(e,t);if(s&&this.parsedArguments){this.parsedArguments[e]=A(s,t.type,e);continue}}throw new B(e)}if(t.required&&t.variadic&&Array.isArray(n)&&n.length===0){if(this.shouldPromptForMissingOptions){const s=await this.promptForArgument(e,t);if(s&&this.parsedArguments){this.parsedArguments[e]=A(s,t.type,e);continue}}throw new B(e)}}}option(e){if(!this.parsedOptions)throw new Error("Options have not been parsed yet. Call init() first.");return this.parsedOptions[e]}setOption(e,t){if(!this.parsedOptions)throw new Error("Options have not been parsed yet. Call init() first.");if(!(e in this.options))throw new S(e,this.options);this.parsedOptions[e]=t}argument(e){if(!this.parsedArguments)throw new Error("Arguments have not been parsed yet. Call init() first.");return this.parsedArguments[e]}setArgument(e,t){if(!this.parsedArguments)throw new Error("Arguments have not been parsed yet. Call init() first.");if(!(e in this.arguments))throw new S(e,this.arguments);this.parsedArguments[e]=t}validateUnknownOptions(e){const t=new Set;for(const n in this.options){t.add(n);const s=y(this.options[n]);for(const i of s.alias)t.add(i)}for(const n in e)if(!t.has(n))throw new S(n,this.options)}handleOptions(e){const t={};for(const n in this.options){const s=y(this.options[n]);t[n]=this.resolveOptionValue(n,s,e)}return t}handleArguments(e){const t={},n=[...e];for(const s in this.arguments){const i=y(this.arguments[s]);if(i.variadic){t[s]=this.handleVariadicArgument(s,i,n);continue}t[s]=this.resolveArgumentValue(s,i,n.shift())}return t}handleVariadicArgument(e,t,n){return n.length?A(n,t.type,e,t.default):t.default}resolveArgumentValue(e,t,n){return n===void 0?t.default:A(n,t.type,e,t.default)}resolveOptionValue(e,t,n){let s;const i=[e,...t.alias];for(const o of i)if(o in n){s=n[o];break}if(s===void 0){if(t.required)throw new F({option:e,reason:"Required option is missing"});return t.default}return A(s,t.type,e,t.default)}optionDefinitions(){const e={};for(const t in this.options)e[t]=y(this.options[t]);return e}argumentDefinitions(){const e={};for(const t in this.arguments)e[t]=y(this.arguments[t]);return e}availableOptions(){return Object.keys(this.options)}availableArguments(){return Object.keys(this.arguments)}disablePrompting(){return this.shouldPromptForMissingOptions=!1,this}async promptForArgument(e,t){if(!Array.isArray(t.type)&&!["string","number","secret"].includes(t.type))return null;let n=`${a.yellow.bold(e)} is required`;return t.description&&(n+=`: ${a.gray(`(${t.description})`)}`),n+=` ${a.green(`(${t.type}${t.variadic==!0?"[]":""})`)}
7
+ `,Array.isArray(t.type)?(n+=`Please provide one or more values, separated by commas:
8
+ `,await this.io.askForList(n,void 0,{separator:",",validate:s=>{if(!s.length)return"Please enter at least one value";if(t.type[0]==="number"){for(const i of s.split(","))if(isNaN(Number(i)))return"Please enter only valid numbers"}return!0}})):await this.io.askForInput(n,void 0,{type:t.type==="number"?"number":t.secret?"password":"text",validate:s=>{if(s==null||typeof s=="string"&&!s.length)return"This value is required";if(t.type==="number"){const i=Number(s);if(isNaN(i))return"Please enter a valid number"}else if(t.type==="string"&&(typeof s!="string"||!s.length))return"Please enter a valid text";return!0}})}}function N(r){return new Array(r+5).join(" ")}class ee{type="boolean";option="help";alias=["h"];default=!1;description=`Display help for the given command. When no command is given display help for the ${a.green("list")} command`;async handler(){const e=this.parser.argumentDefinitions(),t=this.parser.optionDefinitions(),n=Object.entries(e),s=Object.entries(t),i=s.map(([l,d])=>{const p=Array.isArray(d.alias)?d.alias:d.alias?[d.alias]:[];return{name:l,...d,optionWithAlias:`--${l}${p.map(g=>`, -${g}`).join("")}`}}),o=n.filter(([,l])=>l.required);this.io.log(a.yellow("Description:")),this.io.log(` ${this.description}
9
+ `),this.io.log(a.yellow("Usage:")),this.io.log(` ${this.command} ${o.length>0?o.map(([l])=>`<${l}>`).join(" "):"\b"} [options]`);const u=Math.max(...i.map(l=>l.optionWithAlias.length),0),m=Math.max(...n.map(([l])=>l.length),0),h=m>u?m:u;if(n.length>0){this.io.log(`
10
+ ${a.yellow("Arguments")}:`);for(const[l,d]of n){const p=N(h-l.length);let g=` ${a.green(l)} ${p} ${d.description??"\b"}`;if(d.default!==void 0&&!d.required){const re=(Array.isArray(d.type)?`[${d.type[0]}]`:d.type)==="array"||Array.isArray(d.type)?JSON.stringify(d.default):d.default;g+=` ${a.yellow(`[default: ${re}]`)}`}d.variadic&&(g+=` ${a.white("(variadic)")}`),this.io.log(g)}}if(s.length>0){this.io.log(`
11
+ ${a.yellow("Options")}:`);for(const l of i){const d=N(h-l.optionWithAlias.length);let p=`${a.green(l.optionWithAlias)} ${d} ${l.description??"\b"}`;if(l.type){const g=Array.isArray(l.type)?`[${l.type[0]}]`:l.type;p+=` ${a.white(`(${g})`)}`}if(l.default!==void 0&&!l.required){const L=(Array.isArray(l.type)?`[${l.type[0]}]`:l.type)==="array"||Array.isArray(l.type)?JSON.stringify(l.default):l.default;p+=` ${a.yellow(`[default: ${L}]`)}`}this.io.log(p)}}if(this.commandsExamples.length>0){this.io.log(`
12
+ ${a.yellow("Examples")}:`);let l=process.argv[0].split("/").pop();l==="node"&&(l+=" "+process.argv[1].split("/").pop());for(const[d,p]of this.commandsExamples.entries())d>0&&this.io.log(""),this.io.log(` ${p.description}
13
+ `),this.io.log(` ${a.green(`${l} ${p.command}`)}`)}return-1}}class R{_command;description="";group;commandsExamples=[];get command(){return this._command}ctx;io;logger;parser;disablePromptingFlag=!1;_preHandler;_handler;tmp;defaultOptions(){return[new ee]}newCommandParser(e){return new M({io:e.io,options:e.options,arguments:e.arguments})}newCommandIO(e){return new I(e.logger)}constructor(e,t){this._command=e,this.description=t?.description??"",this.group=t?.group,this.tmp={options:t?.options??{},arguments:t?.arguments??{}};const n=this.defaultOptions();if(n.length>0)for(const s of n)this.tmp.options[s.option]=s}disablePrompting(){return this.disablePromptingFlag=!0,this}preHandler(e){return this._preHandler=e,this}handler(e){return this._handler=e,this}options(e){return this.tmp={options:{...this.tmp?.options??{},...e},arguments:this.tmp?.arguments??{}},this}arguments(e){return this.tmp={options:this.tmp?.options??{},arguments:{...this.tmp?.arguments??{},...e}},this}async run(e){if(!this._handler&&!this.handle)throw new Error(`No handler defined for command ${this.command||"(unknown)"}`);let t;if(this.ctx=e.ctx,this.logger=e.logger,this.io=this.newCommandIO({logger:e.logger}),e&&"args"in e){const i=this.tmp?.options??{};for(const o of this.defaultOptions())o.option in i||(i[o.option]=o);this.parser=this.newCommandParser({io:this.io,options:i,arguments:this.tmp?.arguments??{}}),t=this.parser.init(e.args);for(const o of this.defaultOptions())if(t.options[o.option]===!0){const u=await o.handler.call(this);if(u&&u!==0)return u}this.disablePromptingFlag&&this.parser.disablePrompting(),await this.parser.validate()}else t={options:e.options,arguments:e.arguments};const n=this.preHandle?await this.preHandle():null;if(n&&n!==0)return n;if(!this._handler&&this.handle)this._handler=this.handle.bind(this);else if(!this._handler)throw new Error(`No handler defined for command ${this.command||"(unknown)"}`);return await this._handler(e.ctx,t)??0}}class w extends M{command;constructor(e){const t=w.parseSignature(e.signature,e.helperDefinitions,e.defaultOptions);super({io:e.io,options:t.options,arguments:t.arguments}),this.command=t.command}static parseSignature(e,t,n){const[s,...i]=e.split(/\{(.*?)\}/g).map(m=>m.trim()).filter(Boolean),o={},u={};for(const m of i){const{name:h,isOption:l,definition:d}=w.parseParamSignature(m,t);l?o[h]=d:u[h]=d}for(const m of n)o[m.option]={type:m.type,required:m.required,alias:m.alias,variadic:m.variadic??!1,description:m.description,default:m.default??null};return{command:s,options:o,arguments:u}}static parseParamSignature(e,t){let n=e,s=!1;const i={required:!0,type:"string",description:void 0,default:null,variadic:!1};if(n.includes(":")){const[o,u]=n.split(":");n=o.trim(),i.description=u.trim()}if(n.includes("=")){const[o,u]=n.split("=");n=o.trim(),i.default=u.trim(),i.required=!1,typeof i.default=="string"&&!i.default.length?i.default=null:i.default==="true"?(i.default=!0,i.type="boolean"):i.default==="false"&&(i.default=!1,i.type="boolean")}else n.startsWith("--")&&(i.required=!1,i.default=!1,i.type="boolean");if(n.includes("|")){const[o,...u]=n.split("|");n=o.trim(),i.alias=u.map(m=>m.trim())}return n.startsWith("--")&&(s=!0,n=n.slice(2)),i.default==="*"&&(i.default=[],i.type=["string"]),n.endsWith("?")&&(i.required=!1,n=n.slice(0,-1)),n.endsWith("*")&&(i.type=["string"],i.variadic=!0,i.default=[],n=n.slice(0,-1)),i.description=i.description??t[n]??t[`--${n}`],{name:n,isOption:s,definition:i}}}class Ce extends R{helperDefinitions={};get command(){return this.parser?this.parser.command:this.signature.split(" ")[0]}newCommandParser(e){return new w({io:e.io,signature:this.signature,helperDefinitions:this.helperDefinitions,defaultOptions:this.defaultOptions()})}constructor(){super("")}option(e,t=null){return this.parser instanceof w?this.parser.option(e)??t:t}argument(e,t=null){return this.parser instanceof w?this.parser.argument(e)??t:t}async askForConfirmation(...e){return this.io.askForConfirmation(...e)}async askForInput(...e){return this.io.askForInput(...e)}async askForSelect(...e){return this.io.askForSelect(...e)}newLoader(...e){return this.io.newLoader(...e)}}class q{level;constructor(e={}){this.level=e.level??"info"}shouldLog(e){const t=["debug","info","warn","error"],n=t.indexOf(this.level);return t.indexOf(e)>=n}setLevel(e){this.level=e}getLevel(){return this.level}log(...e){console.log(...e)}info(...e){this.shouldLog("info")&&console.log(...e)}warn(...e){this.shouldLog("warn")&&console.warn(...e)}error(...e){this.shouldLog("error")&&console.error(...e)}debug(...e){this.shouldLog("debug")&&console.log(...e)}}class te{commands={};io;logger;get CommandIOClass(){return I}constructor(e){this.logger=e??new q,this.io=new this.CommandIOClass(this.logger)}getAvailableCommands(){return Object.keys(this.commands)}getCommands(){return Object.values(this.commands)}importFile=async e=>(await import(e)).default;commandResolver=async e=>{let t=await this.importFile(e);if(!t)throw new Error(`The command at path ${e} does not have a default export.`);return t&&typeof t=="object"&&"default"in t&&(t=t.default),typeof t=="function"?new t:t instanceof R?t:null};withCommandResolver(e){return this.commandResolver=e,this}withFileImporter(e){return this.importFile=e,this}registerCommand(e,t=!1){const n=e.command;if(!n)throw new Error("Command signature is invalid, it must have a command name.");if(!t&&this.commands[n])throw new Error(`Command ${n} already registered.`);this.commands[n]=e}async loadCommandsPath(e){for await(const t of this.listCommandsFiles(e))try{const n=await this.commandResolver(t);n instanceof R&&this.registerCommand(n)}catch(n){throw new Error(`Command ${t} failed to load. ${n}`,{cause:n})}}async runCommand(e,t,...n){const s=typeof t=="string"?this.commands[t]:t,i=typeof t=="string"?t:s.command;if(!s){const o=await this.suggestCommand(i);return o?await this.runCommand(e,o,...n):1}return await s.run({ctx:e,logger:this.logger,args:n})??0}async suggestCommand(e){const t=this.getAvailableCommands(),{bestMatch:n,bestMatchIndex:s,ratings:i}=le.findBestMatch(e,t),o=i.filter(u=>u.rating>.3).map(u=>u.target);if(n.rating>0&&o.length<=1||n.rating>.7&&o.length>1){const u=t[s];return await this.askRunSimilarCommand(e,u)?u:null}if(o.length){this.io.error(`${a.bgRed(" ERROR ")} Command ${a.yellow(e)} not found.
14
+ `);const u=await this.io.askForSelect(a.green("Did you mean to run one of these commands instead?"),o);if(u)return u}throw new Z(e)}async askRunSimilarCommand(e,t){return this.io.error(`${a.bgRed(" ERROR ")} Command ${a.yellow(e)} not found.
15
+ `),this.io.askForConfirmation(`${a.green(`Do you want to run ${a.yellow(t)} instead?`)} `)}async*listCommandsFiles(e){const t=ae.readdirSync(e,{withFileTypes:!0});for(const n of t){const s=D.resolve(e,n.name);if(n.isDirectory())yield*this.listCommandsFiles(D.resolve(e,n.name));else{if(!s.endsWith(".ts")&&!s.endsWith(".js")&&!s.endsWith(".mjs")&&!s.endsWith(".cjs"))continue;yield s}}}}class ne{logger;constructor(e){this.logger=e}handle(e){if(e instanceof b)return e.pretty(this.logger),-1;throw e}}class Oe extends R{constructor(e){super("help",{description:a.bold("Show help information about the CLI and its commands")}),this.opts=e}async handle(){const e=this.opts.commandRegistry.getCommands(),t=this.opts.cliName??"Bob CLI",n=this.opts.cliVersion??"0.0.0",s=(await Promise.resolve().then(()=>require("./package-D82wayAe.cjs")))?.default?.version??"0.0.0";this.io.log(`${t} ${a.green(n)} (core: ${a.yellow(s)})
4
16
 
5
- {yellow Usage}:
17
+ ${a.yellow("Usage")}:
6
18
  command [options] [arguments]
7
19
 
8
- {yellow Available commands}:
9
- `);const r=Math.max(...e.map(a=>a.command.length))??0,i={};for(const a of e){const m=a.command.split(":")[0];i[m]||(i[m]=[]),i[m].push(a)}const u=Object.entries(i).sort(([a],[m])=>a.toLowerCase().localeCompare(m.toLowerCase())).sort(([,a],[,m])=>a.length-m.length);for(const[a,m]of u){const c=m.length>1;c&&console.log(o`{yellow ${a}}:`);const h=m.sort((d,g)=>d.command.toLowerCase().localeCompare(g.command.toLowerCase()));for(const d of h){let g=C(r-d.command.length);c&&(g=g.slice(2)),console.log(o`${c?" ":""}{green ${d.command}} ${g} ${d.description}`)}}}}class P extends p{constructor(e){let t=`Argument "${e.param}" value is invalid.`;e.reason?t+=` Reason: ${e.reason}`:t+=` Value: "${e.value}"`,super(t),this.param=e}pretty(){const e=console.log;e(o` {white.bgRed ERROR } Argument {bold.yellow ${this.param.param}} value is invalid. `),(this.param.value||this.param.reason)&&e(""),this.param.value&&e(o` {blue Value}: ${this.param.value}`),this.param.reason&&e(o` {yellow Reason}: ${this.param.reason}`)}}class B extends p{constructor(e){let t=`Option "${e.option}" value is invalid.`;e.reason?t+=` Reason: ${e.reason}`:t+=` Value: "${e.value}"`,super(t),this.param=e}pretty(){const e=console.log;e(o` {white.bgRed ERROR } Option {bold.yellow ${this.param.option}} value is invalid. `),(this.param.value||this.param.reason)&&e(""),this.param.value&&e(o` {blue Value}: ${this.param.value}`),this.param.reason&&e(o` {yellow Reason}: ${this.param.reason}`)}}class M{handle(e){if(e instanceof p)return e.pretty(),-1;throw e}}class T{commandRegistry;exceptionHandler;ctx;helpCommand;get CommandRegistryClass(){return I}get HelpCommandClass(){return D}get ExceptionHandlerClass(){return M}constructor(e={}){this.ctx=e.ctx,this.commandRegistry=new this.CommandRegistryClass,this.exceptionHandler=new this.ExceptionHandlerClass,this.helpCommand=new this.HelpCommandClass({cliName:e.name,cliVersion:e.version,commandRegistry:this.commandRegistry})}setCommandResolver(e){this.commandRegistry.setCommandResolver(e)}async withCommands(...e){for(const t of e)typeof t=="string"?await this.commandRegistry.loadCommandsPath(t):typeof t=="function"?this.registerCommand(new t):this.registerCommand(t)}async runCommand(e,...t){return e?await this.commandRegistry.runCommand(this.ctx,e,...t).catch(this.exceptionHandler.handle):await this.runHelpCommand()}async runHelpCommand(){return await this.runCommand(this.helpCommand)}registerCommand(e){this.commandRegistry.registerCommand(e)}}exports.BadCommandOption=B;exports.BadCommandParameter=P;exports.BobError=p;exports.Cli=T;exports.Command=R;exports.CommandIO=v;exports.HelpOption=O;
20
+ ${a.yellow("Available commands")}:
21
+ `);const i=Math.max(...e.map(m=>m.command.length))??0,o={};for(const m of e){const h=m.group??m.command.split(":")[0];o[h]||(o[h]=[]),o[h].push(m)}const u=Object.entries(o).sort(([m],[h])=>m.toLowerCase().localeCompare(h.toLowerCase())).sort(([,m],[,h])=>m.length-h.length);for(const[m,h]of u){const l=h.length>1;l&&this.io.log(a.yellow(`${m}:`));const d=h.sort((p,g)=>p.command.toLowerCase().localeCompare(g.command.toLowerCase()));for(const p of d){let g=N(i-p.command.length);l&&(g=g.slice(2)),this.io.log(`${l?" ":""}${a.green(p.command)} ${g} ${p.description}`)}}}}class Ae{ctx;logger;commandRegistry;exceptionHandler;helpCommand;newCommandRegistry(e){return new te(e.logger)}newHelpCommand(e){return new Oe(e)}newExceptionHandler(e){return new ne(e.logger)}constructor(e={}){this.ctx=e.ctx,this.logger=e.logger??new q,this.commandRegistry=this.newCommandRegistry({logger:this.logger}),this.exceptionHandler=this.newExceptionHandler({logger:this.logger}),this.helpCommand=this.newHelpCommand({cliName:e.name,cliVersion:e.version,commandRegistry:this.commandRegistry})}withCommandResolver(e){return this.commandRegistry.withCommandResolver(e),this}withFileImporter(e){return this.commandRegistry.withFileImporter(e),this}async withCommands(...e){for(const t of e)typeof t=="string"?await this.commandRegistry.loadCommandsPath(t):typeof t=="function"?this.registerCommand(new t):this.registerCommand(t)}async runCommand(e,...t){return e?await this.commandRegistry.runCommand(this.ctx??{},e,...t).catch(this.exceptionHandler.handle.bind(this.exceptionHandler)):await this.runHelpCommand()}async runHelpCommand(){return await this.runCommand(this.helpCommand)}registerCommand(e){this.commandRegistry.registerCommand(e)}}exports.BadCommandOption=F;exports.BadCommandParameter=ve;exports.BobError=b;exports.Cli=Ae;exports.Command=R;exports.CommandIO=I;exports.CommandNotFoundError=Z;exports.CommandParser=M;exports.CommandRegistry=te;exports.CommandSignatureParser=w;exports.CommandWithSignature=Ce;exports.ExceptionHandler=ne;exports.HelpOption=ee;exports.InvalidOption=S;exports.Logger=q;exports.MissingRequiredArgumentValue=B;exports.MissingRequiredOptionValue=X;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="bob-core",t="2.0.0-beta.10",s="BOB Core",i="module",n=!1,r=["dist/**"],o={".":{import:"./dist/esm/index.js",require:"./dist/cjs/index.js"}},c={"*":{"*":["./dist/cjs/*.d.ts"]}},p={start:"node -r @swc-node/register debug/main.ts",build:"rimraf ./dist && vite build",typecheck:"tsc --noEmit",prepack:"npm run build",test:"vitest run",lint:"eslint .","lint:fix":"eslint . --fix"},d="Léo Hubert",l="ISC",a={"@eslint/js":"^9.37.0","@faker-js/faker":"^10.0.0","@swc-node/register":"^1.11.1","@trivago/prettier-plugin-sort-imports":"^5.2.2","@types/minimist":"^1.2.5","@types/node":"^20.14.5","@types/prompts":"^2.4.9","@types/string-similarity":"^4.0.2","@vitest/coverage-v8":"^3.2.4",eslint:"^9.37.0","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.4",prettier:"^3.6.2",rimraf:"^6.0.1",tsx:"^4.20.6",typescript:"^5.7.3","typescript-eslint":"^8.46.0",vite:"^7.1.6","vite-plugin-dts":"^4.5.4",vitest:"^3.2.4"},m={chalk:"^5.6.2",minimist:"^1.2.8",prompts:"^2.4.2","string-similarity":"^4.0.4"},u={name:e,version:t,description:s,type:i,sideEffects:n,files:r,exports:o,typesVersions:c,scripts:p,author:d,license:l,devDependencies:a,dependencies:m};exports.author=d;exports.default=u;exports.dependencies=m;exports.description=s;exports.devDependencies=a;exports.exports=o;exports.files=r;exports.license=l;exports.name=e;exports.scripts=p;exports.sideEffects=n;exports.type=i;exports.typesVersions=c;exports.version=t;
@@ -1,26 +1,35 @@
1
- import { CommandRegistry } from './CommandRegistry.js';
2
1
  import { Command } from './Command.js';
3
- import { default as HelpCommand } from './commands/HelpCommand.js';
2
+ import { CommandRegistry, CommandResolver, FileImporter } from './CommandRegistry.js';
4
3
  import { ExceptionHandler } from './ExceptionHandler.js';
5
- export type CliOptions<C> = {
4
+ import { Logger } from './Logger.js';
5
+ import { default as HelpCommand, HelpCommandOptions } from './commands/HelpCommand.js';
6
+ import { ContextDefinition, OptionsSchema } from './lib/types.js';
7
+ export type CliOptions<C extends ContextDefinition = ContextDefinition> = {
6
8
  ctx?: C;
7
9
  name?: string;
8
10
  version?: string;
11
+ logger?: Logger;
9
12
  };
10
- export declare class Cli<C> {
13
+ export declare class Cli<C extends ContextDefinition = ContextDefinition> {
14
+ private readonly ctx?;
15
+ private readonly logger;
11
16
  readonly commandRegistry: CommandRegistry;
12
17
  private readonly exceptionHandler;
13
- private readonly ctx?;
14
18
  private readonly helpCommand;
15
- get CommandRegistryClass(): typeof CommandRegistry;
16
- get HelpCommandClass(): typeof HelpCommand;
17
- get ExceptionHandlerClass(): typeof ExceptionHandler;
19
+ protected newCommandRegistry(opts: {
20
+ logger: Logger;
21
+ }): CommandRegistry;
22
+ protected newHelpCommand(opts: HelpCommandOptions): HelpCommand;
23
+ protected newExceptionHandler(opts: {
24
+ logger: Logger;
25
+ }): ExceptionHandler;
18
26
  constructor(opts?: CliOptions<C>);
19
- setCommandResolver(resolver: (path: string) => Promise<Command<C>>): void;
20
- withCommands(...commands: Array<Command<C> | {
27
+ withCommandResolver(resolver: CommandResolver): this;
28
+ withFileImporter(importer: FileImporter): this;
29
+ withCommands(...commands: Array<Command<C, OptionsSchema, OptionsSchema> | {
21
30
  new (): Command<C>;
22
31
  } | string>): Promise<void>;
23
- runCommand(command: string | Command, ...args: any[]): Promise<number>;
32
+ runCommand(command: string | Command | undefined, ...args: string[]): Promise<number>;
24
33
  runHelpCommand(): Promise<number>;
25
- protected registerCommand(command: Command<C>): void;
34
+ protected registerCommand(command: Command<C, OptionsSchema, OptionsSchema>): void;
26
35
  }
@@ -1,45 +1,61 @@
1
+ import { CommandIO } from './CommandIO.js';
1
2
  import { CommandParser } from './CommandParser.js';
3
+ import { Logger } from './Logger.js';
2
4
  import { CommandOption } from './contracts/index.js';
3
- import { CommandIO } from './CommandIO.js';
5
+ import { ArgumentsObject, ArgumentsSchema, ContextDefinition, OptionsObject, OptionsSchema } from './lib/types.js';
6
+ export type CommandHandlerOptions<Options extends OptionsSchema, Arguments extends ArgumentsSchema> = {
7
+ options: OptionsObject<Options>;
8
+ arguments: ArgumentsObject<Arguments>;
9
+ };
10
+ export type CommandHandler<C extends ContextDefinition, Options extends OptionsSchema, Arguments extends ArgumentsSchema> = (ctx: C, opts: CommandHandlerOptions<Options, Arguments>) => Promise<number | void> | number | void;
11
+ export type CommandRunOption<C, Options extends OptionsSchema, Arguments extends ArgumentsSchema> = {
12
+ logger: Logger;
13
+ ctx: C;
14
+ } & ({
15
+ args: string[];
16
+ } | {
17
+ options: OptionsObject<Options>;
18
+ arguments: ArgumentsObject<Arguments>;
19
+ });
4
20
  export type CommandExample = {
5
21
  description: string;
6
22
  command: string;
7
23
  };
8
- export declare abstract class Command<C = any> {
9
- abstract signature: string;
10
- abstract description: string;
11
- protected ctx: C;
12
- protected helperDefinitions: {
13
- [key: string]: string;
14
- };
24
+ export declare class Command<C extends ContextDefinition = ContextDefinition, Options extends OptionsSchema = OptionsSchema, Arguments extends ArgumentsSchema = ArgumentsSchema> {
25
+ readonly _command: string;
26
+ readonly description: string;
27
+ readonly group?: string;
15
28
  protected commandsExamples: CommandExample[];
16
- protected parser: CommandParser;
29
+ get command(): string;
30
+ protected ctx: C | undefined;
17
31
  protected io: CommandIO;
18
- protected abstract handle(): Promise<void | number>;
32
+ protected logger: Logger;
33
+ protected parser: CommandParser<Options, Arguments>;
34
+ protected disablePromptingFlag: boolean;
19
35
  protected preHandle?(): Promise<void | number>;
20
- protected get CommandParserClass(): typeof CommandParser;
21
- protected get CommandIOClass(): typeof CommandIO;
22
- protected defaultOptions(): CommandOption<Command<C>>[];
23
- get command(): string;
24
- run(ctx: C, ...args: any[]): Promise<number>;
25
- protected setOption(name: string, value: any): void;
26
- protected setArgument(name: string, value: any): void;
27
- protected option<T = string>(key: string): T | null;
28
- protected option<T = string>(key: string, defaultValue: T): NoInfer<T>;
29
- protected optionBoolean(key: string, defaultValue?: boolean): boolean;
30
- protected optionArray<T = string>(key: string, defaultValue?: Array<T>): Array<NoInfer<T>>;
31
- protected optionNumber(key: string): number | null;
32
- protected optionNumber(key: string, defaultValue: number): number;
33
- protected argument<T = string>(key: string): T | null;
34
- protected argument<T = string>(key: string, defaultValue: T): NoInfer<T>;
35
- protected argumentArray<T = string>(key: string, defaultValue?: Array<any>): Array<T>;
36
- protected argumentBoolean(key: string, defaultValue?: boolean): boolean;
37
- protected argumentNumber(key: string, defaultValue?: number | null): number | null;
38
- /**
39
- * Prompt utils
40
- */
41
- askForConfirmation(...opts: Parameters<typeof this.io.askForConfirmation>): ReturnType<typeof this.io.askForConfirmation>;
42
- askForInput(...opts: Parameters<typeof this.io.askForInput>): ReturnType<typeof this.io.askForInput>;
43
- askForSelect(...opts: Parameters<typeof this.io.askForSelect>): ReturnType<typeof this.io.askForSelect>;
44
- newLoader(...opts: Parameters<typeof this.io.newLoader>): ReturnType<typeof this.io.newLoader>;
36
+ protected _preHandler?: CommandHandler<C, Options, Arguments>;
37
+ protected handle?(ctx: C, opts: CommandHandlerOptions<Options, Arguments>): Promise<number | void> | number | void;
38
+ protected _handler?: CommandHandler<C, Options, Arguments>;
39
+ private tmp?;
40
+ protected defaultOptions(): CommandOption<Command>[];
41
+ protected newCommandParser(opts: {
42
+ io: CommandIO;
43
+ options: Options;
44
+ arguments: Arguments;
45
+ }): CommandParser<Options, Arguments>;
46
+ protected newCommandIO(opts: {
47
+ logger: Logger;
48
+ }): CommandIO;
49
+ constructor(command: string, opts?: {
50
+ description?: string;
51
+ group?: string;
52
+ options?: Options;
53
+ arguments?: Arguments;
54
+ });
55
+ disablePrompting(): this;
56
+ preHandler(handler: CommandHandler<C, Options, Arguments>): this;
57
+ handler(handler: CommandHandler<C, Options, Arguments>): this;
58
+ options<Opts extends OptionsSchema>(opts: Opts): Command<C, Options & Opts, Arguments>;
59
+ arguments<Args extends ArgumentsSchema>(args: Args): Command<C, Options, Arguments & Args>;
60
+ run(opts: CommandRunOption<C, Options, Arguments>): Promise<number | void>;
45
61
  }
@@ -1,11 +1,22 @@
1
+ import { Logger } from './Logger.js';
1
2
  export type SelectOption = {
2
3
  title: string;
3
- value?: any;
4
+ value?: unknown;
4
5
  disabled?: boolean | undefined;
5
6
  selected?: boolean | undefined;
6
7
  description?: string | undefined;
7
8
  };
8
9
  export declare class CommandIO {
10
+ private logger;
11
+ constructor(logger: Logger);
12
+ /**
13
+ * Logger methods
14
+ */
15
+ log(...args: unknown[]): void;
16
+ info(...args: unknown[]): void;
17
+ warn(...args: unknown[]): void;
18
+ error(...args: unknown[]): void;
19
+ debug(...args: unknown[]): void;
9
20
  /**
10
21
  * Prompt utils
11
22
  */
@@ -16,6 +27,15 @@ export declare class CommandIO {
16
27
  min?: number;
17
28
  max?: number;
18
29
  }): Promise<string | null>;
30
+ askForDate(message: string, defaultValue?: Date, opts?: {
31
+ validate?: (value: Date) => boolean | string;
32
+ mask?: string;
33
+ }): Promise<Date | null>;
34
+ askForList(message: string, defaultValue?: string | number, opts?: {
35
+ validate?: (value: string) => boolean | string;
36
+ format?: (value: string) => string;
37
+ separator?: string;
38
+ }): Promise<string[] | null>;
19
39
  askForToggle(message: string, defaultValue?: boolean, opts?: {
20
40
  active?: string;
21
41
  inactive?: string;
@@ -1,48 +1,96 @@
1
- import { CommandOption } from './contracts/index.js';
2
1
  import { CommandIO } from './CommandIO.js';
3
- export type ArgSignature = {
4
- name: string;
5
- type: 'string' | 'boolean' | 'array';
6
- optional?: boolean;
7
- variadic?: boolean;
8
- alias?: string[];
9
- help?: string;
10
- defaultValue: string | boolean | Array<string> | null;
11
- isOption?: boolean;
12
- };
13
- export declare class CommandParser {
14
- protected readonly io: CommandIO;
15
- protected readonly signature: string;
16
- protected readonly helperDefinitions: {
17
- [key: string]: string;
2
+ import { OptionDetails } from './lib/optionHelpers.js';
3
+ import { OptionDefinition, OptionReturnType, OptionsObject, OptionsSchema } from './lib/types.js';
4
+ /**
5
+ * Parses command-line arguments into typed options and arguments
6
+ * Handles validation, type conversion, and default values
7
+ */
8
+ export declare class CommandParser<Options extends OptionsSchema, Arguments extends OptionsSchema> {
9
+ protected options: Options;
10
+ protected parsedOptions: OptionsObject<Options> | null;
11
+ protected arguments: Arguments;
12
+ protected parsedArguments: OptionsObject<Arguments> | null;
13
+ protected io: CommandIO;
14
+ protected shouldPromptForMissingOptions: boolean;
15
+ constructor(opts: {
16
+ io: CommandIO;
17
+ options: Options;
18
+ arguments: Arguments;
19
+ });
20
+ /**
21
+ * Parses raw command-line arguments into structured options and arguments
22
+ * @param args - Raw command line arguments (typically from process.argv.slice(2))
23
+ * @returns Object containing parsed options and arguments
24
+ * @throws {InvalidOption} If an unknown option is provided
25
+ * @throws {BadCommandOption} If a value cannot be converted to the expected type
26
+ */
27
+ init(args: string[]): {
28
+ options: OptionsObject<Options>;
29
+ arguments: OptionsObject<Arguments>;
18
30
  };
19
- protected readonly defaultCommandOptions: CommandOption<any>[];
20
- command: string;
21
- private arguments;
22
- private options;
23
- private argumentsSignature;
24
- private optionSignatures;
25
- private optionAliases;
26
- constructor(io: CommandIO, signature: string, helperDefinitions: {
27
- [key: string]: string;
28
- }, defaultCommandOptions: CommandOption<any>[], ...args: any[]);
29
- option(name: string): any;
30
- setOption(name: string, value: any): void;
31
- optionHelp(name: string): string | undefined;
32
- argument(name: string): any;
33
- setArgument(name: string, value: any): void;
34
- argumentHelp(name: string): string | undefined;
35
- getArgumentSignatures(): {
36
- [argument: string]: ArgSignature;
37
- };
38
- getOptionSignatures(): {
39
- [option: string]: ArgSignature;
40
- };
41
- private getParamValue;
42
- private handleArguments;
43
- private handleOptions;
44
- private parseSignature;
45
- private parseDefaultOptions;
46
- private parseParamSignature;
31
+ /**
32
+ * Validates the parsed options and arguments
33
+ * @throws {Error} If validation fails
34
+ */
47
35
  validate(): Promise<void>;
36
+ /**
37
+ * Retrieves a parsed option value by name
38
+ * @param name - The option name
39
+ * @returns The typed option value
40
+ * @throws {Error} If init() has not been called yet
41
+ */
42
+ option<OptsName extends keyof Options>(name: OptsName): OptionReturnType<Options[OptsName]>;
43
+ setOption<OptsName extends keyof Options>(name: OptsName, value: OptionReturnType<Options[OptsName]>): void;
44
+ /**
45
+ * Retrieves a parsed argument value by name
46
+ * @param name - The argument name
47
+ * @returns The typed argument value
48
+ * @throws {Error} If init() has not been called yet
49
+ */
50
+ argument<ArgName extends keyof Arguments>(name: ArgName): OptionReturnType<Arguments[ArgName]>;
51
+ setArgument<ArgName extends keyof Arguments>(name: ArgName, value: OptionReturnType<Arguments[ArgName]>): void;
52
+ /**
53
+ * Validates that all provided options are recognized
54
+ * @throws {InvalidOption} If an unknown option is found
55
+ */
56
+ private validateUnknownOptions;
57
+ /**
58
+ * Processes named options from minimist output
59
+ */
60
+ private handleOptions;
61
+ /**
62
+ * Processes positional arguments from minimist output
63
+ */
64
+ private handleArguments;
65
+ /**
66
+ * Handles variadic arguments that consume all remaining positional values
67
+ */
68
+ private handleVariadicArgument;
69
+ /**
70
+ * Resolves a single positional argument value with defaults and type conversion
71
+ * Note: Does not validate required arguments - validation happens in subclass validate() methods
72
+ */
73
+ private resolveArgumentValue;
74
+ /**
75
+ * Resolves an option value from the parsed option values object
76
+ * Handles alias resolution, defaults, and type conversion
77
+ */
78
+ private resolveOptionValue;
79
+ optionDefinitions(): Record<string, OptionDetails>;
80
+ argumentDefinitions(): Record<string, OptionDetails>;
81
+ availableOptions(): string[];
82
+ availableArguments(): string[];
83
+ /**
84
+ * Disables prompting for missing argument values
85
+ * Useful for non-interactive environments
86
+ */
87
+ disablePrompting(): this;
88
+ /**
89
+ * Prompts the user to provide a missing argument value via CommandIO
90
+ * Used by validate() when shouldPromptForMissingArgs is enabled
91
+ * @param argumentName - The name of the missing argument
92
+ * @param argDef - The argument's definition for type and description
93
+ * @returns The user-provided value, or null if none given
94
+ */
95
+ protected promptForArgument(argumentName: string, argDef: OptionDefinition): Promise<string | number | string[] | null>;
48
96
  }
@@ -1,19 +1,24 @@
1
1
  import { Command } from './Command.js';
2
2
  import { CommandIO } from './CommandIO.js';
3
- export type CommandResolver = (path: string) => Promise<Command>;
3
+ import { Logger } from './Logger.js';
4
+ import { ArgumentsSchema, ContextDefinition, OptionsSchema } from './lib/types.js';
5
+ export type CommandResolver = (path: string) => Promise<Command | null>;
6
+ export type FileImporter = (filePath: string) => Promise<unknown>;
4
7
  export declare class CommandRegistry {
5
8
  private readonly commands;
6
9
  protected readonly io: CommandIO;
7
- get commandSuffix(): string;
10
+ protected readonly logger: Logger;
8
11
  protected get CommandIOClass(): typeof CommandIO;
9
- constructor();
12
+ constructor(logger?: Logger);
10
13
  getAvailableCommands(): string[];
11
- getCommands(): Command[];
14
+ getCommands(): Array<Command>;
15
+ private importFile;
12
16
  private commandResolver;
13
- setCommandResolver(resolver: (path: string) => Promise<Command>): void;
14
- registerCommand(command: Command, force?: boolean): void;
17
+ withCommandResolver(resolver: CommandResolver): this;
18
+ withFileImporter(importer: FileImporter): this;
19
+ registerCommand<C extends ContextDefinition = ContextDefinition, Opts extends OptionsSchema = OptionsSchema, Args extends ArgumentsSchema = ArgumentsSchema>(command: Command<C, Opts, Args>, force?: boolean): void;
15
20
  loadCommandsPath(commandsPath: string): Promise<void>;
16
- runCommand(ctx: any, command: string | Command, ...args: any[]): Promise<number>;
21
+ runCommand(ctx: ContextDefinition, command: string | Command, ...args: string[]): Promise<number>;
17
22
  private suggestCommand;
18
23
  private askRunSimilarCommand;
19
24
  private listCommandsFiles;
@@ -0,0 +1,40 @@
1
+ import { Command } from './Command.js';
2
+ import { CommandIO } from './CommandIO.js';
3
+ import { CommandParser } from './CommandParser.js';
4
+ import { CommandOption } from './contracts/index.js';
5
+ import { OptionsSchema } from './lib/types.js';
6
+ /**
7
+ * Extends CommandParser to parse command signatures like "command {arg} {--option}"
8
+ * Handles interactive prompting for missing required arguments via CommandIO
9
+ */
10
+ export declare class CommandSignatureParser<Opts extends OptionsSchema = OptionsSchema, Args extends OptionsSchema = OptionsSchema> extends CommandParser<Opts, Args> {
11
+ readonly command: string;
12
+ constructor(opts: {
13
+ io: CommandIO;
14
+ signature: string;
15
+ helperDefinitions: {
16
+ [key: string]: string;
17
+ };
18
+ defaultOptions: CommandOption<Command>[];
19
+ });
20
+ /**
21
+ * Parses command signature string into command name and parameter schemas
22
+ * Example: "migrate {name} {--force}" -> { command: "migrate", arguments: {name: ...}, options: {force: ...} }
23
+ */
24
+ private static parseSignature;
25
+ /**
26
+ * Parses a single parameter signature like "{name}" or "{--force}" or "{files*}"
27
+ * Extracts name, type, default value, aliases, description, etc.
28
+ *
29
+ * Signature syntax:
30
+ * - {arg} -> required string argument
31
+ * - {arg?} -> optional argument
32
+ * - {arg=default} -> argument with default value
33
+ * - {arg*} -> variadic argument (array)
34
+ * - {arg:desc} -> argument with description
35
+ * - {--opt} -> boolean option
36
+ * - {--opt=} -> string option
37
+ * - {--opt|o} -> option with alias
38
+ */
39
+ private static parseParamSignature;
40
+ }
@@ -0,0 +1,28 @@
1
+ import { Command, CommandHandlerOptions } from './Command.js';
2
+ import { CommandIO } from './CommandIO.js';
3
+ import { CommandSignatureParser } from './CommandSignatureParser.js';
4
+ import { ContextDefinition, OptionsSchema } from './lib/types.js';
5
+ export declare abstract class CommandWithSignature<C extends ContextDefinition = ContextDefinition, Opts extends OptionsSchema = OptionsSchema, Args extends OptionsSchema = OptionsSchema> extends Command<C, Opts, Args> {
6
+ abstract signature: string;
7
+ abstract description: string;
8
+ protected helperDefinitions: {
9
+ [key: string]: string;
10
+ };
11
+ get command(): string;
12
+ parser: CommandSignatureParser<Opts, Args>;
13
+ protected newCommandParser(opts: {
14
+ io: CommandIO;
15
+ options: Opts;
16
+ arguments: Args;
17
+ }): CommandSignatureParser<Opts, Args>;
18
+ constructor();
19
+ protected abstract handle(ctx: C, opts: CommandHandlerOptions<Opts, Args>): Promise<number | void>;
20
+ protected option<T = string>(key: string): T | null;
21
+ protected option<T = string>(key: string, defaultValue: T): NoInfer<T>;
22
+ protected argument<T = string>(key: string): T | null;
23
+ protected argument<T = string>(key: string, defaultValue: T): NoInfer<T>;
24
+ askForConfirmation(...opts: Parameters<typeof this.io.askForConfirmation>): ReturnType<typeof this.io.askForConfirmation>;
25
+ askForInput(...opts: Parameters<typeof this.io.askForInput>): ReturnType<typeof this.io.askForInput>;
26
+ askForSelect(...opts: Parameters<typeof this.io.askForSelect>): ReturnType<typeof this.io.askForSelect>;
27
+ newLoader(...opts: Parameters<typeof this.io.newLoader>): ReturnType<typeof this.io.newLoader>;
28
+ }
@@ -1,4 +1,7 @@
1
+ import { Logger } from './Logger.js';
1
2
  import { BobError } from './errors/index.js';
2
3
  export declare class ExceptionHandler {
4
+ private readonly logger;
5
+ constructor(logger: Logger);
3
6
  handle(err: Error | BobError): number;
4
7
  }
@@ -0,0 +1,16 @@
1
+ import { LogLevel, LoggerContract } from './contracts/index.js';
2
+ export type LoggerOptions = {
3
+ level?: LogLevel;
4
+ };
5
+ export declare class Logger implements LoggerContract {
6
+ private level;
7
+ constructor(opts?: LoggerOptions);
8
+ private shouldLog;
9
+ setLevel(level: LogLevel): void;
10
+ getLevel(): LogLevel;
11
+ log(...args: unknown[]): void;
12
+ info(...args: unknown[]): void;
13
+ warn(...args: unknown[]): void;
14
+ error(...args: unknown[]): void;
15
+ debug(...args: unknown[]): void;
16
+ }
@@ -7,8 +7,6 @@ export type HelpCommandOptions = {
7
7
  };
8
8
  export default class HelpCommand extends Command {
9
9
  private opts;
10
- signature: string;
11
- description: string;
12
10
  constructor(opts: HelpCommandOptions);
13
- protected handle(): Promise<void>;
11
+ handle(): Promise<void>;
14
12
  }