bob-core 2.1.0 → 3.0.0-alpha.1
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/package-Brk9TOly.cjs +1 -0
- package/dist/cjs/src/Cli.d.ts +4 -6
- package/dist/cjs/src/Command.d.ts +27 -50
- package/dist/cjs/src/CommandParser.d.ts +48 -50
- package/dist/cjs/src/CommandRegistry.d.ts +5 -5
- package/dist/cjs/src/CommandSignatureParser.d.ts +22 -25
- package/dist/cjs/src/CommandWithSignature.d.ts +19 -23
- package/dist/cjs/src/Flags.d.ts +25 -0
- package/dist/cjs/src/commands/HelpCommand.d.ts +2 -0
- package/dist/cjs/src/contracts/index.d.ts +0 -1
- package/dist/cjs/src/errors/BadCommandArgument.d.ts +14 -0
- package/dist/cjs/src/errors/BadCommandFlag.d.ts +14 -0
- package/dist/cjs/src/errors/InvalidFlag.d.ts +9 -0
- package/dist/cjs/src/errors/MissingRequiredFlagValue.d.ts +7 -0
- package/dist/cjs/src/errors/index.d.ts +4 -4
- package/dist/cjs/src/index.d.ts +3 -2
- package/dist/cjs/src/index.js +5 -14
- package/dist/cjs/src/lib/helpers.d.ts +1 -0
- package/dist/cjs/src/lib/types.d.ts +72 -18
- package/dist/cjs/src/options/HelpOption.d.ts +11 -10
- package/dist/esm/package-DAxovIBA.js +59 -0
- package/dist/esm/src/Cli.d.ts +4 -6
- package/dist/esm/src/Command.d.ts +27 -50
- package/dist/esm/src/CommandParser.d.ts +48 -50
- package/dist/esm/src/CommandRegistry.d.ts +5 -5
- package/dist/esm/src/CommandSignatureParser.d.ts +22 -25
- package/dist/esm/src/CommandWithSignature.d.ts +19 -23
- package/dist/esm/src/Flags.d.ts +25 -0
- package/dist/esm/src/commands/HelpCommand.d.ts +2 -0
- package/dist/esm/src/contracts/index.d.ts +0 -1
- package/dist/esm/src/errors/BadCommandArgument.d.ts +14 -0
- package/dist/esm/src/errors/BadCommandFlag.d.ts +14 -0
- package/dist/esm/src/errors/InvalidFlag.d.ts +9 -0
- package/dist/esm/src/errors/MissingRequiredFlagValue.d.ts +7 -0
- package/dist/esm/src/errors/index.d.ts +4 -4
- package/dist/esm/src/index.d.ts +3 -2
- package/dist/esm/src/index.js +926 -1070
- package/dist/esm/src/lib/helpers.d.ts +1 -0
- package/dist/esm/src/lib/types.d.ts +72 -18
- package/dist/esm/src/options/HelpOption.d.ts +11 -10
- package/package.json +11 -12
- package/dist/cjs/package-DYSfqWOt.cjs +0 -1
- package/dist/cjs/src/contracts/CommandOption.d.ts +0 -6
- package/dist/cjs/src/errors/BadCommandOption.d.ts +0 -12
- package/dist/cjs/src/errors/BadCommandParameter.d.ts +0 -12
- package/dist/cjs/src/errors/InvalidOption.d.ts +0 -9
- package/dist/cjs/src/errors/MissingRequiredOptionValue.d.ts +0 -7
- package/dist/cjs/src/lib/optionHelpers.d.ts +0 -5
- package/dist/cjs/src/lib/valueConverter.d.ts +0 -10
- package/dist/esm/package-uVOgoItG.js +0 -33
- package/dist/esm/src/contracts/CommandOption.d.ts +0 -6
- package/dist/esm/src/errors/BadCommandOption.d.ts +0 -12
- package/dist/esm/src/errors/BadCommandParameter.d.ts +0 -12
- package/dist/esm/src/errors/InvalidOption.d.ts +0 -9
- package/dist/esm/src/errors/MissingRequiredOptionValue.d.ts +0 -7
- package/dist/esm/src/lib/optionHelpers.d.ts +0 -5
- package/dist/esm/src/lib/valueConverter.d.ts +0 -10
package/dist/cjs/src/index.js
CHANGED
|
@@ -1,17 +1,8 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("prompts"),a=require("chalk"),j=require("minimist"),T=require("node:fs"),k=require("node:path");class x{logger;constructor(t){this.logger=t.logger}log(...t){this.logger.log(...t)}info(...t){this.logger.info(...t)}warn(...t){this.logger.warn(...t)}error(...t){this.logger.error(...t)}debug(...t){this.logger.debug(...t)}async askForConfirmation(t="Do you want to continue?",e){return(await y({type:"confirm",name:"value",message:t,initial:e??!1})).value}async askForInput(t,e,i){return(await y({type:"text",name:"value",message:t,initial:e,...i}))?.value??null}async askForDate(t,e,i){return(await y({type:"date",name:"value",message:t,initial:e,...i}))?.value??null}async askForList(t,e,i){return(await y({type:"list",name:"value",message:t,initial:e,...i}))?.value??null}async askForToggle(t,e,i){return(await y({type:"toggle",name:"value",message:t,initial:e,...i}))?.value??null}async askForSelect(t,e,i){if(e.length===0)throw new Error("No options provided");const n=[];for(const o of e)typeof o=="string"?n.push({title:o,value:o}):n.push(o);return(await y({type:"select",name:"value",message:t,choices:n,...i}))?.value??null}newLoader(t="",e=["⠙","⠘","⠰","⠴","⠤","⠦","⠆","⠃","⠋","⠉"],i=100){let n=t,s=null,o=0;const u=setInterval(function(){s&&(process.stdout.write(new TextEncoder().encode("\r"+" ".repeat(s.length+5)+"\r")),s=null),process.stdout.write(new TextEncoder().encode("\r"+e[o++]+" "+n)),o=o%e.length},i),m=()=>{clearInterval(u),process.stdout.write(new TextEncoder().encode("\r"+" ".repeat(n.length+5)+"\r"))};return{[Symbol.dispose]:m,[Symbol.asyncDispose]:m,updateText:h=>{s=n,n=h},stop:m}}}class f extends Error{$type="BobError"}function q(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"||Array.isArray(r)?q(r):r.default!==void 0?r.default:q(r.type)}function g(r){return typeof r=="string"||Array.isArray(r)?{alias:[],default:N(r),description:"",required:!1,secret:!1,type:r,variadic:!1}:{alias:r.alias?Array.isArray(r.alias)?r.alias:[r.alias]:[],default:r.default??N(r.type),description:r.description??"",required:r.required??!1,secret:r.secret??!1,type:r.type,variadic:r.variadic??!1}}class $ extends f{constructor(t,e={}){super(`Invalid option ${t} in not recognized`),this.option=t,this.optionsSchema=e}pretty(t){const e=Object.entries(this.optionsSchema);if(e.length>0){t.log(`
|
|
2
|
-
${a.yellow("Available options")}:`);for(const[i,n]of e){const s=g(n),o=s.alias?typeof s.alias=="string"?[s.alias]:s.alias:[],u=Array.isArray(s.type)?`[${s.type[0]}]`:s.type,m=`--${i}${o.length>0?o.map(l=>`, -${l}`).join(""):""}`,h=" ".repeat(30-m.length);t.log(` ${a.green(m)} ${h} ${s.description||"\b"} ${a.white(`(${u})`)}`)}t.log("")}t.log(`${a.white.bgRed(" ERROR ")} Option ${a.bold.yellow(this.option)} is not recognized.`)}}class A extends f{constructor(t){super(`Argument "${t}" is required.`),this.argument=t}pretty(t){t.log(`${a.white.bgRed(" ERROR ")} Argument ${a.bold.yellow(this.argument)} is required.`)}}class V extends f{constructor(t){super(`Argument "${t}" is required.`),this.option=t}pretty(t){t.log(`${a.white.bgRed(" ERROR ")} Option ${a.bold.yellow(this.option)} is required.`)}}class W extends f{constructor(t){let e=`Argument "${t.param}" value is invalid.`;t.reason?e+=` Reason: ${t.reason}`:e+=` Value: "${t.value}"`,super(e),this.param=t}pretty(t){t.log(` ${a.white.bgRed(" ERROR ")} Argument ${a.bold.yellow(this.param.param)} value is invalid. `),(this.param.value||this.param.reason)&&t.log(""),this.param.value&&t.log(` ${a.blue("Value")}: ${this.param.value}`),this.param.reason&&t.log(` ${a.yellow("Reason")}: ${this.param.reason}`)}}class v extends f{constructor(t){let e=`Option "${t.option}" value is invalid.`;t.reason?e+=` Reason: ${t.reason}`:e+=` Value: "${t.value}"`,super(e),this.param=t}pretty(t){t.log(` ${a.white.bgRed(" ERROR ")} Option ${a.bold.yellow(this.param.option)} value is invalid. `),(this.param.value||this.param.reason)&&t.log(""),this.param.value&&t.log(` ${a.blue("Value")}: ${this.param.value}`),this.param.reason&&t.log(` ${a.yellow("Reason")}: ${this.param.reason}`)}}class P extends f{constructor(t){super(`Command "${t}" not found.`),this.command=t}pretty(t){t.log(`${a.bgRed(" ERROR ")} Command ${a.yellow(this.command)} not found.`)}}class I extends f{constructor(t,e){super(`Too many arguments provided. Expected ${t}, got ${e}.`),this.expected=t,this.received=e}pretty(t){t.log(`${a.white.bgRed(" ERROR ")} Too many arguments provided. Expected ${a.bold.yellow(String(this.expected))}, got ${a.bold.yellow(String(this.received))}.`)}}function w(r,t,e,i){if(r==null)return i??null;if(t==="string")return String(r);if(t==="number"){const n=Number(r);if(isNaN(n))throw new v({option:e,reason:`Expected a number, got "${r}"`});return n}if(t==="boolean")return typeof r=="boolean"?r:r==="true"||r==="1"?!0:r==="false"||r==="0"?!1:!!r;if(Array.isArray(t)){const n=t[0],s=Array.isArray(r)?r:[r];if(n==="string")return s.map(o=>String(o));if(n==="number")return s.map(o=>{const u=Number(o);if(isNaN(u))throw new v({option:e,reason:`Expected array of numbers, got "${o}" in array`});return u})}return r}class E{options;parsedOptions=null;arguments;parsedArguments=null;io;shouldPromptForMissingOptions=!0;shouldValidateUnknownOptions=!0;shouldRejectExtraArguments=!1;constructor(t){this.options=t.options,this.arguments=t.arguments,this.io=t.io}init(t){const{_:e,...i}=j(t);return this.shouldValidateUnknownOptions&&this.validateUnknownOptions(i),this.parsedOptions=this.handleOptions(i),this.parsedArguments=this.handleArguments(e),{options:this.parsedOptions,arguments:this.parsedArguments}}async validate(){for(const t in this.options)if(g(this.options[t]).required&&(this.parsedOptions?.[t]===void 0||this.parsedOptions?.[t]===null))throw new V(t);for(const t in this.arguments){const e=g(this.arguments[t]),i=this.parsedArguments?.[t];if(e.required&&i==null){if(this.shouldPromptForMissingOptions){const n=await this.promptForArgument(t,e);if(n&&this.parsedArguments){this.parsedArguments[t]=w(n,e.type,t);continue}}throw new A(t)}if(e.required&&e.variadic&&Array.isArray(i)&&i.length===0){if(this.shouldPromptForMissingOptions){const n=await this.promptForArgument(t,e);if(n&&this.parsedArguments){this.parsedArguments[t]=w(n,e.type,t);continue}}throw new A(t)}}}option(t,e){if(!this.parsedOptions)throw new Error("Options have not been parsed yet. Call init() first.");return this.isEmptyValue(this.parsedOptions[t])&&e!==void 0?e:this.parsedOptions[t]}setOption(t,e){if(!this.parsedOptions)throw new Error("Options have not been parsed yet. Call init() first.");if(!(t in this.options))throw new $(t,this.options);this.parsedOptions[t]=e}argument(t,e){if(!this.parsedArguments)throw new Error("Arguments have not been parsed yet. Call init() first.");return this.isEmptyValue(this.parsedArguments[t])&&e!==void 0?e:this.parsedArguments[t]}setArgument(t,e){if(!this.parsedArguments)throw new Error("Arguments have not been parsed yet. Call init() first.");if(!(t in this.arguments))throw new $(t,this.arguments);this.parsedArguments[t]=e}isEmptyValue(t){return t==null||Array.isArray(t)&&t.length===0}validateUnknownOptions(t){const e=new Set;for(const i in this.options){e.add(i);const n=g(this.options[i]);for(const s of n.alias)e.add(s)}for(const i in t)if(!e.has(i))throw new $(i,this.options)}handleOptions(t){const e={};for(const i in this.options){const n=g(this.options[i]);e[i]=this.resolveOptionValue(i,n,t)}return e}handleArguments(t){const e={},i=[...t],n=Object.keys(this.arguments).length;for(const s in this.arguments){const o=g(this.arguments[s]);if(o.variadic){e[s]=this.handleVariadicArgument(s,o,i),i.length=0;continue}e[s]=this.resolveArgumentValue(s,o,i.shift())}if(this.shouldRejectExtraArguments&&i.length>0)throw new I(n,n+i.length);return e}handleVariadicArgument(t,e,i){return i.length?w(i,e.type,t,e.default):e.default}resolveArgumentValue(t,e,i){return i===void 0?e.default:w(i,e.type,t,e.default)}resolveOptionValue(t,e,i){let n;const s=[t,...e.alias];for(const o of s)if(o in i){n=i[o];break}if(n===void 0){if(e.required)throw new v({option:t,reason:"Required option is missing"});return e.default}return w(n,e.type,t,e.default)}optionDefinitions(){const t={};for(const e in this.options)t[e]=g(this.options[e]);return t}argumentDefinitions(){const t={};for(const e in this.arguments)t[e]=g(this.arguments[e]);return t}availableOptions(){return Object.keys(this.options)}availableArguments(){return Object.keys(this.arguments)}disablePrompting(){return this.shouldPromptForMissingOptions=!1,this}allowUnknownOptions(){return this.shouldValidateUnknownOptions=!1,this}strictMode(){return this.shouldRejectExtraArguments=!0,this}async promptForArgument(t,e){if(!Array.isArray(e.type)&&!["string","number","secret"].includes(e.type))return null;let i=`${a.yellow.bold(t)} is required`;return e.description&&(i+=`: ${a.gray(`(${e.description})`)}`),i+=` ${a.green(`(${e.type}${e.variadic==!0?"[]":""})`)}
|
|
3
|
-
`,Array.isArray(e.type)?(i+=`Please provide one or more values, separated by commas:
|
|
4
|
-
`,await this.io.askForList(i,void 0,{separator:",",validate:n=>{if(!n.length)return"Please enter at least one value";if(e.type[0]==="number"){for(const s of n.split(","))if(isNaN(Number(s)))return"Please enter only valid numbers"}return!0}})):await this.io.askForInput(i,void 0,{type:e.type==="number"?"number":e.secret?"password":"text",validate:n=>{if(n==null||typeof n=="string"&&!n.length)return"This value is required";if(e.type==="number"){const s=Number(n);if(isNaN(s))return"Please enter a valid number"}else if(e.type==="string"&&(typeof n!="string"||!n.length))return"Please enter a valid text";return!0}})}}function R(r){return new Array(r+5).join(" ")}class L{type="boolean";option="help";alias=["h"];default=!1;description=`Display help for the given command. When no command is given display help for the ${a.green("list")} command`;async handler(){const t=this.parser.argumentDefinitions(),e=this.parser.optionDefinitions(),i=Object.entries(t),n=Object.entries(e),s=n.map(([l,d])=>{const p=Array.isArray(d.alias)?d.alias:d.alias?[d.alias]:[];return{name:l,...d,optionWithAlias:`--${l}${p.map(c=>`, -${c}`).join("")}`}}),o=i.filter(([,l])=>l.required);this.io.log(a.yellow("Description:")),this.io.log(` ${this.description}
|
|
5
|
-
`),this.io.log(a.yellow("Usage:")),this.io.log(` ${this.command} ${o.length>0?o.map(([l])=>`<${l}>`).join(" "):"\b"} [options]`);const u=Math.max(...s.map(l=>l.optionWithAlias.length),0),m=Math.max(...i.map(([l])=>l.length),0),h=m>u?m:u;if(i.length>0){this.io.log(`
|
|
6
|
-
${a.yellow("Arguments")}:`);for(const[l,d]of i){const p=R(h-l.length);let c=` ${a.green(l)} ${p} ${d.description??"\b"}`;if(d.default!==void 0&&!d.required){const B=(Array.isArray(d.type)?`[${d.type[0]}]`:d.type)==="array"||Array.isArray(d.type)?JSON.stringify(d.default):d.default;c+=` ${a.yellow(`[default: ${B}]`)}`}d.variadic&&(c+=` ${a.white("(variadic)")}`),this.io.log(c)}}if(n.length>0){this.io.log(`
|
|
7
|
-
${a.yellow("Options")}:`);for(const l of s){const d=R(h-l.optionWithAlias.length);let p=`${a.green(l.optionWithAlias)} ${d} ${l.description??"\b"}`;if(l.type){const c=Array.isArray(l.type)?`[${l.type[0]}]`:l.type;p+=` ${a.white(`(${c})`)}`}if(l.default!==void 0&&!l.required){const S=(Array.isArray(l.type)?`[${l.type[0]}]`:l.type)==="array"||Array.isArray(l.type)?JSON.stringify(l.default):l.default;p+=` ${a.yellow(`[default: ${S}]`)}`}this.io.log(p)}}if(this.commandsExamples.length>0){this.io.log(`
|
|
8
|
-
${a.yellow("Examples")}:`);let l=process.argv[0].split("/").pop();l==="node"&&(l+=" "+process.argv[1].split("/").pop());for(const[d,p]of this.commandsExamples.entries())d>0&&this.io.log(""),this.io.log(` ${p.description}
|
|
9
|
-
`),this.io.log(` ${a.green(`${l} ${p.command}`)}`)}return-1}}class C{$type="BobCommand";_command;description;group;commandsExamples=[];get command(){return this._command}ctx;io;parser;disablePromptingFlag=!1;allowUnknownOptionsFlag=!1;hiddenFlag=!1;disableDefaultOptionsFlag=!1;strictModeFlag=!1;_preHandler;_handler;tmp;defaultOptions(){return this.disableDefaultOptionsFlag?[]:[new L]}newCommandParser(t){return new E({io:t.io,options:t.options,arguments:t.arguments})}newCommandIO(t){return new x(t)}constructor(t,e){this._command=t,this.description=e?.description??"",this.group=e?.group,this.tmp={options:e?.options??{},arguments:e?.arguments??{}};const i=this.defaultOptions();if(i.length>0)for(const n of i)this.tmp.options[n.option]=n}disablePrompting(){return this.disablePromptingFlag=!0,this}allowUnknownOptions(){return this.allowUnknownOptionsFlag=!0,this}hidden(){return this.hiddenFlag=!0,this}get isHidden(){return this.hiddenFlag}disableDefaultOptions(){return this.disableDefaultOptionsFlag=!0,this}strictMode(){return this.strictModeFlag=!0,this}preHandler(t){return this._preHandler=t,this}handler(t){return this._handler=t,this}options(t){return this.tmp={options:{...this.tmp?.options??{},...t},arguments:this.tmp?.arguments??{}},this}arguments(t){return this.tmp={options:this.tmp?.options??{},arguments:{...this.tmp?.arguments??{},...t}},this}async run(t){if(!this._handler&&!this.handle)throw new Error(`No handler defined for command ${this.command||"(unknown)"}`);let e;if(this.ctx=t.ctx,this.io=this.newCommandIO({logger:t.logger}),t&&"args"in t){const n=this.tmp?.options??{};for(const s of this.defaultOptions())s.option in n||(n[s.option]=s);this.parser=this.newCommandParser({io:this.io,options:n,arguments:this.tmp?.arguments??{}}),this.allowUnknownOptionsFlag&&this.parser.allowUnknownOptions(),this.strictModeFlag&&this.parser.strictMode(),e=this.parser.init(t.args);for(const s of this.defaultOptions())if(e.options[s.option]===!0){const o=await s.handler.call(this);if(o&&o!==0)return o}this.disablePromptingFlag&&this.parser.disablePrompting(),await this.parser.validate()}else e={options:t.options,arguments:t.arguments};if(!this._preHandler&&this.preHandle&&(this._preHandler=this.preHandle.bind(this)),this._preHandler){const n=await this._preHandler(t.ctx,e);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(t.ctx,e)??0}}class b extends E{command;constructor(t){const e=b.parseSignature(t.signature,t.helperDefinitions,t.defaultOptions);super({io:t.io,options:e.options,arguments:e.arguments}),this.command=e.command}static parseSignature(t,e,i){const[n,...s]=t.split(/\{(.*?)\}/g).map(m=>m.trim()).filter(Boolean),o={},u={};for(const m of s){const{name:h,isOption:l,definition:d}=b.parseParamSignature(m,e);l?o[h]=d:u[h]=d}for(const m of i)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:n,options:o,arguments:u}}static parseParamSignature(t,e){let i=t,n=!1;const s={required:!0,type:"string",description:void 0,default:null,variadic:!1};if(i.includes(":")){const[o,u]=i.split(":");i=o.trim(),s.description=u.trim()}if(i.includes("=")){const[o,u]=i.split("=");i=o.trim(),s.default=u.trim(),s.required=!1,typeof s.default=="string"&&!s.default.length?s.default=null:s.default==="true"?(s.default=!0,s.type="boolean"):s.default==="false"&&(s.default=!1,s.type="boolean")}else i.startsWith("--")&&(s.required=!1,s.default=!1,s.type="boolean");if(i.includes("|")){const[o,...u]=i.split("|");i=o.trim(),s.alias=u.map(m=>m.trim())}return i.startsWith("--")&&(n=!0,i=i.slice(2)),s.default==="*"&&(s.default=[],s.type=["string"]),i.endsWith("?")&&(s.required=!1,i=i.slice(0,-1)),i.endsWith("*")&&(s.type=["string"],s.variadic=!0,s.default=[],i=i.slice(0,-1)),s.description=s.description??e[i]??e[`--${i}`],{name:i,isOption:n,definition:s}}}class _ extends C{helperDefinitions={};get command(){return this.parser?this.parser.command:this.signature.split(" ")[0]}newCommandParser(t){return new b({io:t.io,signature:this.signature,helperDefinitions:this.helperDefinitions,defaultOptions:this.defaultOptions()})}constructor(){super("")}option(t,e=null){return this.parser.option(t,e)}argument(t,e=null){return this.parser.argument(t,e)}async askForConfirmation(...t){return this.io.askForConfirmation(...t)}async askForInput(...t){return this.io.askForInput(...t)}async askForSelect(...t){return this.io.askForSelect(...t)}newLoader(...t){return this.io.newLoader(...t)}}class F{level;constructor(t={}){this.level=t.level??"info"}shouldLog(t){const e=["debug","info","warn","error"],i=e.indexOf(this.level);return e.indexOf(t)>=i}setLevel(t){this.level=t}getLevel(){return this.level}log(...t){console.log(...t)}info(...t){this.shouldLog("info")&&console.log(...t)}warn(...t){this.shouldLog("warn")&&console.warn(...t)}error(...t){this.shouldLog("error")&&console.error(...t)}debug(...t){this.shouldLog("debug")&&console.log(...t)}}class H{getBigrams(t){const e=[],i=t.toLowerCase();for(let n=0;n<i.length-1;n++)e.push(i.slice(n,n+2));return e}calculateSimilarity(t,e){if(t===e)return 1;if(t.length<2||e.length<2)return 0;const i=this.getBigrams(t),n=this.getBigrams(e),s=new Set(n);let o=0;for(const u of i)s.has(u)&&(o++,s.delete(u));return 2*o/(i.length+n.length)}findBestMatch(t,e){const i=e.map(o=>({target:o,rating:this.calculateSimilarity(t,o)}));let n=0,s=i[0]?.rating??0;for(let o=1;o<i.length;o++)i[o].rating>s&&(s=i[o].rating,n=o);return{ratings:i,bestMatch:i[n],bestMatchIndex:n}}}function U(r){return typeof r=="object"&&r!==null&&"$type"in r&&r.$type==="BobError"}function O(r){return typeof r=="object"&&r!==null&&(r instanceof C||"$type"in r&&r.$type==="BobCommand")}class M{commands={};io;logger;stringSimilarity;newCommandIO(t){return new x(t)}constructor(t){this.logger=t?.logger??new F,this.io=this.newCommandIO({logger:this.logger}),this.stringSimilarity=t?.stringSimilarity??new H}getAvailableCommands(){return Object.keys(this.commands)}getCommands(){return Object.values(this.commands)}importFile=async t=>(await import(t)).default;commandResolver=async t=>{let e=await this.importFile(t);return e?(e&&typeof e=="object"&&"default"in e&&(e=e.default),typeof e=="function"?new e:O(e)?e:null):null};withCommandResolver(t){return this.commandResolver=t,this}withFileImporter(t){return this.importFile=t,this}registerCommand(t,e=!1){if(!O(t))throw new Error("Invalid command, it must extend the Command class.");const i=t.command;if(!i)throw new Error("Cannot register a command with no name.");if(!e&&this.commands[i])throw new Error(`Command ${i} already registered.`);this.commands[i]=t}async loadCommandsPath(t){for await(const e of this.listCommandsFiles(t))try{const i=await this.commandResolver(e);O(i)&&this.registerCommand(i)}catch(i){throw new Error(`Command ${e} failed to load. ${i}`,{cause:i})}}async runCommand(t,e,...i){const n=typeof e=="string"?this.commands[e]:e,s=typeof e=="string"?e:n.command;if(!n){const o=await this.suggestCommand(s);return o?await this.runCommand(t,o,...i):1}return await n.run({ctx:t,logger:this.logger,args:i})??0}async suggestCommand(t){const e=this.getAvailableCommands(),{bestMatch:i,bestMatchIndex:n,ratings:s}=this.stringSimilarity.findBestMatch(t,e),o=s.filter(u=>u.rating>.3).map(u=>u.target);if(i&&(i.rating>0&&o.length<=1||i.rating>.7&&o.length>1)){const u=e[n];return await this.askRunSimilarCommand(t,u)?u:null}if(o.length){this.io.error(`${a.bgRed(" ERROR ")} Command ${a.yellow(t)} not found.
|
|
10
|
-
`);const u=await this.io.askForSelect(a.green("Did you mean to run one of these commands instead?"),o);if(u)return u}throw new P(t)}async askRunSimilarCommand(t,e){return this.io.error(`${a.bgRed(" ERROR ")} Command ${a.yellow(t)} not found.
|
|
11
|
-
`),this.io.askForConfirmation(`${a.green(`Do you want to run ${a.yellow(e)} instead?`)} `)}async*listCommandsFiles(t){const e=T.readdirSync(t,{withFileTypes:!0});for(const i of e){const n=k.resolve(t,i.name);if(i.isDirectory())yield*this.listCommandsFiles(k.resolve(t,i.name));else{if(!n.endsWith(".ts")&&!n.endsWith(".js")&&!n.endsWith(".mjs")&&!n.endsWith(".cjs"))continue;yield n}}}}class D{logger;constructor(t){this.logger=t}handle(t){if(U(t))return t.pretty(this.logger),-1;throw t}}class G extends C{constructor(t){super("help",{description:a.bold("Show help information about the CLI and its commands")}),this.opts=t}async handle(){const t=this.opts.commandRegistry.getCommands().filter(m=>!m.isHidden),e=this.opts.cliName??"Bob CLI",i=this.opts.cliVersion??"0.0.0",n=(await Promise.resolve().then(()=>require("../package-DYSfqWOt.cjs")))?.default?.version??"0.0.0";this.io.log(`${e} ${a.green(i)} (core: ${a.yellow(n)})
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`prompts`);c=s(c);let l=require(`chalk`);l=s(l);let u=require(`minimist`);u=s(u);let d=require(`node:fs`);d=s(d);let f=require(`node:path`);f=s(f);var p=class{logger;constructor(e){this.logger=e.logger}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(0,c.default)({type:`confirm`,name:`value`,message:e,initial:t??!1})).value}async askForInput(e,t,n){return(await(0,c.default)({type:`text`,name:`value`,message:e,initial:t,...n}))?.value??null}async askForDate(e,t,n){return(await(0,c.default)({type:`date`,name:`value`,message:e,initial:t,...n}))?.value??null}async askForList(e,t,n){return(await(0,c.default)({type:`list`,name:`value`,message:e,initial:t,...n}))?.value??null}async askForToggle(e,t,n){return(await(0,c.default)({type:`toggle`,name:`value`,message:e,initial:t,...n}))?.value??null}async askForSelect(e,t,n){if(t.length===0)throw Error(`No options provided`);let r=[];for(let e of t)typeof e==`string`?r.push({title:e,value:e}):r.push(e);return(await(0,c.default)({type:`select`,name:`value`,message:e,choices:r,...n}))?.value??null}newLoader(e=``,t=[`⠙`,`⠘`,`⠰`,`⠴`,`⠤`,`⠦`,`⠆`,`⠃`,`⠋`,`⠉`],n=100){let r=e,i=null,a=0,o=setInterval(function(){i&&=(process.stdout.write(new TextEncoder().encode(`\r`+` `.repeat(i.length+5)+`\r`)),null),process.stdout.write(new TextEncoder().encode(`\r`+t[a++]+` `+r)),a%=t.length},n),s=()=>{clearInterval(o),process.stdout.write(new TextEncoder().encode(`\r`+` `.repeat(r.length+5)+`\r`))};return{[Symbol.dispose]:s,[Symbol.asyncDispose]:s,updateText:e=>{i=r,r=e},stop:s}}},m=class extends Error{$type=`BobError`},h=class extends m{constructor(e,t={}){super(`Flag ${e} is not recognized`),this.flag=e,this.flagsSchema=t}pretty(e){e.log(``),e.log(` ${l.default.bold.white.bgRed(` ERROR `)} Flag ${l.default.bold.yellow(this.flag)} is not recognized.`);let t=Object.entries(this.flagsSchema);if(t.length>0){e.log(``),e.log(` ${l.default.dim(`Available flags:`)}`),e.log(``);let n=t.map(([e,t])=>{let n=t.alias?typeof t.alias==`string`?[t.alias]:t.alias:[],r=Array.isArray(t.type)?`[${t.type[0]}]`:t.type===`enum`&&t.options?t.options.join(` | `):t.type;return{nameWithAlias:`--${e}${n.length>0?n.map(e=>`, -${e}`).join(``):``}`,description:t.description||``,typeDisplay:r}}),r=Math.max(...n.map(e=>e.nameWithAlias.length));for(let t of n){let n=` `.repeat(r-t.nameWithAlias.length+2);e.log(` ${l.default.green(t.nameWithAlias)}${n}${t.description} ${l.default.dim(`(${t.typeDisplay})`)}`)}}e.log(``)}},g=class extends m{constructor(e){super(`Argument "${e}" is required.`),this.argument=e}pretty(e){e.log(``),e.log(` ${l.default.bold.white.bgRed(` ERROR `)} Argument ${l.default.bold.yellow(this.argument)} is required.`),e.log(``)}},_=class extends m{constructor(e){super(`Flag "${e}" is required.`),this.flag=e}pretty(e){e.log(``),e.log(` ${l.default.bold.white.bgRed(` ERROR `)} Flag ${l.default.bold.yellow(this.flag)} is required.`),e.log(``)}},v=class extends m{constructor(e,t){let n=`Argument "${e.arg}" value is invalid.`;e.reason?n+=` Reason: ${e.reason}`:n+=` Value: "${e.value}"`,super(n),this.detail=e,this.argDefinition=t}pretty(e){let t=[];if(this.detail.reason!=null&&t.push([`Reason`,this.detail.reason]),this.detail.value!=null&&t.push([`Value`,this.detail.value]),this.argDefinition?.help!=null&&t.push([`Help`,l.default.green(this.argDefinition.help)]),e.log(``),e.log(` ${l.default.bold.white.bgRed(` ERROR `)} Argument ${l.default.bold.yellow(this.detail.arg)} value is invalid.`),t.length>0){e.log(``);let n=Math.max(...t.map(([e])=>e.length));for(let[r,i]of t)e.log(` ${` `.repeat(n-r.length)}${l.default.dim(r)} ${i}`)}e.log(``)}},y=class extends m{constructor(e,t){let n=`Flag "${e.flag}" value is invalid.`;e.reason?n+=` Reason: ${e.reason}`:n+=` Value: "${e.value}"`,super(n),this.param=e,this.flagDefinition=t}pretty(e){let t=[];if(this.param.reason!=null&&t.push([`Reason`,this.param.reason]),this.param.value!=null&&t.push([`Value`,this.param.value]),this.flagDefinition?.help!=null&&t.push([`Help`,l.default.green(this.flagDefinition.help)]),e.log(``),e.log(` ${l.default.bold.white.bgRed(` ERROR `)} Flag ${l.default.bold.yellow(this.param.flag)} value is invalid.`),t.length>0){e.log(``);let n=Math.max(...t.map(([e])=>e.length));for(let[r,i]of t)e.log(` ${` `.repeat(n-r.length)}${l.default.dim(r)} ${i}`)}e.log(``)}},b=class extends m{constructor(e){super(`Command "${e}" not found.`),this.command=e}pretty(e){e.log(``),e.log(` ${l.default.bold.white.bgRed(` ERROR `)} Command ${l.default.bold.yellow(this.command)} not found.`),e.log(``)}},x=class extends m{constructor(e,t){super(`Too many arguments provided. Expected ${e}, got ${t}.`),this.expected=e,this.received=t}pretty(e){e.log(``),e.log(` ${l.default.bold.white.bgRed(` ERROR `)} Too many arguments. Expected ${l.default.bold.yellow(String(this.expected))}, got ${l.default.bold.yellow(String(this.received))}.`),e.log(``)}},S=class{flags;parsedFlags=null;args;parsedArguments=null;io;shouldPromptForMissingFlags=!0;shouldValidateUnknownFlags=!0;shouldRejectExtraArguments=!1;constructor(e){this.opts=e,this.io=e.io,this.flags=e.flags,this.args=e.args}async init(e){let{_:t,...n}=(0,u.default)(e);return this.shouldValidateUnknownFlags&&this.validateUnknownFlags(n),this.parsedFlags=await this.handleOptions(n),this.parsedArguments=await this.handleArguments(t),{flags:this.parsedFlags,args:this.parsedArguments}}async validate(){for(let e in this.flags){let t=this.flags[e],n=this.parsedFlags?.[e],r=this.isEmptyValue(n),i=`multiple`in t&&t.multiple;if(t.required&&r)throw new _(e);if(!r&&t.validate){let r=i&&Array.isArray(n)?n:[n];for(let n of r){let r=await t.validate(n);if(r!==!0)throw new y({flag:e,reason:r,value:n})}}}for(let e in this.args){let t=this.args[e],n=this.parsedArguments?.[e],r=this.isEmptyValue(n),i=`multiple`in t&&t.multiple;if(t.required&&r){if(!this.shouldPromptForMissingFlags)throw new g(e);let n=await this.promptForArgument(e,t);if(n&&this.parsedArguments){this.parsedArguments[e]=await this.parseValue(n,t,{name:e,isArg:!0});continue}throw new g(e)}if(!r&&t.validate){let r=i&&Array.isArray(n)?n:[n];for(let n of r){let r=await t.validate(n);if(r!==!0)throw new v({arg:e,reason:r,value:n})}}}}flag(e,t){if(!this.parsedFlags)throw Error(`Flags have not been parsed yet. Call init() first.`);return this.isEmptyValue(this.parsedFlags[e])&&t!==void 0?t:this.parsedFlags[e]}async setFlag(e,t){if(!this.parsedFlags)throw Error(`Flags have not been parsed yet. Call init() first.`);if(!(e in this.flags))throw new h(e,this.flags);if(this.flags[e].validate){let n=await this.flags[e].validate(t);if(n!==!0)throw new y({flag:e,reason:n,value:t})}this.parsedFlags[e]=t}argument(e,t){if(!this.parsedArguments)throw Error(`Arguments have not been parsed yet. Call init() first.`);return this.isEmptyValue(this.parsedArguments[e])&&t!==void 0?t:this.parsedArguments[e]}async setArgument(e,t){if(!this.parsedArguments)throw Error(`Arguments have not been parsed yet. Call init() first.`);if(!(e in this.args))throw new v({arg:e,reason:`Argument "${e}" is not recognized`});if(this.args[e].validate){let n=await this.args[e].validate(t);if(n!==!0)throw new v({arg:e,reason:n,value:t})}this.parsedArguments[e]=t}isEmptyValue(e){return e==null||typeof e==`string`&&e.trim()===``||Array.isArray(e)&&e.length===0}validateUnknownFlags(e){let t=new Set;for(let e in this.flags){t.add(e);let n=this.flags[e];for(let e of n.alias??[])t.add(e)}for(let n in e)if(!t.has(n))throw new h(n,this.flags)}async handleOptions(e){let t={};for(let n in this.flags)t[n]=await this.resolveFlagValue(n,this.flags[n],e);return t}async handleArguments(e){let t={},n=[...e],r=Object.keys(this.args).length;for(let e in this.args){let r=this.args[e];if(`multiple`in r&&r.multiple){t[e]=await this.parseValue(n,r,{name:e,isArg:!0}),n.length=0;continue}t[e]=await this.parseValue(n.shift(),r,{name:e,isArg:!0})}if(this.shouldRejectExtraArguments&&n.length>0)throw new x(r,r+n.length);return t}async resolveFlagValue(e,t,n){let r,i=[e];t.alias&&i.push(...Array.isArray(t.alias)?t.alias:[t.alias]);for(let e of i)if(e in n){r=n[e];break}return this.parseValue(r,t,{name:e})}async parseValue(e,t,n){if(this.isEmptyValue(e))return typeof t.default==`function`?await t.default():t.default;if(`multiple`in t&&t.multiple){Array.isArray(e)||(e=[e]);let r=[];for(let i of e)r.push(await this.safeParse(i,t,n));return r}return this.safeParse(e,t,n)}async safeParse(e,t,n){try{return t.parse(e,this.opts.ctx)}catch(t){if(!n)throw t;let r=t instanceof Error?t.message:String(t);throw n.isArg?new v({arg:n.name,value:e,reason:r}):new y({flag:n.name,value:e,reason:r})}}disablePrompting(){return this.shouldPromptForMissingFlags=!1,this}allowUnknownFlags(){return this.shouldValidateUnknownFlags=!1,this}strictMode(){return this.shouldRejectExtraArguments=!0,this}async promptForArgument(e,t){let n=t.type;if(n===`enum`&&t.options){let n=`${l.default.yellow.bold(e)} is required`;t.description&&(n+=`: ${l.default.gray(`(${t.description})`)}`),n+=` ${l.default.green(`(enum)`)}\n`;let r=t.options.map(e=>({title:e,value:e}));return await this.io.askForSelect(n,r)}let r=`multiple`in t&&t.multiple;if(!r&&![`string`,`number`].includes(n))return null;let i=`${l.default.yellow.bold(e)} is required`;return t.description&&(i+=`: ${l.default.gray(`(${t.description})`)}`),i+=` ${l.default.green(`(${n}${r?`[]`:``})`)}\n`,r?(i+=`Please provide one or more values, separated by commas:
|
|
2
|
+
`,await this.io.askForList(i,void 0,{separator:`,`,validate:e=>{if(this.isEmptyValue(e)&&t.required)return`Please enter at least one value`;for(let n of e.split(`,`)){let e=t.validate?t.validate(n):!0;if(e!==!0)return typeof e==`string`?`${n} ${e}`:`Invalid value: "${n.trim()}"`}return!0}})):await this.io.askForInput(i,void 0,{type:n===`number`?`number`:`secret`in t&&t.secret?`password`:`text`,validate:e=>{if(this.isEmptyValue(e)&&t.required)return`This value is required`;let n=t.validate?t.validate(e):!0;return n===!0?!0:typeof n==`string`?n:`Invalid value`}})}},C={string(e){return{default:e?.multiple?[]:null,parse:e=>{if(typeof e==`boolean`)throw Error(`Expected a string, got boolean "${e}"`);return String(e)},...e,type:`string`}},number(e){return{default:e?.multiple?[]:null,validate(t){return e?.min!==void 0&&t<e.min?`is below minimum ${e.min}`:e?.max!==void 0&&t>e.max?`exceeds maximum ${e.max}`:!0},parse:e=>{let t=typeof e==`number`?e:Number(e);if(isNaN(t))throw Error(`must be a valid number`);return t},...e,type:`number`}},boolean(e){return{default:!1,parse:e=>{if(typeof e==`boolean`)return e;let t=String(e).toLowerCase();return t===`true`||t===`1`?!0:t===`false`||t===`0`?!1:!!e},...e,type:`boolean`}},enum(e){return{default:e.multiple?[]:null,validate(t){return e.options.includes(t)?!0:`must be one of: ${e.options.map(e=>`"${e}"`).join(`, `)}`},parse:e=>String(e),...e,type:`enum`}},file(e){return{default:null,parse:e=>String(e),validate(t){return e?.exists&&!d.default.existsSync(t)?`file does not exist`:!0},...e,type:`file`}},directory(e){return{default:null,parse:e=>String(e),validate(t){return e?.exists&&!(d.default.existsSync(t)&&d.default.lstatSync(t).isDirectory())?`directory does not exist`:!0},...e,type:`directory`}},url(e){return{default:null,parse:e=>new URL(String(e)),...e,type:`url`}},custom(e){return t=>({default:e?.multiple||t?.multiple?[]:null,parse:e=>e,...e,...t,type:`custom`})}},w=C;function T(e){return Array(e+5).join(` `)}function E(e){let t=e.type;return Array.isArray(t)?`[${t[0]}]`:t===`enum`&&e.options?`enum: ${e.options.join(`|`)}`:t}var D=C.boolean({alias:[`h`],handler:(e,t,n)=>{if(!e)return{shouldStop:!1};let r=n.args,i=n.flags,a=Object.entries(r),o=Object.entries(i),s=o.map(([e,t])=>{let n=Array.isArray(t.alias)?t.alias:t.alias?[t.alias]:[];return{name:e,...t,flagWithAlias:`--${e}${n.map(e=>`, -${e}`).join(``)}`}}),c=a.filter(([,e])=>e.required);console.log(l.default.yellow(`Description:`)),console.log(` ${n.description}\n`),console.log(l.default.yellow(`Usage:`)),console.log(` ${n.command} ${c.length>0?c.map(([e])=>`<${e}>`).join(` `):`\b`} [options]`);let u=Math.max(...s.map(e=>e.flagWithAlias.length),0),d=Math.max(...a.map(([e])=>e.length),0),f=d>u?d:u;if(a.length>0){console.log(`\n${l.default.yellow(`Arguments`)}:`);for(let[e,t]of a){let n=T(f-e.length),r=` ${l.default.green(e)} ${n} ${t.description??`\b`}`;if(t.default!==void 0&&!t.required){let e=typeof t.default==`function`?`[function]`:t.multiple?JSON.stringify(t.default):t.default;r+=` ${l.default.yellow(`[default: ${e}]`)}`}`multiple`in t&&t.multiple&&(r+=` ${l.default.white(`(variadic)`)}`),console.log(r)}}if(o.length>0){console.log(`\n${l.default.yellow(`Options`)}:`);for(let e of s){let t=T(f-e.flagWithAlias.length),n=` ${l.default.green(e.flagWithAlias)} ${t} ${e.description??`\b`}`;if(e.type&&(n+=` ${l.default.white(`(${E(e)})`)}`),e.default!==void 0&&!e.required){let t=typeof e.default==`function`?`(function)`:e.default;n+=` ${l.default.yellow(`[default: ${t}]`)}`}console.log(n)}}let p=n.examples??[];if(p.length>0){console.log(`\n${l.default.yellow(`Examples`)}:`);let e=process.argv[0].split(`/`).pop();e===`node`&&(e+=` `+process.argv[1].split(`/`).pop());for(let[t,n]of p.entries())t>0&&console.log(``),console.log(` ${n.description}\n`),console.log(` ${l.default.green(`${e} ${n.command}`)}`)}return{shouldStop:!0}}}),O=class{$type=`BobCommand`;static command=``;static description=``;static group;static args={};static flags={};static examples=[];static hidden=!1;static disableDefaultOptions=!1;static disablePrompting=!1;static allowUnknownFlags=!1;static strictMode=!1;ctx;io;parser;static baseFlags={help:D};newCommandParser(e){return new S({io:e.io,ctx:e.ctx,flags:e.flags,args:e.args})}newCommandIO(e){return new p(e)}async run(e){let t=this.constructor;this.ctx=e.ctx,this.io=this.newCommandIO({logger:e.logger});let n;if(`flags`in e)n={flags:e.flags,args:e.args};else{this.parser=this.newCommandParser({ctx:this.ctx,io:this.io,flags:t.disableDefaultOptions?t.flags:{...t.baseFlags,...t.flags},args:t.args}),t.allowUnknownFlags&&this.parser.allowUnknownFlags(),t.strictMode&&this.parser.strictMode(),t.disablePrompting&&this.parser.disablePrompting();let r=await this.parser.init(e.args);for(let n in r.flags){let i=r.flags[n],a=t.flags[n]||t.baseFlags[n];if(a&&a.handler){let n=a.handler(i,e.ctx,t);if(n&&n.shouldStop)return-1}}await this.parser.validate(),n={flags:r.flags,args:r.args}}if(this.preHandle){let e=await this.preHandle();if(e&&e!==0)return e}return await this.handle(this.ctx,n)??0}},k=class{level;constructor(e={}){this.level=e.level??`info`}shouldLog(e){let 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)}},A=class{getBigrams(e){let t=[],n=e.toLowerCase();for(let e=0;e<n.length-1;e++)t.push(n.slice(e,e+2));return t}calculateSimilarity(e,t){if(e===t)return 1;if(e.length<2||t.length<2)return 0;let n=this.getBigrams(e),r=this.getBigrams(t),i=new Set(r),a=0;for(let e of n)i.has(e)&&(a++,i.delete(e));return 2*a/(n.length+r.length)}findBestMatch(e,t){let n=t.map(t=>({target:t,rating:this.calculateSimilarity(e,t)})),r=0,i=n[0]?.rating??0;for(let e=1;e<n.length;e++)n[e].rating>i&&(i=n[e].rating,r=e);return{ratings:n,bestMatch:n[r],bestMatchIndex:r}}};function j(e){return typeof e==`object`&&!!e&&`$type`in e&&e.$type===`BobError`}function M(e){return typeof e==`function`&&e.prototype instanceof O}var N=class{commands={};io;logger;stringSimilarity;newCommandIO(e){return new p(e)}constructor(e){this.logger=e?.logger??new k,this.io=this.newCommandIO({logger:this.logger}),this.stringSimilarity=e?.stringSimilarity??new A}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);return t?(t&&typeof t==`object`&&`default`in t&&(t=t.default),typeof t==`function`&&M(t)?t:null):null};withCommandResolver(e){return this.commandResolver=e,this}withFileImporter(e){return this.importFile=e,this}registerCommand(e,t=!1){if(!M(e))throw Error(`Invalid command, it must extend the Command class.`);let n=e.command;if(!n)throw Error(`Cannot register a command with no name. ${e.name} `);if(!t&&this.commands[n])throw Error(`Command ${n} already registered.`);this.commands[n]=e}async loadCommandsPath(e){for await(let t of this.listCommandsFiles(e))try{let e=await this.commandResolver(t);M(e)&&this.registerCommand(e)}catch(e){throw Error(`Command ${t} failed to load. ${e}`,{cause:e})}}async runCommand(e,t,...n){let r;if(typeof t==`string`){let i=this.commands[t];if(!i){let r=await this.suggestCommand(t);return r?await this.runCommand(e,r,...n):1}r=new i}else r=M(t)?new t:t;return await r.run({ctx:e,logger:this.logger,args:n})??0}async suggestCommand(e){let t=this.getAvailableCommands(),{bestMatch:n,bestMatchIndex:r,ratings:i}=this.stringSimilarity.findBestMatch(e,t),a=i.filter(e=>e.rating>.3).map(e=>e.target);if(n&&(n.rating>0&&a.length<=1||n.rating>.7&&a.length>1)){let n=t[r];return await this.askRunSimilarCommand(e,n)?n:null}if(a.length){this.io.error(`${l.default.bgRed(` ERROR `)} Command ${l.default.yellow(e)} not found.\n`);let t=await this.io.askForSelect(l.default.green(`Did you mean to run one of these commands instead?`),a);if(t)return t}throw new b(e)}async askRunSimilarCommand(e,t){return this.io.error(`${l.default.bgRed(` ERROR `)} Command ${l.default.yellow(e)} not found.\n`),this.io.askForConfirmation(`${l.default.green(`Do you want to run ${l.default.yellow(t)} instead?`)} `)}async*listCommandsFiles(e){let t=d.default.readdirSync(e,{withFileTypes:!0});for(let n of t){let t=f.default.resolve(e,n.name);if(n.isDirectory())yield*this.listCommandsFiles(f.default.resolve(e,n.name));else{if(!t.endsWith(`.ts`)&&!t.endsWith(`.js`)&&!t.endsWith(`.mjs`)&&!t.endsWith(`.cjs`))continue;yield t}}}},P=class e{static parse(t,n={}){let[r,...i]=t.split(/\{(.*?)\}/g).map(e=>e.trim()).filter(Boolean),a={},o={};for(let t of i){let{name:r,isFlag:i,definition:s}=e.parseParamSignature(t,n);i?a[r]=s:o[r]=s}return{command:r,flags:a,args:o}}static parseParamSignature(e,t){let n=e,r=!1,i,a,o,s=!1,c=!1,l=!0;if(n.includes(`:`)){let[e,t]=n.split(`:`);n=e.trim(),i=t.trim()}if(n.includes(`=`)){let[e,t]=n.split(`=`);n=e.trim();let r=t.trim();l=!1,r.length?r===`*`?(c=!0,a=[]):r===`true`?(s=!0,a=!0):r===`false`?(s=!0,a=!1):a=r:a=null}else n.startsWith(`--`)&&(s=!0,l=!1,a=!1);if(n.includes(`|`)){let[e,...t]=n.split(`|`);n=e.trim(),o=t.map(e=>e.trim())}n.startsWith(`--`)&&(r=!0,n=n.slice(2)),n.endsWith(`?`)&&(l=!1,n=n.slice(0,-1)),n.endsWith(`*`)&&(c=!0,l=!0,a=[],n=n.slice(0,-1)),i=i??t[n]??t[`--${n}`];let u,d=r?C:w;return u=s?C.boolean({description:i,alias:o,...a===void 0?{}:{default:a}}):c?d.string({description:i,alias:o,multiple:!0,...l?{required:!0}:{},default:a??[]}):d.string({description:i,alias:o,...l?{required:!0}:{},...a===void 0?{}:{default:a}}),{name:n,isFlag:r,definition:u}}},F=class extends O{static signature=``;static helperDefinitions={};static get command(){return(this.signature??this.signature).split(/\s/)[0]||``}async run(e){let t=this.constructor;if(t.signature&&!Object.prototype.hasOwnProperty.call(t,`_signatureParsed`)){let e=P.parse(t.signature,t.helperDefinitions),n=Object.prototype.hasOwnProperty.call(t,`flags`)?t.flags:{},r=Object.prototype.hasOwnProperty.call(t,`args`)?t.args:{};t.flags={...e.flags,...n},t.args={...e.args,...r},Object.defineProperty(t,`_signatureParsed`,{value:!0})}return super.run(e)}option(e,t=null){return this.parser.flag(e,t)}argument(e,t=null){return this.parser.argument(e,t)}},I=class{logger;constructor(e){this.logger=e}handle(e){if(j(e))return e.pretty(this.logger),-1;throw e}},L=class extends O{static command=`help`;static description=l.default.bold(`Show help information about the CLI and its commands`);constructor(e){super(),this.opts=e}async handle(){let e=this.opts.commandRegistry.getCommands().filter(e=>!e.hidden),t=this.opts.cliName??`Bob CLI`,n=this.opts.cliVersion??`0.0.0`,r=(await Promise.resolve().then(()=>require(`../package-Brk9TOly.cjs`)))?.default?.version??`0.0.0`;this.io.log(`${t} ${l.default.green(n)} (core: ${l.default.yellow(r)})
|
|
12
3
|
|
|
13
|
-
${
|
|
4
|
+
${l.default.yellow(`Usage`)}:
|
|
14
5
|
command [options] [arguments]
|
|
15
6
|
|
|
16
|
-
${
|
|
17
|
-
`);
|
|
7
|
+
${l.default.yellow(`Available commands`)}:
|
|
8
|
+
`);let i=Math.max(...e.map(e=>e.command.length))??0,a={};for(let t of e){let e=t.group??t.command.split(`:`)[0];a[e]||(a[e]=[]),a[e].push(t)}let o=Object.entries(a).sort(([e],[t])=>e.toLowerCase().localeCompare(t.toLowerCase())).sort(([,e],[,t])=>e.length-t.length);for(let[e,t]of o){let n=t.length>1;n&&this.io.log(l.default.yellow(`${e}:`));let r=t.sort((e,t)=>e.command.toLowerCase().localeCompare(t.command.toLowerCase()));for(let e of r){let t=T(i-e.command.length);n&&(t=t.slice(2)),this.io.log(`${n?` `:``}${l.default.green(e.command)} ${t} ${e.description}`)}}}},R=class{ctx;logger;commandRegistry;exceptionHandler;helpCommand;newCommandRegistry(e){return new N(e)}newHelpCommand(e){return new L(e)}newExceptionHandler(e){return new I(e.logger)}constructor(e={}){this.ctx=e.ctx,this.logger=e.logger??new k,this.commandRegistry=this.newCommandRegistry({logger:this.logger}),this.exceptionHandler=this.newExceptionHandler({logger:this.logger}),this.helpCommand=this.newHelpCommand({cliName:e.name,cliVersion:e.version,commandRegistry:this.commandRegistry})}withCommandResolver(e){return this.commandRegistry.withCommandResolver(e),this}withFileImporter(e){return this.commandRegistry.withFileImporter(e),this}async withCommands(...e){for(let t of e)typeof t==`string`?await this.commandRegistry.loadCommandsPath(t):typeof t==`function`?this.registerCommand(t):this.registerCommand(t.constructor)}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.Args=w,exports.BadCommandArgument=v,exports.BadCommandFlag=y,exports.BobError=m,exports.Cli=R,exports.Command=O,exports.CommandIO=p,exports.CommandNotFoundError=b,exports.CommandParser=S,exports.CommandRegistry=N,exports.CommandSignatureParser=P,exports.CommandWithSignature=F,exports.ExceptionHandler=I,exports.Flags=C,exports.HelpCommandFlag=D,exports.InvalidFlag=h,exports.Logger=k,exports.MissingRequiredArgumentValue=g,exports.MissingRequiredFlagValue=_,exports.StringSimilarity=A,exports.TooManyArguments=x;
|
|
@@ -2,3 +2,4 @@ import { Command } from '../Command.js';
|
|
|
2
2
|
import { BobError } from '../errors/index.js';
|
|
3
3
|
export declare function isBobError(err: Error): err is BobError;
|
|
4
4
|
export declare function isBobCommand(obj: unknown): obj is Command;
|
|
5
|
+
export declare function isBobCommandClass(cls: unknown): cls is typeof Command;
|
|
@@ -1,31 +1,85 @@
|
|
|
1
|
-
|
|
2
|
-
export type
|
|
3
|
-
type: OptionPrimitive;
|
|
1
|
+
import { Command } from '../Command.js';
|
|
2
|
+
export type BaseFlagConfig<T> = {
|
|
4
3
|
description?: string;
|
|
5
4
|
alias?: string | Array<string>;
|
|
6
5
|
required?: boolean;
|
|
6
|
+
default?: T | T[] | null | (() => Promise<T | T[] | null>);
|
|
7
|
+
multiple?: boolean;
|
|
8
|
+
help?: string;
|
|
9
|
+
parse: (input: string, ctx: ContextDefinition) => T;
|
|
10
|
+
validate?(value: T): FlagValidationResult;
|
|
11
|
+
handler?(value: T, ctx: ContextDefinition, cmd: typeof Command): {
|
|
12
|
+
shouldStop: boolean;
|
|
13
|
+
} | void;
|
|
14
|
+
};
|
|
15
|
+
export type StringFlagDef = BaseFlagConfig<string> & {
|
|
16
|
+
type: 'string';
|
|
7
17
|
secret?: boolean;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
};
|
|
19
|
+
export type NumberFlagDef = BaseFlagConfig<number> & {
|
|
20
|
+
type: 'number';
|
|
21
|
+
min?: number;
|
|
22
|
+
max?: number;
|
|
23
|
+
};
|
|
24
|
+
export type BooleanFlagDef = BaseFlagConfig<boolean> & {
|
|
25
|
+
type: 'boolean';
|
|
26
|
+
};
|
|
27
|
+
export type EnumFlagDef<T extends readonly string[] = readonly string[]> = BaseFlagConfig<T[number]> & {
|
|
28
|
+
type: 'enum';
|
|
29
|
+
options: T;
|
|
30
|
+
};
|
|
31
|
+
export type FileFlagDef = BaseFlagConfig<string> & {
|
|
32
|
+
type: 'file';
|
|
33
|
+
exists?: boolean;
|
|
34
|
+
};
|
|
35
|
+
export type DirectoryFlagDef = BaseFlagConfig<string> & {
|
|
36
|
+
type: 'directory';
|
|
37
|
+
exists?: boolean;
|
|
38
|
+
};
|
|
39
|
+
export type UrlFlagDef = BaseFlagConfig<URL> & {
|
|
40
|
+
type: 'url';
|
|
41
|
+
};
|
|
42
|
+
export type CustomFlagDef<R = unknown> = BaseFlagConfig<R> & {
|
|
43
|
+
type: 'custom';
|
|
44
|
+
};
|
|
45
|
+
export type FlagDefinition = StringFlagDef | NumberFlagDef | BooleanFlagDef | EnumFlagDef | FileFlagDef | DirectoryFlagDef | UrlFlagDef | CustomFlagDef<any>;
|
|
46
|
+
export type FlagInput<T extends FlagDefinition, K extends string = never> = Partial<Omit<T, 'type' | K>>;
|
|
47
|
+
export type FlagValidationResult = true | string | Promise<true | string>;
|
|
48
|
+
type MaybeArray<T, O> = O extends {
|
|
49
|
+
multiple: true;
|
|
50
|
+
} ? T[] : T;
|
|
51
|
+
type InferParseReturn<O> = O extends {
|
|
52
|
+
parse: (...args: any[]) => infer R;
|
|
53
|
+
} ? R : never;
|
|
54
|
+
export type FlagType<O extends FlagDefinition> = O extends {
|
|
55
|
+
type: 'enum';
|
|
56
|
+
options: infer T extends readonly string[];
|
|
57
|
+
} ? MaybeArray<T[number], O> : MaybeArray<InferParseReturn<O>, O>;
|
|
58
|
+
export type IsRequired<O extends FlagDefinition> = O extends {
|
|
16
59
|
required: true;
|
|
17
60
|
} ? true : false;
|
|
18
|
-
export type
|
|
19
|
-
export type
|
|
20
|
-
[key: string]:
|
|
61
|
+
export type FlagReturnType<O extends FlagDefinition> = IsRequired<O> extends true ? FlagType<O> : FlagType<O> | null;
|
|
62
|
+
export type FlagsSchema = {
|
|
63
|
+
[key: string]: FlagDefinition;
|
|
21
64
|
};
|
|
22
|
-
export type
|
|
23
|
-
[Key in keyof Options]:
|
|
65
|
+
export type FlagsObject<Options extends FlagsSchema> = {
|
|
66
|
+
[Key in keyof Options]: FlagReturnType<Options[Key]>;
|
|
24
67
|
};
|
|
25
68
|
export type ArgumentsSchema = {
|
|
26
|
-
[key: string]:
|
|
69
|
+
[key: string]: FlagDefinition;
|
|
27
70
|
};
|
|
28
71
|
export type ArgumentsObject<Arguments extends ArgumentsSchema> = {
|
|
29
|
-
[Key in keyof Arguments]:
|
|
72
|
+
[Key in keyof Arguments]: FlagReturnType<Arguments[Key]>;
|
|
30
73
|
};
|
|
31
74
|
export type ContextDefinition = any;
|
|
75
|
+
export type InferFlags<T> = T extends {
|
|
76
|
+
flags: infer O extends FlagsSchema;
|
|
77
|
+
} ? O : any;
|
|
78
|
+
export type InferArgs<T> = T extends {
|
|
79
|
+
args: infer A extends ArgumentsSchema;
|
|
80
|
+
} ? A : any;
|
|
81
|
+
export type Parsed<T> = {
|
|
82
|
+
flags: FlagsObject<InferFlags<T>>;
|
|
83
|
+
args: ArgumentsObject<InferArgs<T>>;
|
|
84
|
+
};
|
|
85
|
+
export {};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Command } from '../Command.js';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
2
|
+
import { ContextDefinition } from '../lib/types.js';
|
|
3
|
+
export declare const HelpCommandFlag: import('../lib/types.js').BaseFlagConfig<boolean> & {
|
|
4
|
+
type: "boolean";
|
|
5
|
+
} & {
|
|
6
|
+
readonly alias: ["h"];
|
|
7
|
+
readonly handler: (value: boolean, ctx: ContextDefinition, cmd: typeof Command) => {
|
|
8
|
+
shouldStop: false;
|
|
9
|
+
} | {
|
|
10
|
+
shouldStop: true;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
var e = {
|
|
2
|
+
name: "bob-core",
|
|
3
|
+
version: "3.0.0-alpha.1",
|
|
4
|
+
description: "BOB Core",
|
|
5
|
+
type: "module",
|
|
6
|
+
main: "./dist/cjs/src/index.js",
|
|
7
|
+
module: "./dist/esm/src/index.js",
|
|
8
|
+
types: "./dist/esm/src/index.d.ts",
|
|
9
|
+
files: ["dist"],
|
|
10
|
+
exports: { ".": {
|
|
11
|
+
import: {
|
|
12
|
+
types: "./dist/esm/src/index.d.ts",
|
|
13
|
+
default: "./dist/esm/src/index.js"
|
|
14
|
+
},
|
|
15
|
+
require: {
|
|
16
|
+
types: "./dist/cjs/src/index.d.ts",
|
|
17
|
+
default: "./dist/cjs/src/index.js"
|
|
18
|
+
}
|
|
19
|
+
} },
|
|
20
|
+
scripts: {
|
|
21
|
+
start: "node -r @swc-node/register debug/main.ts",
|
|
22
|
+
build: "rm -rf ./dist && vite build",
|
|
23
|
+
typecheck: "tsc --noEmit",
|
|
24
|
+
prepack: "npm run build",
|
|
25
|
+
test: "vitest run",
|
|
26
|
+
lint: "eslint .",
|
|
27
|
+
"lint:fix": "eslint . --fix"
|
|
28
|
+
},
|
|
29
|
+
author: "Léo Hubert",
|
|
30
|
+
license: "ISC",
|
|
31
|
+
devDependencies: {
|
|
32
|
+
"@eslint/js": "^9.39.4",
|
|
33
|
+
"@faker-js/faker": "^10.3.0",
|
|
34
|
+
"@swc-node/register": "^1.11.1",
|
|
35
|
+
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
|
36
|
+
"@types/minimist": "^1.2.5",
|
|
37
|
+
"@types/node": "^20.14.5",
|
|
38
|
+
"@types/prompts": "^2.4.9",
|
|
39
|
+
"@types/string-similarity": "^4.0.2",
|
|
40
|
+
"@vitest/coverage-v8": "^4.1.0",
|
|
41
|
+
eslint: "^9.39.4",
|
|
42
|
+
"eslint-config-prettier": "^10.1.8",
|
|
43
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
44
|
+
prettier: "^3.6.2",
|
|
45
|
+
tsx: "^4.21.0",
|
|
46
|
+
typescript: "^5.9.3",
|
|
47
|
+
"typescript-eslint": "^8.57.0",
|
|
48
|
+
vite: "^8.0.0",
|
|
49
|
+
"vite-plugin-dts": "^4.5.4",
|
|
50
|
+
vitest: "^4.1.0"
|
|
51
|
+
},
|
|
52
|
+
dependencies: {
|
|
53
|
+
chalk: "^4.1.2",
|
|
54
|
+
minimist: "^1.2.8",
|
|
55
|
+
prompts: "^2.4.2"
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
//#endregion
|
|
59
|
+
export { e as default };
|
package/dist/esm/src/Cli.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { CommandRegistry, CommandRegistryOptions, CommandResolver, FileImporter
|
|
|
3
3
|
import { ExceptionHandler } from './ExceptionHandler.js';
|
|
4
4
|
import { Logger } from './Logger.js';
|
|
5
5
|
import { default as HelpCommand, HelpCommandOptions } from './commands/HelpCommand.js';
|
|
6
|
-
import { ContextDefinition
|
|
6
|
+
import { ContextDefinition } from './lib/types.js';
|
|
7
7
|
export type CliOptions<C extends ContextDefinition = ContextDefinition> = {
|
|
8
8
|
ctx?: C;
|
|
9
9
|
name?: string;
|
|
@@ -24,10 +24,8 @@ export declare class Cli<C extends ContextDefinition = ContextDefinition> {
|
|
|
24
24
|
constructor(opts?: CliOptions<C>);
|
|
25
25
|
withCommandResolver(resolver: CommandResolver): this;
|
|
26
26
|
withFileImporter(importer: FileImporter): this;
|
|
27
|
-
withCommands(...commands: Array<Command<C
|
|
28
|
-
|
|
29
|
-
} | string>): Promise<void>;
|
|
30
|
-
runCommand(command: string | Command | undefined, ...args: string[]): Promise<number>;
|
|
27
|
+
withCommands(...commands: Array<typeof Command<C> | Command<C> | string>): Promise<void>;
|
|
28
|
+
runCommand(command: string | typeof Command | Command | undefined, ...args: string[]): Promise<number>;
|
|
31
29
|
runHelpCommand(): Promise<number>;
|
|
32
|
-
protected registerCommand(command: Command<C
|
|
30
|
+
protected registerCommand(command: typeof Command<C>): void;
|
|
33
31
|
}
|
|
@@ -1,68 +1,45 @@
|
|
|
1
1
|
import { CommandIO, CommandIOOptions } from './CommandIO.js';
|
|
2
2
|
import { CommandParser } from './CommandParser.js';
|
|
3
3
|
import { Logger } from './Logger.js';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
arguments: ArgumentsObject<Arguments>;
|
|
4
|
+
import { ArgumentsSchema, ContextDefinition, FlagsSchema, Parsed } from './lib/types.js';
|
|
5
|
+
export type CommandRunExample = {
|
|
6
|
+
description: string;
|
|
7
|
+
command: string;
|
|
9
8
|
};
|
|
10
|
-
export type
|
|
11
|
-
export type CommandRunOption<C, Options extends OptionsSchema, Arguments extends ArgumentsSchema> = {
|
|
9
|
+
export type CommandRunOption<C = ContextDefinition> = {
|
|
12
10
|
logger: Logger;
|
|
13
11
|
ctx: C;
|
|
14
12
|
} & ({
|
|
15
13
|
args: string[];
|
|
16
14
|
} | {
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
args: Record<string, any>;
|
|
16
|
+
flags: Record<string, any>;
|
|
19
17
|
});
|
|
20
|
-
export
|
|
21
|
-
description: string;
|
|
22
|
-
command: string;
|
|
23
|
-
};
|
|
24
|
-
export declare class Command<C extends ContextDefinition = ContextDefinition, Options extends OptionsSchema = OptionsSchema, Arguments extends ArgumentsSchema = ArgumentsSchema> {
|
|
18
|
+
export declare abstract class Command<C extends ContextDefinition = ContextDefinition> {
|
|
25
19
|
$type: "BobCommand";
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
static command: string;
|
|
21
|
+
static description: string;
|
|
22
|
+
static group?: string;
|
|
23
|
+
static args: ArgumentsSchema;
|
|
24
|
+
static flags: FlagsSchema;
|
|
25
|
+
static examples: CommandRunExample[];
|
|
26
|
+
static hidden: boolean;
|
|
27
|
+
static disableDefaultOptions: boolean;
|
|
28
|
+
static disablePrompting: boolean;
|
|
29
|
+
static allowUnknownFlags: boolean;
|
|
30
|
+
static strictMode: boolean;
|
|
31
31
|
protected ctx: C;
|
|
32
32
|
protected io: CommandIO;
|
|
33
|
-
protected parser: CommandParser<
|
|
34
|
-
protected disablePromptingFlag: boolean;
|
|
35
|
-
protected allowUnknownOptionsFlag: boolean;
|
|
36
|
-
protected hiddenFlag: boolean;
|
|
37
|
-
protected disableDefaultOptionsFlag: boolean;
|
|
38
|
-
protected strictModeFlag: boolean;
|
|
33
|
+
protected parser: CommandParser<FlagsSchema, FlagsSchema>;
|
|
39
34
|
protected preHandle?(): Promise<void | number>;
|
|
40
|
-
protected
|
|
41
|
-
|
|
42
|
-
protected _handler?: CommandHandler<C, Options, Arguments>;
|
|
43
|
-
private tmp?;
|
|
44
|
-
protected defaultOptions(): CommandOption<Command>[];
|
|
35
|
+
protected abstract handle(ctx: C, parsed: Parsed<any>): Promise<number | void> | number | void;
|
|
36
|
+
static baseFlags: FlagsSchema;
|
|
45
37
|
protected newCommandParser(opts: {
|
|
38
|
+
flags: FlagsSchema;
|
|
39
|
+
args: ArgumentsSchema;
|
|
40
|
+
ctx: ContextDefinition;
|
|
46
41
|
io: CommandIO;
|
|
47
|
-
|
|
48
|
-
arguments: Arguments;
|
|
49
|
-
}): CommandParser<Options, Arguments>;
|
|
42
|
+
}): CommandParser<FlagsSchema, FlagsSchema>;
|
|
50
43
|
protected newCommandIO(opts: CommandIOOptions): CommandIO;
|
|
51
|
-
|
|
52
|
-
description?: string;
|
|
53
|
-
group?: string;
|
|
54
|
-
options?: Options;
|
|
55
|
-
arguments?: Arguments;
|
|
56
|
-
});
|
|
57
|
-
disablePrompting(): this;
|
|
58
|
-
allowUnknownOptions(): this;
|
|
59
|
-
hidden(): this;
|
|
60
|
-
get isHidden(): boolean;
|
|
61
|
-
disableDefaultOptions(): this;
|
|
62
|
-
strictMode(): this;
|
|
63
|
-
preHandler(handler: CommandHandler<C, Options, Arguments>): this;
|
|
64
|
-
handler(handler: CommandHandler<C, Options, Arguments>): this;
|
|
65
|
-
options<Opts extends OptionsSchema>(opts: Opts): Command<C, Options & Opts, Arguments>;
|
|
66
|
-
arguments<Args extends ArgumentsSchema>(args: Args): Command<C, Options, Arguments & Args>;
|
|
67
|
-
run(opts: CommandRunOption<C, Options, Arguments>): Promise<number | void>;
|
|
44
|
+
run(runOpts: CommandRunOption<C>): Promise<number | void>;
|
|
68
45
|
}
|
|
@@ -1,49 +1,55 @@
|
|
|
1
1
|
import { CommandIO } from './CommandIO.js';
|
|
2
|
-
import {
|
|
3
|
-
import { OptionDefinition, OptionReturnType, OptionsObject, OptionsSchema } from './lib/types.js';
|
|
2
|
+
import { ArgumentsSchema, ContextDefinition, FlagDefinition, FlagReturnType, FlagsObject, FlagsSchema } from './lib/types.js';
|
|
4
3
|
/**
|
|
5
|
-
* Parses command-line arguments into typed
|
|
4
|
+
* Parses command-line arguments into typed flags and arguments
|
|
6
5
|
* Handles validation, type conversion, and default values
|
|
7
6
|
*/
|
|
8
|
-
export declare class CommandParser<
|
|
9
|
-
protected
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
export declare class CommandParser<Flags extends FlagsSchema, Arguments extends ArgumentsSchema> {
|
|
8
|
+
protected opts: {
|
|
9
|
+
flags: Flags;
|
|
10
|
+
args: Arguments;
|
|
11
|
+
ctx?: ContextDefinition;
|
|
12
|
+
io: CommandIO;
|
|
13
|
+
};
|
|
14
|
+
protected flags: FlagsSchema;
|
|
15
|
+
protected parsedFlags: FlagsObject<Flags> | null;
|
|
16
|
+
protected args: ArgumentsSchema;
|
|
17
|
+
protected parsedArguments: FlagsObject<Arguments> | null;
|
|
13
18
|
protected io: CommandIO;
|
|
14
|
-
protected
|
|
15
|
-
protected
|
|
19
|
+
protected shouldPromptForMissingFlags: boolean;
|
|
20
|
+
protected shouldValidateUnknownFlags: boolean;
|
|
16
21
|
protected shouldRejectExtraArguments: boolean;
|
|
17
22
|
constructor(opts: {
|
|
23
|
+
flags: Flags;
|
|
24
|
+
args: Arguments;
|
|
25
|
+
ctx?: ContextDefinition;
|
|
18
26
|
io: CommandIO;
|
|
19
|
-
options: Options;
|
|
20
|
-
arguments: Arguments;
|
|
21
27
|
});
|
|
22
28
|
/**
|
|
23
|
-
* Parses raw command-line arguments into structured
|
|
29
|
+
* Parses raw command-line arguments into structured flags and arguments
|
|
24
30
|
* @param args - Raw command line arguments (typically from process.argv.slice(2))
|
|
25
|
-
* @returns Object containing parsed
|
|
26
|
-
* @throws {
|
|
27
|
-
* @throws {
|
|
31
|
+
* @returns Object containing parsed flags and arguments
|
|
32
|
+
* @throws {InvalidFlag} If an unknown flag is provided
|
|
33
|
+
* @throws {BadCommandFlag} If a value cannot be converted to the expected type
|
|
28
34
|
*/
|
|
29
|
-
init(args: string[]): {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
35
|
+
init(args: string[]): Promise<{
|
|
36
|
+
flags: FlagsObject<Flags>;
|
|
37
|
+
args: FlagsObject<Arguments>;
|
|
38
|
+
}>;
|
|
33
39
|
/**
|
|
34
|
-
* Validates the parsed
|
|
40
|
+
* Validates the parsed flags and arguments
|
|
35
41
|
* @throws {Error} If validation fails
|
|
36
42
|
*/
|
|
37
43
|
validate(): Promise<void>;
|
|
38
44
|
/**
|
|
39
|
-
* Retrieves a parsed
|
|
40
|
-
* @param name - The
|
|
41
|
-
* @param defaultValue - Optional default value if
|
|
42
|
-
* @returns The typed
|
|
45
|
+
* Retrieves a parsed flag value by name
|
|
46
|
+
* @param name - The flag name
|
|
47
|
+
* @param defaultValue - Optional default value if flag is not set
|
|
48
|
+
* @returns The typed flag value
|
|
43
49
|
* @throws {Error} If init() has not been called yet
|
|
44
50
|
*/
|
|
45
|
-
|
|
46
|
-
|
|
51
|
+
flag<FlagName extends keyof Flags>(name: FlagName, defaultValue?: FlagReturnType<Flags[FlagName]>): FlagReturnType<Flags[FlagName]>;
|
|
52
|
+
setFlag<FlagName extends keyof Flags>(name: FlagName, value: FlagReturnType<Flags[FlagName]>): Promise<void>;
|
|
47
53
|
/**
|
|
48
54
|
* Retrieves a parsed argument value by name
|
|
49
55
|
* @param name - The argument name
|
|
@@ -51,8 +57,8 @@ export declare class CommandParser<Options extends OptionsSchema, Arguments exte
|
|
|
51
57
|
* @returns The typed argument value
|
|
52
58
|
* @throws {Error} If init() has not been called yet
|
|
53
59
|
*/
|
|
54
|
-
argument<ArgName extends keyof Arguments>(name: ArgName, defaultValue?:
|
|
55
|
-
setArgument<ArgName extends keyof Arguments>(name: ArgName, value:
|
|
60
|
+
argument<ArgName extends keyof Arguments>(name: ArgName, defaultValue?: FlagReturnType<Arguments[ArgName]>): FlagReturnType<Arguments[ArgName]>;
|
|
61
|
+
setArgument<ArgName extends keyof Arguments>(name: ArgName, value: FlagReturnType<Arguments[ArgName]>): Promise<void>;
|
|
56
62
|
/**
|
|
57
63
|
* Checks if a value should be considered "empty" for default value purposes
|
|
58
64
|
* @param value - The value to check
|
|
@@ -60,12 +66,12 @@ export declare class CommandParser<Options extends OptionsSchema, Arguments exte
|
|
|
60
66
|
*/
|
|
61
67
|
private isEmptyValue;
|
|
62
68
|
/**
|
|
63
|
-
* Validates that all provided
|
|
64
|
-
* @throws {
|
|
69
|
+
* Validates that all provided flags are recognized
|
|
70
|
+
* @throws {InvalidFlag} If an unknown flag is found
|
|
65
71
|
*/
|
|
66
|
-
private
|
|
72
|
+
private validateUnknownFlags;
|
|
67
73
|
/**
|
|
68
|
-
* Processes named
|
|
74
|
+
* Processes named flags from minimist output
|
|
69
75
|
*/
|
|
70
76
|
private handleOptions;
|
|
71
77
|
/**
|
|
@@ -73,36 +79,28 @@ export declare class CommandParser<Options extends OptionsSchema, Arguments exte
|
|
|
73
79
|
*/
|
|
74
80
|
private handleArguments;
|
|
75
81
|
/**
|
|
76
|
-
*
|
|
77
|
-
|
|
78
|
-
private handleVariadicArgument;
|
|
79
|
-
/**
|
|
80
|
-
* Resolves a single positional argument value with defaults and type conversion
|
|
81
|
-
* Note: Does not validate required arguments - validation happens in subclass validate() methods
|
|
82
|
+
* Resolves a flag value from the parsed flag values object
|
|
83
|
+
* Handles alias resolution, defaults, and type conversion
|
|
82
84
|
*/
|
|
83
|
-
private
|
|
85
|
+
private resolveFlagValue;
|
|
84
86
|
/**
|
|
85
|
-
*
|
|
86
|
-
* Handles alias resolution, defaults, and type conversion
|
|
87
|
+
* Parses a raw value using the flag's parse function
|
|
87
88
|
*/
|
|
88
|
-
private
|
|
89
|
-
|
|
90
|
-
argumentDefinitions(): Record<string, OptionDetails>;
|
|
91
|
-
availableOptions(): string[];
|
|
92
|
-
availableArguments(): string[];
|
|
89
|
+
private parseValue;
|
|
90
|
+
private safeParse;
|
|
93
91
|
/**
|
|
94
92
|
* Disables prompting for missing argument values
|
|
95
93
|
* Useful for non-interactive environments
|
|
96
94
|
*/
|
|
97
95
|
disablePrompting(): this;
|
|
98
|
-
|
|
96
|
+
allowUnknownFlags(): this;
|
|
99
97
|
strictMode(): this;
|
|
100
98
|
/**
|
|
101
99
|
* Prompts the user to provide a missing argument value via CommandIO
|
|
102
100
|
* Used by validate() when shouldPromptForMissingArgs is enabled
|
|
103
101
|
* @param argumentName - The name of the missing argument
|
|
104
|
-
* @param
|
|
102
|
+
* @param definition - The argument's definition for type and description
|
|
105
103
|
* @returns The user-provided value, or null if none given
|
|
106
104
|
*/
|
|
107
|
-
protected promptForArgument(argumentName: string,
|
|
105
|
+
protected promptForArgument(argumentName: string, definition: FlagDefinition): Promise<string | number | string[] | null>;
|
|
108
106
|
}
|