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

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 P=require("minimist"),a=require("chalk"),w=require("prompts"),W=require("node:fs"),D=require("path"),B=require("string-similarity");function I(r){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const t in r)if(t!=="default"){const n=Object.getOwnPropertyDescriptor(r,t);Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>r[t]})}}return e.default=r,Object.freeze(e)}const _=I(W),G=I(B);class y extends Error{}class U extends y{constructor(e){let t=`Argument "${e.param}" value is invalid.`;e.reason?t+=` Reason: ${e.reason}`:t+=` Value: "${e.value}"`,super(t),this.param=e}pretty(e){e.log(a` {white.bgRed ERROR } Argument {bold.yellow ${this.param.param}} value is invalid. `),(this.param.value||this.param.reason)&&e.log(""),this.param.value&&e.log(a` {blue Value}: ${this.param.value}`),this.param.reason&&e.log(a` {yellow Reason}: ${this.param.reason}`)}}class C extends y{constructor(e){let t=`Option "${e.option}" value is invalid.`;e.reason?t+=` Reason: ${e.reason}`:t+=` Value: "${e.value}"`,super(t),this.param=e}pretty(e){e.log(a` {white.bgRed ERROR } Option {bold.yellow ${this.param.option}} value is invalid. `),(this.param.value||this.param.reason)&&e.log(""),this.param.value&&e.log(a` {blue Value}: ${this.param.value}`),this.param.reason&&e.log(a` {yellow Reason}: ${this.param.reason}`)}}function k(r){if(r==="string"||r==="number")return null;if(r==="boolean")return!1;if(Array.isArray(r)&&r.length===1){if(r[0]==="string")return[];if(r[0]==="number")return[]}throw new Error("Invalid option type: "+r)}function N(r){return typeof r=="string"?k(r):Array.isArray(r)?[]:typeof r=="object"&&r.type?r.default!==void 0?r.default:k(r.type):null}function f(r){return typeof r=="string"||Array.isArray(r)?{type:r,default:N(r),description:"",alias:[],required:!1,variadic:!1}:{type:r.type,default:r.default??N(r.type),description:r.description??"",alias:r.alias?Array.isArray(r.alias)?r.alias:[r.alias]:[],required:r.required??!1,variadic:r.variadic??!1}}class L extends y{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(a`\n{yellow Available options}:`);for(const[n,i]of t){const s=f(i),o=typeof s.alias=="string"?[s.alias]:s.alias,l=Array.isArray(s.type)?`[${s.type[0]}]`:s.type,u=`--${n}${o.length>0?o.map(m=>`, -${m}`).join(""):""}`,d=" ".repeat(30-u.length);e.log(a` {green ${u}} ${d} ${s.description||"\b"} {white (${l})}`)}e.log("")}e.log(a`{white.bgRed ERROR } Option {bold.yellow ${this.option}} is not recognized.`)}}class j extends y{constructor(e){super(`Command "${e}" not found.`),this.command=e}pretty(e){e.log(a`{bgRed ERROR } Command {yellow ${this.command}} not found.`)}}class v extends y{constructor(e,t){super(`Missing ${e} in the command signature`),this.argument=e,this.argumentsSchema=t}pretty(e){const t=Object.entries(this.argumentsSchema);if(t.length){e.log(a`\n{yellow Available arguments}:`);for(const[n,i]of t){const s=f(i),o=Array.isArray(s.type)?`[${s.type[0]}]`:s.type,l=o?a`{white (${o})}`:"",u=" ".repeat(20-n.length);e.log(a` {green ${n}} ${u} ${s.description??"\b"} ${l}`)}e.log("")}e.log(a`{white.bgRed ERROR } Argument {bold.yellow ${this.argument}} is missing in the signature.`)}}class b extends y{constructor(e,t){super(`Missing ${e} in the command signature`),this.option=e,this.optionsSchema=t}pretty(e){const t=Object.entries(this.optionsSchema);if(t.length){e.log(a`{yellow Available options}:`);for(const[n,i]of t){const s=f(i),o=Array.isArray(s.type)?`[${s.type[0]}]`:s.type,l=o?a`{white (${o})}`:"",u=" ".repeat(20-n.length);e.log(a` {green ${n}} ${u} ${s.description??"\b"} ${l}`)}e.log("")}e.log(a`{white.bgRed ERROR } Option {bold.yellow ${this.option}} is missing in the signature.`)}}class O extends y{constructor(e){super(`Argument "${e}" is required.`),this.argument=e}pretty(e){e.log(a`{white.bgRed ERROR } Argument {bold.yellow ${this.argument}} is required.`)}}class F extends y{constructor(e){super(`Argument "${e}" is required.`),this.option=e}pretty(e){e.log(a`{white.bgRed ERROR } Option {bold.yellow ${this.option}} is required.`)}}function $(r,e,t,n){if(r==null)return n??null;if(e==="string")return String(r);if(e==="number"){const i=Number(r);if(isNaN(i))throw new C({option:t,reason:`Expected a number, got "${r}"`});return i}if(e==="boolean")return typeof r=="boolean"?r:r==="true"||r==="1"?!0:r==="false"||r==="0"?!1:!!r;if(Array.isArray(e)){const i=e[0],s=Array.isArray(r)?r:[r];if(i==="string")return s.map(o=>String(o));if(i==="number")return s.map(o=>{const l=Number(o);if(isNaN(l))throw new C({option:t,reason:`Expected array of numbers, got "${o}" in array`});return l})}return r}class S{options;parsedOptions=null;arguments;parsedArguments=null;io;constructor(e){this.options=e.options,this.arguments=e.arguments,this.io=e.io}init(e){const{_:t,...n}=P(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(f(this.options[e]).required&&(this.parsedOptions?.[e]===void 0||this.parsedOptions?.[e]===null))throw new F(e);for(const e in this.arguments)if(f(this.arguments[e]).required&&(this.parsedArguments?.[e]===void 0||this.parsedArguments?.[e]===null))throw new O(e)}option(e){if(!this.parsedOptions)throw new Error("Options have not been parsed yet. Call init() first.");return this.parsedOptions[e]}argument(e){if(!this.parsedArguments)throw new Error("Arguments have not been parsed yet. Call init() first.");return this.parsedArguments[e]}validateUnknownOptions(e){const t=new Set;for(const n in this.options){t.add(n);const i=f(this.options[n]);for(const s of i.alias)t.add(s)}for(const n in e)if(!t.has(n))throw new L(n,this.options)}handleOptions(e){const t={};for(const n in this.options){const i=f(this.options[n]);t[n]=this.resolveOptionValue(n,i,e,"option")}return t}handleArguments(e){const t={},n=[...e];for(const i in this.arguments){const s=f(this.arguments[i]);if(s.variadic){t[i]=this.handleVariadicArgument(i,s,n);continue}t[i]=this.resolveArgumentValue(i,s,n.shift())}return t}handleVariadicArgument(e,t,n){return n.length?$(n,t.type,e,t.default):t.default}resolveArgumentValue(e,t,n){return n===void 0?t.default:$(n,t.type,e,t.default)}resolveOptionValue(e,t,n,i){let s;const o=[e,...t.alias];for(const l of o)if(l in n){s=n[l];break}if(s===void 0){if(t.required)throw new C({option:e,reason:`${i==="option"?"Option":"Argument"} is required but not provided`});return t.default}return $(s,t.type,e,t.default)}optionDefinitions(){const e={};for(const t in this.options)e[t]=f(this.options[t]);return e}argumentDefinitions(){const e={};for(const t in this.arguments)e[t]=f(this.arguments[t]);return e}availableOptions(){return Object.keys(this.options)}availableArguments(){return Object.keys(this.arguments)}}function R(r){return new Array(r+5).join(" ")}class V{type="boolean";option="help";alias=["h"];default=!1;description=a`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),s=i.map(([m,c])=>{const h=Array.isArray(c.alias)?c.alias:c.alias?[c.alias]:[];return{name:m,...c,optionWithAlias:`--${m}${h.map(p=>`, -${p}`).join("")}`}}),o=n.filter(([,m])=>m.required);this.io.log(a`{yellow Description}:`),this.io.log(a` ${this.description}\n`),this.io.log(a`{yellow Usage}:`),this.io.log(a` ${this.command} ${o.length>0?o.map(([m])=>`<${m}>`).join(" "):"\b"} [options]`);const l=Math.max(...s.map(m=>m.optionWithAlias.length),0),u=Math.max(...n.map(([m])=>m.length),0),d=u>l?u:l;if(n.length>0){this.io.log(a`\n{yellow Arguments}:`);for(const[m,c]of n){const h=R(d-m.length);let p=a` {green ${m}} ${h} ${c.description??"\b"}`;if(c.default!==void 0&&!c.required){const T=(Array.isArray(c.type)?`[${c.type[0]}]`:c.type)==="array"||Array.isArray(c.type)?JSON.stringify(c.default):c.default;p+=a` {yellow [default: ${T}]}`}c.variadic&&(p+=a` {white (variadic)}`),this.io.log(p)}}if(i.length>0){this.io.log(a`\n{yellow Options}:`);for(const m of s){const c=R(d-m.optionWithAlias.length);let h=a`{green ${m.optionWithAlias}} ${c} ${m.description??"\b"}`;if(m.type){const p=Array.isArray(m.type)?`[${m.type[0]}]`:m.type;h+=a` {white (${p})}`}if(m.default!==void 0&&!m.required){const q=(Array.isArray(m.type)?`[${m.type[0]}]`:m.type)==="array"||Array.isArray(m.type)?JSON.stringify(m.default):m.default;h+=a` {yellow [default: ${q}]}`}this.io.log(h)}}if(this.commandsExamples.length>0){this.io.log(a`\n{yellow Examples}:`);let m=process.argv[0].split("/").pop();m==="node"&&(m+=" "+process.argv[1].split("/").pop());for(const[c,h]of this.commandsExamples.entries())c>0&&this.io.log(""),this.io.log(` ${h.description}
2
- `),this.io.log(a` {green ${m} ${h.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 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,s=null,o=0;const l=setInterval(function(){s&&(process.stdout.write(new TextEncoder().encode("\r"+" ".repeat(s.length+5)+"\r")),s=null),process.stdout.write(new TextEncoder().encode("\r"+t[o++]+" "+i)),o=o%t.length},n),u=()=>{clearInterval(l),process.stdout.write(new TextEncoder().encode("\r"+" ".repeat(i.length+5)+"\r"))};return{[Symbol.dispose]:u,[Symbol.asyncDispose]:u,updateText:d=>{s=i,i=d},stop:u}}}class A{_command;description="";commandsExamples=[];get command(){return this._command}ctx;io;logger;_handler;parser;tmp;defaultOptions(){return[new V]}newCommandParser(e){return new S({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??"";const n=this.defaultOptions();if(n.length>0){this.tmp={options:{},arguments:{}};for(const i of n)this.tmp.options[i.option]=i}}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 s=this.tmp?.options??{};for(const o of this.defaultOptions())o.option in s||(s[o.option]=o);this.parser=this.newCommandParser({io:this.io,options:s,arguments:this.tmp?.arguments??{}}),t=this.parser.init(e.args);for(const o of this.defaultOptions())if(t.options[o.option]===!0){const l=await o.handler.call(this);if(l&&l!==0)return l}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 g extends S{command;argumentsSchema;optionsSchema;constructor(e){const t=g.parseSignature(e.signature,e.helperDefinitions,e.defaultOptions);super({io:e.io,options:t.options,arguments:t.arguments}),this.command=t.command,this.optionsSchema=t.options,this.argumentsSchema=t.arguments}static parseSignature(e,t,n){const[i,...s]=e.split(/\{(.*?)\}/g).map(u=>u.trim()).filter(Boolean),o={},l={};for(const u of s){const{name:d,isOption:m,definition:c}=g.parseParamSignature(u,t);m?o[d]=c:l[d]=c}for(const u of n)o[u.option]={type:u.type,required:u.required,alias:u.alias,variadic:u.variadic??!1,description:u.description,default:u.default??null};return{command:i,options:o,arguments:l}}option(e){if(!this.optionsSchema[e])throw new b(e,this.optionsSchema);return super.option(e)}setOption(e,t){if(!this.optionsSchema[e])throw new b(e,this.optionsSchema);this.parsedOptions&&(this.parsedOptions[e]=t)}optionHelp(e){if(!this.optionsSchema[e])throw new b(e,this.optionsSchema);return f(this.optionsSchema[e]).description}argumentHelp(e){if(!this.argumentsSchema[e])throw new v(e,this.argumentsSchema);return f(this.argumentsSchema[e]).description}argument(e){if(!this.argumentsSchema[e])throw new v(e,this.argumentsSchema);return super.argument(e)}setArgument(e,t){if(!this.argumentsSchema[e])throw new v(e,this.argumentsSchema);this.parsedArguments&&(this.parsedArguments[e]=t)}getArgumentSignatures(){return this.argumentsSchema}getOptionSignatures(){return this.optionsSchema}static parseParamSignature(e,t){let n=e,i=!1;const s={required:!0,type:"string",description:void 0,default:null,variadic:!1};if(n.includes(":")){const[o,l]=n.split(":");n=o.trim(),s.description=l.trim()}if(n.includes("=")){const[o,l]=n.split("=");n=o.trim(),s.default=l.trim(),s.required=!1,s.default.length?s.default==="true"?(s.default=!0,s.type="boolean"):s.default==="false"&&(s.default=!1,s.type="boolean"):s.default=null}else n.startsWith("--")&&(s.required=!1,s.default=!1,s.type="boolean");if(n.includes("|")){const[o,...l]=n.split("|");n=o.trim(),s.alias=l.map(u=>u.trim())}return n.startsWith("--")&&(i=!0,n=n.slice(2)),s.default==="*"&&(s.default=[],s.type=["string"]),n.endsWith("?")&&(s.required=!1,n=n.slice(0,-1)),n.endsWith("*")&&(s.type=["string"],s.variadic=!0,s.default=[],n=n.slice(0,-1)),s.description=s.description??t[n]??t[`--${n}`],{name:n,isOption:i,definition:s}}async validate(){for(const e in this.argumentsSchema){const t=f(this.argumentsSchema[e]),n=this.argument(e);if(!n&&t.required){const i=await this.promptForArgument(e,t);if(i)this.setArgument(e,i);else throw new O(e)}if(t.variadic&&t.required&&typeof n=="object"&&!n?.length)throw new O(e)}}async promptForArgument(e,t){if(t.type!=="string")return null;let n=a`{yellow.bold ${e}} is required`;return t.description&&(n+=a`: {gray (${t.description})}`),n+=`
3
- `,await this.io.askForInput(n,t.default,{validate:i=>i?.trim()?.length?!0:`${e} cannot be empty`})}optionValues(){if(!this.parsedOptions)throw new Error("Options have not been parsed yet. Call init() first.");return this.parsedOptions}argumentValues(){if(!this.parsedArguments)throw new Error("Arguments have not been parsed yet. Call init() first.");return this.parsedArguments}}class z extends A{helperDefinitions={};get command(){return this.parser?this.parser.command:this.signature.split(" ")[0]}newCommandParser(e){return new g({io:e.io,signature:this.signature,helperDefinitions:this.helperDefinitions,defaultOptions:this.defaultOptions()})}constructor(){super("")}setOption(e,t){this.parser.setOption(e,t)}setArgument(e,t){this.parser instanceof g&&this.parser.setArgument(e,t)}option(e,t=null){return this.parser instanceof g?this.parser.option(e)??t:t}optionBoolean(e,t=!1){return this.parser instanceof g?this.parser.option(e)??t:t}optionArray(e,t=[]){if(this.parser instanceof g){const n=this.parser.option(e);if(!Array.isArray(n))throw new Error(`Option ${e} is not an array`);if(n.length)return n}return t}optionNumber(e,t=null){if(this.parser instanceof g){const n=this.parser.option(e);return n?typeof n=="number"?n:parseInt(n):t}return t}argument(e,t=null){return this.parser instanceof g?this.parser.argument(e)??t:t}argumentArray(e,t=[]){if(this.parser instanceof g){const n=this.parser.argument(e);if(!Array.isArray(n))throw new Error(`Argument ${e} is not an array`);if(n?.length)return n}return t}argumentBoolean(e,t=!1){return this.parser instanceof g?this.parser.argument(e)??t:t}argumentNumber(e,t=null){if(this.parser instanceof g){const n=this.parser.argument(e);return n?typeof n=="number"?n:parseInt(n):t}return 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 H{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 A)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 i=typeof t=="string"?this.commands[t]:t,s=typeof t=="string"?t:i.command;if(!i){const o=await this.suggestCommand(s);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:s}=G.findBestMatch(e,t),o=s.filter(l=>l.rating>.3).map(l=>l.target);if(n.rating>0&&o.length<=1||n.rating>.7&&o.length>1){const l=t[i];return await this.askRunSimilarCommand(e,l)?l:null}if(o.length){this.io.error(a`{bgRed ERROR } Command {yellow ${e}} not found.\n`);const l=await this.io.askForSelect(a`{green Did you mean to run one of these commands instead?}`,o);if(l)return l}throw new j(e)}async askRunSimilarCommand(e,t){return this.io.error(a`{bgRed ERROR } Command {yellow ${e}} not found.\n`),this.io.askForConfirmation(a`{green Do you want to run {yellow ${t}} instead?} `)}async*listCommandsFiles(e){const t=_.readdirSync(e,{withFileTypes:!0});for(const n of t){const i=D.resolve(e,n.name);if(n.isDirectory())yield*this.listCommandsFiles(D.resolve(e,n.name));else{if(!i.endsWith(".ts")&&!i.endsWith(".js"))continue;yield i}}}}class J extends A{constructor(e){super("help",{description:a.bold("Show help information about the CLI and its commands")}),this.opts=e}async handle(){const e=this.opts.commandRegistry.getCommands(),t=this.opts.cliName??"Bob CLI",n=this.opts.cliVersion??"0.0.0",i=(await Promise.resolve().then(()=>require("./package-CXW_8mWb.cjs")))?.default?.version??"0.0.0";this.io.log(a`${t} {green ${n}} (core: {yellow ${i}})
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}})
4
4
 
5
5
  {yellow Usage}:
6
6
  command [options] [arguments]
7
7
 
8
8
  {yellow Available commands}:
9
- `);const s=Math.max(...e.map(u=>u.command.length))??0,o={};for(const u of e){const d=u.command.split(":")[0];o[d]||(o[d]=[]),o[d].push(u)}const l=Object.entries(o).sort(([u],[d])=>u.toLowerCase().localeCompare(d.toLowerCase())).sort(([,u],[,d])=>u.length-d.length);for(const[u,d]of l){const m=d.length>1;m&&this.io.log(a`{yellow ${u}}:`);const c=d.sort((h,p)=>h.command.toLowerCase().localeCompare(p.command.toLowerCase()));for(const h of c){let p=R(s-h.command.length);m&&(p=p.slice(2)),this.io.log(a`${m?" ":""}{green ${h.command}} ${p} ${h.description}`)}}}}class M{logger;constructor(e){this.logger=e}handle(e){if(e instanceof y)return e.pretty(this.logger),-1;throw e}}class K{ctx;logger;commandRegistry;exceptionHandler;helpCommand;newCommandRegistry(e){return new H(e.logger)}newHelpCommand(e){return new J(e)}newExceptionHandler(e){return new M(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=C;exports.BadCommandParameter=U;exports.BobError=y;exports.Cli=K;exports.Command=A;exports.CommandIO=x;exports.CommandNotFoundError=j;exports.CommandParser=S;exports.CommandRegistry=H;exports.CommandSignatureParser=g;exports.CommandWithSignature=z;exports.ExceptionHandler=M;exports.HelpOption=V;exports.InvalidOption=L;exports.Logger=E;exports.MissingRequiredArgumentValue=O;exports.MissingRequiredOptionValue=F;exports.MissingSignatureArgument=v;exports.MissingSignatureOption=b;
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;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="bob-core",s="2.0.0-beta.4",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.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,6 +1,5 @@
1
1
  import { OptionsSchema, OptionsObject, ArgumentsSchema, ArgumentsObject } from './lib/types.js';
2
2
  import { CommandParser } from './CommandParser.js';
3
- import { CommandSignatureParser } from './CommandSignatureParser.js';
4
3
  import { CommandOption } from './contracts/index.js';
5
4
  import { CommandIO } from './CommandIO.js';
6
5
  import { Logger } from './Logger.js';
@@ -28,29 +27,35 @@ export type CommandExample = {
28
27
  export declare class Command<C = any, Options extends OptionsSchema = {}, Arguments extends ArgumentsSchema = {}> {
29
28
  readonly _command: string;
30
29
  readonly description: string;
30
+ readonly group?: string;
31
31
  protected commandsExamples: CommandExample[];
32
32
  get command(): string;
33
33
  protected ctx: C;
34
34
  protected io: CommandIO;
35
35
  protected logger: Logger;
36
- protected _handler?: CommandHandler<C, Options, Arguments>;
37
36
  protected parser: CommandParser<Options, Arguments>;
37
+ protected disablePromptingFlag: boolean;
38
+ protected preHandle?(): Promise<void | number>;
39
+ protected _preHandler?: CommandHandler<C, Options, Arguments>;
40
+ protected handle?(ctx: C, opts: CommandHandlerOptions<Options, Arguments>): Promise<number | void> | number | void;
41
+ protected _handler?: CommandHandler<C, Options, Arguments>;
38
42
  private tmp?;
39
43
  protected defaultOptions(): CommandOption<Command<any, any, any>>[];
40
44
  protected newCommandParser(opts: {
41
45
  io: CommandIO;
42
46
  options: Options;
43
47
  arguments: Arguments;
44
- }): CommandParser<Options, Arguments> | CommandSignatureParser;
48
+ }): CommandParser<Options, Arguments>;
45
49
  protected newCommandIO(opts: {
46
50
  logger: Logger;
47
51
  }): CommandIO;
48
52
  constructor(command: string, opts?: {
49
53
  description?: string;
54
+ group?: string;
50
55
  });
51
- protected preHandle?(): Promise<void | number>;
52
- protected handle?(ctx: C, opts: CommandHandlerOptions<Options, Arguments>): Promise<number | void> | number | void;
53
- handler(handler: CommandHandler<C, Options, Arguments>): Command<C, Options, Arguments>;
56
+ disablePrompting(): this;
57
+ preHandler(handler: CommandHandler<C, Options, Arguments>): this;
58
+ handler(handler: CommandHandler<C, Options, Arguments>): this;
54
59
  options<Opts extends OptionsSchema>(opts: Opts): Command<C, Options & Opts, Arguments>;
55
60
  arguments<Args extends ArgumentsSchema>(args: Args): Command<C, Options, Arguments & Args>;
56
61
  run(opts: CommandRunOption<C, Options, Arguments>): Promise<number | void>;
@@ -27,6 +27,15 @@ export declare class CommandIO {
27
27
  min?: number;
28
28
  max?: number;
29
29
  }): Promise<string | null>;
30
+ askForDate(message: string, defaultValue?: Date, opts?: {
31
+ validate?: (value: Date) => boolean | string;
32
+ mask?: string;
33
+ }): Promise<Date | null>;
34
+ askForList(message: string, defaultValue?: string | number, opts?: {
35
+ validate?: (value: string[]) => boolean | string;
36
+ format?: (value: string) => string;
37
+ separator?: string;
38
+ }): Promise<string[] | null>;
30
39
  askForToggle(message: string, defaultValue?: boolean, opts?: {
31
40
  active?: string;
32
41
  inactive?: string;
@@ -1,4 +1,4 @@
1
- import { OptionsSchema, OptionReturnType, OptionsObject } from './lib/types.js';
1
+ import { OptionsSchema, OptionReturnType, OptionsObject, OptionDefinition } from './lib/types.js';
2
2
  import { OptionDetails } from './lib/optionHelpers.js';
3
3
  import { CommandIO } from './CommandIO.js';
4
4
  /**
@@ -11,6 +11,7 @@ export declare class CommandParser<Options extends OptionsSchema, Arguments exte
11
11
  protected arguments: Arguments;
12
12
  protected parsedArguments: OptionsObject<Arguments> | null;
13
13
  protected io: CommandIO;
14
+ protected shouldPromptForMissingOptions: boolean;
14
15
  constructor(opts: {
15
16
  io: CommandIO;
16
17
  options: Options;
@@ -39,6 +40,7 @@ export declare class CommandParser<Options extends OptionsSchema, Arguments exte
39
40
  * @throws {Error} If init() has not been called yet
40
41
  */
41
42
  option<OptsName extends keyof Options>(name: OptsName): OptionReturnType<Options[OptsName]>;
43
+ setOption<OptsName extends keyof Options>(name: OptsName, value: OptionReturnType<Options[OptsName]>): void;
42
44
  /**
43
45
  * Retrieves a parsed argument value by name
44
46
  * @param name - The argument name
@@ -46,6 +48,7 @@ export declare class CommandParser<Options extends OptionsSchema, Arguments exte
46
48
  * @throws {Error} If init() has not been called yet
47
49
  */
48
50
  argument<ArgName extends keyof Arguments>(name: ArgName): OptionReturnType<Arguments[ArgName]>;
51
+ setArgument<ArgName extends keyof Arguments>(name: ArgName, value: OptionReturnType<Arguments[ArgName]>): void;
49
52
  /**
50
53
  * Validates that all provided options are recognized
51
54
  * @throws {InvalidOption} If an unknown option is found
@@ -77,4 +80,17 @@ export declare class CommandParser<Options extends OptionsSchema, Arguments exte
77
80
  argumentDefinitions(): Record<string, OptionDetails>;
78
81
  availableOptions(): string[];
79
82
  availableArguments(): string[];
83
+ /**
84
+ * Disables prompting for missing argument values
85
+ * Useful for non-interactive environments
86
+ */
87
+ disablePrompting(): this;
88
+ /**
89
+ * Prompts the user to provide a missing argument value via CommandIO
90
+ * Used by validate() when shouldPromptForMissingArgs is enabled
91
+ * @param argumentName - The name of the missing argument
92
+ * @param argDef - The argument's definition for type and description
93
+ * @returns The user-provided value, or null if none given
94
+ */
95
+ protected promptForArgument(argumentName: string, argDef: OptionDefinition): Promise<string | number | string[] | null>;
80
96
  }
@@ -1,6 +1,6 @@
1
1
  import { CommandOption } from './contracts/index.js';
2
2
  import { CommandIO } from './CommandIO.js';
3
- import { OptionsObject, OptionsSchema } from './lib/types.js';
3
+ import { OptionsSchema } from './lib/types.js';
4
4
  import { CommandParser } from './CommandParser.js';
5
5
  /**
6
6
  * Extends CommandParser to parse command signatures like "command {arg} {--option}"
@@ -8,8 +8,6 @@ import { CommandParser } from './CommandParser.js';
8
8
  */
9
9
  export declare class CommandSignatureParser<Opts extends OptionsSchema = any, Args extends OptionsSchema = any> extends CommandParser<Opts, Args> {
10
10
  readonly command: string;
11
- private readonly argumentsSchema;
12
- private readonly optionsSchema;
13
11
  constructor(opts: {
14
12
  io: CommandIO;
15
13
  signature: string;
@@ -23,38 +21,6 @@ export declare class CommandSignatureParser<Opts extends OptionsSchema = any, Ar
23
21
  * Example: "migrate {name} {--force}" -> { command: "migrate", arguments: {name: ...}, options: {force: ...} }
24
22
  */
25
23
  private static parseSignature;
26
- /**
27
- * Retrieves an option value by name, with signature validation
28
- */
29
- option(name: any): any;
30
- /**
31
- * Sets an option value programmatically
32
- */
33
- setOption(name: string, value: any): void;
34
- /**
35
- * Retrieves the description/help text for an option
36
- */
37
- optionHelp(name: string): string | undefined;
38
- /**
39
- * Retrieves the description/help text for an argument
40
- */
41
- argumentHelp(name: string): string | undefined;
42
- /**
43
- * Retrieves an argument value by name, with signature validation
44
- */
45
- argument(name: any): any;
46
- /**
47
- * Sets an argument value programmatically
48
- */
49
- setArgument(name: string, value: any): void;
50
- /**
51
- * Returns all argument definitions from the signature
52
- */
53
- getArgumentSignatures(): OptionsSchema;
54
- /**
55
- * Returns all option definitions from the signature
56
- */
57
- getOptionSignatures(): OptionsSchema;
58
24
  /**
59
25
  * Parses a single parameter signature like "{name}" or "{--force}" or "{files*}"
60
26
  * Extracts name, type, default value, aliases, description, etc.
@@ -70,16 +36,4 @@ export declare class CommandSignatureParser<Opts extends OptionsSchema = any, Ar
70
36
  * - {--opt|o} -> option with alias
71
37
  */
72
38
  private static parseParamSignature;
73
- /**
74
- * Validates that all required arguments are present
75
- * If missing, prompts the user via CommandIO to provide them
76
- * @throws {MissingRequiredArgumentValue} If a required argument cannot be obtained
77
- */
78
- validate(): Promise<void>;
79
- /**
80
- * Prompts the user to provide a missing argument value via CommandIO
81
- */
82
- private promptForArgument;
83
- optionValues(): OptionsObject<Opts>;
84
- argumentValues(): OptionsObject<Args>;
85
39
  }
@@ -14,22 +14,13 @@ export declare abstract class CommandWithSignature<C = any, Opts extends Options
14
14
  io: CommandIO;
15
15
  options: Opts;
16
16
  arguments: Args;
17
- }): CommandSignatureParser;
17
+ }): CommandSignatureParser<Opts, Args>;
18
18
  constructor();
19
19
  protected abstract handle(ctx: C, opts: CommandHandlerOptions<Opts, Args>): Promise<number | void>;
20
- protected setOption(name: string, value: any): void;
21
- protected setArgument(name: string, value: any): void;
22
20
  protected option<T = string>(key: string): T | null;
23
21
  protected option<T = string>(key: string, defaultValue: T): NoInfer<T>;
24
- protected optionBoolean(key: string, defaultValue?: boolean): boolean;
25
- protected optionArray<T = string>(key: string, defaultValue?: Array<T>): Array<NoInfer<T>>;
26
- protected optionNumber(key: string): number | null;
27
- protected optionNumber(key: string, defaultValue: number): number;
28
22
  protected argument<T = string>(key: string): T | null;
29
23
  protected argument<T = string>(key: string, defaultValue: T): NoInfer<T>;
30
- protected argumentArray<T = string>(key: string, defaultValue?: Array<any>): Array<T>;
31
- protected argumentBoolean(key: string, defaultValue?: boolean): boolean;
32
- protected argumentNumber(key: string, defaultValue?: number | null): number | null;
33
24
  askForConfirmation(...opts: Parameters<typeof this.io.askForConfirmation>): ReturnType<typeof this.io.askForConfirmation>;
34
25
  askForInput(...opts: Parameters<typeof this.io.askForInput>): ReturnType<typeof this.io.askForInput>;
35
26
  askForSelect(...opts: Parameters<typeof this.io.askForSelect>): ReturnType<typeof this.io.askForSelect>;
@@ -3,7 +3,5 @@ export * from './BadCommandParameter.js';
3
3
  export * from './BadCommandOption.js';
4
4
  export * from './InvalidOption.js';
5
5
  export * from './CommandNotFoundError.js';
6
- export * from './MissingSignatureArgument.js';
7
- export * from './MissingSignatureOption.js';
8
6
  export * from './MissingRequiredArgumentValue.js';
9
7
  export * from './MissingRequiredOptionValue.js';
@@ -1,5 +1,5 @@
1
1
  import { Option, OptionDefinition, OptionReturnType } from './types.js';
2
2
  export declare function getOptionPrimitiveDefaultValue<Opts extends Option>(type: Opts): OptionReturnType<Opts>;
3
- export declare function getOptionDefaultValue<Opts extends Option>(option: Opts): OptionReturnType<Opts>;
3
+ export declare function getOptionDefaultValue<Opts extends Option>(option: Opts): OptionReturnType<Opts> | null;
4
4
  export type OptionDetails = Required<OptionDefinition>;
5
5
  export declare function getOptionDetails(option: Option): OptionDetails;
@@ -1,4 +1,4 @@
1
- export type OptionPrimitive = 'string' | 'number' | 'boolean' | ['string'] | ['number'];
1
+ export type OptionPrimitive = 'secret' | 'string' | 'number' | 'boolean' | ['string'] | ['number'];
2
2
  export type OptionDefinition = {
3
3
  type: OptionPrimitive;
4
4
  description?: string;
@@ -8,7 +8,7 @@ export type OptionDefinition = {
8
8
  variadic?: boolean;
9
9
  };
10
10
  export type Option = OptionPrimitive | OptionDefinition;
11
- export type OptionType<O extends Option> = O extends 'string' ? string : O extends 'number' ? number : O extends 'boolean' ? boolean : O extends Array<'string'> ? Array<string> : O extends Array<'number'> ? Array<number> : O extends {
11
+ export type OptionType<O extends Option> = O extends 'secret' ? string : O extends 'string' ? string : O extends 'number' ? number : O extends 'boolean' ? boolean : O extends Array<'string'> ? Array<string> : O extends Array<'number'> ? Array<number> : O extends {
12
12
  type: infer T extends Option;
13
13
  } ? OptionType<T> : never;
14
14
  export type IsRequired<O extends Option> = O extends {