bob-core 2.0.0-beta.6 → 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 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+=`
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
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}})
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 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;
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.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
+ "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;
@@ -2,6 +2,7 @@ import { CommandIO } from './CommandIO.js';
2
2
  import { Command } from './Command.js';
3
3
  import { Logger } from './Logger.js';
4
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,10 @@ 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;
15
18
  fileCheck: (filePath: string) => boolean;
16
19
  setFileCheck(check: (filePath: string) => boolean): this;
17
20
  registerCommand(command: Command<any, any, any>, force?: boolean): void;
package/dist/esm/index.js CHANGED
@@ -70,7 +70,7 @@ class b extends f {
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
  }
@@ -86,7 +86,7 @@ class E 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
  }
@@ -159,7 +159,7 @@ 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) {
@@ -374,11 +374,11 @@ class H {
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
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] : [];
377
+ const h = Array.isArray(d.alias) ? d.alias : d.alias ? [d.alias] : [];
378
378
  return {
379
379
  name: a,
380
380
  ...d,
381
- optionWithAlias: `--${a}${c.map((h) => `, -${h}`).join("")}`
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]`);
@@ -386,38 +386,38 @@ class H {
386
386
  if (n.length > 0) {
387
387
  this.io.log(l`\n{yellow Arguments}:`);
388
388
  for (const [a, d] of n) {
389
- const c = O(p - a.length);
390
- let h = l` {green ${a}} ${c} ${d.description ?? "\b"}`;
389
+ const h = O(p - a.length);
390
+ let c = l` {green ${a}} ${h} ${d.description ?? "\b"}`;
391
391
  if (d.default !== void 0 && !d.required) {
392
392
  const N = (Array.isArray(d.type) ? `[${d.type[0]}]` : d.type) === "array" || Array.isArray(d.type) ? JSON.stringify(d.default) : d.default;
393
- h += l` {yellow [default: ${N}]}`;
393
+ c += l` {yellow [default: ${N}]}`;
394
394
  }
395
- d.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
398
  if (s.length > 0) {
399
399
  this.io.log(l`\n{yellow Options}:`);
400
400
  for (const a of r) {
401
401
  const d = O(p - a.optionWithAlias.length);
402
- let c = l`{green ${a.optionWithAlias}} ${d} ${a.description ?? "\b"}`;
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 [d, c] of this.commandsExamples.entries())
419
- d > 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
  }
@@ -783,14 +783,18 @@ class j {
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
791
  return t?.default && (t = t.default), typeof t == "function" ? new t() : t instanceof C ? t : null;
791
792
  };
792
793
  setCommandResolver(e) {
793
- this.commandResolver = e;
794
+ return this.commandResolver = e, this;
795
+ }
796
+ setFileImporter(e) {
797
+ return this.importFile = e, this;
794
798
  }
795
799
  fileCheck = (e) => !0;
796
800
  setFileCheck(e) {
@@ -842,7 +846,7 @@ class j {
842
846
  if (u)
843
847
  return u;
844
848
  }
845
- throw new V(e);
849
+ throw new I(e);
846
850
  }
847
851
  async askRunSimilarCommand(e, t) {
848
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?} `);
@@ -868,7 +872,7 @@ class W extends C {
868
872
  }), this.opts = e;
869
873
  }
870
874
  async handle() {
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";
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";
872
876
  this.io.log(l`${t} {green ${n}} (core: {yellow ${s}})
873
877
 
874
878
  {yellow Usage}:
@@ -885,10 +889,10 @@ class W extends C {
885
889
  for (const [m, p] of u) {
886
890
  const a = p.length > 1;
887
891
  a && this.io.log(l`{yellow ${m}}:`);
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);
891
- 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}`);
892
896
  }
893
897
  }
894
898
  }
@@ -954,7 +958,7 @@ export {
954
958
  J as Cli,
955
959
  C as Command,
956
960
  S as CommandIO,
957
- V as CommandNotFoundError,
961
+ I as CommandNotFoundError,
958
962
  F as CommandParser,
959
963
  j as CommandRegistry,
960
964
  w as CommandSignatureParser,
@@ -964,5 +968,5 @@ export {
964
968
  b as InvalidOption,
965
969
  L as Logger,
966
970
  E as MissingRequiredArgumentValue,
967
- I as MissingRequiredOptionValue
971
+ V as MissingRequiredOptionValue
968
972
  };
@@ -1,4 +1,4 @@
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 = {
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,
@@ -2,6 +2,7 @@ import { CommandIO } from './CommandIO.js';
2
2
  import { Command } from './Command.js';
3
3
  import { Logger } from './Logger.js';
4
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,10 @@ 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;
15
18
  fileCheck: (filePath: string) => boolean;
16
19
  setFileCheck(check: (filePath: string) => boolean): this;
17
20
  registerCommand(command: Command<any, any, any>, force?: boolean): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bob-core",
3
- "version": "2.0.0-beta.6",
3
+ "version": "2.0.0-beta.7",
4
4
  "description": "BOB Core",
5
5
  "type": "module",
6
6
  "sideEffects": false,