bob-core 2.0.1 → 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.1",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;
@@ -22,6 +22,7 @@ export type CommandExample = {
22
22
  command: string;
23
23
  };
24
24
  export declare class Command<C extends ContextDefinition = ContextDefinition, Options extends OptionsSchema = OptionsSchema, Arguments extends ArgumentsSchema = ArgumentsSchema> {
25
+ $type: "BobCommand";
25
26
  readonly _command: string;
26
27
  readonly description: string;
27
28
  readonly group?: string;
@@ -31,6 +32,10 @@ export declare class Command<C extends ContextDefinition = ContextDefinition, Op
31
32
  protected io: CommandIO;
32
33
  protected parser: CommandParser<Options, Arguments>;
33
34
  protected disablePromptingFlag: boolean;
35
+ protected allowUnknownOptionsFlag: boolean;
36
+ protected hiddenFlag: boolean;
37
+ protected disableDefaultOptionsFlag: boolean;
38
+ protected strictModeFlag: boolean;
34
39
  protected preHandle?(): Promise<void | number>;
35
40
  protected _preHandler?: CommandHandler<C, Options, Arguments>;
36
41
  protected handle?(ctx: C, opts: CommandHandlerOptions<Options, Arguments>): Promise<number | void> | number | void;
@@ -50,6 +55,11 @@ export declare class Command<C extends ContextDefinition = ContextDefinition, Op
50
55
  arguments?: Arguments;
51
56
  });
52
57
  disablePrompting(): this;
58
+ allowUnknownOptions(): this;
59
+ hidden(): this;
60
+ get isHidden(): boolean;
61
+ disableDefaultOptions(): this;
62
+ strictMode(): this;
53
63
  preHandler(handler: CommandHandler<C, Options, Arguments>): this;
54
64
  handler(handler: CommandHandler<C, Options, Arguments>): this;
55
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
@@ -1,7 +1,6 @@
1
1
  import { Logger } from './Logger.js';
2
- import { BobError } from './errors/index.js';
3
2
  export declare class ExceptionHandler {
4
3
  private readonly logger;
5
4
  constructor(logger: Logger);
6
- handle(err: Error | BobError): number;
5
+ handle(err: Error): number;
7
6
  }
@@ -1,4 +1,5 @@
1
1
  import { Logger } from '../Logger.js';
2
2
  export declare abstract class BobError extends Error {
3
+ $type: "BobError";
3
4
  abstract pretty(logger: Logger): void;
4
5
  }
