bob-core 2.0.2 → 2.1.0

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.
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="bob-core",t="2.0.2",s="BOB Core",i="module",n="./dist/cjs/src/index.js",r="./dist/esm/src/index.js",c="./dist/esm/src/index.d.ts",o=["dist"],d={".":{import:{types:"./dist/esm/src/index.d.ts",default:"./dist/esm/src/index.js"},require:{types:"./dist/cjs/src/index.d.ts",default:"./dist/cjs/src/index.js"}}},p={start:"node -r @swc-node/register debug/main.ts",build:"rimraf ./dist && vite build",typecheck:"tsc --noEmit",prepack:"npm run build",test:"vitest run",lint:"eslint .","lint:fix":"eslint . --fix"},l="Léo Hubert",m="ISC",a={"@eslint/js":"^9.37.0","@faker-js/faker":"^10.0.0","@swc-node/register":"^1.11.1","@trivago/prettier-plugin-sort-imports":"^5.2.2","@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",eslint:"^9.37.0","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.4",prettier:"^3.6.2",rimraf:"^6.0.1",tsx:"^4.20.6",typescript:"^5.9.3","typescript-eslint":"^8.46.0",vite:"^7.2.7","vite-plugin-dts":"^4.5.4",vitest:"^3.2.4"},u={chalk:"^4.1.2",minimist:"^1.2.8",prompts:"^2.4.2"},y={name:e,version:t,description:s,type:i,main:n,module:r,types:c,files:o,exports:d,scripts:p,author:l,license:m,devDependencies:a,dependencies:u};exports.author=l;exports.default=y;exports.dependencies=u;exports.description=s;exports.devDependencies=a;exports.exports=d;exports.files=o;exports.license=m;exports.main=n;exports.module=r;exports.name=e;exports.scripts=p;exports.type=i;exports.types=c;exports.version=t;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="bob-core",t="2.1.0",s="BOB Core",i="module",n="./dist/cjs/src/index.js",r="./dist/esm/src/index.js",c="./dist/esm/src/index.d.ts",o=["dist"],d={".":{import:{types:"./dist/esm/src/index.d.ts",default:"./dist/esm/src/index.js"},require:{types:"./dist/cjs/src/index.d.ts",default:"./dist/cjs/src/index.js"}}},p={start:"node -r @swc-node/register debug/main.ts",build:"rimraf ./dist && vite build",typecheck:"tsc --noEmit",prepack:"npm run build",test:"vitest run",lint:"eslint .","lint:fix":"eslint . --fix"},l="Léo Hubert",m="ISC",a={"@eslint/js":"^9.37.0","@faker-js/faker":"^10.0.0","@swc-node/register":"^1.11.1","@trivago/prettier-plugin-sort-imports":"^5.2.2","@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",eslint:"^9.37.0","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.4",prettier:"^3.6.2",rimraf:"^6.0.1",tsx:"^4.20.6",typescript:"^5.9.3","typescript-eslint":"^8.46.0",vite:"^7.2.7","vite-plugin-dts":"^4.5.4",vitest:"^3.2.4"},u={chalk:"^4.1.2",minimist:"^1.2.8",prompts:"^2.4.2"},y={name:e,version:t,description:s,type:i,main:n,module:r,types:c,files:o,exports:d,scripts:p,author:l,license:m,devDependencies:a,dependencies:u};exports.author=l;exports.default=y;exports.dependencies=u;exports.description=s;exports.devDependencies=a;exports.exports=d;exports.files=o;exports.license=m;exports.main=n;exports.module=r;exports.name=e;exports.scripts=p;exports.type=i;exports.types=c;exports.version=t;
@@ -32,6 +32,10 @@ export declare class Command<C extends ContextDefinition = ContextDefinition, Op
32
32
  protected io: CommandIO;
33
33
  protected parser: CommandParser<Options, Arguments>;
34
34
  protected disablePromptingFlag: boolean;
35
+ protected allowUnknownOptionsFlag: boolean;
36
+ protected hiddenFlag: boolean;
37
+ protected disableDefaultOptionsFlag: boolean;
38
+ protected strictModeFlag: boolean;
35
39
  protected preHandle?(): Promise<void | number>;
36
40
  protected _preHandler?: CommandHandler<C, Options, Arguments>;
37
41
  protected handle?(ctx: C, opts: CommandHandlerOptions<Options, Arguments>): Promise<number | void> | number | void;
@@ -51,6 +55,11 @@ export declare class Command<C extends ContextDefinition = ContextDefinition, Op
51
55
  arguments?: Arguments;
52
56
  });
53
57
  disablePrompting(): this;
58
+ allowUnknownOptions(): this;
59
+ hidden(): this;
60
+ get isHidden(): boolean;
61
+ disableDefaultOptions(): this;
62
+ strictMode(): this;
54
63
  preHandler(handler: CommandHandler<C, Options, Arguments>): this;
55
64
  handler(handler: CommandHandler<C, Options, Arguments>): this;
56
65
  options<Opts extends OptionsSchema>(opts: Opts): Command<C, Options & Opts, Arguments>;
@@ -12,6 +12,8 @@ export declare class CommandParser<Options extends OptionsSchema, Arguments exte
12
12
  protected parsedArguments: OptionsObject<Arguments> | null;
13
13
  protected io: CommandIO;
14
14
  protected shouldPromptForMissingOptions: boolean;
