bob-core 2.0.0-beta.14 → 2.0.0-beta.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +12 -12
- package/dist/cjs/{package-BfDTyN7_.cjs → package-o2EGFSAP.cjs} +1 -1
- package/dist/cjs/src/Cli.d.ts +2 -4
- package/dist/cjs/src/Command.d.ts +2 -4
- package/dist/cjs/src/CommandIO.d.ts +4 -1
- package/dist/cjs/src/CommandRegistry.d.ts +9 -3
- package/dist/cjs/src/StringSimilarity.d.ts +26 -0
- package/dist/cjs/src/index.d.ts +1 -0
- package/dist/esm/index.js +211 -168
- package/dist/esm/{package-vtMT-dat.js → package-C-2LYcDa.js} +1 -1
- package/dist/esm/src/Cli.d.ts +2 -4
- package/dist/esm/src/Command.d.ts +2 -4
- package/dist/esm/src/CommandIO.d.ts +4 -1
- package/dist/esm/src/CommandRegistry.d.ts +9 -3
- package/dist/esm/src/StringSimilarity.d.ts +26 -0
- package/dist/esm/src/index.d.ts +1 -0
- package/package.json +2 -3
package/dist/cjs/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("prompts"),a=require("chalk"),H=require("minimist"),
|
|
2
|
-
${a.yellow("Available options")}:`);for(const[n
|
|
3
|
-
`,Array.isArray(
|
|
4
|
-
`,await this.io.askForList(
|
|
5
|
-
`),this.io.log(a.yellow("Usage:")),this.io.log(` ${this.command} ${o.length>0?o.map(([l])=>`<${l}>`).join(" "):"\b"} [options]`);const
|
|
6
|
-
${a.yellow("Arguments")}:`);for(const[l,d]of
|
|
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} ${
|
|
10
|
-
`);const
|
|
11
|
-
`),this.io.askForConfirmation(`${a.green(`Do you want to run ${a.yellow(
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("prompts"),a=require("chalk"),H=require("minimist"),M=require("node:fs"),F=require("path");function T(s){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(s){for(const e in s)if(e!=="default"){const i=Object.getOwnPropertyDescriptor(s,e);Object.defineProperty(t,e,i.get?i:{enumerable:!0,get:()=>s[e]})}}return t.default=s,Object.freeze(t)}const W=T(M);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 m=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),u=()=>{clearInterval(m),process.stdout.write(new TextEncoder().encode("\r"+" ".repeat(n.length+5)+"\r"))};return{[Symbol.dispose]:u,[Symbol.asyncDispose]:u,updateText:c=>{r=n,n=c},stop:u}}}class f extends Error{}function k(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 q(s){return typeof s=="string"||Array.isArray(s)?k(s):s.default!==void 0?s.default:k(s.type)}function g(s){return typeof s=="string"||Array.isArray(s)?{alias:[],default:q(s),description:"",required:!1,secret:!1,type:s,variadic:!1}:{alias:s.alias?Array.isArray(s.alias)?s.alias:[s.alias]:[],default:s.default??q(s.type),description:s.description??"",required:s.required??!1,secret:s.secret??!1,type:s.type,variadic:s.variadic??!1}}class $ extends f{constructor(t,e={}){super(`Invalid option ${t} in not recognized`),this.option=t,this.optionsSchema=e}pretty(t){const e=Object.entries(this.optionsSchema);if(e.length>0){t.log(`
|
|
2
|
+
${a.yellow("Available options")}:`);for(const[i,n]of e){const r=g(n),o=typeof r.alias=="string"?[r.alias]:r.alias,m=Array.isArray(r.type)?`[${r.type[0]}]`:r.type,u=`--${i}${o.length>0?o.map(l=>`, -${l}`).join(""):""}`,c=" ".repeat(30-u.length);t.log(` ${a.green(u)} ${c} ${r.description||"\b"} ${a.white(`(${m})`)}`)}t.log("")}t.log(`${a.white.bgRed(" ERROR ")} Option ${a.bold.yellow(this.option)} is not recognized.`)}}class O 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 B 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 m=Number(o);if(isNaN(m))throw new C({option:e,reason:`Expected array of numbers, got "${o}" in array`});return m})}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}=H(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 O(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 O(t)}}}option(t,e){if(!this.parsedOptions)throw new Error("Options have not been parsed yet. Call init() first.");return this.isEmptyValue(this.parsedOptions[t])&&e!==void 0?e:this.parsedOptions[t]}setOption(t,e){if(!this.parsedOptions)throw new Error("Options have not been parsed yet. Call init() first.");if(!(t in this.options))throw new $(t,this.options);this.parsedOptions[t]=e}argument(t,e){if(!this.parsedArguments)throw new Error("Arguments have not been parsed yet. Call init() first.");return this.isEmptyValue(this.parsedArguments[t])&&e!==void 0?e:this.parsedArguments[t]}setArgument(t,e){if(!this.parsedArguments)throw new Error("Arguments have not been parsed yet. Call init() first.");if(!(t in this.arguments))throw new $(t,this.arguments);this.parsedArguments[t]=e}isEmptyValue(t){return t==null||Array.isArray(t)&&t.length===0}validateUnknownOptions(t){const e=new Set;for(const i in this.options){e.add(i);const n=g(this.options[i]);for(const r of n.alias)e.add(r)}for(const i in t)if(!e.has(i))throw new $(i,this.options)}handleOptions(t){const e={};for(const i in this.options){const n=g(this.options[i]);e[i]=this.resolveOptionValue(i,n,t)}return e}handleArguments(t){const e={},i=[...t];for(const n in this.arguments){const r=g(this.arguments[n]);if(r.variadic){e[n]=this.handleVariadicArgument(n,r,i);continue}e[n]=this.resolveArgumentValue(n,r,i.shift())}return e}handleVariadicArgument(t,e,i){return i.length?w(i,e.type,t,e.default):e.default}resolveArgumentValue(t,e,i){return i===void 0?e.default:w(i,e.type,t,e.default)}resolveOptionValue(t,e,i){let n;const r=[t,...e.alias];for(const o of r)if(o in i){n=i[o];break}if(n===void 0){if(e.required)throw new 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?"[]":""})`)}
|
|
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 A(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 h=Array.isArray(d.alias)?d.alias:d.alias?[d.alias]:[];return{name:l,...d,optionWithAlias:`--${l}${h.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 m=Math.max(...r.map(l=>l.optionWithAlias.length),0),u=Math.max(...i.map(([l])=>l.length),0),c=u>m?u:m;if(i.length>0){this.io.log(`
|
|
6
|
+
${a.yellow("Arguments")}:`);for(const[l,d]of i){const h=A(c-l.length);let p=` ${a.green(l)} ${h} ${d.description??"\b"}`;if(d.default!==void 0&&!d.required){const j=(Array.isArray(d.type)?`[${d.type[0]}]`:d.type)==="array"||Array.isArray(d.type)?JSON.stringify(d.default):d.default;p+=` ${a.yellow(`[default: ${j}]`)}`}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=A(c-l.optionWithAlias.length);let h=`${a.green(l.optionWithAlias)} ${d} ${l.description??"\b"}`;if(l.type){const p=Array.isArray(l.type)?`[${l.type[0]}]`:l.type;h+=` ${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;h+=` ${a.yellow(`[default: ${E}]`)}`}this.io.log(h)}}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,h]of this.commandsExamples.entries())d>0&&this.io.log(""),this.io.log(` ${h.description}
|
|
9
|
+
`),this.io.log(` ${a.green(`${l} ${h.command}`)}`)}return-1}}class v{_command;description;group;commandsExamples=[];get command(){return this._command}ctx;io;logger;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.logger=t.logger,this.io=this.newCommandIO({logger:t.logger}),t&&"args"in t){const r=this.tmp?.options??{};for(const o of this.defaultOptions())o.option in r||(r[o.option]=o);this.parser=this.newCommandParser({io:this.io,options:r,arguments:this.tmp?.arguments??{}}),e=this.parser.init(t.args);for(const o of this.defaultOptions())if(e.options[o.option]===!0){const m=await o.handler.call(this);if(m&&m!==0)return m}this.disablePromptingFlag&&this.parser.disablePrompting(),await this.parser.validate()}else e={options:t.options,arguments:t.arguments};const i=this.preHandle?await this.preHandle():null;if(i&&i!==0)return i;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 x{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,...r]=t.split(/\{(.*?)\}/g).map(u=>u.trim()).filter(Boolean),o={},m={};for(const u of r){const{name:c,isOption:l,definition:d}=b.parseParamSignature(u,e);l?o[c]=d:m[c]=d}for(const u of i)o[u.option]={type:u.type,required:u.required,alias:u.alias,variadic:u.variadic??!1,description:u.description,default:u.default??null};return{command:n,options:o,arguments:m}}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,m]=i.split(":");i=o.trim(),r.description=m.trim()}if(i.includes("=")){const[o,m]=i.split("=");i=o.trim(),r.default=m.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,...m]=i.split("|");i=o.trim(),r.alias=m.map(u=>u.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 _ extends v{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 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 m of i)r.has(m)&&(o++,r.delete(m));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);if(!e)throw new Error(`The command at path ${t} does not have a default export.`);return e&&typeof e=="object"&&"default"in e&&(e=e.default),typeof e=="function"?new e:e instanceof v?e: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(m=>m.rating>.3).map(m=>m.target);if(i.rating>0&&o.length<=1||i.rating>.7&&o.length>1){const m=e[n];return await this.askRunSimilarCommand(t,m)?m:null}if(o.length){this.io.error(`${a.bgRed(" ERROR ")} Command ${a.yellow(t)} not found.
|
|
10
|
+
`);const m=await this.io.askForSelect(a.green("Did you mean to run one of these commands instead?"),o);if(m)return m}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=W.readdirSync(t,{withFileTypes:!0});for(const i of e){const n=F.resolve(t,i.name);if(i.isDirectory())yield*this.listCommandsFiles(F.resolve(t,i.name));else{if(!n.endsWith(".ts")&&!n.endsWith(".js")&&!n.endsWith(".mjs")&&!n.endsWith(".cjs"))continue;yield n}}}}class D{logger;constructor(t){this.logger=t}handle(t){if(t instanceof f)return t.pretty(this.logger),-1;throw t}}class G 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-o2EGFSAP.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 r=Math.max(...t.map(u=>u.command.length))??0,o={};for(const u of t){const c=u.group??u.command.split(":")[0];o[c]||(o[c]=[]),o[c].push(u)}const m=Object.entries(o).sort(([u],[c])=>u.toLowerCase().localeCompare(c.toLowerCase())).sort(([,u],[,c])=>u.length-c.length);for(const[u,c]of m){const l=c.length>1;l&&this.io.log(a.yellow(`${u}:`));const d=c.sort((h,p)=>h.command.toLowerCase().localeCompare(p.command.toLowerCase()));for(const h of d){let p=A(r-h.command.length);l&&(p=p.slice(2)),this.io.log(`${l?" ":""}${a.green(h.command)} ${p} ${h.description}`)}}}}class z{ctx;logger;commandRegistry;exceptionHandler;helpCommand;newCommandRegistry(t){return new V(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 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=B;exports.BobError=f;exports.Cli=z;exports.Command=v;exports.CommandIO=R;exports.CommandNotFoundError=P;exports.CommandParser=x;exports.CommandRegistry=V;exports.CommandSignatureParser=b;exports.CommandWithSignature=_;exports.ExceptionHandler=D;exports.HelpOption=L;exports.InvalidOption=$;exports.Logger=S;exports.MissingRequiredArgumentValue=O;exports.MissingRequiredOptionValue=N;exports.StringSimilarity=I;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="bob-core",t="2.0.0-beta.
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="bob-core",t="2.0.0-beta.15",s="BOB Core",i="module",n=!1,r=["dist/**"],o={".":{import:"./dist/esm/index.js",require:"./dist/cjs/index.js"}},c={"*":{"*":["./dist/cjs/*.d.ts"]}},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"},d="Léo Hubert",l="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.7.3","typescript-eslint":"^8.46.0",vite:"^7.1.6","vite-plugin-dts":"^4.5.4",vitest:"^3.2.4"},m={chalk:"^5.6.2",minimist:"^1.2.8",prompts:"^2.4.2"},u={name:e,version:t,description:s,type:i,sideEffects:n,files:r,exports:o,typesVersions:c,scripts:p,author:d,license:l,devDependencies:a,dependencies:m};exports.author=d;exports.default=u;exports.dependencies=m;exports.description=s;exports.devDependencies=a;exports.exports=o;exports.files=r;exports.license=l;exports.name=e;exports.scripts=p;exports.sideEffects=n;exports.type=i;exports.typesVersions=c;exports.version=t;
|
package/dist/cjs/src/Cli.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from './Command.js';
|
|
2
|
-
import { CommandRegistry, CommandResolver, FileImporter } from './CommandRegistry.js';
|
|
2
|
+
import { CommandRegistry, CommandRegistryOptions, CommandResolver, FileImporter } from './CommandRegistry.js';
|
|
3
3
|
import { ExceptionHandler } from './ExceptionHandler.js';
|
|
4
4
|
import { Logger } from './Logger.js';
|
|
5
5
|
import { default as HelpCommand, HelpCommandOptions } from './commands/HelpCommand.js';
|
|
@@ -16,9 +16,7 @@ export declare class Cli<C extends ContextDefinition = ContextDefinition> {
|
|
|
16
16
|
readonly commandRegistry: CommandRegistry;
|
|
17
17
|
private readonly exceptionHandler;
|
|
18
18
|
private readonly helpCommand;
|
|
19
|
-
protected newCommandRegistry(opts:
|
|
20
|
-
logger: Logger;
|
|
21
|
-
}): CommandRegistry;
|
|
19
|
+
protected newCommandRegistry(opts: CommandRegistryOptions): CommandRegistry;
|
|
22
20
|
protected newHelpCommand(opts: HelpCommandOptions): HelpCommand;
|
|
23
21
|
protected newExceptionHandler(opts: {
|
|
24
22
|
logger: Logger;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CommandIO } from './CommandIO.js';
|
|
1
|
+
import { CommandIO, CommandIOOptions } from './CommandIO.js';
|
|
2
2
|
import { CommandParser } from './CommandParser.js';
|
|
3
3
|
import { Logger } from './Logger.js';
|
|
4
4
|
import { CommandOption } from './contracts/index.js';
|
|
@@ -43,9 +43,7 @@ export declare class Command<C extends ContextDefinition = ContextDefinition, Op
|
|
|
43
43
|
options: Options;
|
|
44
44
|
arguments: Arguments;
|
|
45
45
|
}): CommandParser<Options, Arguments>;
|
|
46
|
-
protected newCommandIO(opts:
|
|
47
|
-
logger: Logger;
|
|
48
|
-
}): CommandIO;
|
|
46
|
+
protected newCommandIO(opts: CommandIOOptions): CommandIO;
|
|
49
47
|
constructor(command: string, opts?: {
|
|
50
48
|
description?: string;
|
|
51
49
|
group?: string;
|
|
@@ -6,9 +6,12 @@ export type SelectOption = {
|
|
|
6
6
|
selected?: boolean | undefined;
|
|
7
7
|
description?: string | undefined;
|
|
8
8
|
};
|
|
9
|
+
export type CommandIOOptions = {
|
|
10
|
+
logger: Logger;
|
|
11
|
+
};
|
|
9
12
|
export declare class CommandIO {
|
|
10
13
|
private logger;
|
|
11
|
-
constructor(
|
|
14
|
+
constructor(opts: CommandIOOptions);
|
|
12
15
|
/**
|
|
13
16
|
* Logger methods
|
|
14
17
|
*/
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { Command } from './Command.js';
|
|
2
|
-
import { CommandIO } from './CommandIO.js';
|
|
2
|
+
import { CommandIO, CommandIOOptions } from './CommandIO.js';
|
|
3
3
|
import { Logger } from './Logger.js';
|
|
4
|
+
import { StringSimilarity } from './StringSimilarity.js';
|
|
4
5
|
import { ArgumentsSchema, ContextDefinition, OptionsSchema } from './lib/types.js';
|
|
5
6
|
export type CommandResolver = (path: string) => Promise<Command | null>;
|
|
6
7
|
export type FileImporter = (filePath: string) => Promise<unknown>;
|
|
8
|
+
export type CommandRegistryOptions = {
|
|
9
|
+
logger?: Logger;
|
|
10
|
+
stringSimilarity?: StringSimilarity;
|
|
11
|
+
};
|
|
7
12
|
export declare class CommandRegistry {
|
|
8
13
|
private readonly commands;
|
|
9
14
|
protected readonly io: CommandIO;
|
|
10
15
|
protected readonly logger: Logger;
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
private readonly stringSimilarity;
|
|
17
|
+
protected newCommandIO(opts: CommandIOOptions): CommandIO;
|
|
18
|
+
constructor(opts?: CommandRegistryOptions);
|
|
13
19
|
getAvailableCommands(): string[];
|
|
14
20
|
getCommands(): Array<Command>;
|
|
15
21
|
private importFile;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface SimilarityResult {
|
|
2
|
+
rating: number;
|
|
3
|
+
target: string;
|
|
4
|
+
}
|
|
5
|
+
export interface BestMatchResult {
|
|
6
|
+
bestMatch: SimilarityResult;
|
|
7
|
+
bestMatchIndex: number;
|
|
8
|
+
ratings: SimilarityResult[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* String similarity calculator using Dice's Coefficient algorithm
|
|
12
|
+
*/
|
|
13
|
+
export declare class StringSimilarity {
|
|
14
|
+
/**
|
|
15
|
+
* Generate bigrams (character pairs) from a string
|
|
16
|
+
*/
|
|
17
|
+
private getBigrams;
|
|
18
|
+
/**
|
|
19
|
+
* Calculate Dice's Coefficient similarity between two strings (0-1 scale)
|
|
20
|
+
*/
|
|
21
|
+
calculateSimilarity(str1: string, str2: string): number;
|
|
22
|
+
/**
|
|
23
|
+
* Find best matching string and ratings for all candidates
|
|
24
|
+
*/
|
|
25
|
+
findBestMatch(target: string, candidates: string[]): BestMatchResult;
|
|
26
|
+
}
|
package/dist/cjs/src/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * from './CommandRegistry.js';
|
|
|
7
7
|
export * from './Cli.js';
|
|
8
8
|
export * from './Logger.js';
|
|
9
9
|
export * from './ExceptionHandler.js';
|
|
10
|
+
export * from './StringSimilarity.js';
|
|
10
11
|
export * from './lib/types.js';
|
|
11
12
|
export * from './errors/index.js';
|
|
12
13
|
export * from './options/index.js';
|
package/dist/esm/index.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import y from "prompts";
|
|
2
2
|
import a from "chalk";
|
|
3
|
-
import
|
|
4
|
-
import * as
|
|
3
|
+
import q from "minimist";
|
|
4
|
+
import * as I from "node:fs";
|
|
5
5
|
import R from "path";
|
|
6
|
-
|
|
7
|
-
class k {
|
|
6
|
+
class S {
|
|
8
7
|
logger;
|
|
9
8
|
constructor(t) {
|
|
10
|
-
this.logger = t;
|
|
9
|
+
this.logger = t.logger;
|
|
11
10
|
}
|
|
12
11
|
/**
|
|
13
12
|
* Logger methods
|
|
@@ -77,31 +76,31 @@ class k {
|
|
|
77
76
|
async askForSelect(t, e, i) {
|
|
78
77
|
if (e.length === 0)
|
|
79
78
|
throw new Error("No options provided");
|
|
80
|
-
const
|
|
79
|
+
const n = [];
|
|
81
80
|
for (const o of e)
|
|
82
|
-
typeof o == "string" ?
|
|
81
|
+
typeof o == "string" ? n.push({ title: o, value: o }) : n.push(o);
|
|
83
82
|
return (await y({
|
|
84
83
|
type: "select",
|
|
85
84
|
name: "value",
|
|
86
85
|
message: t,
|
|
87
|
-
choices:
|
|
86
|
+
choices: n,
|
|
88
87
|
...i
|
|
89
88
|
}))?.value ?? null;
|
|
90
89
|
}
|
|
91
90
|
newLoader(t = "", e = ["⠙", "⠘", "⠰", "⠴", "⠤", "⠦", "⠆", "⠃", "⠋", "⠉"], i = 100) {
|
|
92
|
-
let
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
}, i),
|
|
96
|
-
clearInterval(
|
|
91
|
+
let n = t, s = null, o = 0;
|
|
92
|
+
const m = setInterval(function() {
|
|
93
|
+
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;
|
|
94
|
+
}, i), u = () => {
|
|
95
|
+
clearInterval(m), process.stdout.write(new TextEncoder().encode("\r" + " ".repeat(n.length + 5) + "\r"));
|
|
97
96
|
};
|
|
98
97
|
return {
|
|
99
|
-
[Symbol.dispose]:
|
|
100
|
-
[Symbol.asyncDispose]:
|
|
101
|
-
updateText: (
|
|
102
|
-
|
|
98
|
+
[Symbol.dispose]: u,
|
|
99
|
+
[Symbol.asyncDispose]: u,
|
|
100
|
+
updateText: (h) => {
|
|
101
|
+
s = n, n = h;
|
|
103
102
|
},
|
|
104
|
-
stop:
|
|
103
|
+
stop: u
|
|
105
104
|
};
|
|
106
105
|
}
|
|
107
106
|
}
|
|
@@ -147,9 +146,9 @@ class b extends f {
|
|
|
147
146
|
if (e.length > 0) {
|
|
148
147
|
t.log(`
|
|
149
148
|
${a.yellow("Available options")}:`);
|
|
150
|
-
for (const [i,
|
|
151
|
-
const
|
|
152
|
-
t.log(` ${a.green(
|
|
149
|
+
for (const [i, n] of e) {
|
|
150
|
+
const s = g(n), o = typeof s.alias == "string" ? [s.alias] : s.alias, m = Array.isArray(s.type) ? `[${s.type[0]}]` : s.type, u = `--${i}${o.length > 0 ? o.map((l) => `, -${l}`).join("") : ""}`, h = " ".repeat(30 - u.length);
|
|
151
|
+
t.log(` ${a.green(u)} ${h} ${s.description || "\b"} ${a.white(`(${m})`)}`);
|
|
153
152
|
}
|
|
154
153
|
t.log("");
|
|
155
154
|
}
|
|
@@ -164,7 +163,7 @@ class F extends f {
|
|
|
164
163
|
t.log(`${a.white.bgRed(" ERROR ")} Argument ${a.bold.yellow(this.argument)} is required.`);
|
|
165
164
|
}
|
|
166
165
|
}
|
|
167
|
-
class
|
|
166
|
+
class V extends f {
|
|
168
167
|
constructor(t) {
|
|
169
168
|
super(`Argument "${t}" is required.`), this.option = t;
|
|
170
169
|
}
|
|
@@ -190,7 +189,7 @@ class C extends f {
|
|
|
190
189
|
t.log(` ${a.white.bgRed(" ERROR ")} Option ${a.bold.yellow(this.param.option)} value is invalid. `), (this.param.value || this.param.reason) && t.log(""), this.param.value && t.log(` ${a.blue("Value")}: ${this.param.value}`), this.param.reason && t.log(` ${a.yellow("Reason")}: ${this.param.reason}`);
|
|
191
190
|
}
|
|
192
191
|
}
|
|
193
|
-
class
|
|
192
|
+
class P extends f {
|
|
194
193
|
constructor(t) {
|
|
195
194
|
super(`Command "${t}" not found.`), this.command = t;
|
|
196
195
|
}
|
|
@@ -204,34 +203,34 @@ function w(r, t, e, i) {
|
|
|
204
203
|
if (t === "string")
|
|
205
204
|
return String(r);
|
|
206
205
|
if (t === "number") {
|
|
207
|
-
const
|
|
208
|
-
if (isNaN(
|
|
206
|
+
const n = Number(r);
|
|
207
|
+
if (isNaN(n))
|
|
209
208
|
throw new C({
|
|
210
209
|
option: e,
|
|
211
210
|
reason: `Expected a number, got "${r}"`
|
|
212
211
|
});
|
|
213
|
-
return
|
|
212
|
+
return n;
|
|
214
213
|
}
|
|
215
214
|
if (t === "boolean")
|
|
216
215
|
return typeof r == "boolean" ? r : r === "true" || r === "1" ? !0 : r === "false" || r === "0" ? !1 : !!r;
|
|
217
216
|
if (Array.isArray(t)) {
|
|
218
|
-
const
|
|
219
|
-
if (
|
|
220
|
-
return
|
|
221
|
-
if (
|
|
222
|
-
return
|
|
223
|
-
const
|
|
224
|
-
if (isNaN(
|
|
217
|
+
const n = t[0], s = Array.isArray(r) ? r : [r];
|
|
218
|
+
if (n === "string")
|
|
219
|
+
return s.map((o) => String(o));
|
|
220
|
+
if (n === "number")
|
|
221
|
+
return s.map((o) => {
|
|
222
|
+
const m = Number(o);
|
|
223
|
+
if (isNaN(m))
|
|
225
224
|
throw new C({
|
|
226
225
|
option: e,
|
|
227
226
|
reason: `Expected array of numbers, got "${o}" in array`
|
|
228
227
|
});
|
|
229
|
-
return
|
|
228
|
+
return m;
|
|
230
229
|
});
|
|
231
230
|
}
|
|
232
231
|
return r;
|
|
233
232
|
}
|
|
234
|
-
class
|
|
233
|
+
class k {
|
|
235
234
|
options;
|
|
236
235
|
parsedOptions = null;
|
|
237
236
|
arguments;
|
|
@@ -250,7 +249,7 @@ class N {
|
|
|
250
249
|
* @throws {BadCommandOption} If a value cannot be converted to the expected type
|
|
251
250
|
*/
|
|
252
251
|
init(t) {
|
|
253
|
-
const { _: e, ...i } =
|
|
252
|
+
const { _: e, ...i } = q(t);
|
|
254
253
|
return this.validateUnknownOptions(i), this.parsedOptions = this.handleOptions(i), this.parsedArguments = this.handleArguments(e), {
|
|
255
254
|
options: this.parsedOptions,
|
|
256
255
|
arguments: this.parsedArguments
|
|
@@ -263,14 +262,14 @@ class N {
|
|
|
263
262
|
async validate() {
|
|
264
263
|
for (const t in this.options)
|
|
265
264
|
if (g(this.options[t]).required && (this.parsedOptions?.[t] === void 0 || this.parsedOptions?.[t] === null))
|
|
266
|
-
throw new
|
|
265
|
+
throw new V(t);
|
|
267
266
|
for (const t in this.arguments) {
|
|
268
267
|
const e = g(this.arguments[t]), i = this.parsedArguments?.[t];
|
|
269
268
|
if (e.required && i == null) {
|
|
270
269
|
if (this.shouldPromptForMissingOptions) {
|
|
271
|
-
const
|
|
272
|
-
if (
|
|
273
|
-
this.parsedArguments[t] = w(
|
|
270
|
+
const n = await this.promptForArgument(t, e);
|
|
271
|
+
if (n && this.parsedArguments) {
|
|
272
|
+
this.parsedArguments[t] = w(n, e.type, t);
|
|
274
273
|
continue;
|
|
275
274
|
}
|
|
276
275
|
}
|
|
@@ -278,9 +277,9 @@ class N {
|
|
|
278
277
|
}
|
|
279
278
|
if (e.required && e.variadic && Array.isArray(i) && i.length === 0) {
|
|
280
279
|
if (this.shouldPromptForMissingOptions) {
|
|
281
|
-
const
|
|
282
|
-
if (
|
|
283
|
-
this.parsedArguments[t] = w(
|
|
280
|
+
const n = await this.promptForArgument(t, e);
|
|
281
|
+
if (n && this.parsedArguments) {
|
|
282
|
+
this.parsedArguments[t] = w(n, e.type, t);
|
|
284
283
|
continue;
|
|
285
284
|
}
|
|
286
285
|
}
|
|
@@ -343,9 +342,9 @@ class N {
|
|
|
343
342
|
const e = /* @__PURE__ */ new Set();
|
|
344
343
|
for (const i in this.options) {
|
|
345
344
|
e.add(i);
|
|
346
|
-
const
|
|
347
|
-
for (const
|
|
348
|
-
e.add(
|
|
345
|
+
const n = g(this.options[i]);
|
|
346
|
+
for (const s of n.alias)
|
|
347
|
+
e.add(s);
|
|
349
348
|
}
|
|
350
349
|
for (const i in t)
|
|
351
350
|
if (!e.has(i))
|
|
@@ -357,8 +356,8 @@ class N {
|
|
|
357
356
|
handleOptions(t) {
|
|
358
357
|
const e = {};
|
|
359
358
|
for (const i in this.options) {
|
|
360
|
-
const
|
|
361
|
-
e[i] = this.resolveOptionValue(i,
|
|
359
|
+
const n = g(this.options[i]);
|
|
360
|
+
e[i] = this.resolveOptionValue(i, n, t);
|
|
362
361
|
}
|
|
363
362
|
return e;
|
|
364
363
|
}
|
|
@@ -367,13 +366,13 @@ class N {
|
|
|
367
366
|
*/
|
|
368
367
|
handleArguments(t) {
|
|
369
368
|
const e = {}, i = [...t];
|
|
370
|
-
for (const
|
|
371
|
-
const
|
|
372
|
-
if (
|
|
373
|
-
e[
|
|
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);
|
|
374
373
|
continue;
|
|
375
374
|
}
|
|
376
|
-
e[
|
|
375
|
+
e[n] = this.resolveArgumentValue(n, s, i.shift());
|
|
377
376
|
}
|
|
378
377
|
return e;
|
|
379
378
|
}
|
|
@@ -395,14 +394,14 @@ class N {
|
|
|
395
394
|
* Handles alias resolution, defaults, and type conversion
|
|
396
395
|
*/
|
|
397
396
|
resolveOptionValue(t, e, i) {
|
|
398
|
-
let
|
|
399
|
-
const
|
|
400
|
-
for (const o of
|
|
397
|
+
let n;
|
|
398
|
+
const s = [t, ...e.alias];
|
|
399
|
+
for (const o of s)
|
|
401
400
|
if (o in i) {
|
|
402
|
-
|
|
401
|
+
n = i[o];
|
|
403
402
|
break;
|
|
404
403
|
}
|
|
405
|
-
if (
|
|
404
|
+
if (n === void 0) {
|
|
406
405
|
if (e.required)
|
|
407
406
|
throw new C({
|
|
408
407
|
option: t,
|
|
@@ -410,7 +409,7 @@ class N {
|
|
|
410
409
|
});
|
|
411
410
|
return e.default;
|
|
412
411
|
}
|
|
413
|
-
return w(
|
|
412
|
+
return w(n, e.type, t, e.default);
|
|
414
413
|
}
|
|
415
414
|
optionDefinitions() {
|
|
416
415
|
const t = {};
|
|
@@ -452,26 +451,26 @@ class N {
|
|
|
452
451
|
`, Array.isArray(e.type) ? (i += `Please provide one or more values, separated by commas:
|
|
453
452
|
`, await this.io.askForList(i, void 0, {
|
|
454
453
|
separator: ",",
|
|
455
|
-
validate: (
|
|
456
|
-
if (!
|
|
454
|
+
validate: (n) => {
|
|
455
|
+
if (!n.length)
|
|
457
456
|
return "Please enter at least one value";
|
|
458
457
|
if (e.type[0] === "number") {
|
|
459
|
-
for (const
|
|
460
|
-
if (isNaN(Number(
|
|
458
|
+
for (const s of n.split(","))
|
|
459
|
+
if (isNaN(Number(s)))
|
|
461
460
|
return "Please enter only valid numbers";
|
|
462
461
|
}
|
|
463
462
|
return !0;
|
|
464
463
|
}
|
|
465
464
|
})) : await this.io.askForInput(i, void 0, {
|
|
466
465
|
type: e.type === "number" ? "number" : e.secret ? "password" : "text",
|
|
467
|
-
validate: (
|
|
468
|
-
if (
|
|
466
|
+
validate: (n) => {
|
|
467
|
+
if (n == null || typeof n == "string" && !n.length)
|
|
469
468
|
return "This value is required";
|
|
470
469
|
if (e.type === "number") {
|
|
471
|
-
const
|
|
472
|
-
if (isNaN(
|
|
470
|
+
const s = Number(n);
|
|
471
|
+
if (isNaN(s))
|
|
473
472
|
return "Please enter a valid number";
|
|
474
|
-
} else if (e.type === "string" && (typeof
|
|
473
|
+
} else if (e.type === "string" && (typeof n != "string" || !n.length))
|
|
475
474
|
return "Please enter a valid text";
|
|
476
475
|
return !0;
|
|
477
476
|
}
|
|
@@ -481,52 +480,52 @@ class N {
|
|
|
481
480
|
function A(r) {
|
|
482
481
|
return new Array(r + 5).join(" ");
|
|
483
482
|
}
|
|
484
|
-
class
|
|
483
|
+
class D {
|
|
485
484
|
type = "boolean";
|
|
486
485
|
option = "help";
|
|
487
486
|
alias = ["h"];
|
|
488
487
|
default = !1;
|
|
489
488
|
description = `Display help for the given command. When no command is given display help for the ${a.green("list")} command`;
|
|
490
489
|
async handler() {
|
|
491
|
-
const t = this.parser.argumentDefinitions(), e = this.parser.optionDefinitions(), i = Object.entries(t),
|
|
492
|
-
const
|
|
490
|
+
const t = this.parser.argumentDefinitions(), e = this.parser.optionDefinitions(), i = Object.entries(t), n = Object.entries(e), s = n.map(([l, d]) => {
|
|
491
|
+
const c = Array.isArray(d.alias) ? d.alias : d.alias ? [d.alias] : [];
|
|
493
492
|
return {
|
|
494
493
|
name: l,
|
|
495
494
|
...d,
|
|
496
|
-
optionWithAlias: `--${l}${
|
|
495
|
+
optionWithAlias: `--${l}${c.map((p) => `, -${p}`).join("")}`
|
|
497
496
|
};
|
|
498
497
|
}), o = i.filter(([, l]) => l.required);
|
|
499
498
|
this.io.log(a.yellow("Description:")), this.io.log(` ${this.description}
|
|
500
499
|
`), this.io.log(a.yellow("Usage:")), this.io.log(` ${this.command} ${o.length > 0 ? o.map(([l]) => `<${l}>`).join(" ") : "\b"} [options]`);
|
|
501
|
-
const
|
|
500
|
+
const m = Math.max(...s.map((l) => l.optionWithAlias.length), 0), u = Math.max(...i.map(([l]) => l.length), 0), h = u > m ? u : m;
|
|
502
501
|
if (i.length > 0) {
|
|
503
502
|
this.io.log(`
|
|
504
503
|
${a.yellow("Arguments")}:`);
|
|
505
504
|
for (const [l, d] of i) {
|
|
506
|
-
const
|
|
507
|
-
let
|
|
505
|
+
const c = A(h - l.length);
|
|
506
|
+
let p = ` ${a.green(l)} ${c} ${d.description ?? "\b"}`;
|
|
508
507
|
if (d.default !== void 0 && !d.required) {
|
|
509
|
-
const
|
|
510
|
-
|
|
508
|
+
const L = (Array.isArray(d.type) ? `[${d.type[0]}]` : d.type) === "array" || Array.isArray(d.type) ? JSON.stringify(d.default) : d.default;
|
|
509
|
+
p += ` ${a.yellow(`[default: ${L}]`)}`;
|
|
511
510
|
}
|
|
512
|
-
d.variadic && (
|
|
511
|
+
d.variadic && (p += ` ${a.white("(variadic)")}`), this.io.log(p);
|
|
513
512
|
}
|
|
514
513
|
}
|
|
515
|
-
if (
|
|
514
|
+
if (n.length > 0) {
|
|
516
515
|
this.io.log(`
|
|
517
516
|
${a.yellow("Options")}:`);
|
|
518
|
-
for (const l of
|
|
519
|
-
const d = A(
|
|
520
|
-
let
|
|
517
|
+
for (const l of s) {
|
|
518
|
+
const d = A(h - l.optionWithAlias.length);
|
|
519
|
+
let c = `${a.green(l.optionWithAlias)} ${d} ${l.description ?? "\b"}`;
|
|
521
520
|
if (l.type) {
|
|
522
|
-
const
|
|
523
|
-
|
|
521
|
+
const p = Array.isArray(l.type) ? `[${l.type[0]}]` : l.type;
|
|
522
|
+
c += ` ${a.white(`(${p})`)}`;
|
|
524
523
|
}
|
|
525
524
|
if (l.default !== void 0 && !l.required) {
|
|
526
525
|
const O = (Array.isArray(l.type) ? `[${l.type[0]}]` : l.type) === "array" || Array.isArray(l.type) ? JSON.stringify(l.default) : l.default;
|
|
527
|
-
|
|
526
|
+
c += ` ${a.yellow(`[default: ${O}]`)}`;
|
|
528
527
|
}
|
|
529
|
-
this.io.log(
|
|
528
|
+
this.io.log(c);
|
|
530
529
|
}
|
|
531
530
|
}
|
|
532
531
|
if (this.commandsExamples.length > 0) {
|
|
@@ -534,9 +533,9 @@ ${a.yellow("Options")}:`);
|
|
|
534
533
|
${a.yellow("Examples")}:`);
|
|
535
534
|
let l = process.argv[0].split("/").pop();
|
|
536
535
|
l === "node" && (l += " " + process.argv[1].split("/").pop());
|
|
537
|
-
for (const [d,
|
|
538
|
-
d > 0 && this.io.log(""), this.io.log(` ${
|
|
539
|
-
`), this.io.log(` ${a.green(`${l} ${
|
|
536
|
+
for (const [d, c] of this.commandsExamples.entries())
|
|
537
|
+
d > 0 && this.io.log(""), this.io.log(` ${c.description}
|
|
538
|
+
`), this.io.log(` ${a.green(`${l} ${c.command}`)}`);
|
|
540
539
|
}
|
|
541
540
|
return -1;
|
|
542
541
|
}
|
|
@@ -558,17 +557,17 @@ class v {
|
|
|
558
557
|
_handler;
|
|
559
558
|
tmp;
|
|
560
559
|
defaultOptions() {
|
|
561
|
-
return [new
|
|
560
|
+
return [new D()];
|
|
562
561
|
}
|
|
563
562
|
newCommandParser(t) {
|
|
564
|
-
return new
|
|
563
|
+
return new k({
|
|
565
564
|
io: t.io,
|
|
566
565
|
options: t.options,
|
|
567
566
|
arguments: t.arguments
|
|
568
567
|
});
|
|
569
568
|
}
|
|
570
569
|
newCommandIO(t) {
|
|
571
|
-
return new
|
|
570
|
+
return new S(t);
|
|
572
571
|
}
|
|
573
572
|
constructor(t, e) {
|
|
574
573
|
this._command = t, this.description = e?.description ?? "", this.group = e?.group, this.tmp = {
|
|
@@ -577,8 +576,8 @@ class v {
|
|
|
577
576
|
};
|
|
578
577
|
const i = this.defaultOptions();
|
|
579
578
|
if (i.length > 0)
|
|
580
|
-
for (const
|
|
581
|
-
this.tmp.options[
|
|
579
|
+
for (const n of i)
|
|
580
|
+
this.tmp.options[n.option] = n;
|
|
582
581
|
}
|
|
583
582
|
disablePrompting() {
|
|
584
583
|
return this.disablePromptingFlag = !0, this;
|
|
@@ -614,19 +613,19 @@ class v {
|
|
|
614
613
|
if (this.ctx = t.ctx, this.logger = t.logger, this.io = this.newCommandIO({
|
|
615
614
|
logger: t.logger
|
|
616
615
|
}), t && "args" in t) {
|
|
617
|
-
const
|
|
616
|
+
const s = this.tmp?.options ?? {};
|
|
618
617
|
for (const o of this.defaultOptions())
|
|
619
|
-
o.option in
|
|
618
|
+
o.option in s || (s[o.option] = o);
|
|
620
619
|
this.parser = this.newCommandParser({
|
|
621
620
|
io: this.io,
|
|
622
|
-
options:
|
|
621
|
+
options: s,
|
|
623
622
|
arguments: this.tmp?.arguments ?? {}
|
|
624
623
|
}), e = this.parser.init(t.args);
|
|
625
624
|
for (const o of this.defaultOptions())
|
|
626
625
|
if (e.options[o.option] === !0) {
|
|
627
|
-
const
|
|
628
|
-
if (
|
|
629
|
-
return
|
|
626
|
+
const m = await o.handler.call(this);
|
|
627
|
+
if (m && m !== 0)
|
|
628
|
+
return m;
|
|
630
629
|
}
|
|
631
630
|
this.disablePromptingFlag && this.parser.disablePrompting(), await this.parser.validate();
|
|
632
631
|
} else
|
|
@@ -644,7 +643,7 @@ class v {
|
|
|
644
643
|
return await this._handler(t.ctx, e) ?? 0;
|
|
645
644
|
}
|
|
646
645
|
}
|
|
647
|
-
class $ extends
|
|
646
|
+
class $ extends k {
|
|
648
647
|
command;
|
|
649
648
|
constructor(t) {
|
|
650
649
|
const e = $.parseSignature(t.signature, t.helperDefinitions, t.defaultOptions);
|
|
@@ -659,24 +658,24 @@ class $ extends N {
|
|
|
659
658
|
* Example: "migrate {name} {--force}" -> { command: "migrate", arguments: {name: ...}, options: {force: ...} }
|
|
660
659
|
*/
|
|
661
660
|
static parseSignature(t, e, i) {
|
|
662
|
-
const [
|
|
663
|
-
for (const
|
|
664
|
-
const { name:
|
|
665
|
-
l ? o[
|
|
661
|
+
const [n, ...s] = t.split(/\{(.*?)\}/g).map((u) => u.trim()).filter(Boolean), o = {}, m = {};
|
|
662
|
+
for (const u of s) {
|
|
663
|
+
const { name: h, isOption: l, definition: d } = $.parseParamSignature(u, e);
|
|
664
|
+
l ? o[h] = d : m[h] = d;
|
|
666
665
|
}
|
|
667
|
-
for (const
|
|
668
|
-
o[
|
|
669
|
-
type:
|
|
670
|
-
required:
|
|
671
|
-
alias:
|
|
672
|
-
variadic:
|
|
673
|
-
description:
|
|
674
|
-
default:
|
|
666
|
+
for (const u of i)
|
|
667
|
+
o[u.option] = {
|
|
668
|
+
type: u.type,
|
|
669
|
+
required: u.required,
|
|
670
|
+
alias: u.alias,
|
|
671
|
+
variadic: u.variadic ?? !1,
|
|
672
|
+
description: u.description,
|
|
673
|
+
default: u.default ?? null
|
|
675
674
|
};
|
|
676
675
|
return {
|
|
677
|
-
command:
|
|
676
|
+
command: n,
|
|
678
677
|
options: o,
|
|
679
|
-
arguments:
|
|
678
|
+
arguments: m
|
|
680
679
|
};
|
|
681
680
|
}
|
|
682
681
|
/**
|
|
@@ -694,8 +693,8 @@ class $ extends N {
|
|
|
694
693
|
* - {--opt|o} -> option with alias
|
|
695
694
|
*/
|
|
696
695
|
static parseParamSignature(t, e) {
|
|
697
|
-
let i = t,
|
|
698
|
-
const
|
|
696
|
+
let i = t, n = !1;
|
|
697
|
+
const s = {
|
|
699
698
|
required: !0,
|
|
700
699
|
type: "string",
|
|
701
700
|
description: void 0,
|
|
@@ -703,18 +702,18 @@ class $ extends N {
|
|
|
703
702
|
variadic: !1
|
|
704
703
|
};
|
|
705
704
|
if (i.includes(":")) {
|
|
706
|
-
const [o,
|
|
707
|
-
i = o.trim(),
|
|
705
|
+
const [o, m] = i.split(":");
|
|
706
|
+
i = o.trim(), s.description = m.trim();
|
|
708
707
|
}
|
|
709
708
|
if (i.includes("=")) {
|
|
710
|
-
const [o,
|
|
711
|
-
i = o.trim(),
|
|
712
|
-
} else i.startsWith("--") && (
|
|
709
|
+
const [o, m] = i.split("=");
|
|
710
|
+
i = o.trim(), s.default = m.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");
|
|
711
|
+
} else i.startsWith("--") && (s.required = !1, s.default = !1, s.type = "boolean");
|
|
713
712
|
if (i.includes("|")) {
|
|
714
|
-
const [o, ...
|
|
715
|
-
i = o.trim(),
|
|
713
|
+
const [o, ...m] = i.split("|");
|
|
714
|
+
i = o.trim(), s.alias = m.map((u) => u.trim());
|
|
716
715
|
}
|
|
717
|
-
return i.startsWith("--") && (
|
|
716
|
+
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
717
|
}
|
|
719
718
|
}
|
|
720
719
|
class z extends v {
|
|
@@ -753,7 +752,7 @@ class z extends v {
|
|
|
753
752
|
return this.io.newLoader(...t);
|
|
754
753
|
}
|
|
755
754
|
}
|
|
756
|
-
class
|
|
755
|
+
class N {
|
|
757
756
|
level;
|
|
758
757
|
constructor(t = {}) {
|
|
759
758
|
this.level = t.level ?? "info";
|
|
@@ -784,15 +783,58 @@ class S {
|
|
|
784
783
|
this.shouldLog("debug") && console.log(...t);
|
|
785
784
|
}
|
|
786
785
|
}
|
|
786
|
+
class H {
|
|
787
|
+
/**
|
|
788
|
+
* Generate bigrams (character pairs) from a string
|
|
789
|
+
*/
|
|
790
|
+
getBigrams(t) {
|
|
791
|
+
const e = [], i = t.toLowerCase();
|
|
792
|
+
for (let n = 0; n < i.length - 1; n++)
|
|
793
|
+
e.push(i.slice(n, n + 2));
|
|
794
|
+
return e;
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Calculate Dice's Coefficient similarity between two strings (0-1 scale)
|
|
798
|
+
*/
|
|
799
|
+
calculateSimilarity(t, e) {
|
|
800
|
+
if (t === e) return 1;
|
|
801
|
+
if (t.length < 2 || e.length < 2) return 0;
|
|
802
|
+
const i = this.getBigrams(t), n = this.getBigrams(e), s = new Set(n);
|
|
803
|
+
let o = 0;
|
|
804
|
+
for (const m of i)
|
|
805
|
+
s.has(m) && (o++, s.delete(m));
|
|
806
|
+
return 2 * o / (i.length + n.length);
|
|
807
|
+
}
|
|
808
|
+
/**
|
|
809
|
+
* Find best matching string and ratings for all candidates
|
|
810
|
+
*/
|
|
811
|
+
findBestMatch(t, e) {
|
|
812
|
+
const i = e.map((o) => ({
|
|
813
|
+
target: o,
|
|
814
|
+
rating: this.calculateSimilarity(t, o)
|
|
815
|
+
}));
|
|
816
|
+
let n = 0, s = i[0]?.rating ?? 0;
|
|
817
|
+
for (let o = 1; o < i.length; o++)
|
|
818
|
+
i[o].rating > s && (s = i[o].rating, n = o);
|
|
819
|
+
return {
|
|
820
|
+
ratings: i,
|
|
821
|
+
bestMatch: i[n],
|
|
822
|
+
bestMatchIndex: n
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
}
|
|
787
826
|
class j {
|
|
788
827
|
commands = {};
|
|
789
828
|
io;
|
|
790
829
|
logger;
|
|
791
|
-
|
|
792
|
-
|
|
830
|
+
stringSimilarity;
|
|
831
|
+
newCommandIO(t) {
|
|
832
|
+
return new S(t);
|
|
793
833
|
}
|
|
794
834
|
constructor(t) {
|
|
795
|
-
this.logger = t ?? new
|
|
835
|
+
this.logger = t?.logger ?? new N(), this.io = this.newCommandIO({
|
|
836
|
+
logger: this.logger
|
|
837
|
+
}), this.stringSimilarity = t?.stringSimilarity ?? new H();
|
|
796
838
|
}
|
|
797
839
|
getAvailableCommands() {
|
|
798
840
|
return Object.keys(this.commands);
|
|
@@ -833,46 +875,46 @@ class j {
|
|
|
833
875
|
}
|
|
834
876
|
}
|
|
835
877
|
async runCommand(t, e, ...i) {
|
|
836
|
-
const
|
|
837
|
-
if (!
|
|
838
|
-
const o = await this.suggestCommand(
|
|
878
|
+
const n = typeof e == "string" ? this.commands[e] : e, s = typeof e == "string" ? e : n.command;
|
|
879
|
+
if (!n) {
|
|
880
|
+
const o = await this.suggestCommand(s);
|
|
839
881
|
return o ? await this.runCommand(t, o, ...i) : 1;
|
|
840
882
|
}
|
|
841
|
-
return await
|
|
883
|
+
return await n.run({
|
|
842
884
|
ctx: t,
|
|
843
885
|
logger: this.logger,
|
|
844
886
|
args: i
|
|
845
887
|
}) ?? 0;
|
|
846
888
|
}
|
|
847
889
|
async suggestCommand(t) {
|
|
848
|
-
const e = this.getAvailableCommands(), { bestMatch: i, bestMatchIndex:
|
|
890
|
+
const e = this.getAvailableCommands(), { bestMatch: i, bestMatchIndex: n, ratings: s } = this.stringSimilarity.findBestMatch(t, e), o = s.filter((m) => m.rating > 0.3).map((m) => m.target);
|
|
849
891
|
if (i.rating > 0 && o.length <= 1 || i.rating > 0.7 && o.length > 1) {
|
|
850
|
-
const
|
|
851
|
-
return await this.askRunSimilarCommand(t,
|
|
892
|
+
const m = e[n];
|
|
893
|
+
return await this.askRunSimilarCommand(t, m) ? m : null;
|
|
852
894
|
}
|
|
853
895
|
if (o.length) {
|
|
854
896
|
this.io.error(`${a.bgRed(" ERROR ")} Command ${a.yellow(t)} not found.
|
|
855
897
|
`);
|
|
856
|
-
const
|
|
857
|
-
if (
|
|
858
|
-
return
|
|
898
|
+
const m = await this.io.askForSelect(a.green("Did you mean to run one of these commands instead?"), o);
|
|
899
|
+
if (m)
|
|
900
|
+
return m;
|
|
859
901
|
}
|
|
860
|
-
throw new
|
|
902
|
+
throw new P(t);
|
|
861
903
|
}
|
|
862
904
|
async askRunSimilarCommand(t, e) {
|
|
863
905
|
return this.io.error(`${a.bgRed(" ERROR ")} Command ${a.yellow(t)} not found.
|
|
864
906
|
`), this.io.askForConfirmation(`${a.green(`Do you want to run ${a.yellow(e)} instead?`)} `);
|
|
865
907
|
}
|
|
866
908
|
async *listCommandsFiles(t) {
|
|
867
|
-
const e =
|
|
909
|
+
const e = I.readdirSync(t, { withFileTypes: !0 });
|
|
868
910
|
for (const i of e) {
|
|
869
|
-
const
|
|
911
|
+
const n = R.resolve(t, i.name);
|
|
870
912
|
if (i.isDirectory())
|
|
871
913
|
yield* this.listCommandsFiles(R.resolve(t, i.name));
|
|
872
914
|
else {
|
|
873
|
-
if (!
|
|
915
|
+
if (!n.endsWith(".ts") && !n.endsWith(".js") && !n.endsWith(".mjs") && !n.endsWith(".cjs"))
|
|
874
916
|
continue;
|
|
875
|
-
yield
|
|
917
|
+
yield n;
|
|
876
918
|
}
|
|
877
919
|
}
|
|
878
920
|
}
|
|
@@ -888,34 +930,34 @@ class W {
|
|
|
888
930
|
throw t;
|
|
889
931
|
}
|
|
890
932
|
}
|
|
891
|
-
class
|
|
933
|
+
class M extends v {
|
|
892
934
|
constructor(t) {
|
|
893
935
|
super("help", {
|
|
894
936
|
description: a.bold("Show help information about the CLI and its commands")
|
|
895
937
|
}), this.opts = t;
|
|
896
938
|
}
|
|
897
939
|
async handle() {
|
|
898
|
-
const t = this.opts.commandRegistry.getCommands(), e = this.opts.cliName ?? "Bob CLI", i = this.opts.cliVersion ?? "0.0.0",
|
|
899
|
-
this.io.log(`${e} ${a.green(i)} (core: ${a.yellow(
|
|
940
|
+
const t = this.opts.commandRegistry.getCommands(), e = this.opts.cliName ?? "Bob CLI", i = this.opts.cliVersion ?? "0.0.0", n = (await import("./package-C-2LYcDa.js"))?.default?.version ?? "0.0.0";
|
|
941
|
+
this.io.log(`${e} ${a.green(i)} (core: ${a.yellow(n)})
|
|
900
942
|
|
|
901
943
|
${a.yellow("Usage")}:
|
|
902
944
|
command [options] [arguments]
|
|
903
945
|
|
|
904
946
|
${a.yellow("Available commands")}:
|
|
905
947
|
`);
|
|
906
|
-
const
|
|
907
|
-
for (const
|
|
908
|
-
const
|
|
909
|
-
o[
|
|
948
|
+
const s = Math.max(...t.map((u) => u.command.length)) ?? 0, o = {};
|
|
949
|
+
for (const u of t) {
|
|
950
|
+
const h = u.group ?? u.command.split(":")[0];
|
|
951
|
+
o[h] || (o[h] = []), o[h].push(u);
|
|
910
952
|
}
|
|
911
|
-
const
|
|
912
|
-
for (const [
|
|
913
|
-
const l =
|
|
914
|
-
l && this.io.log(a.yellow(`${
|
|
915
|
-
const d =
|
|
916
|
-
for (const
|
|
917
|
-
let
|
|
918
|
-
l && (
|
|
953
|
+
const m = Object.entries(o).sort(([u], [h]) => u.toLowerCase().localeCompare(h.toLowerCase())).sort(([, u], [, h]) => u.length - h.length);
|
|
954
|
+
for (const [u, h] of m) {
|
|
955
|
+
const l = h.length > 1;
|
|
956
|
+
l && this.io.log(a.yellow(`${u}:`));
|
|
957
|
+
const d = h.sort((c, p) => c.command.toLowerCase().localeCompare(p.command.toLowerCase()));
|
|
958
|
+
for (const c of d) {
|
|
959
|
+
let p = A(s - c.command.length);
|
|
960
|
+
l && (p = p.slice(2)), this.io.log(`${l ? " " : ""}${a.green(c.command)} ${p} ${c.description}`);
|
|
919
961
|
}
|
|
920
962
|
}
|
|
921
963
|
}
|
|
@@ -927,16 +969,16 @@ class J {
|
|
|
927
969
|
exceptionHandler;
|
|
928
970
|
helpCommand;
|
|
929
971
|
newCommandRegistry(t) {
|
|
930
|
-
return new j(t
|
|
972
|
+
return new j(t);
|
|
931
973
|
}
|
|
932
974
|
newHelpCommand(t) {
|
|
933
|
-
return new
|
|
975
|
+
return new M(t);
|
|
934
976
|
}
|
|
935
977
|
newExceptionHandler(t) {
|
|
936
978
|
return new W(t.logger);
|
|
937
979
|
}
|
|
938
980
|
constructor(t = {}) {
|
|
939
|
-
this.ctx = t.ctx, this.logger = t.logger ?? new
|
|
981
|
+
this.ctx = t.ctx, this.logger = t.logger ?? new N(), this.commandRegistry = this.newCommandRegistry({
|
|
940
982
|
logger: this.logger
|
|
941
983
|
}), this.exceptionHandler = this.newExceptionHandler({
|
|
942
984
|
logger: this.logger
|
|
@@ -972,16 +1014,17 @@ export {
|
|
|
972
1014
|
f as BobError,
|
|
973
1015
|
J as Cli,
|
|
974
1016
|
v as Command,
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1017
|
+
S as CommandIO,
|
|
1018
|
+
P as CommandNotFoundError,
|
|
1019
|
+
k as CommandParser,
|
|
978
1020
|
j as CommandRegistry,
|
|
979
1021
|
$ as CommandSignatureParser,
|
|
980
1022
|
z as CommandWithSignature,
|
|
981
1023
|
W as ExceptionHandler,
|
|
982
|
-
|
|
1024
|
+
D as HelpOption,
|
|
983
1025
|
b as InvalidOption,
|
|
984
|
-
|
|
1026
|
+
N as Logger,
|
|
985
1027
|
F as MissingRequiredArgumentValue,
|
|
986
|
-
|
|
1028
|
+
V as MissingRequiredOptionValue,
|
|
1029
|
+
H as StringSimilarity
|
|
987
1030
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const t = "bob-core", e = "2.0.0-beta.
|
|
1
|
+
const t = "bob-core", e = "2.0.0-beta.15", s = "BOB Core", i = "module", m = !1, n = ["dist/**"], r = { ".": { import: "./dist/esm/index.js", require: "./dist/cjs/index.js" } }, o = { "*": { "*": ["./dist/cjs/*.d.ts"] } }, c = { 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" }, p = "Léo Hubert", d = "ISC", l = { "@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.7.3", "typescript-eslint": "^8.46.0", vite: "^7.1.6", "vite-plugin-dts": "^4.5.4", vitest: "^3.2.4" }, a = { chalk: "^5.6.2", minimist: "^1.2.8", prompts: "^2.4.2" }, f = {
|
|
2
2
|
name: t,
|
|
3
3
|
version: e,
|
|
4
4
|
description: s,
|
package/dist/esm/src/Cli.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from './Command.js';
|
|
2
|
-
import { CommandRegistry, CommandResolver, FileImporter } from './CommandRegistry.js';
|
|
2
|
+
import { CommandRegistry, CommandRegistryOptions, CommandResolver, FileImporter } from './CommandRegistry.js';
|
|
3
3
|
import { ExceptionHandler } from './ExceptionHandler.js';
|
|
4
4
|
import { Logger } from './Logger.js';
|
|
5
5
|
import { default as HelpCommand, HelpCommandOptions } from './commands/HelpCommand.js';
|
|
@@ -16,9 +16,7 @@ export declare class Cli<C extends ContextDefinition = ContextDefinition> {
|
|
|
16
16
|
readonly commandRegistry: CommandRegistry;
|
|
17
17
|
private readonly exceptionHandler;
|
|
18
18
|
private readonly helpCommand;
|
|
19
|
-
protected newCommandRegistry(opts:
|
|
20
|
-
logger: Logger;
|
|
21
|
-
}): CommandRegistry;
|
|
19
|
+
protected newCommandRegistry(opts: CommandRegistryOptions): CommandRegistry;
|
|
22
20
|
protected newHelpCommand(opts: HelpCommandOptions): HelpCommand;
|
|
23
21
|
protected newExceptionHandler(opts: {
|
|
24
22
|
logger: Logger;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CommandIO } from './CommandIO.js';
|
|
1
|
+
import { CommandIO, CommandIOOptions } from './CommandIO.js';
|
|
2
2
|
import { CommandParser } from './CommandParser.js';
|
|
3
3
|
import { Logger } from './Logger.js';
|
|
4
4
|
import { CommandOption } from './contracts/index.js';
|
|
@@ -43,9 +43,7 @@ export declare class Command<C extends ContextDefinition = ContextDefinition, Op
|
|
|
43
43
|
options: Options;
|
|
44
44
|
arguments: Arguments;
|
|
45
45
|
}): CommandParser<Options, Arguments>;
|
|
46
|
-
protected newCommandIO(opts:
|
|
47
|
-
logger: Logger;
|
|
48
|
-
}): CommandIO;
|
|
46
|
+
protected newCommandIO(opts: CommandIOOptions): CommandIO;
|
|
49
47
|
constructor(command: string, opts?: {
|
|
50
48
|
description?: string;
|
|
51
49
|
group?: string;
|
|
@@ -6,9 +6,12 @@ export type SelectOption = {
|
|
|
6
6
|
selected?: boolean | undefined;
|
|
7
7
|
description?: string | undefined;
|
|
8
8
|
};
|
|
9
|
+
export type CommandIOOptions = {
|
|
10
|
+
logger: Logger;
|
|
11
|
+
};
|
|
9
12
|
export declare class CommandIO {
|
|
10
13
|
private logger;
|
|
11
|
-
constructor(
|
|
14
|
+
constructor(opts: CommandIOOptions);
|
|
12
15
|
/**
|
|
13
16
|
* Logger methods
|
|
14
17
|
*/
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { Command } from './Command.js';
|
|
2
|
-
import { CommandIO } from './CommandIO.js';
|
|
2
|
+
import { CommandIO, CommandIOOptions } from './CommandIO.js';
|
|
3
3
|
import { Logger } from './Logger.js';
|
|
4
|
+
import { StringSimilarity } from './StringSimilarity.js';
|
|
4
5
|
import { ArgumentsSchema, ContextDefinition, OptionsSchema } from './lib/types.js';
|
|
5
6
|
export type CommandResolver = (path: string) => Promise<Command | null>;
|
|
6
7
|
export type FileImporter = (filePath: string) => Promise<unknown>;
|
|
8
|
+
export type CommandRegistryOptions = {
|
|
9
|
+
logger?: Logger;
|
|
10
|
+
stringSimilarity?: StringSimilarity;
|
|
11
|
+
};
|
|
7
12
|
export declare class CommandRegistry {
|
|
8
13
|
private readonly commands;
|
|
9
14
|
protected readonly io: CommandIO;
|
|
10
15
|
protected readonly logger: Logger;
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
private readonly stringSimilarity;
|
|
17
|
+
protected newCommandIO(opts: CommandIOOptions): CommandIO;
|
|
18
|
+
constructor(opts?: CommandRegistryOptions);
|
|
13
19
|
getAvailableCommands(): string[];
|
|
14
20
|
getCommands(): Array<Command>;
|
|
15
21
|
private importFile;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface SimilarityResult {
|
|
2
|
+
rating: number;
|
|
3
|
+
target: string;
|
|
4
|
+
}
|
|
5
|
+
export interface BestMatchResult {
|
|
6
|
+
bestMatch: SimilarityResult;
|
|
7
|
+
bestMatchIndex: number;
|
|
8
|
+
ratings: SimilarityResult[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* String similarity calculator using Dice's Coefficient algorithm
|
|
12
|
+
*/
|
|
13
|
+
export declare class StringSimilarity {
|
|
14
|
+
/**
|
|
15
|
+
* Generate bigrams (character pairs) from a string
|
|
16
|
+
*/
|
|
17
|
+
private getBigrams;
|
|
18
|
+
/**
|
|
19
|
+
* Calculate Dice's Coefficient similarity between two strings (0-1 scale)
|
|
20
|
+
*/
|
|
21
|
+
calculateSimilarity(str1: string, str2: string): number;
|
|
22
|
+
/**
|
|
23
|
+
* Find best matching string and ratings for all candidates
|
|
24
|
+
*/
|
|
25
|
+
findBestMatch(target: string, candidates: string[]): BestMatchResult;
|
|
26
|
+
}
|
package/dist/esm/src/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * from './CommandRegistry.js';
|
|
|
7
7
|
export * from './Cli.js';
|
|
8
8
|
export * from './Logger.js';
|
|
9
9
|
export * from './ExceptionHandler.js';
|
|
10
|
+
export * from './StringSimilarity.js';
|
|
10
11
|
export * from './lib/types.js';
|
|
11
12
|
export * from './errors/index.js';
|
|
12
13
|
export * from './options/index.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bob-core",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.15",
|
|
4
4
|
"description": "BOB Core",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -56,7 +56,6 @@
|
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"chalk": "^5.6.2",
|
|
58
58
|
"minimist": "^1.2.8",
|
|
59
|
-
"prompts": "^2.4.2"
|
|
60
|
-
"string-similarity": "^4.0.4"
|
|
59
|
+
"prompts": "^2.4.2"
|
|
61
60
|
}
|
|
62
61
|
}
|