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

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"),F=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 S(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 q(s){return!Array.isArray(s)&&typeof s=="object"&&s.type?s.default!==void 0?s.default:S(s.type):S(s)}function g(s){return typeof s=="string"||Array.isArray(s)?{type:s,default:q(s),description:"",alias:[],required:!1,variadic:!1}:{type:s.type,default:s.default??q(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 I{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)}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?.default&&(t=t.default),typeof t=="function"?new t:t instanceof C?t:null};setCommandResolver(e){return this.commandResolver=e,this}setFileImporter(e){return this.importFile=e,this}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=F.resolve(e,n.name);if(n.isDirectory())yield*this.listCommandsFiles(F.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-COb9yxnx.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 V{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 I(e.logger)}newHelpCommand(e){return new U(e)}newExceptionHandler(e){return new V(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=I;exports.CommandSignatureParser=y;exports.CommandWithSignature=G;exports.ExceptionHandler=V;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.7",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,8 @@
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
+ export type FileImporter = (filePath: string) => Promise<any>;
5
6
  export declare class CommandRegistry {
6
7
  private readonly commands;
7
8
  protected readonly io: CommandIO;
@@ -10,8 +11,12 @@ export declare class CommandRegistry {
10
11
  constructor(logger?: Logger);
11
12
  getAvailableCommands(): string[];
12
13
  getCommands(): Array<Command>;
14
+ private importFile;
13
15
  private commandResolver;
14
- setCommandResolver(resolver: CommandResolver): void;
16
+ setCommandResolver(resolver: CommandResolver): this;
17
+ setFileImporter(importer: FileImporter): this;
18
+ fileCheck: (filePath: string) => boolean;
19
+ setFileCheck(check: (filePath: string) => boolean): this;
15
20
  registerCommand(command: Command<any, any, any>, force?: boolean): void;
16
21
  loadCommandsPath(commandsPath: string): Promise<void>;
17
22
  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,16 +61,16 @@ 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
  }
70
70
  e.log(l`{white.bgRed ERROR } Option {bold.yellow ${this.option}} is not recognized.`);
71
71
  }
72
72
  }
73
- class V extends f {
73
+ class I extends f {
74
74
  constructor(e) {
75
75
  super(`Command "${e}" not found.`), this.command = e;
76
76
  }
@@ -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
  }
@@ -86,7 +86,7 @@ class k extends f {
86
86
  e.log(l`{white.bgRed ERROR } Argument {bold.yellow ${this.argument}} is required.`);
87
87
  }
88
88
  }