@@ -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"),j=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{}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 b 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 N 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 C 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.`)}}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 C({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 C({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 N(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 b(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 b(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 b(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 C({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 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),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 E=(Array.isArray(l.type)?`[${l.type[0]}]`:l.type)==="array"||Array.isArray(l.type)?JSON.stringify(l.default):l.default;c+=` ${a.yellow(`[default: ${E}]`)}`}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 v{_command;description;group;commandsExamples=[];get command(){return this._command}ctx;io;parser;disablePromptingFlag=!1;_preHandler;_handler;tmp;defaultOptions(){return[new L]}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 $ extends x{command;constructor(t){const e=$.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}=$.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 B extends v{helperDefinitions={};get command(){return this.parser?this.parser.command:this.signature.split(" ")[0]}newCommandParser(t){return new $({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 S{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 I{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}}}class V{commands={};io;logger;stringSimilarity;newCommandIO(t){return new R(t)}constructor(t){this.logger=t?.logger??new S,this.io=this.newCommandIO({logger:this.logger}),this.stringSimilarity=t?.stringSimilarity??new I}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:e instanceof v?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);i instanceof v&&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.
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
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=j.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 H{logger;constructor(t){this.logger=t}handle(t){if(t instanceof f)return t.pretty(this.logger),-1;throw t}}class T extends v{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-DO_9Y5-u.cjs")))?.default?.version??"0.0.0";this.io.log(`${e} ${a.green(i)} (core: ${a.yellow(n)})
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 _{ctx;logger;commandRegistry;exceptionHandler;helpCommand;newCommandRegistry(t){return new V(t)}newHelpCommand(t){return new T(t)}newExceptionHandler(t){return new H(t.logger)}constructor(t={}){this.ctx=t.ctx,this.logger=t.logger??new S,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=C;exports.BadCommandParameter=W;exports.BobError=f;exports.Cli=_;exports.Command=v;exports.CommandIO=R;exports.CommandNotFoundError=P;exports.CommandParser=x;exports.CommandRegistry=V;exports.CommandSignatureParser=$;exports.CommandWithSignature=B;exports.ExceptionHandler=H;exports.HelpOption=L;exports.InvalidOption=b;exports.Logger=S;exports.MissingRequiredArgumentValue=A;exports.MissingRequiredOptionValue=N;exports.StringSimilarity=I;
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;
@@ -0,0 +1,4 @@
1
+ import { Command } from '../Command.js';
2
+ import { BobError } from '../errors/index.js';
3
+ export declare function isBobError(err: Error): err is BobError;
4
+ export declare function isBobCommand(obj: unknown): obj is Command;
@@ -1,4 +1,4 @@
1
- const t = "bob-core", s = "2.0.1", 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,
@@ -22,6 +22,7 @@ export type CommandExample = {
22
22
  command: string;
23
23
  };
24
24
  export declare class Command<C extends ContextDefinition = ContextDefinition, Options extends OptionsSchema = OptionsSchema, Arguments extends ArgumentsSchema = ArgumentsSchema> {
25
+ $type: "BobCommand";
25
26
  readonly _command: string;
26
27
  readonly description: string;
27
28
  readonly group?: string;
@@ -31,6 +32,10 @@ export declare class Command<C extends ContextDefinition = ContextDefinition, Op
31
32
  protected io: CommandIO;
32
33
  protected parser: CommandParser<Options, Arguments>;
33
34
  protected disablePromptingFlag: boolean;
35
+ protected allowUnknownOptionsFlag: boolean;
36
+ protected hiddenFlag: boolean;
37
+ protected disableDefaultOptionsFlag: boolean;
38
+ protected strictModeFlag: boolean;
34
39
  protected preHandle?(): Promise<void | number>;
35
40
  protected _preHandler?: CommandHandler<C, Options, Arguments>;
36
41
  protected handle?(ctx: C, opts: CommandHandlerOptions<Options, Arguments>): Promise<number | void> | number | void;
@@ -50,6 +55,11 @@ export declare class Command<C extends ContextDefinition = ContextDefinition, Op
50
55
  arguments?: Arguments;
51
56
  });
52
57
  disablePrompting(): this;
58
+ allowUnknownOptions(): this;
59
+ hidden(): this;
60
+ get isHidden(): boolean;
61
+ disableDefaultOptions(): this;
62
+ strictMode(): this;
53
63
  preHandler(handler: CommandHandler<C, Options, Arguments>): this;
54
64
  handler(handler: CommandHandler<C, Options, Arguments>): this;
55
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
@@ -1,7 +1,6 @@
1
1
  import { Logger } from './Logger.js';
2
- import { BobError } from './errors/index.js';
3
2
  export declare class ExceptionHandler {
4
3
  private readonly logger;
5
4
  constructor(logger: Logger);
6
- handle(err: Error | BobError): number;
5
+ handle(err: Error): number;
7
6
  }
@@ -1,4 +1,5 @@
1
1
  import { Logger } from '../Logger.js';
2
2
  export declare abstract class BobError extends Error {
3
+ $type: "BobError";
3
4
  abstract pretty(logger: Logger): void;
4
5
  }
@@ -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';
@@ -2,7 +2,7 @@ import y from "prompts";
2
2
  import a from "chalk";
3
3
  import q from "minimist";
4
4
  import I from "node:fs";
5
- import R from "node:path";
5
+ import x from "node:path";
6
6
  class S {
7
7
  logger;
8
8
  constructor(t) {
@@ -105,8 +105,9 @@ class S {
105
105
  }
106
106
  }
107
107
  class f extends Error {
108
+ $type = "BobError";
108
109
  }
109
- function x(r) {
110
+ function F(r) {
110
111
  if (r === "string" || r === "number") return null;
111
112
  if (r === "boolean") return !1;
112
113
  if (Array.isArray(r) && r.length === 1) {
@@ -116,7 +117,7 @@ function x(r) {
116
117
  throw new Error("Invalid option type: " + r);
117
118
  }
118
119
  function E(r) {
119
- 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);
120
121
  }
121
122
  function g(r) {
122
123
  return typeof r == "string" || Array.isArray(r) ? {
@@ -155,7 +156,7 @@ ${a.yellow("Available options")}:`);
155
156
  t.log(`${a.white.bgRed(" ERROR ")} Option ${a.bold.yellow(this.option)} is not recognized.`);
156
157
  }
157
158
  }
158
- class F extends f {
159
+ class k extends f {
159
160
  constructor(t) {
160
161
  super(`Argument "${t}" is required.`), this.argument = t;
161
162
  }
@@ -163,7 +164,7 @@ class F extends f {
163
164
  t.log(`${a.white.bgRed(" ERROR ")} Argument ${a.bold.yellow(this.argument)} is required.`);
164
165
  }
165
166
  }
166
- class V extends f {
167
+ class D extends f {
167
168
  constructor(t) {
168
169
  super(`Argument "${t}" is required.`), this.option = t;
169
170
  }
@@ -171,7 +172,7 @@ class V extends f {
171
172
  t.log(`${a.white.bgRed(" ERROR ")} Option ${a.bold.yellow(this.option)} is required.`);
172
173
  }
173
174
  }
174
- class z extends f {
175
+ class Q extends f {
175
176
  constructor(t) {
176
177
  let e = `Argument "${t.param}" value is invalid.`;
177
178
  t.reason ? e += ` Reason: ${t.reason}` : e += ` Value: "${t.value}"`, super(e), this.param = t;
@@ -189,7 +190,7 @@ class C extends f {
189
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}`);
190
191
  }
191
192
  }
192
- class P extends f {
193
+ class H extends f {
193
194
  constructor(t) {
194
195
  super(`Command "${t}" not found.`), this.command = t;
195
196
  }
@@ -197,6 +198,16 @@ class P extends f {
197
198
  t.log(`${a.bgRed(" ERROR ")} Command ${a.yellow(this.command)} not found.`);
198
199
  }
199
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
+ }
200
211
  function w(r, t, e, i) {
201
212
  if (r == null)
202
213
  return i ?? null;
@@ -230,13 +241,15 @@ function w(r, t, e, i) {
230
241
  }
231
242
  return r;
232
243
  }
233
- class k {
244
+ class N {
234
245
  options;
235
246
  parsedOptions = null;
236
247
  arguments;
237
248
  parsedArguments = null;
238
249
  io;
239
250
  shouldPromptForMissingOptions = !0;
251
+ shouldValidateUnknownOptions = !0;
252
+ shouldRejectExtraArguments = !1;
240
253
  constructor(t) {
241
254
  this.options = t.options, this.arguments = t.arguments, this.io = t.io;
242
255
  }
@@ -250,7 +263,7 @@ class k {
250
263
  */
251
264
  init(t) {
252
265
  const { _: e, ...i } = q(t);
253
- return this.validateUnknownOptions(i), this.parsedOptions = this.handleOptions(i), this.parsedArguments = this.handleArguments(e), {
266
+ return this.shouldValidateUnknownOptions && this.validateUnknownOptions(i), this.parsedOptions = this.handleOptions(i), this.parsedArguments = this.handleArguments(e), {
254
267
  options: this.parsedOptions,
255
268
  arguments: this.parsedArguments
256
269
  };
@@ -262,7 +275,7 @@ class k {
262
275
  async validate() {
263
276
  for (const t in this.options)
264
277
  if (g(this.options[t]).required && (this.parsedOptions?.[t] === void 0 || this.parsedOptions?.[t] === null))
265
- throw new V(t);
278
+ throw new D(t);
266
279
  for (const t in this.arguments) {
267
280
  const e = g(this.arguments[t]), i = this.parsedArguments?.[t];
268
281
  if (e.required && i == null) {
@@ -273,7 +286,7 @@ class k {
273
286
  continue;
274
287
  }
275
288
  }
276
- throw new F(t);
289
+ throw new k(t);
277
290
  }
278
291
  if (e.required && e.variadic && Array.isArray(i) && i.length === 0) {
279
292
  if (this.shouldPromptForMissingOptions) {
@@ -283,7 +296,7 @@ class k {
283
296
  continue;
284
297
  }
285
298
  }
286
- throw new F(t);
299
+ throw new k(t);
287
300
  }
288
301
  }
289
302
  }
@@ -365,15 +378,17 @@ class k {
365
378
  * Processes positional arguments from minimist output
366
379
  */
367
380
  handleArguments(t) {
368
- const e = {}, i = [...t];
369
- for (const n in this.arguments) {
370
- const s = g(this.arguments[n]);
371
- if (s.variadic) {
372
- 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;
373
386
  continue;
374
387
  }
375
- e[n] = this.resolveArgumentValue(n, s, i.shift());
388
+ e[s] = this.resolveArgumentValue(s, o, i.shift());
376
389
  }
390
+ if (this.shouldRejectExtraArguments && i.length > 0)
391
+ throw new P(n, n + i.length);
377
392
  return e;
378
393
  }
379
394
  /**
@@ -436,6 +451,12 @@ class k {
436
451
  disablePrompting() {
437
452
  return this.shouldPromptForMissingOptions = !1, this;
438
453
  }
454
+ allowUnknownOptions() {
455
+ return this.shouldValidateUnknownOptions = !1, this;
456
+ }
457
+ strictMode() {
458
+ return this.shouldRejectExtraArguments = !0, this;
459
+ }
439
460
  /**
440
461
  * Prompts the user to provide a missing argument value via CommandIO
441
462
  * Used by validate() when shouldPromptForMissingArgs is enabled
@@ -477,10 +498,10 @@ class k {
477
498
  });
478
499
  }
479
500
  }
480
- function A(r) {
501
+ function O(r) {
481
502
  return new Array(r + 5).join(" ");
482
503
  }
483
- class H {
504
+ class M {
484
505
  type = "boolean";
485
506
  option = "help";
486
507
  alias = ["h"];
@@ -502,7 +523,7 @@ class H {
502
523
  this.io.log(`
503
524
  ${a.yellow("Arguments")}:`);
504
525
  for (const [l, d] of i) {
505
- const p = A(h - l.length);
526
+ const p = O(h - l.length);
506
527
  let c = ` ${a.green(l)} ${p} ${d.description ?? "\b"}`;
507
528
  if (d.default !== void 0 && !d.required) {
508
529
  const L = (Array.isArray(d.type) ? `[${d.type[0]}]` : d.type) === "array" || Array.isArray(d.type) ? JSON.stringify(d.default) : d.default;
@@ -515,15 +536,15 @@ ${a.yellow("Arguments")}:`);
515
536
  this.io.log(`
516
537
  ${a.yellow("Options")}:`);
517
538
  for (const l of s) {
518
- const d = A(h - l.optionWithAlias.length);
539
+ const d = O(h - l.optionWithAlias.length);
519
540
  let p = `${a.green(l.optionWithAlias)} ${d} ${l.description ?? "\b"}`;
520
541
  if (l.type) {
521
542
  const c = Array.isArray(l.type) ? `[${l.type[0]}]` : l.type;
522
543
  p += ` ${a.white(`(${c})`)}`;
523
544
  }
524
545
  if (l.default !== void 0 && !l.required) {
525
- const O = (Array.isArray(l.type) ? `[${l.type[0]}]` : l.type) === "array" || Array.isArray(l.type) ? JSON.stringify(l.default) : l.default;
526
- 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}]`)}`;
527
548
  }
528
549
  this.io.log(p);
529
550
  }
@@ -540,7 +561,8 @@ ${a.yellow("Examples")}:`);
540
561
  return -1;
541
562
  }
542
563
  }
543
- class v {
564
+ class A {
565
+ $type = "BobCommand";
544
566
  _command;
545
567
  description;
546
568
  group;
@@ -552,14 +574,18 @@ class v {
552
574
  io;
553
575
  parser;
554
576
  disablePromptingFlag = !1;
577
+ allowUnknownOptionsFlag = !1;
578
+ hiddenFlag = !1;
579
+ disableDefaultOptionsFlag = !1;
580
+ strictModeFlag = !1;
555
581
  _preHandler;
556
582
  _handler;
557
583
  tmp;
558
584
  defaultOptions() {
559
- return [new H()];
585
+ return this.disableDefaultOptionsFlag ? [] : [new M()];
560
586
  }
561
587
  newCommandParser(t) {
562
- return new k({
588
+ return new N({
563
589
  io: t.io,
564
590
  options: t.options,
565
591
  arguments: t.arguments
@@ -581,6 +607,21 @@ class v {
581
607
  disablePrompting() {
582
608
  return this.disablePromptingFlag = !0, this;
583
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
+ }
584
625
  preHandler(t) {
585
626
  return this._preHandler = t, this;
586
627
  }
@@ -619,7 +660,7 @@ class v {
619
660
  io: this.io,
620
661
  options: n,
621
662
  arguments: this.tmp?.arguments ?? {}
622
- }), e = this.parser.init(t.args);
663
+ }), this.allowUnknownOptionsFlag && this.parser.allowUnknownOptions(), this.strictModeFlag && this.parser.strictMode(), e = this.parser.init(t.args);
623
664
  for (const s of this.defaultOptions())
624
665
  if (e.options[s.option] === !0) {
625
666
  const o = await s.handler.call(this);
@@ -644,7 +685,7 @@ class v {
644
685
  return await this._handler(t.ctx, e) ?? 0;
645
686
  }
646
687
  }
647
- class $ extends k {
688
+ class $ extends N {
648
689
  command;
649
690
  constructor(t) {
650
691
  const e = $.parseSignature(t.signature, t.helperDefinitions, t.defaultOptions);
@@ -717,7 +758,7 @@ class $ extends k {
717
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 };
718
759
  }
719
760
  }
720
- class J extends v {
761
+ class X extends A {
721
762
  helperDefinitions = {};
722
763
  get command() {
723
764
  return this.parser ? this.parser.command : this.signature.split(" ")[0];
@@ -753,7 +794,7 @@ class J extends v {
753
794
  return this.io.newLoader(...t);
754
795
  }
755
796
  }
756
- class N {
797
+ class V {
757
798
  level;
758
799
  constructor(t = {}) {
759
800
  this.level = t.level ?? "info";
@@ -784,7 +825,7 @@ class N {
784
825
  this.shouldLog("debug") && console.log(...t);
785
826
  }
786
827
  }
787
- class D {
828
+ class B {
788
829
  /**
789
830
  * Generate bigrams (character pairs) from a string
790
831
  */
@@ -824,7 +865,13 @@ class D {
824
865
  };
825
866
  }
826
867
  }
827
- class j {
868
+ function j(r) {
869
+ return typeof r == "object" && r !== null && "$type" in r && r.$type === "BobError";
870
+ }
871
+ function v(r) {
872
+ return typeof r == "object" && r !== null && (r instanceof A || "$type" in r && r.$type === "BobCommand");
873
+ }
874
+ class T {
828
875
  commands = {};
829
876
  io;
830
877
  logger;
@@ -833,9 +880,9 @@ class j {
833
880
  return new S(t);
834
881
  }
835
882
  constructor(t) {
836
- this.logger = t?.logger ?? new N(), this.io = this.newCommandIO({
883
+ this.logger = t?.logger ?? new V(), this.io = this.newCommandIO({
837
884
  logger: this.logger
838
- }), this.stringSimilarity = t?.stringSimilarity ?? new D();
885
+ }), this.stringSimilarity = t?.stringSimilarity ?? new B();
839
886
  }
840
887
  getAvailableCommands() {
841
888
  return Object.keys(this.commands);
@@ -846,7 +893,7 @@ class j {
846
893
  importFile = async (t) => (await import(t)).default;
847
894
  commandResolver = async (t) => {
848
895
  let e = await this.importFile(t);
849
- return e ? (e && typeof e == "object" && "default" in e && (e = e.default), typeof e == "function" ? new e() : e instanceof v ? 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;
850
897
  };
851
898
  withCommandResolver(t) {
852
899
  return this.commandResolver = t, this;
@@ -855,9 +902,11 @@ class j {
855
902
  return this.importFile = t, this;
856
903
  }
857
904
  registerCommand(t, e = !1) {
905
+ if (!v(t))
906
+ throw new Error("Invalid command, it must extend the Command class.");
858
907
  const i = t.command;
859
908
  if (!i)
860
- throw new Error("Command signature is invalid, it must have a command name.");
909
+ throw new Error("Cannot register a command with no name.");
861
910
  if (!e && this.commands[i])
862
911
  throw new Error(`Command ${i} already registered.`);
863
912
  this.commands[i] = t;
@@ -866,7 +915,7 @@ class j {
866
915
  for await (const e of this.listCommandsFiles(t))
867
916
  try {
868
917
  const i = await this.commandResolver(e);
869
- i instanceof v && this.registerCommand(i);
918
+ v(i) && this.registerCommand(i);
870
919
  } catch (i) {
871
920
  throw new Error(`Command ${e} failed to load. ${i}`, {
872
921
  cause: i
@@ -898,7 +947,7 @@ class j {
898
947
  if (u)
899
948
  return u;
900
949
  }
901
- throw new P(t);
950
+ throw new H(t);
902
951
  }
903
952
  async askRunSimilarCommand(t, e) {
904
953
  return this.io.error(`${a.bgRed(" ERROR ")} Command ${a.yellow(t)} not found.
@@ -907,9 +956,9 @@ class j {
907
956
  async *listCommandsFiles(t) {
908
957
  const e = I.readdirSync(t, { withFileTypes: !0 });
909
958
  for (const i of e) {
910
- const n = R.resolve(t, i.name);
959
+ const n = x.resolve(t, i.name);
911
960
  if (i.isDirectory())
912
- yield* this.listCommandsFiles(R.resolve(t, i.name));
961
+ yield* this.listCommandsFiles(x.resolve(t, i.name));
913
962
  else {
914
963
  if (!n.endsWith(".ts") && !n.endsWith(".js") && !n.endsWith(".mjs") && !n.endsWith(".cjs"))
915
964
  continue;
@@ -924,19 +973,19 @@ class W {
924
973
  this.logger = t;
925
974
  }
926
975
  handle(t) {
927
- if (t instanceof f)
976
+ if (j(t))
928
977
  return t.pretty(this.logger), -1;
929
978
  throw t;
930
979
  }
931
980
  }
932
- class M extends v {
981
+ class _ extends A {
933
982
  constructor(t) {
934
983
  super("help", {
935
984
  description: a.bold("Show help information about the CLI and its commands")
936
985
  }), this.opts = t;
937
986
  }
938
987
  async handle() {
939
- const t = this.opts.commandRegistry.getCommands(), e = this.opts.cliName ?? "Bob CLI", i = this.opts.cliVersion ?? "0.0.0", n = (await import("../package-Drh2xcXq.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";
940
989
  this.io.log(`${e} ${a.green(i)} (core: ${a.yellow(n)})
941
990
 
942
991
  ${a.yellow("Usage")}:
@@ -955,29 +1004,29 @@ ${a.yellow("Available commands")}:
955
1004
  l && this.io.log(a.yellow(`${m}:`));
956
1005
  const d = h.sort((p, c) => p.command.toLowerCase().localeCompare(c.command.toLowerCase()));
957
1006
  for (const p of d) {
958
- let c = A(s - p.command.length);
1007
+ let c = O(s - p.command.length);
959
1008
  l && (c = c.slice(2)), this.io.log(`${l ? " " : ""}${a.green(p.command)} ${c} ${p.description}`);
960
1009
  }
961
1010
  }
962
1011
  }
963
1012
  }
964
- class K {
1013
+ class Y {
965
1014
  ctx;
966
1015
  logger;
967
1016
  commandRegistry;
968
1017
  exceptionHandler;
969
1018
  helpCommand;
970
1019
  newCommandRegistry(t) {
971
- return new j(t);
1020
+ return new T(t);
972
1021
  }
973
1022
  newHelpCommand(t) {
974
- return new M(t);
1023
+ return new _(t);
975
1024
  }
976
1025
  newExceptionHandler(t) {
977
1026
  return new W(t.logger);
978
1027
  }
979
1028
  constructor(t = {}) {
980
- this.ctx = t.ctx, this.logger = t.logger ?? new N(), this.commandRegistry = this.newCommandRegistry({
1029
+ this.ctx = t.ctx, this.logger = t.logger ?? new V(), this.commandRegistry = this.newCommandRegistry({
981
1030
  logger: this.logger
982
1031
  }), this.exceptionHandler = this.newExceptionHandler({
983
1032
  logger: this.logger
@@ -1009,21 +1058,22 @@ class K {
1009
1058
  }
1010
1059
  export {
1011
1060
  C as BadCommandOption,
1012
- z as BadCommandParameter,
1061
+ Q as BadCommandParameter,
1013
1062
  f as BobError,
1014
- K as Cli,
1015
- v as Command,
1063
+ Y as Cli,
1064
+ A as Command,
1016
1065
  S as CommandIO,
1017
- P as CommandNotFoundError,
1018
- k as CommandParser,
1019
- j as CommandRegistry,
1066
+ H as CommandNotFoundError,
1067
+ N as CommandParser,
1068
+ T as CommandRegistry,
1020
1069
  $ as CommandSignatureParser,
1021
- J as CommandWithSignature,
1070
+ X as CommandWithSignature,
1022
1071
  W as ExceptionHandler,
1023
- H as HelpOption,
1072
+ M as HelpOption,
1024
1073
  b as InvalidOption,
1025
- N as Logger,
1026
- F as MissingRequiredArgumentValue,
1027
- V as MissingRequiredOptionValue,
1028
- D as StringSimilarity
1074
+ V as Logger,
1075
+ k as MissingRequiredArgumentValue,
1076
+ D as MissingRequiredOptionValue,
1077
+ B as StringSimilarity,
1078
+ P as TooManyArguments
1029
1079
  };
@@ -0,0 +1,4 @@
1
+ import { Command } from '../Command.js';
2
+ import { BobError } from '../errors/index.js';
3
+ export declare function isBobError(err: Error): err is BobError;
4
+ export declare function isBobCommand(obj: unknown): obj is Command;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bob-core",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "BOB Core",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/src/index.js",