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.
- package/dist/cjs/{package-DO_9Y5-u.cjs → package-DYSfqWOt.cjs} +1 -1
- package/dist/cjs/src/Command.d.ts +10 -0
- package/dist/cjs/src/CommandParser.d.ts +4 -0
- package/dist/cjs/src/ExceptionHandler.d.ts +1 -2
- package/dist/cjs/src/errors/BobError.d.ts +1 -0
- package/dist/cjs/src/errors/TooManyArguments.d.ts +8 -0
- package/dist/cjs/src/errors/index.d.ts +1 -0
- package/dist/cjs/src/index.js +10 -10
- package/dist/cjs/src/lib/helpers.d.ts +4 -0
- package/dist/esm/{package-Drh2xcXq.js → package-uVOgoItG.js} +1 -1
- package/dist/esm/src/Command.d.ts +10 -0
- package/dist/esm/src/CommandParser.d.ts +4 -0
- package/dist/esm/src/ExceptionHandler.d.ts +1 -2
- package/dist/esm/src/errors/BobError.d.ts +1 -0
- package/dist/esm/src/errors/TooManyArguments.d.ts +8 -0
- package/dist/esm/src/errors/index.d.ts +1 -0
- package/dist/esm/src/index.js +111 -61
- package/dist/esm/src/lib/helpers.d.ts +4 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="bob-core",t="2.0
|
|
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
|
|
@@ -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
|
+
}
|
package/dist/cjs/src/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("prompts"),a=require("chalk"),
|
|
2
|
-
${a.yellow("Available options")}:`);for(const[i,n]of e){const
|
|
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
|
|
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(...
|
|
6
|
-
${a.yellow("Arguments")}:`);for(const[l,d]of i){const
|
|
7
|
-
${a.yellow("Options")}:`);for(const l of
|
|
8
|
-
${a.yellow("Examples")}:`);let l=process.argv[0].split("/").pop();l==="node"&&(l+=" "+process.argv[1].split("/").pop());for(const[d,
|
|
9
|
-
`),this.io.log(` ${a.green(`${l} ${
|
|
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=
|
|
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
|
|
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
|
|
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
|
|
@@ -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
|
+
}
|
package/dist/esm/src/index.js
CHANGED
|
@@ -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
|
|
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
|
|
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) ?
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
370
|
-
const
|
|
371
|
-
if (
|
|
372
|
-
e[
|
|
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[
|
|
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
|
|
501
|
+
function O(r) {
|
|
481
502
|
return new Array(r + 5).join(" ");
|
|
482
503
|
}
|
|
483
|
-
class
|
|
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 =
|
|
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 =
|
|
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
|
|
526
|
-
p += ` ${a.yellow(`[default: ${
|
|
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
|
|
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
|
|
585
|
+
return this.disableDefaultOptionsFlag ? [] : [new M()];
|
|
560
586
|
}
|
|
561
587
|
newCommandParser(t) {
|
|
562
|
-
return new
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
883
|
+
this.logger = t?.logger ?? new V(), this.io = this.newCommandIO({
|
|
837
884
|
logger: this.logger
|
|
838
|
-
}), this.stringSimilarity = t?.stringSimilarity ?? new
|
|
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
|
|
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("
|
|
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
|
|
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
|
|
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 =
|
|
959
|
+
const n = x.resolve(t, i.name);
|
|
911
960
|
if (i.isDirectory())
|
|
912
|
-
yield* this.listCommandsFiles(
|
|
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
|
|
976
|
+
if (j(t))
|
|
928
977
|
return t.pretty(this.logger), -1;
|
|
929
978
|
throw t;
|
|
930
979
|
}
|
|
931
980
|
}
|
|
932
|
-
class
|
|
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-
|
|
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 =
|
|
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
|
|
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
|
|
1020
|
+
return new T(t);
|
|
972
1021
|
}
|
|
973
1022
|
newHelpCommand(t) {
|
|
974
|
-
return new
|
|
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
|
|
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
|
-
|
|
1061
|
+
Q as BadCommandParameter,
|
|
1013
1062
|
f as BobError,
|
|
1014
|
-
|
|
1015
|
-
|
|
1063
|
+
Y as Cli,
|
|
1064
|
+
A as Command,
|
|
1016
1065
|
S as CommandIO,
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1066
|
+
H as CommandNotFoundError,
|
|
1067
|
+
N as CommandParser,
|
|
1068
|
+
T as CommandRegistry,
|
|
1020
1069
|
$ as CommandSignatureParser,
|
|
1021
|
-
|
|
1070
|
+
X as CommandWithSignature,
|
|
1022
1071
|
W as ExceptionHandler,
|
|
1023
|
-
|
|
1072
|
+
M as HelpOption,
|
|
1024
1073
|
b as InvalidOption,
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1074
|
+
V as Logger,
|
|
1075
|
+
k as MissingRequiredArgumentValue,
|
|
1076
|
+
D as MissingRequiredOptionValue,
|
|
1077
|
+
B as StringSimilarity,
|
|
1078
|
+
P as TooManyArguments
|
|
1029
1079
|
};
|