89
- class I extends f {
89
+ class V extends f {
90
90
  constructor(e) {
91
91
  super(`Argument "${e}" is required.`), this.option = e;
92
92
  }
@@ -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;
@@ -159,28 +159,28 @@ class F {
159
159
  async validate() {
160
160
  for (const e in this.options)
161
161
  if (g(this.options[e]).required && (this.parsedOptions?.[e] === void 0 || this.parsedOptions?.[e] === null))
162
- throw new I(e);
162
+ throw new V(e);
163
163
  for (const e in this.arguments) {
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,51 +373,51 @@ 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 h = Array.isArray(d.alias) ? d.alias : d.alias ? [d.alias] : [];
378
378
  return {
379
379
  name: a,
380
- ...u,
381
- optionWithAlias: `--${a}${c.map((h) => `, -${h}`).join("")}`
380
+ ...d,
381
+ optionWithAlias: `--${a}${h.map((c) => `, -${c}`).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;
393
- h += l` {yellow [default: ${N}]}`;
388
+ for (const [a, d] of n) {
389
+ const h = O(p - a.length);
390
+ let c = l` {green ${a}} ${h} ${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
+ c += l` {yellow [default: ${N}]}`;
394
394
  }
395
- u.variadic && (h += l` {white (variadic)}`), this.io.log(h);
395
+ d.variadic && (c += l` {white (variadic)}`), this.io.log(c);
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 h = l`{green ${a.optionWithAlias}} ${d} ${a.description ?? "\b"}`;
403
403
  if (a.type) {
404
- const h = Array.isArray(a.type) ? `[${a.type[0]}]` : a.type;
405
- c += l` {white (${h})}`;
404
+ const c = Array.isArray(a.type) ? `[${a.type[0]}]` : a.type;
405
+ h += l` {white (${c})}`;
406
406
  }
407
407
  if (a.default !== void 0 && !a.required) {
408
408
  const $ = (Array.isArray(a.type) ? `[${a.type[0]}]` : a.type) === "array" || Array.isArray(a.type) ? JSON.stringify(a.default) : a.default;
409
- c += l` {yellow [default: ${$}]}`;
409
+ h += l` {yellow [default: ${$}]}`;
410
410
  }
411
- this.io.log(c);
411
+ this.io.log(h);
412
412
  }
413
413
  }
414
414
  if (this.commandsExamples.length > 0) {
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}
420
- `), this.io.log(l` {green ${a} ${c.command}}`);
418
+ for (const [d, h] of this.commandsExamples.entries())
419
+ d > 0 && this.io.log(""), this.io.log(` ${h.description}
420
+ `), this.io.log(l` {green ${a} ${h.command}}`);
421
421
  }
422
422
  return -1;
423
423
  }
@@ -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;
@@ -783,22 +783,22 @@ class T {
783
783
  getCommands() {
784
784
  return Object.values(this.commands);
785
785
  }
786
+ importFile = async (e) => (await import(e)).default;
786
787
  commandResolver = async (e) => {
787
- let t = (await import(e)).default;
788
+ let t = await this.importFile(e);
788
789
  if (!t)
789
790
  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;
791
+ return t?.default && (t = t.default), typeof t == "function" ? new t() : t instanceof C ? t : null;
799
792
  };
800
793
  setCommandResolver(e) {
801
- this.commandResolver = e;
794
+ return this.commandResolver = e, this;
795
+ }
796
+ setFileImporter(e) {
797
+ return this.importFile = e, this;
798
+ }
799
+ fileCheck = (e) => !0;
800
+ setFileCheck(e) {
801
+ return this.fileCheck = e, this;
802
802
  }
803
803
  registerCommand(e, t = !1) {
804
804
  const n = e.command;
@@ -812,7 +812,7 @@ class T {
812
812
  for await (const t of this.listCommandsFiles(e))
813
813
  try {
814
814
  const n = await this.commandResolver(t);
815
- this.registerCommand(n);
815
+ n instanceof C && this.registerCommand(n);
816
816
  } catch (n) {
817
817
  throw new Error(`Command ${t} failed to load. ${n}`, {
818
818
  cause: n
@@ -820,33 +820,33 @@ class T {
820
820
  }
821
821
  }
822
822
  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) {
823
+ const s = typeof t == "string" ? this.commands[t] : t, r = typeof t == "string" ? t : s.command;
824
+ if (!s) {
825
825
  const o = await this.suggestCommand(r);
826
826
  return o ? await this.runCommand(e, o, ...n) : 1;
827
827
  }
828
- return await i.run({
828
+ return await s.run({
829
829
  ctx: e,
830
830
  logger: this.logger,
831
831
  args: n
832
832
  }) ?? 0;
833
833
  }
834
834
  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);
835
+ 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
836
  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;
837
+ const u = t[s];
838
+ return await this.askRunSimilarCommand(e, u) ? u : null;
839
839
  }
840
840
  if (o.length) {
841
841
  this.io.error(l`{bgRed ERROR } Command {yellow ${e}} not found.\n`);
842
- const d = await this.io.askForSelect(
842
+ const u = await this.io.askForSelect(
843
843
  l`{green Did you mean to run one of these commands instead?}`,
844
844
  o
845
845
  );
846
- if (d)
847
- return d;
846
+ if (u)
847
+ return u;
848
848
  }
849
- throw new V(e);
849
+ throw new I(e);
850
850
  }
851
851
  async askRunSimilarCommand(e, t) {
852
852
  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?} `);
@@ -854,26 +854,26 @@ class T {
854
854
  async *listCommandsFiles(e) {
855
855
  const t = D.readdirSync(e, { withFileTypes: !0 });
856
856
  for (const n of t) {
857
- const i = R.resolve(e, n.name);
857
+ const s = R.resolve(e, n.name);
858
858
  if (n.isDirectory())
859
859
  yield* this.listCommandsFiles(R.resolve(e, n.name));
860
860
  else {
861
- if (!i.endsWith(".ts") && !i.endsWith(".js"))
861
+ if (!s.endsWith(".ts") && !s.endsWith(".js") && !s.endsWith(".mjs") && !s.endsWith(".cjs"))
862
862
  continue;
863
- yield i;
863
+ yield s;
864
864
  }
865
865
  }
866
866
  }
867
867
  }
868
- class j extends O {
868
+ class W extends C {
869
869
  constructor(e) {
870
870
  super("help", {
871
871
  description: l.bold("Show help information about the CLI and its commands")
872
872
  }), this.opts = e;
873
873
  }
874
874
  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}})
875
+ const e = this.opts.commandRegistry.getCommands(), t = this.opts.cliName ?? "Bob CLI", n = this.opts.cliVersion ?? "0.0.0", s = (await import("./package-D2VbJdgN.js"))?.default?.version ?? "0.0.0";
876
+ this.io.log(l`${t} {green ${n}} (core: {yellow ${s}})
877
877
 
878
878
  {yellow Usage}:
879
879
  command [options] [arguments]
@@ -885,19 +885,19 @@ class j extends O {
885
885
  const p = m.group ?? m.command.split(":")[0];
886
886
  o[p] || (o[p] = []), o[p].push(m);
887
887
  }
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) {
888
+ const u = Object.entries(o).sort(([m], [p]) => m.toLowerCase().localeCompare(p.toLowerCase())).sort(([, m], [, p]) => m.length - p.length);
889
+ for (const [m, p] of u) {
890
890
  const a = p.length > 1;
891
891
  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);
895
- a && (h = h.slice(2)), this.io.log(l`${a ? " " : ""}{green ${c.command}} ${h} ${c.description}`);
892
+ const d = p.sort((h, c) => h.command.toLowerCase().localeCompare(c.command.toLowerCase()));
893
+ for (const h of d) {
894
+ let c = O(r - h.command.length);
895
+ a && (c = c.slice(2)), this.io.log(l`${a ? " " : ""}{green ${h.command}} ${c} ${h.description}`);
896
896
  }
897
897
  }
898
898
  }
899
899
  }
900
- class W {
900
+ class T {
901
901
  logger;
902
902
  constructor(e) {
903
903
  this.logger = e;
@@ -915,13 +915,13 @@ class J {
915
915
  exceptionHandler;
916
916
  helpCommand;
917
917
  newCommandRegistry(e) {
918
- return new T(e.logger);
918
+ return new j(e.logger);
919
919
  }
920
920
  newHelpCommand(e) {
921
- return new j(e);
921
+ return new W(e);
922
922
  }
923
923
  newExceptionHandler(e) {
924
- return new W(e.logger);
924
+ return new T(e.logger);
925
925
  }
926
926
  constructor(e = {}) {
927
927
  this.ctx = e.ctx, this.logger = e.logger ?? new L(), this.commandRegistry = this.newCommandRegistry({
@@ -952,21 +952,21 @@ class J {
952
952
  }
953
953
  }
954
954
  export {
955
- b as BadCommandOption,
955
+ A as BadCommandOption,
956
956
  U as BadCommandParameter,
957
957
  f as BobError,
958
958
  J as Cli,
959
- O as Command,
959
+ C as Command,
960
960
  S as CommandIO,
961
- V as CommandNotFoundError,
961
+ I as CommandNotFoundError,
962
962
  F as CommandParser,
963
- T as CommandRegistry,
963
+ j as CommandRegistry,
964
964
  w as CommandSignatureParser,
965
965
  z as CommandWithSignature,
966
- W as ExceptionHandler,
966
+ T as ExceptionHandler,
967
967
  H as HelpOption,
968
- C as InvalidOption,
968
+ b as InvalidOption,
969
969
  L as Logger,
970
- k as MissingRequiredArgumentValue,
971
- I as MissingRequiredOptionValue
970
+ E as MissingRequiredArgumentValue,
971
+ V as MissingRequiredOptionValue
972
972
  };
@@ -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.7", 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,8 @@
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
+ export type FileImporter = (filePath: string) => Promise<any>;
5
6
  export declare class CommandRegistry {
6
7
  private readonly commands;
7
8
  protected readonly io: CommandIO;
@@ -10,8 +11,12 @@ export declare class CommandRegistry {
10
11
  constructor(logger?: Logger);
11
12
  getAvailableCommands(): string[];
12
13
  getCommands(): Array<Command>;
14
+ private importFile;
13
15
  private commandResolver;
14
- setCommandResolver(resolver: CommandResolver): void;
16
+ setCommandResolver(resolver: CommandResolver): this;
17
+ setFileImporter(importer: FileImporter): this;
18
+ fileCheck: (filePath: string) => boolean;
19
+ setFileCheck(check: (filePath: string) => boolean): this;
15
20
  registerCommand(command: Command<any, any, any>, force?: boolean): void;
16
21
  loadCommandsPath(commandsPath: string): Promise<void>;
17
22
  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.7",
4
4
  "description": "BOB Core",
5
5
  "type": "module",
6
6
  "sideEffects": false,