15
+ protected shouldValidateUnknownOptions: boolean;
16
+ protected shouldRejectExtraArguments: boolean;
15
17
  constructor(opts: {
16
18
  io: CommandIO;
17
19
  options: Options;
@@ -93,6 +95,8 @@ export declare class CommandParser<Options extends OptionsSchema, Arguments exte
93
95
  * Useful for non-interactive environments
94
96
  */
95
97
  disablePrompting(): this;
98
+ allowUnknownOptions(): this;
99
+ strictMode(): this;
96
100
  /**
97
101
  * Prompts the user to provide a missing argument value via CommandIO
98
102
  * Used by validate() when shouldPromptForMissingArgs is enabled
@@ -0,0 +1,8 @@
1
+ import { Logger } from '../Logger.js';
2
+ import { BobError } from './BobError.js';
3
+ export declare class TooManyArguments extends BobError {
4
+ readonly expected: number;
5
+ readonly received: number;
6
+ constructor(expected: number, received: number);
7
+ pretty(logger: Logger): void;
8
+ }
@@ -5,3 +5,4 @@ export * from './InvalidOption.js';
5
5
  export * from './CommandNotFoundError.js';
6
6
  export * from './MissingRequiredArgumentValue.js';
7
7
  export * from './MissingRequiredOptionValue.js';
8
+ export * from './TooManyArguments.js';
@@ -1,17 +1,17 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("prompts"),a=require("chalk"),M=require("minimist"),W=require("node:fs"),F=require("node:path");class R{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,r=null,o=0;const u=setInterval(function(){r&&(process.stdout.write(new TextEncoder().encode("\r"+" ".repeat(r.length+5)+"\r")),r=null),process.stdout.write(new TextEncoder().encode("\r"+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=>{r=n,n=h},stop:m}}}class f extends Error{$type="BobError"}function q(s){if(s==="string"||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 k(s){return typeof s=="string"||Array.isArray(s)?q(s):s.default!==void 0?s.default:q(s.type)}function g(s){return typeof s=="string"||Array.isArray(s)?{alias:[],default:k(s),description:"",required:!1,secret:!1,type:s,variadic:!1}:{alias:s.alias?Array.isArray(s.alias)?s.alias:[s.alias]:[],default:s.default??k(s.type),description:s.description??"",required:s.required??!1,secret:s.secret??!1,type:s.type,variadic:s.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 r=g(n),o=r.alias?typeof r.alias=="string"?[r.alias]:r.alias:[],u=Array.isArray(r.type)?`[${r.type[0]}]`:r.type,m=`--${i}${o.length>0?o.map(l=>`, -${l}`).join(""):""}`,h=" ".repeat(30-m.length);t.log(` ${a.green(m)} ${h} ${r.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 P 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 j 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 b 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 L 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.`)}}function w(s,t,e,i){if(s==null)return i??null;if(t==="string")return String(s);if(t==="number"){const n=Number(s);if(isNaN(n))throw new b({option:e,reason:`Expected a number, got "${s}"`});return n}if(t==="boolean")return typeof s=="boolean"?s:s==="true"||s==="1"?!0:s==="false"||s==="0"?!1:!!s;if(Array.isArray(t)){const n=t[0],r=Array.isArray(s)?s:[s];if(n==="string")return r.map(o=>String(o));if(n==="number")return r.map(o=>{const u=Number(o);if(isNaN(u))throw new b({option:e,reason:`Expected array of numbers, got "${o}" in array`});return u})}return s}class x{options;parsedOptions=null;arguments;parsedArguments=null;io;shouldPromptForMissingOptions=!0;constructor(t){this.options=t.options,this.arguments=t.arguments,this.io=t.io}init(t){const{_:e,...i}=M(t);return 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 P(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 r of n.alias)e.add(r)}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];for(const n in this.arguments){const r=g(this.arguments[n]);if(r.variadic){e[n]=this.handleVariadicArgument(n,r,i);continue}e[n]=this.resolveArgumentValue(n,r,i.shift())}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 r=[t,...e.alias];for(const o of r)if(o in i){n=i[o];break}if(n===void 0){if(e.required)throw new b({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}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?"[]":""})`)}
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
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 r of n.split(","))if(isNaN(Number(r)))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 r=Number(n);if(isNaN(r))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 O(s){return new Array(s+5).join(" ")}class I{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),r=n.map(([l,d])=>{const c=Array.isArray(d.alias)?d.alias:d.alias?[d.alias]:[];return{name:l,...d,optionWithAlias:`--${l}${c.map(p=>`, -${p}`).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(...r.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 c=O(h-l.length);let p=` ${a.green(l)} ${c} ${d.description??"\b"}`;if(d.default!==void 0&&!d.required){const D=(Array.isArray(d.type)?`[${d.type[0]}]`:d.type)==="array"||Array.isArray(d.type)?JSON.stringify(d.default):d.default;p+=` ${a.yellow(`[default: ${D}]`)}`}d.variadic&&(p+=` ${a.white("(variadic)")}`),this.io.log(p)}}if(n.length>0){this.io.log(`
7
- ${a.yellow("Options")}:`);for(const l of r){const d=O(h-l.optionWithAlias.length);let c=`${a.green(l.optionWithAlias)} ${d} ${l.description??"\b"}`;if(l.type){const p=Array.isArray(l.type)?`[${l.type[0]}]`:l.type;c+=` ${a.white(`(${p})`)}`}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;c+=` ${a.yellow(`[default: ${S}]`)}`}this.io.log(c)}}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,c]of this.commandsExamples.entries())d>0&&this.io.log(""),this.io.log(` ${c.description}
9
- `),this.io.log(` ${a.green(`${l} ${c.command}`)}`)}return-1}}class C{$type="BobCommand";_command;description;group;commandsExamples=[];get command(){return this._command}ctx;io;parser;disablePromptingFlag=!1;_preHandler;_handler;tmp;defaultOptions(){return[new I]}newCommandParser(t){return new x({io:t.io,options:t.options,arguments:t.arguments})}newCommandIO(t){return new R(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}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 r of this.defaultOptions())r.option in n||(n[r.option]=r);this.parser=this.newCommandParser({io:this.io,options:n,arguments:this.tmp?.arguments??{}}),e=this.parser.init(t.args);for(const r of this.defaultOptions())if(e.options[r.option]===!0){const o=await r.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 v extends x{command;constructor(t){const e=v.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,...r]=t.split(/\{(.*?)\}/g).map(m=>m.trim()).filter(Boolean),o={},u={};for(const m of r){const{name:h,isOption:l,definition:d}=v.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 r={required:!0,type:"string",description:void 0,default:null,variadic:!1};if(i.includes(":")){const[o,u]=i.split(":");i=o.trim(),r.description=u.trim()}if(i.includes("=")){const[o,u]=i.split("=");i=o.trim(),r.default=u.trim(),r.required=!1,typeof r.default=="string"&&!r.default.length?r.default=null:r.default==="true"?(r.default=!0,r.type="boolean"):r.default==="false"&&(r.default=!1,r.type="boolean")}else i.startsWith("--")&&(r.required=!1,r.default=!1,r.type="boolean");if(i.includes("|")){const[o,...u]=i.split("|");i=o.trim(),r.alias=u.map(m=>m.trim())}return i.startsWith("--")&&(n=!0,i=i.slice(2)),r.default==="*"&&(r.default=[],r.type=["string"]),i.endsWith("?")&&(r.required=!1,i=i.slice(0,-1)),i.endsWith("*")&&(r.type=["string"],r.variadic=!0,r.default=[],i=i.slice(0,-1)),r.description=r.description??e[i]??e[`--${i}`],{name:i,isOption:n,definition:r}}}class T extends C{helperDefinitions={};get command(){return this.parser?this.parser.command:this.signature.split(" ")[0]}newCommandParser(t){return new v({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 E{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 V{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),r=new Set(n);let o=0;for(const u of i)r.has(u)&&(o++,r.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,r=i[0]?.rating??0;for(let o=1;o<i.length;o++)i[o].rating>r&&(r=i[o].rating,n=o);return{ratings:i,bestMatch:i[n],bestMatchIndex:n}}}function _(s){return typeof s=="object"&&s!==null&&"$type"in s&&s.$type==="BobError"}function N(s){return typeof s=="object"&&s!==null&&(s instanceof C||"$type"in s&&s.$type==="BobCommand")}class H{commands={};io;logger;stringSimilarity;newCommandIO(t){return new R(t)}constructor(t){this.logger=t?.logger??new E,this.io=this.newCommandIO({logger:this.logger}),this.stringSimilarity=t?.stringSimilarity??new V}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:N(e)?e:null):null};withCommandResolver(t){return this.commandResolver=t,this}withFileImporter(t){return this.importFile=t,this}registerCommand(t,e=!1){const i=t.command;if(!i)throw new Error("Command signature is invalid, it must have a command 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);N(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,r=typeof e=="string"?e:n.command;if(!n){const o=await this.suggestCommand(r);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:r}=this.stringSimilarity.findBestMatch(t,e),o=r.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 L(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=W.readdirSync(t,{withFileTypes:!0});for(const i of e){const n=F.resolve(t,i.name);if(i.isDirectory())yield*this.listCommandsFiles(F.resolve(t,i.name));else{if(!n.endsWith(".ts")&&!n.endsWith(".js")&&!n.endsWith(".mjs")&&!n.endsWith(".cjs"))continue;yield n}}}}class B{logger;constructor(t){this.logger=t}handle(t){if(_(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(),e=this.opts.cliName??"Bob CLI",i=this.opts.cliVersion??"0.0.0",n=(await Promise.resolve().then(()=>require("../package-B3VP5AzR.cjs")))?.default?.version??"0.0.0";this.io.log(`${e} ${a.green(i)} (core: ${a.yellow(n)})
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)})
12
12
 
13
13
  ${a.yellow("Usage")}:
14
14
  command [options] [arguments]
15
15
 
16
16
  ${a.yellow("Available commands")}:
17
- `);const r=Math.max(...t.map(m=>m.command.length))??0,o={};for(const m of t){const h=m.group??m.command.split(":")[0];o[h]||(o[h]=[]),o[h].push(m)}const u=Object.entries(o).sort(([m],[h])=>m.toLowerCase().localeCompare(h.toLowerCase())).sort(([,m],[,h])=>m.length-h.length);for(const[m,h]of u){const l=h.length>1;l&&this.io.log(a.yellow(`${m}:`));const d=h.sort((c,p)=>c.command.toLowerCase().localeCompare(p.command.toLowerCase()));for(const c of d){let p=O(r-c.command.length);l&&(p=p.slice(2)),this.io.log(`${l?" ":""}${a.green(c.command)} ${p} ${c.description}`)}}}}class U{ctx;logger;commandRegistry;exceptionHandler;helpCommand;newCommandRegistry(t){return new H(t)}newHelpCommand(t){return new G(t)}newExceptionHandler(t){return new B(t.logger)}constructor(t={}){this.ctx=t.ctx,this.logger=t.logger??new E,this.commandRegistry=this.newCommandRegistry({logger:this.logger}),this.exceptionHandler=this.newExceptionHandler({logger:this.logger}),this.helpCommand=this.newHelpCommand({cliName:t.name,cliVersion:t.version,commandRegistry:this.commandRegistry})}withCommandResolver(t){return this.commandRegistry.withCommandResolver(t),this}withFileImporter(t){return this.commandRegistry.withFileImporter(t),this}async withCommands(...t){for(const e of t)typeof e=="string"?await this.commandRegistry.loadCommandsPath(e):typeof e=="function"?this.registerCommand(new e):this.registerCommand(e)}async runCommand(t,...e){return t?await this.commandRegistry.runCommand(this.ctx??{},t,...e).catch(this.exceptionHandler.handle.bind(this.exceptionHandler)):await this.runHelpCommand()}async runHelpCommand(){return await this.runCommand(this.helpCommand)}registerCommand(t){this.commandRegistry.registerCommand(t)}}exports.BadCommandOption=b;exports.BadCommandParameter=j;exports.BobError=f;exports.Cli=U;exports.Command=C;exports.CommandIO=R;exports.CommandNotFoundError=L;exports.CommandParser=x;exports.CommandRegistry=H;exports.CommandSignatureParser=v;exports.CommandWithSignature=T;exports.ExceptionHandler=B;exports.HelpOption=I;exports.InvalidOption=$;exports.Logger=E;exports.MissingRequiredArgumentValue=A;exports.MissingRequiredOptionValue=P;exports.StringSimilarity=V;
17
+ `);const s=Math.max(...t.map(m=>m.command.length))??0,o={};for(const m of t){const h=m.group??m.command.split(":")[0];o[h]||(o[h]=[]),o[h].push(m)}const u=Object.entries(o).sort(([m],[h])=>m.toLowerCase().localeCompare(h.toLowerCase())).sort(([,m],[,h])=>m.length-h.length);for(const[m,h]of u){const l=h.length>1;l&&this.io.log(a.yellow(`${m}:`));const d=h.sort((p,c)=>p.command.toLowerCase().localeCompare(c.command.toLowerCase()));for(const p of d){let c=R(s-p.command.length);l&&(c=c.slice(2)),this.io.log(`${l?" ":""}${a.green(p.command)} ${c} ${p.description}`)}}}}class z{ctx;logger;commandRegistry;exceptionHandler;helpCommand;newCommandRegistry(t){return new M(t)}newHelpCommand(t){return new G(t)}newExceptionHandler(t){return new D(t.logger)}constructor(t={}){this.ctx=t.ctx,this.logger=t.logger??new F,this.commandRegistry=this.newCommandRegistry({logger:this.logger}),this.exceptionHandler=this.newExceptionHandler({logger:this.logger}),this.helpCommand=this.newHelpCommand({cliName:t.name,cliVersion:t.version,commandRegistry:this.commandRegistry})}withCommandResolver(t){return this.commandRegistry.withCommandResolver(t),this}withFileImporter(t){return this.commandRegistry.withFileImporter(t),this}async withCommands(...t){for(const e of t)typeof e=="string"?await this.commandRegistry.loadCommandsPath(e):typeof e=="function"?this.registerCommand(new e):this.registerCommand(e)}async runCommand(t,...e){return t?await this.commandRegistry.runCommand(this.ctx??{},t,...e).catch(this.exceptionHandler.handle.bind(this.exceptionHandler)):await this.runHelpCommand()}async runHelpCommand(){return await this.runCommand(this.helpCommand)}registerCommand(t){this.commandRegistry.registerCommand(t)}}exports.BadCommandOption=v;exports.BadCommandParameter=W;exports.BobError=f;exports.Cli=z;exports.Command=C;exports.CommandIO=x;exports.CommandNotFoundError=P;exports.CommandParser=E;exports.CommandRegistry=M;exports.CommandSignatureParser=b;exports.CommandWithSignature=_;exports.ExceptionHandler=D;exports.HelpOption=L;exports.InvalidOption=$;exports.Logger=F;exports.MissingRequiredArgumentValue=A;exports.MissingRequiredOptionValue=V;exports.StringSimilarity=H;exports.TooManyArguments=I;
@@ -1,4 +1,4 @@
1
- const t = "bob-core", s = "2.0.2", e = "BOB Core", i = "module", n = "./dist/cjs/src/index.js", r = "./dist/esm/src/index.js", c = "./dist/esm/src/index.d.ts", o = ["dist"], d = { ".": { import: { types: "./dist/esm/src/index.d.ts", default: "./dist/esm/src/index.js" }, require: { types: "./dist/cjs/src/index.d.ts", default: "./dist/cjs/src/index.js" } } }, p = { start: "node -r @swc-node/register debug/main.ts", build: "rimraf ./dist && vite build", typecheck: "tsc --noEmit", prepack: "npm run build", test: "vitest run", lint: "eslint .", "lint:fix": "eslint . --fix" }, l = "Léo Hubert", m = "ISC", a = { "@eslint/js": "^9.37.0", "@faker-js/faker": "^10.0.0", "@swc-node/register": "^1.11.1", "@trivago/prettier-plugin-sort-imports": "^5.2.2", "@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", eslint: "^9.37.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.5.4", prettier: "^3.6.2", rimraf: "^6.0.1", tsx: "^4.20.6", typescript: "^5.9.3", "typescript-eslint": "^8.46.0", vite: "^7.2.7", "vite-plugin-dts": "^4.5.4", vitest: "^3.2.4" }, u = { chalk: "^4.1.2", minimist: "^1.2.8", prompts: "^2.4.2" }, x = {
1
+ const t = "bob-core", s = "2.1.0", e = "BOB Core", i = "module", n = "./dist/cjs/src/index.js", r = "./dist/esm/src/index.js", c = "./dist/esm/src/index.d.ts", o = ["dist"], d = { ".": { import: { types: "./dist/esm/src/index.d.ts", default: "./dist/esm/src/index.js" }, require: { types: "./dist/cjs/src/index.d.ts", default: "./dist/cjs/src/index.js" } } }, p = { start: "node -r @swc-node/register debug/main.ts", build: "rimraf ./dist && vite build", typecheck: "tsc --noEmit", prepack: "npm run build", test: "vitest run", lint: "eslint .", "lint:fix": "eslint . --fix" }, l = "Léo Hubert", m = "ISC", a = { "@eslint/js": "^9.37.0", "@faker-js/faker": "^10.0.0", "@swc-node/register": "^1.11.1", "@trivago/prettier-plugin-sort-imports": "^5.2.2", "@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", eslint: "^9.37.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.5.4", prettier: "^3.6.2", rimraf: "^6.0.1", tsx: "^4.20.6", typescript: "^5.9.3", "typescript-eslint": "^8.46.0", vite: "^7.2.7", "vite-plugin-dts": "^4.5.4", vitest: "^3.2.4" }, u = { chalk: "^4.1.2", minimist: "^1.2.8", prompts: "^2.4.2" }, x = {
2
2
  name: t,
3
3
  version: s,
4
4
  description: e,
@@ -32,6 +32,10 @@ export declare class Command<C extends ContextDefinition = ContextDefinition, Op
32
32
  protected io: CommandIO;
33
33
  protected parser: CommandParser<Options, Arguments>;
34
34
  protected disablePromptingFlag: boolean;
35
+ protected allowUnknownOptionsFlag: boolean;
36
+ protected hiddenFlag: boolean;
37
+ protected disableDefaultOptionsFlag: boolean;
38
+ protected strictModeFlag: boolean;
35
39
  protected preHandle?(): Promise<void | number>;
36
40
  protected _preHandler?: CommandHandler<C, Options, Arguments>;
37
41
  protected handle?(ctx: C, opts: CommandHandlerOptions<Options, Arguments>): Promise<number | void> | number | void;
@@ -51,6 +55,11 @@ export declare class Command<C extends ContextDefinition = ContextDefinition, Op
51
55
  arguments?: Arguments;
52
56
  });
53
57
  disablePrompting(): this;
58
+ allowUnknownOptions(): this;
59
+ hidden(): this;
60
+ get isHidden(): boolean;
61
+ disableDefaultOptions(): this;
62
+ strictMode(): this;
54
63
  preHandler(handler: CommandHandler<C, Options, Arguments>): this;
55
64
  handler(handler: CommandHandler<C, Options, Arguments>): this;
56
65
  options<Opts extends OptionsSchema>(opts: Opts): Command<C, Options & Opts, Arguments>;
@@ -12,6 +12,8 @@ export declare class CommandParser<Options extends OptionsSchema, Arguments exte
12
12
  protected parsedArguments: OptionsObject<Arguments> | null;
13
13
  protected io: CommandIO;
14
14
  protected shouldPromptForMissingOptions: boolean;
15
+ protected shouldValidateUnknownOptions: boolean;
16
+ protected shouldRejectExtraArguments: boolean;
15
17
  constructor(opts: {
16
18
  io: CommandIO;
17
19
  options: Options;
@@ -93,6 +95,8 @@ export declare class CommandParser<Options extends OptionsSchema, Arguments exte
93
95
  * Useful for non-interactive environments
94
96
  */
95
97
  disablePrompting(): this;
98
+ allowUnknownOptions(): this;
99
+ strictMode(): this;
96
100
  /**
97
101
  * Prompts the user to provide a missing argument value via CommandIO
98
102
  * Used by validate() when shouldPromptForMissingArgs is enabled
@@ -0,0 +1,8 @@
1
+ import { Logger } from '../Logger.js';
2
+ import { BobError } from './BobError.js';
3
+ export declare class TooManyArguments extends BobError {
4
+ readonly expected: number;
5
+ readonly received: number;
6
+ constructor(expected: number, received: number);
7
+ pretty(logger: Logger): void;
8
+ }
@@ -5,3 +5,4 @@ export * from './InvalidOption.js';
5
5
  export * from './CommandNotFoundError.js';
6
6
  export * from './MissingRequiredArgumentValue.js';
7
7
  export * from './MissingRequiredOptionValue.js';
8
+ export * from './TooManyArguments.js';
@@ -1,9 +1,9 @@
1
- import f from "prompts";
1
+ import y from "prompts";
2
2
  import a from "chalk";
3
- import I from "minimist";
4
- import V from "node:fs";
5
- import R from "node:path";
6
- class k {
3
+ import q from "minimist";
4
+ import I from "node:fs";
5
+ import x from "node:path";
6
+ class S {
7
7
  logger;
8
8
  constructor(t) {
9
9
  this.logger = t.logger;
@@ -30,7 +30,7 @@ class k {
30
30
  * Prompt utils
31
31
  */
32
32
  async askForConfirmation(t = "Do you want to continue?", e) {
33
- return (await f({
33
+ return (await y({
34
34
  type: "confirm",
35
35
  name: "value",
36
36
  message: t,
@@ -38,7 +38,7 @@ class k {
38
38
  })).value;
39
39
  }
40
40
  async askForInput(t, e, i) {
41
- return (await f({
41
+ return (await y({
42
42
  type: "text",
43
43
  name: "value",
44
44
  message: t,
@@ -47,7 +47,7 @@ class k {
47
47
  }))?.value ?? null;
48
48
  }
49
49
  async askForDate(t, e, i) {
50
- return (await f({
50
+ return (await y({
51
51
  type: "date",
52
52
  name: "value",
53
53
  message: t,
@@ -56,7 +56,7 @@ class k {
56
56
  }))?.value ?? null;
57
57
  }
58
58
  async askForList(t, e, i) {
59
- return (await f({
59
+ return (await y({
60
60
  type: "list",
61
61
  name: "value",
62
62
  message: t,
@@ -65,7 +65,7 @@ class k {
65
65
  }))?.value ?? null;
66
66
  }
67
67
  async askForToggle(t, e, i) {
68
- return (await f({
68
+ return (await y({
69
69
  type: "toggle",
70
70
  name: "value",
71
71
  message: t,
@@ -79,7 +79,7 @@ class k {
79
79
  const n = [];
80
80
  for (const o of e)
81
81
  typeof o == "string" ? n.push({ title: o, value: o }) : n.push(o);
82
- return (await f({
82
+ return (await y({
83
83
  type: "select",
84
84
  name: "value",
85
85
  message: t,
@@ -104,10 +104,10 @@ class k {
104
104
  };
105
105
  }
106
106
  }
107
- class y extends Error {
107
+ class f extends Error {
108
108
  $type = "BobError";
109
109
  }
110
- function x(r) {
110
+ function F(r) {
111
111
  if (r === "string" || r === "number") return null;
112
112
  if (r === "boolean") return !1;
113
113
  if (Array.isArray(r) && r.length === 1) {
@@ -117,7 +117,7 @@ function x(r) {
117
117
  throw new Error("Invalid option type: " + r);
118
118
  }
119
119
  function E(r) {
120
- return typeof r == "string" || Array.isArray(r) ? x(r) : r.default !== void 0 ? r.default : x(r.type);
120
+ return typeof r == "string" || Array.isArray(r) ? F(r) : r.default !== void 0 ? r.default : F(r.type);
121
121
  }
122
122
  function g(r) {
123
123
  return typeof r == "string" || Array.isArray(r) ? {
@@ -138,7 +138,7 @@ function g(r) {
138
138
  variadic: r.variadic ?? !1
139
139
  };
140
140
  }
141
- class v extends y {
141
+ class b extends f {
142
142
  constructor(t, e = {}) {
143
143
  super(`Invalid option ${t} in not recognized`), this.option = t, this.optionsSchema = e;
144
144
  }
@@ -156,7 +156,7 @@ ${a.yellow("Available options")}:`);
156
156
  t.log(`${a.white.bgRed(" ERROR ")} Option ${a.bold.yellow(this.option)} is not recognized.`);
157
157
  }
158
158
  }
159
- class F extends y {
159
+ class k extends f {
160
160
  constructor(t) {
161
161
  super(`Argument "${t}" is required.`), this.argument = t;
162
162
  }
@@ -164,7 +164,7 @@ class F extends y {
164
164
  t.log(`${a.white.bgRed(" ERROR ")} Argument ${a.bold.yellow(this.argument)} is required.`);
165
165
  }
166
166
  }
167
- class P extends y {
167
+ class D extends f {
168
168
  constructor(t) {
169
169
  super(`Argument "${t}" is required.`), this.option = t;
170
170
  }
@@ -172,7 +172,7 @@ class P extends y {
172
172
  t.log(`${a.white.bgRed(" ERROR ")} Option ${a.bold.yellow(this.option)} is required.`);
173
173
  }
174
174
  }
175
- class K extends y {
175
+ class Q extends f {
176
176
  constructor(t) {
177
177
  let e = `Argument "${t.param}" value is invalid.`;
178
178
  t.reason ? e += ` Reason: ${t.reason}` : e += ` Value: "${t.value}"`, super(e), this.param = t;
@@ -181,7 +181,7 @@ class K extends y {
181
181
  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}`);
182
182
  }
183
183
  }
184
- class b extends y {
184
+ class C extends f {
185
185
  constructor(t) {
186
186
  let e = `Option "${t.option}" value is invalid.`;
187
187
  t.reason ? e += ` Reason: ${t.reason}` : e += ` Value: "${t.value}"`, super(e), this.param = t;
@@ -190,7 +190,7 @@ class b extends y {
190
190
  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}`);
191
191
  }
192
192
  }
193
- class H extends y {
193
+ class H extends f {
194
194
  constructor(t) {
195
195
  super(`Command "${t}" not found.`), this.command = t;
196
196
  }
@@ -198,6 +198,16 @@ class H extends y {
198
198
  t.log(`${a.bgRed(" ERROR ")} Command ${a.yellow(this.command)} not found.`);
199
199
  }
200
200
  }
201
+ class P extends f {
202
+ constructor(t, e) {
203
+ super(`Too many arguments provided. Expected ${t}, got ${e}.`), this.expected = t, this.received = e;
204
+ }
205
+ pretty(t) {
206
+ t.log(
207
+ `${a.white.bgRed(" ERROR ")} Too many arguments provided. Expected ${a.bold.yellow(String(this.expected))}, got ${a.bold.yellow(String(this.received))}.`
208
+ );
209
+ }
210
+ }
201
211
  function w(r, t, e, i) {
202
212
  if (r == null)
203
213
  return i ?? null;
@@ -206,7 +216,7 @@ function w(r, t, e, i) {
206
216
  if (t === "number") {
207
217
  const n = Number(r);
208
218
  if (isNaN(n))
209
- throw new b({
219
+ throw new C({
210
220
  option: e,
211
221
  reason: `Expected a number, got "${r}"`
212
222
  });
@@ -222,7 +232,7 @@ function w(r, t, e, i) {
222
232
  return s.map((o) => {
223
233
  const u = Number(o);
224
234
  if (isNaN(u))
225
- throw new b({
235
+ throw new C({
226
236
  option: e,
227
237
  reason: `Expected array of numbers, got "${o}" in array`
228
238
  });
@@ -238,6 +248,8 @@ class N {
238
248
  parsedArguments = null;
239
249
  io;
240
250
  shouldPromptForMissingOptions = !0;
251
+ shouldValidateUnknownOptions = !0;
252
+ shouldRejectExtraArguments = !1;
241
253
  constructor(t) {
242
254
  this.options = t.options, this.arguments = t.arguments, this.io = t.io;
243
255
  }
@@ -250,8 +262,8 @@ class N {
250
262
  * @throws {BadCommandOption} If a value cannot be converted to the expected type
251
263
  */
252
264
  init(t) {
253
- const { _: e, ...i } = I(t);
254
- return this.validateUnknownOptions(i), this.parsedOptions = this.handleOptions(i), this.parsedArguments = this.handleArguments(e), {
265
+ const { _: e, ...i } = q(t);
266
+ return this.shouldValidateUnknownOptions && this.validateUnknownOptions(i), this.parsedOptions = this.handleOptions(i), this.parsedArguments = this.handleArguments(e), {
255
267
  options: this.parsedOptions,
256
268
  arguments: this.parsedArguments
257
269
  };
@@ -263,7 +275,7 @@ class N {
263
275
  async validate() {
264
276
  for (const t in this.options)
265
277
  if (g(this.options[t]).required && (this.parsedOptions?.[t] === void 0 || this.parsedOptions?.[t] === null))
266
- throw new P(t);
278
+ throw new D(t);
267
279
  for (const t in this.arguments) {
268
280
  const e = g(this.arguments[t]), i = this.parsedArguments?.[t];
269
281
  if (e.required && i == null) {
@@ -274,7 +286,7 @@ class N {
274
286
  continue;
275
287
  }
276
288
  }
277
- throw new F(t);
289
+ throw new k(t);
278
290
  }
279
291
  if (e.required && e.variadic && Array.isArray(i) && i.length === 0) {
280
292
  if (this.shouldPromptForMissingOptions) {
@@ -284,7 +296,7 @@ class N {
284
296
  continue;
285
297
  }
286
298
  }
287
- throw new F(t);
299
+ throw new k(t);
288
300
  }
289
301
  }
290
302
  }
@@ -304,7 +316,7 @@ class N {
304
316
  if (!this.parsedOptions)
305
317
  throw new Error("Options have not been parsed yet. Call init() first.");
306
318
  if (!(t in this.options))
307
- throw new v(t, this.options);
319
+ throw new b(t, this.options);
308
320
  this.parsedOptions[t] = e;
309
321
  }
310
322
  /**
@@ -323,7 +335,7 @@ class N {
323
335
  if (!this.parsedArguments)
324
336
  throw new Error("Arguments have not been parsed yet. Call init() first.");
325
337
  if (!(t in this.arguments))
326
- throw new v(t, this.arguments);
338
+ throw new b(t, this.arguments);
327
339
  this.parsedArguments[t] = e;
328
340
  }
329
341
  // === PRIVATE HELPERS ===
@@ -349,7 +361,7 @@ class N {
349
361
  }
350
362
  for (const i in t)
351
363
  if (!e.has(i))
352
- throw new v(i, this.options);
364
+ throw new b(i, this.options);
353
365
  }
354
366
  /**
355
367
  * Processes named options from minimist output
@@ -366,15 +378,17 @@ class N {
366
378
  * Processes positional arguments from minimist output
367
379
  */
368
380
  handleArguments(t) {
369
- const e = {}, i = [...t];
370
- for (const n in this.arguments) {
371
- const s = g(this.arguments[n]);
372
- if (s.variadic) {
373
- e[n] = this.handleVariadicArgument(n, s, i);
381
+ const e = {}, i = [...t], n = Object.keys(this.arguments).length;
382
+ for (const s in this.arguments) {
383
+ const o = g(this.arguments[s]);
384
+ if (o.variadic) {
385
+ e[s] = this.handleVariadicArgument(s, o, i), i.length = 0;
374
386
  continue;
375
387
  }
376
- e[n] = this.resolveArgumentValue(n, s, i.shift());
388
+ e[s] = this.resolveArgumentValue(s, o, i.shift());
377
389
  }
390
+ if (this.shouldRejectExtraArguments && i.length > 0)
391
+ throw new P(n, n + i.length);
378
392
  return e;
379
393
  }
380
394
  /**
@@ -404,7 +418,7 @@ class N {
404
418
  }
405
419
  if (n === void 0) {
406
420
  if (e.required)
407
- throw new b({
421
+ throw new C({
408
422
  option: t,
409
423
  reason: "Required option is missing"
410
424
  });
@@ -437,6 +451,12 @@ class N {
437
451
  disablePrompting() {
438
452
  return this.shouldPromptForMissingOptions = !1, this;
439
453
  }
454
+ allowUnknownOptions() {
455
+ return this.shouldValidateUnknownOptions = !1, this;
456
+ }
457
+ strictMode() {
458
+ return this.shouldRejectExtraArguments = !0, this;
459
+ }
440
460
  /**
441
461
  * Prompts the user to provide a missing argument value via CommandIO
442
462
  * Used by validate() when shouldPromptForMissingArgs is enabled
@@ -478,10 +498,10 @@ class N {
478
498
  });
479
499
  }
480
500
  }
481
- function C(r) {
501
+ function O(r) {
482
502
  return new Array(r + 5).join(" ");
483
503
  }
484
- class D {
504
+ class M {
485
505
  type = "boolean";
486
506
  option = "help";
487
507
  alias = ["h"];
@@ -503,11 +523,11 @@ class D {
503
523
  this.io.log(`
504
524
  ${a.yellow("Arguments")}:`);
505
525
  for (const [l, d] of i) {
506
- const p = C(h - l.length);
526
+ const p = O(h - l.length);
507
527
  let c = ` ${a.green(l)} ${p} ${d.description ?? "\b"}`;
508
528
  if (d.default !== void 0 && !d.required) {
509
- const q = (Array.isArray(d.type) ? `[${d.type[0]}]` : d.type) === "array" || Array.isArray(d.type) ? JSON.stringify(d.default) : d.default;
510
- c += ` ${a.yellow(`[default: ${q}]`)}`;
529
+ const L = (Array.isArray(d.type) ? `[${d.type[0]}]` : d.type) === "array" || Array.isArray(d.type) ? JSON.stringify(d.default) : d.default;
530
+ c += ` ${a.yellow(`[default: ${L}]`)}`;
511
531
  }
512
532
  d.variadic && (c += ` ${a.white("(variadic)")}`), this.io.log(c);
513
533
  }
@@ -516,15 +536,15 @@ ${a.yellow("Arguments")}:`);
516
536
  this.io.log(`
517
537
  ${a.yellow("Options")}:`);
518
538
  for (const l of s) {
519
- const d = C(h - l.optionWithAlias.length);
539
+ const d = O(h - l.optionWithAlias.length);
520
540
  let p = `${a.green(l.optionWithAlias)} ${d} ${l.description ?? "\b"}`;
521
541
  if (l.type) {
522
542
  const c = Array.isArray(l.type) ? `[${l.type[0]}]` : l.type;
523
543
  p += ` ${a.white(`(${c})`)}`;
524
544
  }
525
545
  if (l.default !== void 0 && !l.required) {
526
- const O = (Array.isArray(l.type) ? `[${l.type[0]}]` : l.type) === "array" || Array.isArray(l.type) ? JSON.stringify(l.default) : l.default;
527
- p += ` ${a.yellow(`[default: ${O}]`)}`;
546
+ const R = (Array.isArray(l.type) ? `[${l.type[0]}]` : l.type) === "array" || Array.isArray(l.type) ? JSON.stringify(l.default) : l.default;
547
+ p += ` ${a.yellow(`[default: ${R}]`)}`;
528
548
  }
529
549
  this.io.log(p);
530
550
  }
@@ -554,11 +574,15 @@ class A {
554
574
  io;
555
575
  parser;
556
576
  disablePromptingFlag = !1;
577
+ allowUnknownOptionsFlag = !1;
578
+ hiddenFlag = !1;
579
+ disableDefaultOptionsFlag = !1;
580
+ strictModeFlag = !1;
557
581
  _preHandler;
558
582
  _handler;
559
583
  tmp;
560
584
  defaultOptions() {
561
- return [new D()];
585
+ return this.disableDefaultOptionsFlag ? [] : [new M()];
562
586
  }
563
587
  newCommandParser(t) {
564
588
  return new N({
@@ -568,7 +592,7 @@ class A {
568
592
  });
569
593
  }
570
594
  newCommandIO(t) {
571
- return new k(t);
595
+ return new S(t);
572
596
  }
573
597
  constructor(t, e) {
574
598
  this._command = t, this.description = e?.description ?? "", this.group = e?.group, this.tmp = {
@@ -583,6 +607,21 @@ class A {
583
607
  disablePrompting() {
584
608
  return this.disablePromptingFlag = !0, this;
585
609
  }
610
+ allowUnknownOptions() {
611
+ return this.allowUnknownOptionsFlag = !0, this;
612
+ }
613
+ hidden() {
614
+ return this.hiddenFlag = !0, this;
615
+ }
616
+ get isHidden() {
617
+ return this.hiddenFlag;
618
+ }
619
+ disableDefaultOptions() {
620
+ return this.disableDefaultOptionsFlag = !0, this;
621
+ }
622
+ strictMode() {
623
+ return this.strictModeFlag = !0, this;
624
+ }
586
625
  preHandler(t) {
587
626
  return this._preHandler = t, this;
588
627
  }
@@ -621,7 +660,7 @@ class A {
621
660
  io: this.io,
622
661
  options: n,
623
662
  arguments: this.tmp?.arguments ?? {}
624
- }), e = this.parser.init(t.args);
663
+ }), this.allowUnknownOptionsFlag && this.parser.allowUnknownOptions(), this.strictModeFlag && this.parser.strictMode(), e = this.parser.init(t.args);
625
664
  for (const s of this.defaultOptions())
626
665
  if (e.options[s.option] === !0) {
627
666
  const o = await s.handler.call(this);
@@ -719,7 +758,7 @@ class $ extends N {
719
758
  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 };
720
759
  }
721
760
  }
722
- class Q extends A {
761
+ class X extends A {
723
762
  helperDefinitions = {};
724
763
  get command() {
725
764
  return this.parser ? this.parser.command : this.signature.split(" ")[0];
@@ -755,7 +794,7 @@ class Q extends A {
755
794
  return this.io.newLoader(...t);
756
795
  }
757
796
  }
758
- class L {
797
+ class V {
759
798
  level;
760
799
  constructor(t = {}) {
761
800
  this.level = t.level ?? "info";
@@ -826,22 +865,22 @@ class B {
826
865
  };
827
866
  }
828
867
  }
829
- function W(r) {
868
+ function j(r) {
830
869
  return typeof r == "object" && r !== null && "$type" in r && r.$type === "BobError";
831
870
  }
832
- function S(r) {
871
+ function v(r) {
833
872
  return typeof r == "object" && r !== null && (r instanceof A || "$type" in r && r.$type === "BobCommand");
834
873
  }
835
- class M {
874
+ class T {
836
875
  commands = {};
837
876
  io;
838
877
  logger;
839
878
  stringSimilarity;
840
879
  newCommandIO(t) {
841
- return new k(t);
880
+ return new S(t);
842
881
  }
843
882
  constructor(t) {
844
- this.logger = t?.logger ?? new L(), this.io = this.newCommandIO({
883
+ this.logger = t?.logger ?? new V(), this.io = this.newCommandIO({
845
884
  logger: this.logger
846
885
  }), this.stringSimilarity = t?.stringSimilarity ?? new B();
847
886
  }
@@ -854,7 +893,7 @@ class M {
854
893
  importFile = async (t) => (await import(t)).default;
855
894
  commandResolver = async (t) => {
856
895
  let e = await this.importFile(t);
857
- return e ? (e && typeof e == "object" && "default" in e && (e = e.default), typeof e == "function" ? new e() : S(e) ? e : null) : null;
896
+ return e ? (e && typeof e == "object" && "default" in e && (e = e.default), typeof e == "function" ? new e() : v(e) ? e : null) : null;
858
897
  };
859
898
  withCommandResolver(t) {
860
899
  return this.commandResolver = t, this;
@@ -863,9 +902,11 @@ class M {
863
902
  return this.importFile = t, this;
864
903
  }
865
904
  registerCommand(t, e = !1) {
905
+ if (!v(t))
906
+ throw new Error("Invalid command, it must extend the Command class.");
866
907
  const i = t.command;
867
908
  if (!i)
868
- throw new Error("Command signature is invalid, it must have a command name.");
909
+ throw new Error("Cannot register a command with no name.");
869
910
  if (!e && this.commands[i])
870
911
  throw new Error(`Command ${i} already registered.`);
871
912
  this.commands[i] = t;
@@ -874,7 +915,7 @@ class M {
874
915
  for await (const e of this.listCommandsFiles(t))
875
916
  try {
876
917
  const i = await this.commandResolver(e);
877
- S(i) && this.registerCommand(i);
918
+ v(i) && this.registerCommand(i);
878
919
  } catch (i) {
879
920
  throw new Error(`Command ${e} failed to load. ${i}`, {
880
921
  cause: i
@@ -913,11 +954,11 @@ class M {
913
954
  `), this.io.askForConfirmation(`${a.green(`Do you want to run ${a.yellow(e)} instead?`)} `);
914
955
  }
915
956
  async *listCommandsFiles(t) {
916
- const e = V.readdirSync(t, { withFileTypes: !0 });
957
+ const e = I.readdirSync(t, { withFileTypes: !0 });
917
958
  for (const i of e) {
918
- const n = R.resolve(t, i.name);
959
+ const n = x.resolve(t, i.name);
919
960
  if (i.isDirectory())
920
- yield* this.listCommandsFiles(R.resolve(t, i.name));
961
+ yield* this.listCommandsFiles(x.resolve(t, i.name));
921
962
  else {
922
963
  if (!n.endsWith(".ts") && !n.endsWith(".js") && !n.endsWith(".mjs") && !n.endsWith(".cjs"))
923
964
  continue;
@@ -926,25 +967,25 @@ class M {
926
967
  }
927
968
  }
928
969
  }
929
- class _ {
970
+ class W {
930
971
  logger;
931
972
  constructor(t) {
932
973
  this.logger = t;
933
974
  }
934
975
  handle(t) {
935
- if (W(t))
976
+ if (j(t))
936
977
  return t.pretty(this.logger), -1;
937
978
  throw t;
938
979
  }
939
980
  }
940
- class j extends A {
981
+ class _ extends A {
941
982
  constructor(t) {
942
983
  super("help", {
943
984
  description: a.bold("Show help information about the CLI and its commands")
944
985
  }), this.opts = t;
945
986
  }
946
987
  async handle() {
947
- const t = this.opts.commandRegistry.getCommands(), e = this.opts.cliName ?? "Bob CLI", i = this.opts.cliVersion ?? "0.0.0", n = (await import("../package-DuYxJEEx.js"))?.default?.version ?? "0.0.0";
988
+ 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 import("../package-uVOgoItG.js"))?.default?.version ?? "0.0.0";
948
989
  this.io.log(`${e} ${a.green(i)} (core: ${a.yellow(n)})
949
990
 
950
991
  ${a.yellow("Usage")}:
@@ -963,29 +1004,29 @@ ${a.yellow("Available commands")}:
963
1004
  l && this.io.log(a.yellow(`${m}:`));
964
1005
  const d = h.sort((p, c) => p.command.toLowerCase().localeCompare(c.command.toLowerCase()));
965
1006
  for (const p of d) {
966
- let c = C(s - p.command.length);
1007
+ let c = O(s - p.command.length);
967
1008
  l && (c = c.slice(2)), this.io.log(`${l ? " " : ""}${a.green(p.command)} ${c} ${p.description}`);
968
1009
  }
969
1010
  }
970
1011
  }
971
1012
  }
972
- class X {
1013
+ class Y {
973
1014
  ctx;
974
1015
  logger;
975
1016
  commandRegistry;
976
1017
  exceptionHandler;
977
1018
  helpCommand;
978
1019
  newCommandRegistry(t) {
979
- return new M(t);
1020
+ return new T(t);
980
1021
  }
981
1022
  newHelpCommand(t) {
982
- return new j(t);
1023
+ return new _(t);
983
1024
  }
984
1025
  newExceptionHandler(t) {
985
- return new _(t.logger);
1026
+ return new W(t.logger);
986
1027
  }
987
1028
  constructor(t = {}) {
988
- this.ctx = t.ctx, this.logger = t.logger ?? new L(), this.commandRegistry = this.newCommandRegistry({
1029
+ this.ctx = t.ctx, this.logger = t.logger ?? new V(), this.commandRegistry = this.newCommandRegistry({
989
1030
  logger: this.logger
990
1031
  }), this.exceptionHandler = this.newExceptionHandler({
991
1032
  logger: this.logger
@@ -1016,22 +1057,23 @@ class X {
1016
1057
  }
1017
1058
  }
1018
1059
  export {
1019
- b as BadCommandOption,
1020
- K as BadCommandParameter,
1021
- y as BobError,
1022
- X as Cli,
1060
+ C as BadCommandOption,
1061
+ Q as BadCommandParameter,
1062
+ f as BobError,
1063
+ Y as Cli,
1023
1064
  A as Command,
1024
- k as CommandIO,
1065
+ S as CommandIO,
1025
1066
  H as CommandNotFoundError,
1026
1067
  N as CommandParser,
1027
- M as CommandRegistry,
1068
+ T as CommandRegistry,
1028
1069
  $ as CommandSignatureParser,
1029
- Q as CommandWithSignature,
1030
- _ as ExceptionHandler,
1031
- D as HelpOption,
1032
- v as InvalidOption,
1033
- L as Logger,
1034
- F as MissingRequiredArgumentValue,
1035
- P as MissingRequiredOptionValue,
1036
- B as StringSimilarity
1070
+ X as CommandWithSignature,
1071
+ W as ExceptionHandler,
1072
+ M as HelpOption,
1073
+ b as InvalidOption,
1074
+ V as Logger,
1075
+ k as MissingRequiredArgumentValue,
1076
+ D as MissingRequiredOptionValue,
1077
+ B as StringSimilarity,
1078
+ P as TooManyArguments
1037
1079
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bob-core",
3
- "version": "2.0.2",
3
+ "version": "2.1.0",
4
4
  "description": "BOB Core",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/src/index.js",