bob-core 2.0.0-beta.5 → 2.0.0-beta.6

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/cjs/index.js CHANGED
@@ -1,9 +1,9 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const j=require("minimist"),l=require("chalk"),w=require("prompts"),T=require("node:fs"),k=require("path"),M=require("string-similarity");function P(s){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(s){for(const t in s)if(t!=="default"){const n=Object.getOwnPropertyDescriptor(s,t);Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>s[t]})}}return e.default=s,Object.freeze(e)}const _=P(T),W=P(M);class f extends Error{}class B extends f{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(l` {white.bgRed ERROR } Argument {bold.yellow ${this.param.param}} value is invalid. `),(this.param.value||this.param.reason)&&e.log(""),this.param.value&&e.log(l` {blue Value}: ${this.param.value}`),this.param.reason&&e.log(l` {yellow Reason}: ${this.param.reason}`)}}class b extends f{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(l` {white.bgRed ERROR } Option {bold.yellow ${this.param.option}} value is invalid. `),(this.param.value||this.param.reason)&&e.log(""),this.param.value&&e.log(l` {blue Value}: ${this.param.value}`),this.param.reason&&e.log(l` {yellow Reason}: ${this.param.reason}`)}}function q(s){if(s==="string"||s==="secret"||s==="number")return null;if(s==="boolean")return!1;if(Array.isArray(s)&&s.length===1){if(s[0]==="string")return[];if(s[0]==="number")return[]}throw new Error("Invalid option type: "+s)}function F(s){return!Array.isArray(s)&&typeof s=="object"&&s.type?s.default!==void 0?s.default:q(s.type):q(s)}function g(s){return typeof s=="string"||Array.isArray(s)?{type:s,default:F(s),description:"",alias:[],required:!1,variadic:!1}:{type:s.type,default:s.default??F(s.type),description:s.description??"",alias:s.alias?Array.isArray(s.alias)?s.alias:[s.alias]:[],required:s.required??!1,variadic:s.variadic??!1}}class C extends f{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(l`\n{yellow Available options}:`);for(const[n,r]of t){const i=g(r),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(a=>`, -${a}`).join(""):""}`,c=" ".repeat(30-m.length);e.log(l` {green ${m}} ${c} ${i.description||"\b"} {white (${u})}`)}e.log("")}e.log(l`{white.bgRed ERROR } Option {bold.yellow ${this.option}} is not recognized.`)}}class N extends f{constructor(e){super(`Command "${e}" not found.`),this.command=e}pretty(e){e.log(l`{bgRed ERROR } Command {yellow ${this.command}} not found.`)}}class A extends f{constructor(e){super(`Argument "${e}" is required.`),this.argument=e}pretty(e){e.log(l`{white.bgRed ERROR } Argument {bold.yellow ${this.argument}} is required.`)}}class L extends f{constructor(e){super(`Argument "${e}" is required.`),this.option=e}pretty(e){e.log(l`{white.bgRed ERROR } Option {bold.yellow ${this.option}} is required.`)}}function v(s,e,t,n){if(s==null)return n??null;if(e==="string")return String(s);if(e==="number"){const r=Number(s);if(isNaN(r))throw new b({option:t,reason:`Expected a number, got "${s}"`});return r}if(e==="boolean")return typeof s=="boolean"?s:s==="true"||s==="1"?!0:s==="false"||s==="0"?!1:!!s;if(Array.isArray(e)){const r=e[0],i=Array.isArray(s)?s:[s];if(r==="string")return i.map(o=>String(o));if(r==="number")return i.map(o=>{const u=Number(o);if(isNaN(u))throw new b({option:t,reason:`Expected array of numbers, got "${o}" in array`});return u})}return s}class R{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}=j(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(g(this.options[e]).required&&(this.parsedOptions?.[e]===void 0||this.parsedOptions?.[e]===null))throw new L(e);for(const e in this.arguments){const t=g(this.arguments[e]),n=this.parsedArguments?.[e];if(t.required&&n==null){if(this.shouldPromptForMissingOptions){const r=await this.promptForArgument(e,t);if(r&&this.parsedArguments){this.parsedArguments[e]=v(r,t.type,e);continue}}throw new A(e)}if(t.required&&t.variadic&&Array.isArray(n)&&n.length===0){if(this.shouldPromptForMissingOptions){const r=await this.promptForArgument(e,t);if(r&&this.parsedArguments){this.parsedArguments[e]=v(r,t.type,e);continue}}throw new A(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 C(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 C(e,this.arguments);this.parsedArguments[e]=t}validateUnknownOptions(e){const t=new Set;for(const n in this.options){t.add(n);const r=g(this.options[n]);for(const i of r.alias)t.add(i)}for(const n in e)if(!t.has(n))throw new C(n,this.options)}handleOptions(e){const t={};for(const n in this.options){const r=g(this.options[n]);t[n]=this.resolveOptionValue(n,r,e)}return t}handleArguments(e){const t={},n=[...e];for(const r in this.arguments){const i=g(this.arguments[r]);if(i.variadic){t[r]=this.handleVariadicArgument(r,i,n);continue}t[r]=this.resolveArgumentValue(r,i,n.shift())}return t}handleVariadicArgument(e,t,n){return n.length?v(n,t.type,e,t.default):t.default}resolveArgumentValue(e,t,n){return n===void 0?t.default:v(n,t.type,e,t.default)}resolveOptionValue(e,t,n){let r;const i=[e,...t.alias];for(const o of i)if(o in n){r=n[o];break}if(r===void 0){if(t.required)throw new b({option:e,reason:"Required option is missing"});return t.default}return v(r,t.type,e,t.default)}optionDefinitions(){const e={};for(const t in this.options)e[t]=g(this.options[t]);return e}argumentDefinitions(){const e={};for(const t in this.arguments)e[t]=g(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=l`{yellow.bold ${e}} is required`;return t.description&&(n+=l`: {gray (${t.description})}`),n+=`
2
- `,Array.isArray(t.type)?(n+=l`Please provide one or more values, separated by commas:\n`,await this.io.askForList(n,void 0,{validate:r=>r.length?!0:"Please enter at least one value"})):await this.io.askForInput(n,void 0,{type:t.type==="number"?"number":t.type==="secret"?"password":"text",validate:r=>{if(t.type==="number"){const i=Number(r);if(isNaN(i))return"Please enter a valid number"}else if(t.type==="string"&&(typeof r!="string"||!r.length))return"Please enter a valid text";return!0}})}}function $(s){return new Array(s+5).join(" ")}class D{type="boolean";option="help";alias=["h"];default=!1;description=l`Display help for the given command. When no command is given display help for the {green list} command`;async handler(){const e=this.parser.argumentDefinitions(),t=this.parser.optionDefinitions(),n=Object.entries(e),r=Object.entries(t),i=r.map(([a,d])=>{const p=Array.isArray(d.alias)?d.alias:d.alias?[d.alias]:[];return{name:a,...d,optionWithAlias:`--${a}${p.map(h=>`, -${h}`).join("")}`}}),o=n.filter(([,a])=>a.required);this.io.log(l`{yellow Description}:`),this.io.log(l` ${this.description}\n`),this.io.log(l`{yellow Usage}:`),this.io.log(l` ${this.command} ${o.length>0?o.map(([a])=>`<${a}>`).join(" "):"\b"} [options]`);const u=Math.max(...i.map(a=>a.optionWithAlias.length),0),m=Math.max(...n.map(([a])=>a.length),0),c=m>u?m:u;if(n.length>0){this.io.log(l`\n{yellow Arguments}:`);for(const[a,d]of n){const p=$(c-a.length);let h=l` {green ${a}} ${p} ${d.description??"\b"}`;if(d.default!==void 0&&!d.required){const H=(Array.isArray(d.type)?`[${d.type[0]}]`:d.type)==="array"||Array.isArray(d.type)?JSON.stringify(d.default):d.default;h+=l` {yellow [default: ${H}]}`}d.variadic&&(h+=l` {white (variadic)}`),this.io.log(h)}}if(r.length>0){this.io.log(l`\n{yellow Options}:`);for(const a of i){const d=$(c-a.optionWithAlias.length);let p=l`{green ${a.optionWithAlias}} ${d} ${a.description??"\b"}`;if(a.type){const h=Array.isArray(a.type)?`[${a.type[0]}]`:a.type;p+=l` {white (${h})}`}if(a.default!==void 0&&!a.required){const S=(Array.isArray(a.type)?`[${a.type[0]}]`:a.type)==="array"||Array.isArray(a.type)?JSON.stringify(a.default):a.default;p+=l` {yellow [default: ${S}]}`}this.io.log(p)}}if(this.commandsExamples.length>0){this.io.log(l`\n{yellow Examples}:`);let a=process.argv[0].split("/").pop();a==="node"&&(a+=" "+process.argv[1].split("/").pop());for(const[d,p]of this.commandsExamples.entries())d>0&&this.io.log(""),this.io.log(` ${p.description}
3
- `),this.io.log(l` {green ${a} ${p.command}}`)}return-1}}class x{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 w({type:"confirm",name:"value",message:e,initial:t??!1})).value}async askForInput(e,t,n){return(await w({type:"text",name:"value",message:e,initial:t,...n}))?.value??null}async askForDate(e,t,n){return(await w({type:"date",name:"value",message:e,initial:t,...n}))?.value??null}async askForList(e,t,n){return(await w({type:"list",name:"value",message:e,initial:t,...n}))?.value??null}async askForToggle(e,t,n){return(await w({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 r=[];for(const o of t)typeof o=="string"?r.push({title:o,value:o}):r.push(o);return(await w({type:"select",name:"value",message:e,choices:r,...n}))?.value??null}newLoader(e="",t=["⠙","⠘","⠰","⠴","⠤","⠦","⠆","⠃","⠋","⠉"],n=100){let r=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++]+" "+r)),o=o%t.length},n),m=()=>{clearInterval(u),process.stdout.write(new TextEncoder().encode("\r"+" ".repeat(r.length+5)+"\r"))};return{[Symbol.dispose]:m,[Symbol.asyncDispose]:m,updateText:c=>{i=r,r=c},stop:m}}}class O{_command;description="";group;commandsExamples=[];get command(){return this._command}ctx;io;logger;parser;disablePromptingFlag=!1;_preHandler;_handler;tmp;defaultOptions(){return[new D]}newCommandParser(e){return new R({io:e.io,options:e.options,arguments:e.arguments})}newCommandIO(e){return new x(e.logger)}constructor(e,t){this._command=e,this.description=t?.description??"",this.group=t?.group;const n=this.defaultOptions();if(n.length>0){this.tmp={options:{},arguments:{}};for(const r of n)this.tmp.options[r.option]=r}}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 y extends R{command;constructor(e){const t=y.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[r,...i]=e.split(/\{(.*?)\}/g).map(m=>m.trim()).filter(Boolean),o={},u={};for(const m of i){const{name:c,isOption:a,definition:d}=y.parseParamSignature(m,t);a?o[c]=d:u[c]=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:r,options:o,arguments:u}}static parseParamSignature(e,t){let n=e,r=!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,i.default.length?i.default==="true"?(i.default=!0,i.type="boolean"):i.default==="false"&&(i.default=!1,i.type="boolean"):i.default=null}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("--")&&(r=!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:r,definition:i}}}class G extends O{helperDefinitions={};get command(){return this.parser?this.parser.command:this.signature.split(" ")[0]}newCommandParser(e){return new y({io:e.io,signature:this.signature,helperDefinitions:this.helperDefinitions,defaultOptions:this.defaultOptions()})}constructor(){super("")}option(e,t=null){return this.parser instanceof y?this.parser.option(e)??t:t}argument(e,t=null){return this.parser instanceof y?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 E{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 V{commands={};io;logger;get CommandIOClass(){return x}constructor(e){this.logger=e??new E,this.io=new this.CommandIOClass(this.logger)}getAvailableCommands(){return Object.keys(this.commands)}getCommands(){return Object.values(this.commands)}commandResolver=async e=>{let t=(await import(e)).default;if(!t)throw new Error(`The command at path ${e} does not have a default export.`);t?.default&&(t=t.default);let n;if(typeof t=="function")n=new t;else if(t instanceof O)n=t;else throw new Error(`The command at path ${e} is not a valid command class.`);return n};setCommandResolver(e){this.commandResolver=e}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);this.registerCommand(n)}catch(n){throw new Error(`Command ${t} failed to load. ${n}`,{cause:n})}}async runCommand(e,t,...n){const r=typeof t=="string"?this.commands[t]:t,i=typeof t=="string"?t:r.command;if(!r){const o=await this.suggestCommand(i);return o?await this.runCommand(e,o,...n):1}return await r.run({ctx:e,logger:this.logger,args:n})??0}async suggestCommand(e){const t=this.getAvailableCommands(),{bestMatch:n,bestMatchIndex:r,ratings:i}=W.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[r];return await this.askRunSimilarCommand(e,u)?u:null}if(o.length){this.io.error(l`{bgRed ERROR } Command {yellow ${e}} not found.\n`);const u=await this.io.askForSelect(l`{green Did you mean to run one of these commands instead?}`,o);if(u)return u}throw new N(e)}async askRunSimilarCommand(e,t){return this.io.error(l`{bgRed ERROR } Command {yellow ${e}} not found.\n`),this.io.askForConfirmation(l`{green Do you want to run {yellow ${t}} instead?} `)}async*listCommandsFiles(e){const t=_.readdirSync(e,{withFileTypes:!0});for(const n of t){const r=k.resolve(e,n.name);if(n.isDirectory())yield*this.listCommandsFiles(k.resolve(e,n.name));else{if(!r.endsWith(".ts")&&!r.endsWith(".js"))continue;yield r}}}}class U extends O{constructor(e){super("help",{description:l.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",r=(await Promise.resolve().then(()=>require("./package-CjQA1PE1.cjs")))?.default?.version??"0.0.0";this.io.log(l`${t} {green ${n}} (core: {yellow ${r}})
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const H=require("minimist"),l=require("chalk"),w=require("prompts"),W=require("node:fs"),S=require("path"),M=require("string-similarity");function P(s){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(s){for(const t in s)if(t!=="default"){const n=Object.getOwnPropertyDescriptor(s,t);Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>s[t]})}}return e.default=s,Object.freeze(e)}const T=P(W),_=P(M);class f extends Error{}class B extends f{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(l` {white.bgRed ERROR } Argument {bold.yellow ${this.param.param}} value is invalid. `),(this.param.value||this.param.reason)&&e.log(""),this.param.value&&e.log(l` {blue Value}: ${this.param.value}`),this.param.reason&&e.log(l` {yellow Reason}: ${this.param.reason}`)}}class O extends f{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(l` {white.bgRed ERROR } Option {bold.yellow ${this.param.option}} value is invalid. `),(this.param.value||this.param.reason)&&e.log(""),this.param.value&&e.log(l` {blue Value}: ${this.param.value}`),this.param.reason&&e.log(l` {yellow Reason}: ${this.param.reason}`)}}function q(s){if(s==="string"||s==="secret"||s==="number")return null;if(s==="boolean")return!1;if(Array.isArray(s)&&s.length===1){if(s[0]==="string")return[];if(s[0]==="number")return[]}throw new Error("Invalid option type: "+s)}function F(s){return!Array.isArray(s)&&typeof s=="object"&&s.type?s.default!==void 0?s.default:q(s.type):q(s)}function g(s){return typeof s=="string"||Array.isArray(s)?{type:s,default:F(s),description:"",alias:[],required:!1,variadic:!1}:{type:s.type,default:s.default??F(s.type),description:s.description??"",alias:s.alias?Array.isArray(s.alias)?s.alias:[s.alias]:[],required:s.required??!1,variadic:s.variadic??!1}}class b extends f{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(l`\n{yellow Available options}:`);for(const[n,i]of t){const r=g(i),o=typeof r.alias=="string"?[r.alias]:r.alias,u=Array.isArray(r.type)?`[${r.type[0]}]`:r.type,m=`--${n}${o.length>0?o.map(a=>`, -${a}`).join(""):""}`,c=" ".repeat(30-m.length);e.log(l` {green ${m}} ${c} ${r.description||"\b"} {white (${u})}`)}e.log("")}e.log(l`{white.bgRed ERROR } Option {bold.yellow ${this.option}} is not recognized.`)}}class N extends f{constructor(e){super(`Command "${e}" not found.`),this.command=e}pretty(e){e.log(l`{bgRed ERROR } Command {yellow ${this.command}} not found.`)}}class A extends f{constructor(e){super(`Argument "${e}" is required.`),this.argument=e}pretty(e){e.log(l`{white.bgRed ERROR } Argument {bold.yellow ${this.argument}} is required.`)}}class L extends f{constructor(e){super(`Argument "${e}" is required.`),this.option=e}pretty(e){e.log(l`{white.bgRed ERROR } Option {bold.yellow ${this.option}} is required.`)}}function v(s,e,t,n){if(s==null)return n??null;if(e==="string")return String(s);if(e==="number"){const i=Number(s);if(isNaN(i))throw new O({option:t,reason:`Expected a number, got "${s}"`});return i}if(e==="boolean")return typeof s=="boolean"?s:s==="true"||s==="1"?!0:s==="false"||s==="0"?!1:!!s;if(Array.isArray(e)){const i=e[0],r=Array.isArray(s)?s:[s];if(i==="string")return r.map(o=>String(o));if(i==="number")return r.map(o=>{const u=Number(o);if(isNaN(u))throw new O({option:t,reason:`Expected array of numbers, got "${o}" in array`});return u})}return s}class R{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}=H(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(g(this.options[e]).required&&(this.parsedOptions?.[e]===void 0||this.parsedOptions?.[e]===null))throw new L(e);for(const e in this.arguments){const t=g(this.arguments[e]),n=this.parsedArguments?.[e];if(t.required&&n==null){if(this.shouldPromptForMissingOptions){const i=await this.promptForArgument(e,t);if(i&&this.parsedArguments){this.parsedArguments[e]=v(i,t.type,e);continue}}throw new A(e)}if(t.required&&t.variadic&&Array.isArray(n)&&n.length===0){if(this.shouldPromptForMissingOptions){const i=await this.promptForArgument(e,t);if(i&&this.parsedArguments){this.parsedArguments[e]=v(i,t.type,e);continue}}throw new A(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 b(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 b(e,this.arguments);this.parsedArguments[e]=t}validateUnknownOptions(e){const t=new Set;for(const n in this.options){t.add(n);const i=g(this.options[n]);for(const r of i.alias)t.add(r)}for(const n in e)if(!t.has(n))throw new b(n,this.options)}handleOptions(e){const t={};for(const n in this.options){const i=g(this.options[n]);t[n]=this.resolveOptionValue(n,i,e)}return t}handleArguments(e){const t={},n=[...e];for(const i in this.arguments){const r=g(this.arguments[i]);if(r.variadic){t[i]=this.handleVariadicArgument(i,r,n);continue}t[i]=this.resolveArgumentValue(i,r,n.shift())}return t}handleVariadicArgument(e,t,n){return n.length?v(n,t.type,e,t.default):t.default}resolveArgumentValue(e,t,n){return n===void 0?t.default:v(n,t.type,e,t.default)}resolveOptionValue(e,t,n){let i;const r=[e,...t.alias];for(const o of r)if(o in n){i=n[o];break}if(i===void 0){if(t.required)throw new O({option:e,reason:"Required option is missing"});return t.default}return v(i,t.type,e,t.default)}optionDefinitions(){const e={};for(const t in this.options)e[t]=g(this.options[t]);return e}argumentDefinitions(){const e={};for(const t in this.arguments)e[t]=g(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=l`{yellow.bold ${e}} is required`;return t.description&&(n+=l`: {gray (${t.description})}`),n+=`
2
+ `,Array.isArray(t.type)?(n+=l`Please provide one or more values, separated by commas:\n`,await this.io.askForList(n,void 0,{validate:i=>i.length?!0:"Please enter at least one value"})):await this.io.askForInput(n,void 0,{type:t.type==="number"?"number":t.type==="secret"?"password":"text",validate:i=>{if(t.type==="number"){const r=Number(i);if(isNaN(r))return"Please enter a valid number"}else if(t.type==="string"&&(typeof i!="string"||!i.length))return"Please enter a valid text";return!0}})}}function $(s){return new Array(s+5).join(" ")}class D{type="boolean";option="help";alias=["h"];default=!1;description=l`Display help for the given command. When no command is given display help for the {green list} command`;async handler(){const e=this.parser.argumentDefinitions(),t=this.parser.optionDefinitions(),n=Object.entries(e),i=Object.entries(t),r=i.map(([a,d])=>{const p=Array.isArray(d.alias)?d.alias:d.alias?[d.alias]:[];return{name:a,...d,optionWithAlias:`--${a}${p.map(h=>`, -${h}`).join("")}`}}),o=n.filter(([,a])=>a.required);this.io.log(l`{yellow Description}:`),this.io.log(l` ${this.description}\n`),this.io.log(l`{yellow Usage}:`),this.io.log(l` ${this.command} ${o.length>0?o.map(([a])=>`<${a}>`).join(" "):"\b"} [options]`);const u=Math.max(...r.map(a=>a.optionWithAlias.length),0),m=Math.max(...n.map(([a])=>a.length),0),c=m>u?m:u;if(n.length>0){this.io.log(l`\n{yellow Arguments}:`);for(const[a,d]of n){const p=$(c-a.length);let h=l` {green ${a}} ${p} ${d.description??"\b"}`;if(d.default!==void 0&&!d.required){const j=(Array.isArray(d.type)?`[${d.type[0]}]`:d.type)==="array"||Array.isArray(d.type)?JSON.stringify(d.default):d.default;h+=l` {yellow [default: ${j}]}`}d.variadic&&(h+=l` {white (variadic)}`),this.io.log(h)}}if(i.length>0){this.io.log(l`\n{yellow Options}:`);for(const a of r){const d=$(c-a.optionWithAlias.length);let p=l`{green ${a.optionWithAlias}} ${d} ${a.description??"\b"}`;if(a.type){const h=Array.isArray(a.type)?`[${a.type[0]}]`:a.type;p+=l` {white (${h})}`}if(a.default!==void 0&&!a.required){const k=(Array.isArray(a.type)?`[${a.type[0]}]`:a.type)==="array"||Array.isArray(a.type)?JSON.stringify(a.default):a.default;p+=l` {yellow [default: ${k}]}`}this.io.log(p)}}if(this.commandsExamples.length>0){this.io.log(l`\n{yellow Examples}:`);let a=process.argv[0].split("/").pop();a==="node"&&(a+=" "+process.argv[1].split("/").pop());for(const[d,p]of this.commandsExamples.entries())d>0&&this.io.log(""),this.io.log(` ${p.description}
3
+ `),this.io.log(l` {green ${a} ${p.command}}`)}return-1}}class x{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 w({type:"confirm",name:"value",message:e,initial:t??!1})).value}async askForInput(e,t,n){return(await w({type:"text",name:"value",message:e,initial:t,...n}))?.value??null}async askForDate(e,t,n){return(await w({type:"date",name:"value",message:e,initial:t,...n}))?.value??null}async askForList(e,t,n){return(await w({type:"list",name:"value",message:e,initial:t,...n}))?.value??null}async askForToggle(e,t,n){return(await w({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 i=[];for(const o of t)typeof o=="string"?i.push({title:o,value:o}):i.push(o);return(await w({type:"select",name:"value",message:e,choices:i,...n}))?.value??null}newLoader(e="",t=["⠙","⠘","⠰","⠴","⠤","⠦","⠆","⠃","⠋","⠉"],n=100){let i=e,r=null,o=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[o++]+" "+i)),o=o%t.length},n),m=()=>{clearInterval(u),process.stdout.write(new TextEncoder().encode("\r"+" ".repeat(i.length+5)+"\r"))};return{[Symbol.dispose]:m,[Symbol.asyncDispose]:m,updateText:c=>{r=i,i=c},stop:m}}}class C{_command;description="";group;commandsExamples=[];get command(){return this._command}ctx;io;logger;parser;disablePromptingFlag=!1;_preHandler;_handler;tmp;defaultOptions(){return[new D]}newCommandParser(e){return new R({io:e.io,options:e.options,arguments:e.arguments})}newCommandIO(e){return new x(e.logger)}constructor(e,t){this._command=e,this.description=t?.description??"",this.group=t?.group;const n=this.defaultOptions();if(n.length>0){this.tmp={options:{},arguments:{}};for(const i of n)this.tmp.options[i.option]=i}}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 r=this.tmp?.options??{};for(const o of this.defaultOptions())o.option in r||(r[o.option]=o);this.parser=this.newCommandParser({io:this.io,options:r,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 y extends R{command;constructor(e){const t=y.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[i,...r]=e.split(/\{(.*?)\}/g).map(m=>m.trim()).filter(Boolean),o={},u={};for(const m of r){const{name:c,isOption:a,definition:d}=y.parseParamSignature(m,t);a?o[c]=d:u[c]=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:i,options:o,arguments:u}}static parseParamSignature(e,t){let n=e,i=!1;const r={required:!0,type:"string",description:void 0,default:null,variadic:!1};if(n.includes(":")){const[o,u]=n.split(":");n=o.trim(),r.description=u.trim()}if(n.includes("=")){const[o,u]=n.split("=");n=o.trim(),r.default=u.trim(),r.required=!1,r.default.length?r.default==="true"?(r.default=!0,r.type="boolean"):r.default==="false"&&(r.default=!1,r.type="boolean"):r.default=null}else n.startsWith("--")&&(r.required=!1,r.default=!1,r.type="boolean");if(n.includes("|")){const[o,...u]=n.split("|");n=o.trim(),r.alias=u.map(m=>m.trim())}return n.startsWith("--")&&(i=!0,n=n.slice(2)),r.default==="*"&&(r.default=[],r.type=["string"]),n.endsWith("?")&&(r.required=!1,n=n.slice(0,-1)),n.endsWith("*")&&(r.type=["string"],r.variadic=!0,r.default=[],n=n.slice(0,-1)),r.description=r.description??t[n]??t[`--${n}`],{name:n,isOption:i,definition:r}}}class G extends C{helperDefinitions={};get command(){return this.parser?this.parser.command:this.signature.split(" ")[0]}newCommandParser(e){return new y({io:e.io,signature:this.signature,helperDefinitions:this.helperDefinitions,defaultOptions:this.defaultOptions()})}constructor(){super("")}option(e,t=null){return this.parser instanceof y?this.parser.option(e)??t:t}argument(e,t=null){return this.parser instanceof y?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 E{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 V{commands={};io;logger;get CommandIOClass(){return x}constructor(e){this.logger=e??new E,this.io=new this.CommandIOClass(this.logger)}getAvailableCommands(){return Object.keys(this.commands)}getCommands(){return Object.values(this.commands)}commandResolver=async e=>{let t=(await import(e)).default;if(!t)throw new Error(`The command at path ${e} does not have a default export.`);return t?.default&&(t=t.default),typeof t=="function"?new t:t instanceof C?t:null};setCommandResolver(e){this.commandResolver=e}fileCheck=e=>!0;setFileCheck(e){return this.fileCheck=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 C&&this.registerCommand(n)}catch(n){throw new Error(`Command ${t} failed to load. ${n}`,{cause:n})}}async runCommand(e,t,...n){const i=typeof t=="string"?this.commands[t]:t,r=typeof t=="string"?t:i.command;if(!i){const o=await this.suggestCommand(r);return o?await this.runCommand(e,o,...n):1}return await i.run({ctx:e,logger:this.logger,args:n})??0}async suggestCommand(e){const t=this.getAvailableCommands(),{bestMatch:n,bestMatchIndex:i,ratings:r}=_.findBestMatch(e,t),o=r.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[i];return await this.askRunSimilarCommand(e,u)?u:null}if(o.length){this.io.error(l`{bgRed ERROR } Command {yellow ${e}} not found.\n`);const u=await this.io.askForSelect(l`{green Did you mean to run one of these commands instead?}`,o);if(u)return u}throw new N(e)}async askRunSimilarCommand(e,t){return this.io.error(l`{bgRed ERROR } Command {yellow ${e}} not found.\n`),this.io.askForConfirmation(l`{green Do you want to run {yellow ${t}} instead?} `)}async*listCommandsFiles(e){const t=T.readdirSync(e,{withFileTypes:!0});for(const n of t){const i=S.resolve(e,n.name);if(n.isDirectory())yield*this.listCommandsFiles(S.resolve(e,n.name));else{if(!i.endsWith(".ts")&&!i.endsWith(".js")&&!i.endsWith(".mjs")&&!i.endsWith(".cjs"))continue;yield i}}}}class U extends C{constructor(e){super("help",{description:l.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",i=(await Promise.resolve().then(()=>require("./package-BKcK1zXi.cjs")))?.default?.version??"0.0.0";this.io.log(l`${t} {green ${n}} (core: {yellow ${i}})
4
4
 
5
5
  {yellow Usage}:
6
6
  command [options] [arguments]
7
7
 
8
8
  {yellow Available commands}:
9
- `);const i=Math.max(...e.map(m=>m.command.length))??0,o={};for(const m of e){const c=m.group??m.command.split(":")[0];o[c]||(o[c]=[]),o[c].push(m)}const u=Object.entries(o).sort(([m],[c])=>m.toLowerCase().localeCompare(c.toLowerCase())).sort(([,m],[,c])=>m.length-c.length);for(const[m,c]of u){const a=c.length>1;a&&this.io.log(l`{yellow ${m}}:`);const d=c.sort((p,h)=>p.command.toLowerCase().localeCompare(h.command.toLowerCase()));for(const p of d){let h=$(i-p.command.length);a&&(h=h.slice(2)),this.io.log(l`${a?" ":""}{green ${p.command}} ${h} ${p.description}`)}}}}class I{logger;constructor(e){this.logger=e}handle(e){if(e instanceof f)return e.pretty(this.logger),-1;throw e}}class z{ctx;logger;commandRegistry;exceptionHandler;helpCommand;newCommandRegistry(e){return new V(e.logger)}newHelpCommand(e){return new U(e)}newExceptionHandler(e){return new I(e.logger)}constructor(e={}){this.ctx=e.ctx,this.logger=e.logger??new E,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})}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.bind(this.exceptionHandler)):await this.runHelpCommand()}async runHelpCommand(){return await this.runCommand(this.helpCommand)}registerCommand(e){this.commandRegistry.registerCommand(e)}}exports.BadCommandOption=b;exports.BadCommandParameter=B;exports.BobError=f;exports.Cli=z;exports.Command=O;exports.CommandIO=x;exports.CommandNotFoundError=N;exports.CommandParser=R;exports.CommandRegistry=V;exports.CommandSignatureParser=y;exports.CommandWithSignature=G;exports.ExceptionHandler=I;exports.HelpOption=D;exports.InvalidOption=C;exports.Logger=E;exports.MissingRequiredArgumentValue=A;exports.MissingRequiredOptionValue=L;
9
+ `);const r=Math.max(...e.map(m=>m.command.length))??0,o={};for(const m of e){const c=m.group??m.command.split(":")[0];o[c]||(o[c]=[]),o[c].push(m)}const u=Object.entries(o).sort(([m],[c])=>m.toLowerCase().localeCompare(c.toLowerCase())).sort(([,m],[,c])=>m.length-c.length);for(const[m,c]of u){const a=c.length>1;a&&this.io.log(l`{yellow ${m}}:`);const d=c.sort((p,h)=>p.command.toLowerCase().localeCompare(h.command.toLowerCase()));for(const p of d){let h=$(r-p.command.length);a&&(h=h.slice(2)),this.io.log(l`${a?" ":""}{green ${p.command}} ${h} ${p.description}`)}}}}class I{logger;constructor(e){this.logger=e}handle(e){if(e instanceof f)return e.pretty(this.logger),-1;throw e}}class z{ctx;logger;commandRegistry;exceptionHandler;helpCommand;newCommandRegistry(e){return new V(e.logger)}newHelpCommand(e){return new U(e)}newExceptionHandler(e){return new I(e.logger)}constructor(e={}){this.ctx=e.ctx,this.logger=e.logger??new E,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})}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.bind(this.exceptionHandler)):await this.runHelpCommand()}async runHelpCommand(){return await this.runCommand(this.helpCommand)}registerCommand(e){this.commandRegistry.registerCommand(e)}}exports.BadCommandOption=O;exports.BadCommandParameter=B;exports.BobError=f;exports.Cli=z;exports.Command=C;exports.CommandIO=x;exports.CommandNotFoundError=N;exports.CommandParser=R;exports.CommandRegistry=V;exports.CommandSignatureParser=y;exports.CommandWithSignature=G;exports.ExceptionHandler=I;exports.HelpOption=D;exports.InvalidOption=b;exports.Logger=E;exports.MissingRequiredArgumentValue=A;exports.MissingRequiredOptionValue=L;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="bob-core",s="2.0.0-beta.5",t="BOB Core",i="module",n=!1,r=["dist/**"],o={".":{import:"./dist/esm/index.js",require:"./dist/cjs/index.js"}},c={"*":{"*":["./dist/cjs/*.d.ts"]}},d={start:"node -r @swc-node/register debug/main.ts",build:"rimraf ./dist && vite build",typecheck:"tsc --noEmit",prepare:"npm run build",test:"vitest run"},p="Léo Hubert",a="ISC",m={"@faker-js/faker":"^10.0.0","@swc-node/register":"^1.11.1","@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",rimraf:"^6.0.1",tsx:"^4.20.6",typescript:"^5.7.3",vite:"^7.1.6","vite-plugin-dts":"^4.5.4",vitest:"^3.2.4"},l={chalk:"^4.1.2",minimist:"^1.2.8",prompts:"^2.4.2","string-similarity":"^4.0.4"},u={name:e,version:s,description:t,type:i,sideEffects:n,files:r,exports:o,typesVersions:c,scripts:d,author:p,license:a,devDependencies:m,dependencies:l};exports.author=p;exports.default=u;exports.dependencies=l;exports.description=t;exports.devDependencies=m;exports.exports=o;exports.files=r;exports.license=a;exports.name=e;exports.scripts=d;exports.sideEffects=n;exports.type=i;exports.typesVersions=c;exports.version=s;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="bob-core",s="2.0.0-beta.6",t="BOB Core",i="module",n=!1,r=["dist/**"],o={".":{import:"./dist/esm/index.js",require:"./dist/cjs/index.js"}},c={"*":{"*":["./dist/cjs/*.d.ts"]}},d={start:"node -r @swc-node/register debug/main.ts",build:"rimraf ./dist && vite build",typecheck:"tsc --noEmit",prepare:"npm run build",test:"vitest run"},p="Léo Hubert",a="ISC",m={"@faker-js/faker":"^10.0.0","@swc-node/register":"^1.11.1","@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",rimraf:"^6.0.1",tsx:"^4.20.6",typescript:"^5.7.3",vite:"^7.1.6","vite-plugin-dts":"^4.5.4",vitest:"^3.2.4"},l={chalk:"^4.1.2",minimist:"^1.2.8",prompts:"^2.4.2","string-similarity":"^4.0.4"},u={name:e,version:s,description:t,type:i,sideEffects:n,files:r,exports:o,typesVersions:c,scripts:d,author:p,license:a,devDependencies:m,dependencies:l};exports.author=p;exports.default=u;exports.dependencies=l;exports.description=t;exports.devDependencies=m;exports.exports=o;exports.files=r;exports.license=a;exports.name=e;exports.scripts=d;exports.sideEffects=n;exports.type=i;exports.typesVersions=c;exports.version=s;
@@ -1,7 +1,7 @@
1
1
  import { CommandIO } from './CommandIO.js';
2
2
  import { Command } from './Command.js';
3
3
  import { Logger } from './Logger.js';
4
- export type CommandResolver = (path: string) => Promise<Command>;
4
+ export type CommandResolver = (path: string) => Promise<Command | null>;
5
5
  export declare class CommandRegistry {
6
6
  private readonly commands;
7
7
  protected readonly io: CommandIO;
@@ -12,6 +12,8 @@ export declare class CommandRegistry {
12
12
  getCommands(): Array<Command>;
13
13
  private commandResolver;
14
14
  setCommandResolver(resolver: CommandResolver): void;
15
+ fileCheck: (filePath: string) => boolean;
16
+ setFileCheck(check: (filePath: string) => boolean): this;
15
17
  registerCommand(command: Command<any, any, any>, force?: boolean): void;
16
18
  loadCommandsPath(commandsPath: string): Promise<void>;
17
19
  runCommand(ctx: any, command: string | Command, ...args: any[]): Promise<number>;
package/dist/esm/index.js CHANGED
@@ -15,7 +15,7 @@ class U extends f {
15
15
  e.log(l` {white.bgRed ERROR } Argument {bold.yellow ${this.param.param}} value is invalid. `), (this.param.value || this.param.reason) && e.log(""), this.param.value && e.log(l` {blue Value}: ${this.param.value}`), this.param.reason && e.log(l` {yellow Reason}: ${this.param.reason}`);
16
16
  }
17
17
  }
18
- class b extends f {
18
+ class A extends f {
19
19
  constructor(e) {
20
20
  let t = `Option "${e.option}" value is invalid.`;
21
21
  e.reason ? t += ` Reason: ${e.reason}` : t += ` Value: "${e.value}"`, super(t), this.param = e;
@@ -24,36 +24,36 @@ class b extends f {
24
24
  e.log(l` {white.bgRed ERROR } Option {bold.yellow ${this.param.option}} value is invalid. `), (this.param.value || this.param.reason) && e.log(""), this.param.value && e.log(l` {blue Value}: ${this.param.value}`), this.param.reason && e.log(l` {yellow Reason}: ${this.param.reason}`);
25
25
  }
26
26
  }
27
- function x(s) {
28
- if (s === "string" || s === "secret" || s === "number") return null;
29
- if (s === "boolean") return !1;
30
- if (Array.isArray(s) && s.length === 1) {
31
- if (s[0] === "string") return [];
32
- if (s[0] === "number") return [];
33
- }
34
- throw new Error("Invalid option type: " + s);
27
+ function x(i) {
28
+ if (i === "string" || i === "secret" || i === "number") return null;
29
+ if (i === "boolean") return !1;
30
+ if (Array.isArray(i) && i.length === 1) {
31
+ if (i[0] === "string") return [];
32
+ if (i[0] === "number") return [];
33
+ }
34
+ throw new Error("Invalid option type: " + i);
35
35
  }
36
- function E(s) {
37
- return !Array.isArray(s) && typeof s == "object" && s.type ? s.default !== void 0 ? s.default : x(s.type) : x(s);
36
+ function k(i) {
37
+ return !Array.isArray(i) && typeof i == "object" && i.type ? i.default !== void 0 ? i.default : x(i.type) : x(i);
38
38
  }
39
- function g(s) {
40
- return typeof s == "string" || Array.isArray(s) ? {
41
- type: s,
42
- default: E(s),
39
+ function g(i) {
40
+ return typeof i == "string" || Array.isArray(i) ? {
41
+ type: i,
42
+ default: k(i),
43
43
  description: "",
44
44
  alias: [],
45
45
  required: !1,
46
46
  variadic: !1
47
47
  } : {
48
- type: s.type,
49
- default: s.default ?? E(s.type),
50
- description: s.description ?? "",
51
- alias: s.alias ? Array.isArray(s.alias) ? s.alias : [s.alias] : [],
52
- required: s.required ?? !1,
53
- variadic: s.variadic ?? !1
48
+ type: i.type,
49
+ default: i.default ?? k(i.type),
50
+ description: i.description ?? "",
51
+ alias: i.alias ? Array.isArray(i.alias) ? i.alias : [i.alias] : [],
52
+ required: i.required ?? !1,
53
+ variadic: i.variadic ?? !1
54
54
  };
55
55
  }
56
- class C extends f {
56
+ class b extends f {
57
57
  constructor(e, t = {}) {
58
58
  super(`Invalid option ${e} in not recognized`), this.option = e, this.optionsSchema = t;
59
59
  }
@@ -61,9 +61,9 @@ class C extends f {
61
61
  const t = Object.entries(this.optionsSchema);
62
62
  if (t.length > 0) {
63
63
  e.log(l`\n{yellow Available options}:`);
64
- for (const [n, i] of t) {
65
- const r = g(i), o = typeof r.alias == "string" ? [r.alias] : r.alias, d = Array.isArray(r.type) ? `[${r.type[0]}]` : r.type, m = `--${n}${o.length > 0 ? o.map((a) => `, -${a}`).join("") : ""}`, p = " ".repeat(30 - m.length);
66
- e.log(l` {green ${m}} ${p} ${r.description || "\b"} {white (${d})}`);
64
+ for (const [n, s] of t) {
65
+ const r = g(s), o = typeof r.alias == "string" ? [r.alias] : r.alias, u = Array.isArray(r.type) ? `[${r.type[0]}]` : r.type, m = `--${n}${o.length > 0 ? o.map((a) => `, -${a}`).join("") : ""}`, p = " ".repeat(30 - m.length);
66
+ e.log(l` {green ${m}} ${p} ${r.description || "\b"} {white (${u})}`);
67
67
  }
68
68
  e.log("");
69
69
  }
@@ -78,7 +78,7 @@ class V extends f {
78
78
  e.log(l`{bgRed ERROR } Command {yellow ${this.command}} not found.`);
79
79
  }
80
80
  }
81
- class k extends f {
81
+ class E extends f {
82
82
  constructor(e) {
83
83
  super(`Argument "${e}" is required.`), this.argument = e;
84
84
  }
@@ -94,38 +94,38 @@ class I extends f {
94
94
  e.log(l`{white.bgRed ERROR } Option {bold.yellow ${this.option}} is required.`);
95
95
  }
96
96
  }
97
- function v(s, e, t, n) {
98
- if (s == null)
97
+ function v(i, e, t, n) {
98
+ if (i == null)
99
99
  return n ?? null;
100
100
  if (e === "string")
101
- return String(s);
101
+ return String(i);
102
102
  if (e === "number") {
103
- const i = Number(s);
104
- if (isNaN(i))
105
- throw new b({
103
+ const s = Number(i);
104
+ if (isNaN(s))
105
+ throw new A({
106
106
  option: t,
107
- reason: `Expected a number, got "${s}"`
107
+ reason: `Expected a number, got "${i}"`
108
108
  });
109
- return i;
109
+ return s;
110
110
  }
111
111
  if (e === "boolean")
112
- return typeof s == "boolean" ? s : s === "true" || s === "1" ? !0 : s === "false" || s === "0" ? !1 : !!s;
112
+ return typeof i == "boolean" ? i : i === "true" || i === "1" ? !0 : i === "false" || i === "0" ? !1 : !!i;
113
113
  if (Array.isArray(e)) {
114
- const i = e[0], r = Array.isArray(s) ? s : [s];
115
- if (i === "string")
114
+ const s = e[0], r = Array.isArray(i) ? i : [i];
115
+ if (s === "string")
116
116
  return r.map((o) => String(o));
117
- if (i === "number")
117
+ if (s === "number")
118
118
  return r.map((o) => {
119
- const d = Number(o);
120
- if (isNaN(d))
121
- throw new b({
119
+ const u = Number(o);
120
+ if (isNaN(u))
121
+ throw new A({
122
122
  option: t,
123
123
  reason: `Expected array of numbers, got "${o}" in array`
124
124
  });
125
- return d;
125
+ return u;
126
126
  });
127
127
  }
128
- return s;
128
+ return i;
129
129
  }
130
130
  class F {
131
131
  options;
@@ -164,23 +164,23 @@ class F {
164
164
  const t = g(this.arguments[e]), n = this.parsedArguments?.[e];
165
165
  if (t.required && n == null) {
166
166
  if (this.shouldPromptForMissingOptions) {
167
- const i = await this.promptForArgument(e, t);
168
- if (i && this.parsedArguments) {
169
- this.parsedArguments[e] = v(i, t.type, e);
167
+ const s = await this.promptForArgument(e, t);
168
+ if (s && this.parsedArguments) {
169
+ this.parsedArguments[e] = v(s, t.type, e);
170
170
  continue;
171
171
  }
172
172
  }
173
- throw new k(e);
173
+ throw new E(e);
174
174
  }
175
175
  if (t.required && t.variadic && Array.isArray(n) && n.length === 0) {
176
176
  if (this.shouldPromptForMissingOptions) {
177
- const i = await this.promptForArgument(e, t);
178
- if (i && this.parsedArguments) {
179
- this.parsedArguments[e] = v(i, t.type, e);
177
+ const s = await this.promptForArgument(e, t);
178
+ if (s && this.parsedArguments) {
179
+ this.parsedArguments[e] = v(s, t.type, e);
180
180
  continue;
181
181
  }
182
182
  }
183
- throw new k(e);
183
+ throw new E(e);
184
184
  }
185
185
  }
186
186
  }
@@ -199,7 +199,7 @@ class F {
199
199
  if (!this.parsedOptions)
200
200
  throw new Error("Options have not been parsed yet. Call init() first.");
201
201
  if (!(e in this.options))
202
- throw new C(e, this.options);
202
+ throw new b(e, this.options);
203
203
  this.parsedOptions[e] = t;
204
204
  }
205
205
  /**
@@ -217,7 +217,7 @@ class F {
217
217
  if (!this.parsedArguments)
218
218
  throw new Error("Arguments have not been parsed yet. Call init() first.");
219
219
  if (!(e in this.arguments))
220
- throw new C(e, this.arguments);
220
+ throw new b(e, this.arguments);
221
221
  this.parsedArguments[e] = t;
222
222
  }
223
223
  // === PRIVATE HELPERS ===
@@ -229,13 +229,13 @@ class F {
229
229
  const t = /* @__PURE__ */ new Set();
230
230
  for (const n in this.options) {
231
231
  t.add(n);
232
- const i = g(this.options[n]);
233
- for (const r of i.alias)
232
+ const s = g(this.options[n]);
233
+ for (const r of s.alias)
234
234
  t.add(r);
235
235
  }
236
236
  for (const n in e)
237
237
  if (!t.has(n))
238
- throw new C(n, this.options);
238
+ throw new b(n, this.options);
239
239
  }
240
240
  /**
241
241
  * Processes named options from minimist output
@@ -243,10 +243,10 @@ class F {
243
243
  handleOptions(e) {
244
244
  const t = {};
245
245
  for (const n in this.options) {
246
- const i = g(this.options[n]);
246
+ const s = g(this.options[n]);
247
247
  t[n] = this.resolveOptionValue(
248
248
  n,
249
- i,
249
+ s,
250
250
  e
251
251
  );
252
252
  }
@@ -257,13 +257,13 @@ class F {
257
257
  */
258
258
  handleArguments(e) {
259
259
  const t = {}, n = [...e];
260
- for (const i in this.arguments) {
261
- const r = g(this.arguments[i]);
260
+ for (const s in this.arguments) {
261
+ const r = g(this.arguments[s]);
262
262
  if (r.variadic) {
263
- t[i] = this.handleVariadicArgument(i, r, n);
263
+ t[s] = this.handleVariadicArgument(s, r, n);
264
264
  continue;
265
265
  }
266
- t[i] = this.resolveArgumentValue(i, r, n.shift());
266
+ t[s] = this.resolveArgumentValue(s, r, n.shift());
267
267
  }
268
268
  return t;
269
269
  }
@@ -285,22 +285,22 @@ class F {
285
285
  * Handles alias resolution, defaults, and type conversion
286
286
  */
287
287
  resolveOptionValue(e, t, n) {
288
- let i;
288
+ let s;
289
289
  const r = [e, ...t.alias];
290
290
  for (const o of r)
291
291
  if (o in n) {
292
- i = n[o];
292
+ s = n[o];
293
293
  break;
294
294
  }
295
- if (i === void 0) {
295
+ if (s === void 0) {
296
296
  if (t.required)
297
- throw new b({
297
+ throw new A({
298
298
  option: e,
299
299
  reason: "Required option is missing"
300
300
  });
301
301
  return t.default;
302
302
  }
303
- return v(i, t.type, e, t.default);
303
+ return v(s, t.type, e, t.default);
304
304
  }
305
305
  optionDefinitions() {
306
306
  const e = {};
@@ -343,19 +343,19 @@ class F {
343
343
  n,
344
344
  void 0,
345
345
  {
346
- validate: (i) => i.length ? !0 : "Please enter at least one value"
346
+ validate: (s) => s.length ? !0 : "Please enter at least one value"
347
347
  }
348
348
  )) : await this.io.askForInput(
349
349
  n,
350
350
  void 0,
351
351
  {
352
352
  type: t.type === "number" ? "number" : t.type === "secret" ? "password" : "text",
353
- validate: (i) => {
353
+ validate: (s) => {
354
354
  if (t.type === "number") {
355
- const r = Number(i);
355
+ const r = Number(s);
356
356
  if (isNaN(r))
357
357
  return "Please enter a valid number";
358
- } else if (t.type === "string" && (typeof i != "string" || !i.length))
358
+ } else if (t.type === "string" && (typeof s != "string" || !s.length))
359
359
  return "Please enter a valid text";
360
360
  return !0;
361
361
  }
@@ -363,8 +363,8 @@ class F {
363
363
  );
364
364
  }
365
365
  }
366
- function A(s) {
367
- return new Array(s + 5).join(" ");
366
+ function O(i) {
367
+ return new Array(i + 5).join(" ");
368
368
  }
369
369
  class H {
370
370
  type = "boolean";
@@ -373,33 +373,33 @@ class H {
373
373
  default = !1;
374
374
  description = l`Display help for the given command. When no command is given display help for the {green list} command`;
375
375
  async handler() {
376
- const e = this.parser.argumentDefinitions(), t = this.parser.optionDefinitions(), n = Object.entries(e), i = Object.entries(t), r = i.map(([a, u]) => {
377
- const c = Array.isArray(u.alias) ? u.alias : u.alias ? [u.alias] : [];
376
+ const e = this.parser.argumentDefinitions(), t = this.parser.optionDefinitions(), n = Object.entries(e), s = Object.entries(t), r = s.map(([a, d]) => {
377
+ const c = Array.isArray(d.alias) ? d.alias : d.alias ? [d.alias] : [];
378
378
  return {
379
379
  name: a,
380
- ...u,
380
+ ...d,
381
381
  optionWithAlias: `--${a}${c.map((h) => `, -${h}`).join("")}`
382
382
  };
383
383
  }), o = n.filter(([, a]) => a.required);
384
384
  this.io.log(l`{yellow Description}:`), this.io.log(l` ${this.description}\n`), this.io.log(l`{yellow Usage}:`), this.io.log(l` ${this.command} ${o.length > 0 ? o.map(([a]) => `<${a}>`).join(" ") : "\b"} [options]`);
385
- const d = Math.max(...r.map((a) => a.optionWithAlias.length), 0), m = Math.max(...n.map(([a]) => a.length), 0), p = m > d ? m : d;
385
+ const u = Math.max(...r.map((a) => a.optionWithAlias.length), 0), m = Math.max(...n.map(([a]) => a.length), 0), p = m > u ? m : u;
386
386
  if (n.length > 0) {
387
387
  this.io.log(l`\n{yellow Arguments}:`);
388
- for (const [a, u] of n) {
389
- const c = A(p - a.length);
390
- let h = l` {green ${a}} ${c} ${u.description ?? "\b"}`;
391
- if (u.default !== void 0 && !u.required) {
392
- const N = (Array.isArray(u.type) ? `[${u.type[0]}]` : u.type) === "array" || Array.isArray(u.type) ? JSON.stringify(u.default) : u.default;
388
+ for (const [a, d] of n) {
389
+ const c = O(p - a.length);
390
+ let h = l` {green ${a}} ${c} ${d.description ?? "\b"}`;
391
+ if (d.default !== void 0 && !d.required) {
392
+ const N = (Array.isArray(d.type) ? `[${d.type[0]}]` : d.type) === "array" || Array.isArray(d.type) ? JSON.stringify(d.default) : d.default;
393
393
  h += l` {yellow [default: ${N}]}`;
394
394
  }
395
- u.variadic && (h += l` {white (variadic)}`), this.io.log(h);
395
+ d.variadic && (h += l` {white (variadic)}`), this.io.log(h);
396
396
  }
397
397
  }
398
- if (i.length > 0) {
398
+ if (s.length > 0) {
399
399
  this.io.log(l`\n{yellow Options}:`);
400
400
  for (const a of r) {
401
- const u = A(p - a.optionWithAlias.length);
402
- let c = l`{green ${a.optionWithAlias}} ${u} ${a.description ?? "\b"}`;
401
+ const d = O(p - a.optionWithAlias.length);
402
+ let c = l`{green ${a.optionWithAlias}} ${d} ${a.description ?? "\b"}`;
403
403
  if (a.type) {
404
404
  const h = Array.isArray(a.type) ? `[${a.type[0]}]` : a.type;
405
405
  c += l` {white (${h})}`;
@@ -415,8 +415,8 @@ class H {
415
415
  this.io.log(l`\n{yellow Examples}:`);
416
416
  let a = process.argv[0].split("/").pop();
417
417
  a === "node" && (a += " " + process.argv[1].split("/").pop());
418
- for (const [u, c] of this.commandsExamples.entries())
419
- u > 0 && this.io.log(""), this.io.log(` ${c.description}
418
+ for (const [d, c] of this.commandsExamples.entries())
419
+ d > 0 && this.io.log(""), this.io.log(` ${c.description}
420
420
  `), this.io.log(l` {green ${a} ${c.command}}`);
421
421
  }
422
422
  return -1;
@@ -495,35 +495,35 @@ class S {
495
495
  async askForSelect(e, t, n) {
496
496
  if (t.length === 0)
497
497
  throw new Error("No options provided");
498
- const i = [];
498
+ const s = [];
499
499
  for (const o of t)
500
- typeof o == "string" ? i.push({ title: o, value: o }) : i.push(o);
500
+ typeof o == "string" ? s.push({ title: o, value: o }) : s.push(o);
501
501
  return (await y({
502
502
  type: "select",
503
503
  name: "value",
504
504
  message: e,
505
- choices: i,
505
+ choices: s,
506
506
  ...n
507
507
  }))?.value ?? null;
508
508
  }
509
509
  newLoader(e = "", t = ["⠙", "⠘", "⠰", "⠴", "⠤", "⠦", "⠆", "⠃", "⠋", "⠉"], n = 100) {
510
- let i = e, r = null, o = 0;
511
- const d = setInterval(function() {
512
- r && (process.stdout.write(new TextEncoder().encode("\r" + " ".repeat(r.length + 5) + "\r")), r = null), process.stdout.write(new TextEncoder().encode("\r" + t[o++] + " " + i)), o = o % t.length;
510
+ let s = e, r = null, o = 0;
511
+ const u = setInterval(function() {
512
+ r && (process.stdout.write(new TextEncoder().encode("\r" + " ".repeat(r.length + 5) + "\r")), r = null), process.stdout.write(new TextEncoder().encode("\r" + t[o++] + " " + s)), o = o % t.length;
513
513
  }, n), m = () => {
514
- clearInterval(d), process.stdout.write(new TextEncoder().encode("\r" + " ".repeat(i.length + 5) + "\r"));
514
+ clearInterval(u), process.stdout.write(new TextEncoder().encode("\r" + " ".repeat(s.length + 5) + "\r"));
515
515
  };
516
516
  return {
517
517
  [Symbol.dispose]: m,
518
518
  [Symbol.asyncDispose]: m,
519
519
  updateText: (p) => {
520
- r = i, i = p;
520
+ r = s, s = p;
521
521
  },
522
522
  stop: m
523
523
  };
524
524
  }
525
525
  }
526
- class O {
526
+ class C {
527
527
  _command;
528
528
  description = "";
529
529
  group;
@@ -560,8 +560,8 @@ class O {
560
560
  options: {},
561
561
  arguments: {}
562
562
  };
563
- for (const i of n)
564
- this.tmp.options[i.option] = i;
563
+ for (const s of n)
564
+ this.tmp.options[s.option] = s;
565
565
  }
566
566
  }
567
567
  disablePrompting() {
@@ -608,9 +608,9 @@ class O {
608
608
  }), t = this.parser.init(e.args);
609
609
  for (const o of this.defaultOptions())
610
610
  if (t.options[o.option] === !0) {
611
- const d = await o.handler.call(this);
612
- if (d && d !== 0)
613
- return d;
611
+ const u = await o.handler.call(this);
612
+ if (u && u !== 0)
613
+ return u;
614
614
  }
615
615
  this.disablePromptingFlag && this.parser.disablePrompting(), await this.parser.validate();
616
616
  } else
@@ -643,13 +643,13 @@ class w extends F {
643
643
  * Example: "migrate {name} {--force}" -> { command: "migrate", arguments: {name: ...}, options: {force: ...} }
644
644
  */
645
645
  static parseSignature(e, t, n) {
646
- const [i, ...r] = e.split(/\{(.*?)\}/g).map((m) => m.trim()).filter(Boolean), o = {}, d = {};
646
+ const [s, ...r] = e.split(/\{(.*?)\}/g).map((m) => m.trim()).filter(Boolean), o = {}, u = {};
647
647
  for (const m of r) {
648
- const { name: p, isOption: a, definition: u } = w.parseParamSignature(
648
+ const { name: p, isOption: a, definition: d } = w.parseParamSignature(
649
649
  m,
650
650
  t
651
651
  );
652
- a ? o[p] = u : d[p] = u;
652
+ a ? o[p] = d : u[p] = d;
653
653
  }
654
654
  for (const m of n)
655
655
  o[m.option] = {
@@ -660,7 +660,7 @@ class w extends F {
660
660
  description: m.description,
661
661
  default: m.default ?? null
662
662
  };
663
- return { command: i, options: o, arguments: d };
663
+ return { command: s, options: o, arguments: u };
664
664
  }
665
665
  /**
666
666
  * Parses a single parameter signature like "{name}" or "{--force}" or "{files*}"
@@ -677,7 +677,7 @@ class w extends F {
677
677
  * - {--opt|o} -> option with alias
678
678
  */
679
679
  static parseParamSignature(e, t) {
680
- let n = e, i = !1;
680
+ let n = e, s = !1;
681
681
  const r = {
682
682
  required: !0,
683
683
  type: "string",
@@ -686,21 +686,21 @@ class w extends F {
686
686
  variadic: !1
687
687
  };
688
688
  if (n.includes(":")) {
689
- const [o, d] = n.split(":");
690
- n = o.trim(), r.description = d.trim();
689
+ const [o, u] = n.split(":");
690
+ n = o.trim(), r.description = u.trim();
691
691
  }
692
692
  if (n.includes("=")) {
693
- const [o, d] = n.split("=");
694
- n = o.trim(), r.default = d.trim(), r.required = !1, r.default.length ? r.default === "true" ? (r.default = !0, r.type = "boolean") : r.default === "false" && (r.default = !1, r.type = "boolean") : r.default = null;
693
+ const [o, u] = n.split("=");
694
+ n = o.trim(), r.default = u.trim(), r.required = !1, r.default.length ? r.default === "true" ? (r.default = !0, r.type = "boolean") : r.default === "false" && (r.default = !1, r.type = "boolean") : r.default = null;
695
695
  } else n.startsWith("--") && (r.required = !1, r.default = !1, r.type = "boolean");
696
696
  if (n.includes("|")) {
697
- const [o, ...d] = n.split("|");
698
- n = o.trim(), r.alias = d.map((m) => m.trim());
697
+ const [o, ...u] = n.split("|");
698
+ n = o.trim(), r.alias = u.map((m) => m.trim());
699
699
  }
700
- return n.startsWith("--") && (i = !0, n = n.slice(2)), r.default === "*" && (r.default = [], r.type = ["string"]), n.endsWith("?") && (r.required = !1, n = n.slice(0, -1)), n.endsWith("*") && (r.type = ["string"], r.variadic = !0, r.default = [], n = n.slice(0, -1)), r.description = r.description ?? t[n] ?? t[`--${n}`], { name: n, isOption: i, definition: r };
700
+ return n.startsWith("--") && (s = !0, n = n.slice(2)), r.default === "*" && (r.default = [], r.type = ["string"]), n.endsWith("?") && (r.required = !1, n = n.slice(0, -1)), n.endsWith("*") && (r.type = ["string"], r.variadic = !0, r.default = [], n = n.slice(0, -1)), r.description = r.description ?? t[n] ?? t[`--${n}`], { name: n, isOption: s, definition: r };
701
701
  }
702
702
  }
703
- class z extends O {
703
+ class z extends C {
704
704
  helperDefinitions = {};
705
705
  get command() {
706
706
  return this.parser ? this.parser.command : this.signature.split(" ")[0];
@@ -767,7 +767,7 @@ class L {
767
767
  this.shouldLog("debug") && console.log(...e);
768
768
  }
769
769
  }
770
- class T {
770
+ class j {
771
771
  commands = {};
772
772
  io;
773
773
  logger;
@@ -787,19 +787,15 @@ class T {
787
787
  let t = (await import(e)).default;
788
788
  if (!t)
789
789
  throw new Error(`The command at path ${e} does not have a default export.`);
790
- t?.default && (t = t.default);
791
- let n;
792
- if (typeof t == "function")
793
- n = new t();
794
- else if (t instanceof O)
795
- n = t;
796
- else
797
- throw new Error(`The command at path ${e} is not a valid command class.`);
798
- return n;
790
+ return t?.default && (t = t.default), typeof t == "function" ? new t() : t instanceof C ? t : null;
799
791
  };
800
792
  setCommandResolver(e) {
801
793
  this.commandResolver = e;
802
794
  }
795
+ fileCheck = (e) => !0;
796
+ setFileCheck(e) {
797
+ return this.fileCheck = e, this;
798
+ }
803
799
  registerCommand(e, t = !1) {
804
800
  const n = e.command;
805
801
  if (!n)
@@ -812,7 +808,7 @@ class T {
812
808
  for await (const t of this.listCommandsFiles(e))
813
809
  try {
814
810
  const n = await this.commandResolver(t);
815
- this.registerCommand(n);
811
+ n instanceof C && this.registerCommand(n);
816
812
  } catch (n) {
817
813
  throw new Error(`Command ${t} failed to load. ${n}`, {
818
814
  cause: n
@@ -820,31 +816,31 @@ class T {
820
816
  }
821
817
  }
822
818
  async runCommand(e, t, ...n) {
823
- const i = typeof t == "string" ? this.commands[t] : t, r = typeof t == "string" ? t : i.command;
824
- if (!i) {
819
+ const s = typeof t == "string" ? this.commands[t] : t, r = typeof t == "string" ? t : s.command;
820
+ if (!s) {
825
821
  const o = await this.suggestCommand(r);
826
822
  return o ? await this.runCommand(e, o, ...n) : 1;
827
823
  }
828
- return await i.run({
824
+ return await s.run({
829
825
  ctx: e,
830
826
  logger: this.logger,
831
827
  args: n
832
828
  }) ?? 0;
833
829
  }
834
830
  async suggestCommand(e) {
835
- const t = this.getAvailableCommands(), { bestMatch: n, bestMatchIndex: i, ratings: r } = P.findBestMatch(e, t), o = r.filter((d) => d.rating > 0.3).map((d) => d.target);
831
+ const t = this.getAvailableCommands(), { bestMatch: n, bestMatchIndex: s, ratings: r } = P.findBestMatch(e, t), o = r.filter((u) => u.rating > 0.3).map((u) => u.target);
836
832
  if (n.rating > 0 && o.length <= 1 || n.rating > 0.7 && o.length > 1) {
837
- const d = t[i];
838
- return await this.askRunSimilarCommand(e, d) ? d : null;
833
+ const u = t[s];
834
+ return await this.askRunSimilarCommand(e, u) ? u : null;
839
835
  }
840
836
  if (o.length) {
841
837
  this.io.error(l`{bgRed ERROR } Command {yellow ${e}} not found.\n`);
842
- const d = await this.io.askForSelect(
838
+ const u = await this.io.askForSelect(
843
839
  l`{green Did you mean to run one of these commands instead?}`,
844
840
  o
845
841
  );
846
- if (d)
847
- return d;
842
+ if (u)
843
+ return u;
848
844
  }
849
845
  throw new V(e);
850
846
  }
@@ -854,26 +850,26 @@ class T {
854
850
  async *listCommandsFiles(e) {
855
851
  const t = D.readdirSync(e, { withFileTypes: !0 });
856
852
  for (const n of t) {
857
- const i = R.resolve(e, n.name);
853
+ const s = R.resolve(e, n.name);
858
854
  if (n.isDirectory())
859
855
  yield* this.listCommandsFiles(R.resolve(e, n.name));
860
856
  else {
861
- if (!i.endsWith(".ts") && !i.endsWith(".js"))
857
+ if (!s.endsWith(".ts") && !s.endsWith(".js") && !s.endsWith(".mjs") && !s.endsWith(".cjs"))
862
858
  continue;
863
- yield i;
859
+ yield s;
864
860
  }
865
861
  }
866
862
  }
867
863
  }
868
- class j extends O {
864
+ class W extends C {
869
865
  constructor(e) {
870
866
  super("help", {
871
867
  description: l.bold("Show help information about the CLI and its commands")
872
868
  }), this.opts = e;
873
869
  }
874
870
  async handle() {
875
- const e = this.opts.commandRegistry.getCommands(), t = this.opts.cliName ?? "Bob CLI", n = this.opts.cliVersion ?? "0.0.0", i = (await import("./package-CmpNUcph.js"))?.default?.version ?? "0.0.0";
876
- this.io.log(l`${t} {green ${n}} (core: {yellow ${i}})
871
+ const e = this.opts.commandRegistry.getCommands(), t = this.opts.cliName ?? "Bob CLI", n = this.opts.cliVersion ?? "0.0.0", s = (await import("./package-B_VxJm2q.js"))?.default?.version ?? "0.0.0";
872
+ this.io.log(l`${t} {green ${n}} (core: {yellow ${s}})
877
873
 
878
874
  {yellow Usage}:
879
875
  command [options] [arguments]
@@ -885,19 +881,19 @@ class j extends O {
885
881
  const p = m.group ?? m.command.split(":")[0];
886
882
  o[p] || (o[p] = []), o[p].push(m);
887
883
  }
888
- const d = Object.entries(o).sort(([m], [p]) => m.toLowerCase().localeCompare(p.toLowerCase())).sort(([, m], [, p]) => m.length - p.length);
889
- for (const [m, p] of d) {
884
+ const u = Object.entries(o).sort(([m], [p]) => m.toLowerCase().localeCompare(p.toLowerCase())).sort(([, m], [, p]) => m.length - p.length);
885
+ for (const [m, p] of u) {
890
886
  const a = p.length > 1;
891
887
  a && this.io.log(l`{yellow ${m}}:`);
892
- const u = p.sort((c, h) => c.command.toLowerCase().localeCompare(h.command.toLowerCase()));
893
- for (const c of u) {
894
- let h = A(r - c.command.length);
888
+ const d = p.sort((c, h) => c.command.toLowerCase().localeCompare(h.command.toLowerCase()));
889
+ for (const c of d) {
890
+ let h = O(r - c.command.length);
895
891
  a && (h = h.slice(2)), this.io.log(l`${a ? " " : ""}{green ${c.command}} ${h} ${c.description}`);
896
892
  }
897
893
  }
898
894
  }
899
895
  }
900
- class W {
896
+ class T {
901
897
  logger;
902
898
  constructor(e) {
903
899
  this.logger = e;
@@ -915,13 +911,13 @@ class J {
915
911
  exceptionHandler;
916
912
  helpCommand;
917
913
  newCommandRegistry(e) {
918
- return new T(e.logger);
914
+ return new j(e.logger);
919
915
  }
920
916
  newHelpCommand(e) {
921
- return new j(e);
917
+ return new W(e);
922
918
  }
923
919
  newExceptionHandler(e) {
924
- return new W(e.logger);
920
+ return new T(e.logger);
925
921
  }
926
922
  constructor(e = {}) {
927
923
  this.ctx = e.ctx, this.logger = e.logger ?? new L(), this.commandRegistry = this.newCommandRegistry({
@@ -952,21 +948,21 @@ class J {
952
948
  }
953
949
  }
954
950
  export {
955
- b as BadCommandOption,
951
+ A as BadCommandOption,
956
952
  U as BadCommandParameter,
957
953
  f as BobError,
958
954
  J as Cli,
959
- O as Command,
955
+ C as Command,
960
956
  S as CommandIO,
961
957
  V as CommandNotFoundError,
962
958
  F as CommandParser,
963
- T as CommandRegistry,
959
+ j as CommandRegistry,
964
960
  w as CommandSignatureParser,
965
961
  z as CommandWithSignature,
966
- W as ExceptionHandler,
962
+ T as ExceptionHandler,
967
963
  H as HelpOption,
968
- C as InvalidOption,
964
+ b as InvalidOption,
969
965
  L as Logger,
970
- k as MissingRequiredArgumentValue,
966
+ E as MissingRequiredArgumentValue,
971
967
  I as MissingRequiredOptionValue
972
968
  };
@@ -1,4 +1,4 @@
1
- const s = "bob-core", t = "2.0.0-beta.5", e = "BOB Core", i = "module", l = !1, n = ["dist/**"], r = { ".": { import: "./dist/esm/index.js", require: "./dist/cjs/index.js" } }, o = { "*": { "*": ["./dist/cjs/*.d.ts"] } }, c = { start: "node -r @swc-node/register debug/main.ts", build: "rimraf ./dist && vite build", typecheck: "tsc --noEmit", prepare: "npm run build", test: "vitest run" }, d = "Léo Hubert", p = "ISC", a = { "@faker-js/faker": "^10.0.0", "@swc-node/register": "^1.11.1", "@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", rimraf: "^6.0.1", tsx: "^4.20.6", typescript: "^5.7.3", vite: "^7.1.6", "vite-plugin-dts": "^4.5.4", vitest: "^3.2.4" }, m = { chalk: "^4.1.2", minimist: "^1.2.8", prompts: "^2.4.2", "string-similarity": "^4.0.4" }, u = {
1
+ const s = "bob-core", t = "2.0.0-beta.6", e = "BOB Core", i = "module", l = !1, n = ["dist/**"], r = { ".": { import: "./dist/esm/index.js", require: "./dist/cjs/index.js" } }, o = { "*": { "*": ["./dist/cjs/*.d.ts"] } }, c = { start: "node -r @swc-node/register debug/main.ts", build: "rimraf ./dist && vite build", typecheck: "tsc --noEmit", prepare: "npm run build", test: "vitest run" }, d = "Léo Hubert", p = "ISC", a = { "@faker-js/faker": "^10.0.0", "@swc-node/register": "^1.11.1", "@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", rimraf: "^6.0.1", tsx: "^4.20.6", typescript: "^5.7.3", vite: "^7.1.6", "vite-plugin-dts": "^4.5.4", vitest: "^3.2.4" }, m = { chalk: "^4.1.2", minimist: "^1.2.8", prompts: "^2.4.2", "string-similarity": "^4.0.4" }, u = {
2
2
  name: s,
3
3
  version: t,
4
4
  description: e,
@@ -1,7 +1,7 @@
1
1
  import { CommandIO } from './CommandIO.js';
2
2
  import { Command } from './Command.js';
3
3
  import { Logger } from './Logger.js';
4
- export type CommandResolver = (path: string) => Promise<Command>;
4
+ export type CommandResolver = (path: string) => Promise<Command | null>;
5
5
  export declare class CommandRegistry {
6
6
  private readonly commands;
7
7
  protected readonly io: CommandIO;
@@ -12,6 +12,8 @@ export declare class CommandRegistry {
12
12
  getCommands(): Array<Command>;
13
13
  private commandResolver;
14
14
  setCommandResolver(resolver: CommandResolver): void;
15
+ fileCheck: (filePath: string) => boolean;
16
+ setFileCheck(check: (filePath: string) => boolean): this;
15
17
  registerCommand(command: Command<any, any, any>, force?: boolean): void;
16
18
  loadCommandsPath(commandsPath: string): Promise<void>;
17
19
  runCommand(ctx: any, command: string | Command, ...args: any[]): Promise<number>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bob-core",
3
- "version": "2.0.0-beta.5",
3
+ "version": "2.0.0-beta.6",
4
4
  "description": "BOB Core",
5
5
  "type": "module",
6
6
  "sideEffects": false,