bob-core 3.0.0-alpha.0 → 3.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- var e={name:`bob-core`,version:`3.0.0-alpha.0`,description:`BOB Core`,type:`module`,main:`./dist/cjs/src/index.js`,module:`./dist/esm/src/index.js`,types:`./dist/esm/src/index.d.ts`,files:[`dist`],exports:{".":{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`}}},scripts:{start:`node -r @swc-node/register debug/main.ts`,build:`rm -rf ./dist && vite build`,typecheck:`tsc --noEmit`,prepack:`npm run build`,test:`vitest run`,lint:`eslint .`,"lint:fix":`eslint . --fix`},author:`Léo Hubert`,license:`ISC`,devDependencies:{"@eslint/js":`^9.39.4`,"@faker-js/faker":`^10.3.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":`^4.1.0`,eslint:`^9.39.4`,"eslint-config-prettier":`^10.1.8`,"eslint-plugin-prettier":`^5.5.5`,prettier:`^3.6.2`,tsx:`^4.21.0`,typescript:`^5.9.3`,"typescript-eslint":`^8.57.0`,vite:`^8.0.0`,"vite-plugin-dts":`^4.5.4`,vitest:`^4.1.0`},dependencies:{chalk:`^4.1.2`,minimist:`^1.2.8`,prompts:`^2.4.2`}};exports.default=e;
1
+ var e={name:`bob-core`,version:`3.0.0-alpha.2`,description:`BOB Core`,type:`module`,main:`./dist/cjs/src/index.js`,module:`./dist/esm/src/index.js`,types:`./dist/esm/src/index.d.ts`,files:[`dist`],exports:{".":{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`}}},scripts:{start:`node -r @swc-node/register debug/main.ts`,build:`rm -rf ./dist && vite build`,typecheck:`tsc --noEmit`,prepack:`npm run build`,test:`vitest run`,lint:`eslint .`,"lint:fix":`eslint . --fix`},author:`Léo Hubert`,license:`ISC`,devDependencies:{"@eslint/js":`^9.39.4`,"@faker-js/faker":`^10.3.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":`^4.1.0`,eslint:`^9.39.4`,"eslint-config-prettier":`^10.1.8`,"eslint-plugin-prettier":`^5.5.5`,prettier:`^3.6.2`,tsx:`^4.21.0`,typescript:`^5.9.3`,"typescript-eslint":`^8.57.0`,vite:`^8.0.0`,"vite-plugin-dts":`^4.5.4`,vitest:`^4.1.0`},dependencies:{chalk:`^4.1.2`,minimist:`^1.2.8`,prompts:`^2.4.2`}};exports.default=e;
@@ -11,14 +11,12 @@ export declare abstract class CommandWithSignature<C extends ContextDefinition =
11
11
  static helperDefinitions: Record<string, string>;
12
12
  static get command(): string;
13
13
  run(runOpts: CommandRunOption<C>): Promise<number | void>;
14
- /**
15
- * Convenience accessor for a parsed flag value.
16
- */
17
- protected flag<T = string>(key: string): T | null;
18
- protected flag<T = string>(key: string, defaultValue: T): NoInfer<T>;
19
- /**
20
- * Convenience accessor for a parsed argument value.
21
- */
14
+ protected option<T = string>(key: string): T | null;
15
+ protected option<T = string>(key: string, defaultValue: T): NoInfer<T>;
22
16
  protected argument<T = string>(key: string): T | null;
23
17
  protected argument<T = string>(key: string, defaultValue: T): NoInfer<T>;
18
+ askForConfirmation(...opts: Parameters<typeof this.io.askForConfirmation>): ReturnType<typeof this.io.askForConfirmation>;
19
+ askForInput(...opts: Parameters<typeof this.io.askForInput>): ReturnType<typeof this.io.askForInput>;
20
+ askForSelect(...opts: Parameters<typeof this.io.askForSelect>): ReturnType<typeof this.io.askForSelect>;
21
+ newLoader(...opts: Parameters<typeof this.io.newLoader>): ReturnType<typeof this.io.newLoader>;
24
22
  }
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`prompts`);c=s(c);let l=require(`chalk`);l=s(l);let u=require(`minimist`);u=s(u);let d=require(`node:fs`);d=s(d);let f=require(`node:path`);f=s(f);var p=class{logger;constructor(e){this.logger=e.logger}log(...e){this.logger.log(...e)}info(...e){this.logger.info(...e)}warn(...e){this.logger.warn(...e)}error(...e){this.logger.error(...e)}debug(...e){this.logger.debug(...e)}async askForConfirmation(e=`Do you want to continue?`,t){return(await(0,c.default)({type:`confirm`,name:`value`,message:e,initial:t??!1})).value}async askForInput(e,t,n){return(await(0,c.default)({type:`text`,name:`value`,message:e,initial:t,...n}))?.value??null}async askForDate(e,t,n){return(await(0,c.default)({type:`date`,name:`value`,message:e,initial:t,...n}))?.value??null}async askForList(e,t,n){return(await(0,c.default)({type:`list`,name:`value`,message:e,initial:t,...n}))?.value??null}async askForToggle(e,t,n){return(await(0,c.default)({type:`toggle`,name:`value`,message:e,initial:t,...n}))?.value??null}async askForSelect(e,t,n){if(t.length===0)throw Error(`No options provided`);let r=[];for(let e of t)typeof e==`string`?r.push({title:e,value:e}):r.push(e);return(await(0,c.default)({type:`select`,name:`value`,message:e,choices:r,...n}))?.value??null}newLoader(e=``,t=[`⠙`,`⠘`,`⠰`,`⠴`,`⠤`,`⠦`,`⠆`,`⠃`,`⠋`,`⠉`],n=100){let r=e,i=null,a=0,o=setInterval(function(){i&&=(process.stdout.write(new TextEncoder().encode(`\r`+` `.repeat(i.length+5)+`\r`)),null),process.stdout.write(new TextEncoder().encode(`\r`+t[a++]+` `+r)),a%=t.length},n),s=()=>{clearInterval(o),process.stdout.write(new TextEncoder().encode(`\r`+` `.repeat(r.length+5)+`\r`))};return{[Symbol.dispose]:s,[Symbol.asyncDispose]:s,updateText:e=>{i=r,r=e},stop:s}}},m=class extends Error{$type=`BobError`},h=class extends m{constructor(e,t={}){super(`Flag ${e} is not recognized`),this.flag=e,this.flagsSchema=t}pretty(e){e.log(``),e.log(` ${l.default.bold.white.bgRed(` ERROR `)} Flag ${l.default.bold.yellow(this.flag)} is not recognized.`);let t=Object.entries(this.flagsSchema);if(t.length>0){e.log(``),e.log(` ${l.default.dim(`Available flags:`)}`),e.log(``);let n=t.map(([e,t])=>{let n=t.alias?typeof t.alias==`string`?[t.alias]:t.alias:[],r=Array.isArray(t.type)?`[${t.type[0]}]`:t.type===`enum`&&t.options?t.options.join(` | `):t.type;return{nameWithAlias:`--${e}${n.length>0?n.map(e=>`, -${e}`).join(``):``}`,description:t.description||``,typeDisplay:r}}),r=Math.max(...n.map(e=>e.nameWithAlias.length));for(let t of n){let n=` `.repeat(r-t.nameWithAlias.length+2);e.log(` ${l.default.green(t.nameWithAlias)}${n}${t.description} ${l.default.dim(`(${t.typeDisplay})`)}`)}}e.log(``)}},g=class extends m{constructor(e){super(`Argument "${e}" is required.`),this.argument=e}pretty(e){e.log(``),e.log(` ${l.default.bold.white.bgRed(` ERROR `)} Argument ${l.default.bold.yellow(this.argument)} is required.`),e.log(``)}},_=class extends m{constructor(e){super(`Flag "${e}" is required.`),this.flag=e}pretty(e){e.log(``),e.log(` ${l.default.bold.white.bgRed(` ERROR `)} Flag ${l.default.bold.yellow(this.flag)} is required.`),e.log(``)}},v=class extends m{constructor(e,t){let n=`Argument "${e.arg}" value is invalid.`;e.reason?n+=` Reason: ${e.reason}`:n+=` Value: "${e.value}"`,super(n),this.detail=e,this.argDefinition=t}pretty(e){let t=[];if(this.detail.reason!=null&&t.push([`Reason`,this.detail.reason]),this.detail.value!=null&&t.push([`Value`,this.detail.value]),this.argDefinition?.help!=null&&t.push([`Help`,l.default.green(this.argDefinition.help)]),e.log(``),e.log(` ${l.default.bold.white.bgRed(` ERROR `)} Argument ${l.default.bold.yellow(this.detail.arg)} value is invalid.`),t.length>0){e.log(``);let n=Math.max(...t.map(([e])=>e.length));for(let[r,i]of t)e.log(` ${` `.repeat(n-r.length)}${l.default.dim(r)} ${i}`)}e.log(``)}},y=class extends m{constructor(e,t){let n=`Flag "${e.flag}" value is invalid.`;e.reason?n+=` Reason: ${e.reason}`:n+=` Value: "${e.value}"`,super(n),this.param=e,this.flagDefinition=t}pretty(e){let t=[];if(this.param.reason!=null&&t.push([`Reason`,this.param.reason]),this.param.value!=null&&t.push([`Value`,this.param.value]),this.flagDefinition?.help!=null&&t.push([`Help`,l.default.green(this.flagDefinition.help)]),e.log(``),e.log(` ${l.default.bold.white.bgRed(` ERROR `)} Flag ${l.default.bold.yellow(this.param.flag)} value is invalid.`),t.length>0){e.log(``);let n=Math.max(...t.map(([e])=>e.length));for(let[r,i]of t)e.log(` ${` `.repeat(n-r.length)}${l.default.dim(r)} ${i}`)}e.log(``)}},b=class extends m{constructor(e){super(`Command "${e}" not found.`),this.command=e}pretty(e){e.log(``),e.log(` ${l.default.bold.white.bgRed(` ERROR `)} Command ${l.default.bold.yellow(this.command)} not found.`),e.log(``)}},x=class extends m{constructor(e,t){super(`Too many arguments provided. Expected ${e}, got ${t}.`),this.expected=e,this.received=t}pretty(e){e.log(``),e.log(` ${l.default.bold.white.bgRed(` ERROR `)} Too many arguments. Expected ${l.default.bold.yellow(String(this.expected))}, got ${l.default.bold.yellow(String(this.received))}.`),e.log(``)}},S=class{flags;parsedFlags=null;args;parsedArguments=null;io;shouldPromptForMissingFlags=!0;shouldValidateUnknownFlags=!0;shouldRejectExtraArguments=!1;constructor(e){this.opts=e,this.io=e.io,this.flags=e.flags,this.args=e.args}async init(e){let{_:t,...n}=(0,u.default)(e);return this.shouldValidateUnknownFlags&&this.validateUnknownFlags(n),this.parsedFlags=await this.handleOptions(n),this.parsedArguments=await this.handleArguments(t),{flags:this.parsedFlags,args:this.parsedArguments}}async validate(){for(let e in this.flags){let t=this.flags[e],n=this.parsedFlags?.[e],r=this.isEmptyValue(n),i=`multiple`in t&&t.multiple;if(t.required&&r)throw new _(e);if(!r&&t.validate){let r=i&&Array.isArray(n)?n:[n];for(let n of r){let r=await t.validate(n);if(r!==!0)throw new y({flag:e,reason:r,value:n})}}}for(let e in this.args){let t=this.args[e],n=this.parsedArguments?.[e],r=this.isEmptyValue(n),i=`multiple`in t&&t.multiple;if(t.required&&r){if(!this.shouldPromptForMissingFlags)throw new g(e);let n=await this.promptForArgument(e,t);if(n&&this.parsedArguments){this.parsedArguments[e]=await this.parseValue(n,t,{name:e,isArg:!0});continue}throw new g(e)}if(!r&&t.validate){let r=i&&Array.isArray(n)?n:[n];for(let n of r){let r=await t.validate(n);if(r!==!0)throw new v({arg:e,reason:r,value:n})}}}}flag(e,t){if(!this.parsedFlags)throw Error(`Flags have not been parsed yet. Call init() first.`);return this.isEmptyValue(this.parsedFlags[e])&&t!==void 0?t:this.parsedFlags[e]}async setFlag(e,t){if(!this.parsedFlags)throw Error(`Flags have not been parsed yet. Call init() first.`);if(!(e in this.flags))throw new h(e,this.flags);if(this.flags[e].validate){let n=await this.flags[e].validate(t);if(n!==!0)throw new y({flag:e,reason:n,value:t})}this.parsedFlags[e]=t}argument(e,t){if(!this.parsedArguments)throw Error(`Arguments have not been parsed yet. Call init() first.`);return this.isEmptyValue(this.parsedArguments[e])&&t!==void 0?t:this.parsedArguments[e]}async setArgument(e,t){if(!this.parsedArguments)throw Error(`Arguments have not been parsed yet. Call init() first.`);if(!(e in this.args))throw new v({arg:e,reason:`Argument "${e}" is not recognized`});if(this.args[e].validate){let n=await this.args[e].validate(t);if(n!==!0)throw new v({arg:e,reason:n,value:t})}this.parsedArguments[e]=t}isEmptyValue(e){return e==null||typeof e==`string`&&e.trim()===``||Array.isArray(e)&&e.length===0}validateUnknownFlags(e){let t=new Set;for(let e in this.flags){t.add(e);let n=this.flags[e];for(let e of n.alias??[])t.add(e)}for(let n in e)if(!t.has(n))throw new h(n,this.flags)}async handleOptions(e){let t={};for(let n in this.flags)t[n]=await this.resolveFlagValue(n,this.flags[n],e);return t}async handleArguments(e){let t={},n=[...e],r=Object.keys(this.args).length;for(let e in this.args){let r=this.args[e];if(`multiple`in r&&r.multiple){t[e]=await this.parseValue(n,r,{name:e,isArg:!0}),n.length=0;continue}t[e]=await this.parseValue(n.shift(),r,{name:e,isArg:!0})}if(this.shouldRejectExtraArguments&&n.length>0)throw new x(r,r+n.length);return t}async resolveFlagValue(e,t,n){let r,i=[e];t.alias&&i.push(...Array.isArray(t.alias)?t.alias:[t.alias]);for(let e of i)if(e in n){r=n[e];break}return this.parseValue(r,t,{name:e})}async parseValue(e,t,n){if(this.isEmptyValue(e))return typeof t.default==`function`?await t.default():t.default;if(`multiple`in t&&t.multiple){Array.isArray(e)||(e=[e]);let r=[];for(let i of e)r.push(await this.safeParse(i,t,n));return r}return this.safeParse(e,t,n)}async safeParse(e,t,n){try{return t.parse(e,this.opts.ctx)}catch(t){if(!n)throw t;let r=t instanceof Error?t.message:String(t);throw n.isArg?new v({arg:n.name,value:e,reason:r}):new y({flag:n.name,value:e,reason:r})}}disablePrompting(){return this.shouldPromptForMissingFlags=!1,this}allowUnknownFlags(){return this.shouldValidateUnknownFlags=!1,this}strictMode(){return this.shouldRejectExtraArguments=!0,this}async promptForArgument(e,t){let n=t.type;if(n===`enum`&&t.options){let n=`${l.default.yellow.bold(e)} is required`;t.description&&(n+=`: ${l.default.gray(`(${t.description})`)}`),n+=` ${l.default.green(`(enum)`)}\n`;let r=t.options.map(e=>({title:e,value:e}));return await this.io.askForSelect(n,r)}let r=`multiple`in t&&t.multiple;if(!r&&![`string`,`number`].includes(n))return null;let i=`${l.default.yellow.bold(e)} is required`;return t.description&&(i+=`: ${l.default.gray(`(${t.description})`)}`),i+=` ${l.default.green(`(${n}${r?`[]`:``})`)}\n`,r?(i+=`Please provide one or more values, separated by commas:
2
- `,await this.io.askForList(i,void 0,{separator:`,`,validate:e=>{if(this.isEmptyValue(e)&&t.required)return`Please enter at least one value`;for(let n of e.split(`,`)){let e=t.validate?t.validate(n):!0;if(e!==!0)return typeof e==`string`?`${n} ${e}`:`Invalid value: "${n.trim()}"`}return!0}})):await this.io.askForInput(i,void 0,{type:n===`number`?`number`:`secret`in t&&t.secret?`password`:`text`,validate:e=>{if(this.isEmptyValue(e)&&t.required)return`This value is required`;let n=t.validate?t.validate(e):!0;return n===!0?!0:typeof n==`string`?n:`Invalid value`}})}},C={string(e){return{default:e?.multiple?[]:null,parse:e=>{if(typeof e==`boolean`)throw Error(`Expected a string, got boolean "${e}"`);return String(e)},...e,type:`string`}},number(e){return{default:e?.multiple?[]:null,validate(t){return e?.min!==void 0&&t<e.min?`is below minimum ${e.min}`:e?.max!==void 0&&t>e.max?`exceeds maximum ${e.max}`:!0},parse:e=>{let t=typeof e==`number`?e:Number(e);if(isNaN(t))throw Error(`must be a valid number`);return t},...e,type:`number`}},boolean(e){return{default:!1,parse:e=>{if(typeof e==`boolean`)return e;let t=String(e).toLowerCase();return t===`true`||t===`1`?!0:t===`false`||t===`0`?!1:!!e},...e,type:`boolean`}},enum(e){return{default:e.multiple?[]:null,validate(t){return e.options.includes(t)?!0:`must be one of: ${e.options.map(e=>`"${e}"`).join(`, `)}`},parse:e=>String(e),...e,type:`enum`}},file(e){return{default:null,parse:e=>String(e),validate(t){return e?.exists&&!d.default.existsSync(t)?`file does not exist`:!0},...e,type:`file`}},directory(e){return{default:null,parse:e=>String(e),validate(t){return e?.exists&&!(d.default.existsSync(t)&&d.default.lstatSync(t).isDirectory())?`directory does not exist`:!0},...e,type:`directory`}},url(e){return{default:null,parse:e=>new URL(String(e)),...e,type:`url`}},custom(e){return t=>({default:e?.multiple||t?.multiple?[]:null,parse:e=>e,...e,...t,type:`custom`})}},w=C;function T(e){return Array(e+5).join(` `)}function E(e){let t=e.type;return Array.isArray(t)?`[${t[0]}]`:t===`enum`&&e.options?`enum: ${e.options.join(`|`)}`:t}var D=C.boolean({alias:[`h`],handler:(e,t,n)=>{if(!e)return{shouldStop:!1};let r=n.args,i=n.flags,a=Object.entries(r),o=Object.entries(i),s=o.map(([e,t])=>{let n=Array.isArray(t.alias)?t.alias:t.alias?[t.alias]:[];return{name:e,...t,flagWithAlias:`--${e}${n.map(e=>`, -${e}`).join(``)}`}}),c=a.filter(([,e])=>e.required);console.log(l.default.yellow(`Description:`)),console.log(` ${n.description}\n`),console.log(l.default.yellow(`Usage:`)),console.log(` ${n.command} ${c.length>0?c.map(([e])=>`<${e}>`).join(` `):`\b`} [options]`);let u=Math.max(...s.map(e=>e.flagWithAlias.length),0),d=Math.max(...a.map(([e])=>e.length),0),f=d>u?d:u;if(a.length>0){console.log(`\n${l.default.yellow(`Arguments`)}:`);for(let[e,t]of a){let n=T(f-e.length),r=` ${l.default.green(e)} ${n} ${t.description??`\b`}`;if(t.default!==void 0&&!t.required){let e=typeof t.default==`function`?`[function]`:t.multiple?JSON.stringify(t.default):t.default;r+=` ${l.default.yellow(`[default: ${e}]`)}`}`multiple`in t&&t.multiple&&(r+=` ${l.default.white(`(variadic)`)}`),console.log(r)}}if(o.length>0){console.log(`\n${l.default.yellow(`Options`)}:`);for(let e of s){let t=T(f-e.flagWithAlias.length),n=` ${l.default.green(e.flagWithAlias)} ${t} ${e.description??`\b`}`;if(e.type&&(n+=` ${l.default.white(`(${E(e)})`)}`),e.default!==void 0&&!e.required){let t=typeof e.default==`function`?`(function)`:e.default;n+=` ${l.default.yellow(`[default: ${t}]`)}`}console.log(n)}}let p=n.examples??[];if(p.length>0){console.log(`\n${l.default.yellow(`Examples`)}:`);let e=process.argv[0].split(`/`).pop();e===`node`&&(e+=` `+process.argv[1].split(`/`).pop());for(let[t,n]of p.entries())t>0&&console.log(``),console.log(` ${n.description}\n`),console.log(` ${l.default.green(`${e} ${n.command}`)}`)}return{shouldStop:!0}}}),O=class{$type=`BobCommand`;static command=``;static description=``;static group;static args={};static flags={};static examples=[];static hidden=!1;static disableDefaultOptions=!1;static disablePrompting=!1;static allowUnknownFlags=!1;static strictMode=!1;ctx;io;parser;static baseFlags={help:D};newCommandParser(e){return new S({io:e.io,ctx:e.ctx,flags:e.flags,args:e.args})}newCommandIO(e){return new p(e)}async run(e){let t=this.constructor;this.ctx=e.ctx,this.io=this.newCommandIO({logger:e.logger});let n;if(`flags`in e)n={flags:e.flags,args:e.args};else{this.parser=this.newCommandParser({ctx:this.ctx,io:this.io,flags:t.disableDefaultOptions?t.flags:{...t.baseFlags,...t.flags},args:t.args}),t.allowUnknownFlags&&this.parser.allowUnknownFlags(),t.strictMode&&this.parser.strictMode(),t.disablePrompting&&this.parser.disablePrompting();let r=await this.parser.init(e.args);for(let n in r.flags){let i=r.flags[n],a=t.flags[n]||t.baseFlags[n];if(a&&a.handler){let n=a.handler(i,e.ctx,t);if(n&&n.shouldStop)return-1}}await this.parser.validate(),n={flags:r.flags,args:r.args}}if(this.preHandle){let e=await this.preHandle();if(e&&e!==0)return e}return await this.handle(this.ctx,n)??0}},k=class{level;constructor(e={}){this.level=e.level??`info`}shouldLog(e){let t=[`debug`,`info`,`warn`,`error`],n=t.indexOf(this.level);return t.indexOf(e)>=n}setLevel(e){this.level=e}getLevel(){return this.level}log(...e){console.log(...e)}info(...e){this.shouldLog(`info`)&&console.log(...e)}warn(...e){this.shouldLog(`warn`)&&console.warn(...e)}error(...e){this.shouldLog(`error`)&&console.error(...e)}debug(...e){this.shouldLog(`debug`)&&console.log(...e)}},A=class{getBigrams(e){let t=[],n=e.toLowerCase();for(let e=0;e<n.length-1;e++)t.push(n.slice(e,e+2));return t}calculateSimilarity(e,t){if(e===t)return 1;if(e.length<2||t.length<2)return 0;let n=this.getBigrams(e),r=this.getBigrams(t),i=new Set(r),a=0;for(let e of n)i.has(e)&&(a++,i.delete(e));return 2*a/(n.length+r.length)}findBestMatch(e,t){let n=t.map(t=>({target:t,rating:this.calculateSimilarity(e,t)})),r=0,i=n[0]?.rating??0;for(let e=1;e<n.length;e++)n[e].rating>i&&(i=n[e].rating,r=e);return{ratings:n,bestMatch:n[r],bestMatchIndex:r}}};function j(e){return typeof e==`object`&&!!e&&`$type`in e&&e.$type===`BobError`}function M(e){return typeof e==`function`&&e.prototype instanceof O}var N=class{commands={};io;logger;stringSimilarity;newCommandIO(e){return new p(e)}constructor(e){this.logger=e?.logger??new k,this.io=this.newCommandIO({logger:this.logger}),this.stringSimilarity=e?.stringSimilarity??new A}getAvailableCommands(){return Object.keys(this.commands)}getCommands(){return Object.values(this.commands)}importFile=async e=>(await import(e)).default;commandResolver=async e=>{let t=await this.importFile(e);return t?(t&&typeof t==`object`&&`default`in t&&(t=t.default),typeof t==`function`&&M(t)?t:null):null};withCommandResolver(e){return this.commandResolver=e,this}withFileImporter(e){return this.importFile=e,this}registerCommand(e,t=!1){if(!M(e))throw Error(`Invalid command, it must extend the Command class.`);let n=e.command;if(!n)throw Error(`Cannot register a command with no name. ${e.name} `);if(!t&&this.commands[n])throw Error(`Command ${n} already registered.`);this.commands[n]=e}async loadCommandsPath(e){for await(let t of this.listCommandsFiles(e))try{let e=await this.commandResolver(t);M(e)&&this.registerCommand(e)}catch(e){throw Error(`Command ${t} failed to load. ${e}`,{cause:e})}}async runCommand(e,t,...n){let r;if(typeof t==`string`){let i=this.commands[t];if(!i){let r=await this.suggestCommand(t);return r?await this.runCommand(e,r,...n):1}r=new i}else r=M(t)?new t:t;return await r.run({ctx:e,logger:this.logger,args:n})??0}async suggestCommand(e){let t=this.getAvailableCommands(),{bestMatch:n,bestMatchIndex:r,ratings:i}=this.stringSimilarity.findBestMatch(e,t),a=i.filter(e=>e.rating>.3).map(e=>e.target);if(n&&(n.rating>0&&a.length<=1||n.rating>.7&&a.length>1)){let n=t[r];return await this.askRunSimilarCommand(e,n)?n:null}if(a.length){this.io.error(`${l.default.bgRed(` ERROR `)} Command ${l.default.yellow(e)} not found.\n`);let t=await this.io.askForSelect(l.default.green(`Did you mean to run one of these commands instead?`),a);if(t)return t}throw new b(e)}async askRunSimilarCommand(e,t){return this.io.error(`${l.default.bgRed(` ERROR `)} Command ${l.default.yellow(e)} not found.\n`),this.io.askForConfirmation(`${l.default.green(`Do you want to run ${l.default.yellow(t)} instead?`)} `)}async*listCommandsFiles(e){let t=d.default.readdirSync(e,{withFileTypes:!0});for(let n of t){let t=f.default.resolve(e,n.name);if(n.isDirectory())yield*this.listCommandsFiles(f.default.resolve(e,n.name));else{if(!t.endsWith(`.ts`)&&!t.endsWith(`.js`)&&!t.endsWith(`.mjs`)&&!t.endsWith(`.cjs`))continue;yield t}}}},P=class e{static parse(t,n={}){let[r,...i]=t.split(/\{(.*?)\}/g).map(e=>e.trim()).filter(Boolean),a={},o={};for(let t of i){let{name:r,isFlag:i,definition:s}=e.parseParamSignature(t,n);i?a[r]=s:o[r]=s}return{command:r,flags:a,args:o}}static parseParamSignature(e,t){let n=e,r=!1,i,a,o,s=!1,c=!1,l=!0;if(n.includes(`:`)){let[e,t]=n.split(`:`);n=e.trim(),i=t.trim()}if(n.includes(`=`)){let[e,t]=n.split(`=`);n=e.trim();let r=t.trim();l=!1,r.length?r===`*`?(c=!0,a=[]):r===`true`?(s=!0,a=!0):r===`false`?(s=!0,a=!1):a=r:a=null}else n.startsWith(`--`)&&(s=!0,l=!1,a=!1);if(n.includes(`|`)){let[e,...t]=n.split(`|`);n=e.trim(),o=t.map(e=>e.trim())}n.startsWith(`--`)&&(r=!0,n=n.slice(2)),n.endsWith(`?`)&&(l=!1,n=n.slice(0,-1)),n.endsWith(`*`)&&(c=!0,l=!0,a=[],n=n.slice(0,-1)),i=i??t[n]??t[`--${n}`];let u,d=r?C:w;return u=s?C.boolean({description:i,alias:o,...a===void 0?{}:{default:a}}):c?d.string({description:i,alias:o,multiple:!0,...l?{required:!0}:{},default:a??[]}):d.string({description:i,alias:o,...l?{required:!0}:{},...a===void 0?{}:{default:a}}),{name:n,isFlag:r,definition:u}}},F=class extends O{static signature=``;static helperDefinitions={};static get command(){return this.signature.split(/\s/)[0]||``}async run(e){let t=this.constructor;if(t.signature&&!Object.prototype.hasOwnProperty.call(t,`_signatureParsed`)){let e=P.parse(t.signature,t.helperDefinitions),n=Object.prototype.hasOwnProperty.call(t,`flags`)?t.flags:{},r=Object.prototype.hasOwnProperty.call(t,`args`)?t.args:{};t.flags={...e.flags,...n},t.args={...e.args,...r},Object.defineProperty(t,`_signatureParsed`,{value:!0})}return super.run(e)}flag(e,t=null){return this.parser.flag(e,t)}argument(e,t=null){return this.parser.argument(e,t)}},I=class{logger;constructor(e){this.logger=e}handle(e){if(j(e))return e.pretty(this.logger),-1;throw e}},L=class extends O{static command=`help`;static description=l.default.bold(`Show help information about the CLI and its commands`);constructor(e){super(),this.opts=e}async handle(){let e=this.opts.commandRegistry.getCommands().filter(e=>!e.hidden),t=this.opts.cliName??`Bob CLI`,n=this.opts.cliVersion??`0.0.0`,r=(await Promise.resolve().then(()=>require(`../package-I_hjzzxG.cjs`)))?.default?.version??`0.0.0`;this.io.log(`${t} ${l.default.green(n)} (core: ${l.default.yellow(r)})
2
+ `,await this.io.askForList(i,void 0,{separator:`,`,validate:e=>{if(this.isEmptyValue(e)&&t.required)return`Please enter at least one value`;for(let n of e.split(`,`)){let e=t.validate?t.validate(n):!0;if(e!==!0)return typeof e==`string`?`${n} ${e}`:`Invalid value: "${n.trim()}"`}return!0}})):await this.io.askForInput(i,void 0,{type:n===`number`?`number`:`secret`in t&&t.secret?`password`:`text`,validate:e=>{if(this.isEmptyValue(e)&&t.required)return`This value is required`;let n=t.validate?t.validate(e):!0;return n===!0?!0:typeof n==`string`?n:`Invalid value`}})}},C={string(e){return{default:e?.multiple?[]:null,parse:e=>{if(typeof e==`boolean`)throw Error(`Expected a string, got boolean "${e}"`);return String(e)},...e,type:`string`}},number(e){return{default:e?.multiple?[]:null,validate(t){return e?.min!==void 0&&t<e.min?`is below minimum ${e.min}`:e?.max!==void 0&&t>e.max?`exceeds maximum ${e.max}`:!0},parse:e=>{let t=typeof e==`number`?e:Number(e);if(isNaN(t))throw Error(`must be a valid number`);return t},...e,type:`number`}},boolean(e){return{default:!1,parse:e=>{if(typeof e==`boolean`)return e;let t=String(e).toLowerCase();return t===`true`||t===`1`?!0:t===`false`||t===`0`?!1:!!e},...e,type:`boolean`}},enum(e){return{default:e.multiple?[]:null,validate(t){return e.options.includes(t)?!0:`must be one of: ${e.options.map(e=>`"${e}"`).join(`, `)}`},parse:e=>String(e),...e,type:`enum`}},file(e){return{default:null,parse:e=>String(e),validate(t){return e?.exists&&!d.default.existsSync(t)?`file does not exist`:!0},...e,type:`file`}},directory(e){return{default:null,parse:e=>String(e),validate(t){return e?.exists&&!(d.default.existsSync(t)&&d.default.lstatSync(t).isDirectory())?`directory does not exist`:!0},...e,type:`directory`}},url(e){return{default:null,parse:e=>new URL(String(e)),...e,type:`url`}},custom(e){return t=>({default:e?.multiple||t?.multiple?[]:null,parse:e=>e,...e,...t,type:`custom`})}},w=C;function T(e){return Array(e+5).join(` `)}function E(e){let t=e.type;return Array.isArray(t)?`[${t[0]}]`:t===`enum`&&e.options?`enum: ${e.options.join(`|`)}`:t}var D=C.boolean({alias:[`h`],handler:(e,t,n)=>{if(!e)return{shouldStop:!1};let r=n.args,i=n.flags,a=Object.entries(r),o=Object.entries(i),s=o.map(([e,t])=>{let n=Array.isArray(t.alias)?t.alias:t.alias?[t.alias]:[];return{name:e,...t,flagWithAlias:`--${e}${n.map(e=>`, -${e}`).join(``)}`}}),c=a.filter(([,e])=>e.required);console.log(l.default.yellow(`Description:`)),console.log(` ${n.description}\n`),console.log(l.default.yellow(`Usage:`)),console.log(` ${n.command} ${c.length>0?c.map(([e])=>`<${e}>`).join(` `):`\b`} [options]`);let u=Math.max(...s.map(e=>e.flagWithAlias.length),0),d=Math.max(...a.map(([e])=>e.length),0),f=d>u?d:u;if(a.length>0){console.log(`\n${l.default.yellow(`Arguments`)}:`);for(let[e,t]of a){let n=T(f-e.length),r=` ${l.default.green(e)} ${n} ${t.description??`\b`}`;if(t.default!==void 0&&!t.required){let e=typeof t.default==`function`?`[function]`:t.multiple?JSON.stringify(t.default):t.default;r+=` ${l.default.yellow(`[default: ${e}]`)}`}`multiple`in t&&t.multiple&&(r+=` ${l.default.white(`(variadic)`)}`),console.log(r)}}if(o.length>0){console.log(`\n${l.default.yellow(`Options`)}:`);for(let e of s){let t=T(f-e.flagWithAlias.length),n=` ${l.default.green(e.flagWithAlias)} ${t} ${e.description??`\b`}`;if(e.type&&(n+=` ${l.default.white(`(${E(e)})`)}`),e.default!==void 0&&!e.required){let t=typeof e.default==`function`?`(function)`:e.default;n+=` ${l.default.yellow(`[default: ${t}]`)}`}console.log(n)}}let p=n.examples??[];if(p.length>0){console.log(`\n${l.default.yellow(`Examples`)}:`);let e=process.argv[0].split(`/`).pop();e===`node`&&(e+=` `+process.argv[1].split(`/`).pop());for(let[t,n]of p.entries())t>0&&console.log(``),console.log(` ${n.description}\n`),console.log(` ${l.default.green(`${e} ${n.command}`)}`)}return{shouldStop:!0}}}),O=class{$type=`BobCommand`;static command=``;static description=``;static group;static args={};static flags={};static examples=[];static hidden=!1;static disableDefaultOptions=!1;static disablePrompting=!1;static allowUnknownFlags=!1;static strictMode=!1;ctx;io;parser;static baseFlags={help:D};newCommandParser(e){return new S({io:e.io,ctx:e.ctx,flags:e.flags,args:e.args})}newCommandIO(e){return new p(e)}async run(e){let t=this.constructor;this.ctx=e.ctx,this.io=this.newCommandIO({logger:e.logger});let n;if(`flags`in e)n={flags:e.flags,args:e.args};else{this.parser=this.newCommandParser({ctx:this.ctx,io:this.io,flags:t.disableDefaultOptions?t.flags:{...t.baseFlags,...t.flags},args:t.args}),t.allowUnknownFlags&&this.parser.allowUnknownFlags(),t.strictMode&&this.parser.strictMode(),t.disablePrompting&&this.parser.disablePrompting();let r=await this.parser.init(e.args);for(let n in r.flags){let i=r.flags[n],a=t.flags[n]||t.baseFlags[n];if(a&&a.handler){let n=a.handler(i,e.ctx,t);if(n&&n.shouldStop)return-1}}await this.parser.validate(),n={flags:r.flags,args:r.args}}if(this.preHandle){let e=await this.preHandle();if(e&&e!==0)return e}return await this.handle(this.ctx,n)??0}},k=class{level;constructor(e={}){this.level=e.level??`info`}shouldLog(e){let t=[`debug`,`info`,`warn`,`error`],n=t.indexOf(this.level);return t.indexOf(e)>=n}setLevel(e){this.level=e}getLevel(){return this.level}log(...e){console.log(...e)}info(...e){this.shouldLog(`info`)&&console.log(...e)}warn(...e){this.shouldLog(`warn`)&&console.warn(...e)}error(...e){this.shouldLog(`error`)&&console.error(...e)}debug(...e){this.shouldLog(`debug`)&&console.log(...e)}},A=class{getBigrams(e){let t=[],n=e.toLowerCase();for(let e=0;e<n.length-1;e++)t.push(n.slice(e,e+2));return t}calculateSimilarity(e,t){if(e===t)return 1;if(e.length<2||t.length<2)return 0;let n=this.getBigrams(e),r=this.getBigrams(t),i=new Set(r),a=0;for(let e of n)i.has(e)&&(a++,i.delete(e));return 2*a/(n.length+r.length)}findBestMatch(e,t){let n=t.map(t=>({target:t,rating:this.calculateSimilarity(e,t)})),r=0,i=n[0]?.rating??0;for(let e=1;e<n.length;e++)n[e].rating>i&&(i=n[e].rating,r=e);return{ratings:n,bestMatch:n[r],bestMatchIndex:r}}};function j(e){return typeof e==`object`&&!!e&&`$type`in e&&e.$type===`BobError`}function M(e){return typeof e==`function`&&e.prototype instanceof O}var N=class{commands={};io;logger;stringSimilarity;newCommandIO(e){return new p(e)}constructor(e){this.logger=e?.logger??new k,this.io=this.newCommandIO({logger:this.logger}),this.stringSimilarity=e?.stringSimilarity??new A}getAvailableCommands(){return Object.keys(this.commands)}getCommands(){return Object.values(this.commands)}importFile=async e=>(await import(e)).default;commandResolver=async e=>{let t=await this.importFile(e);return t?(t&&typeof t==`object`&&`default`in t&&(t=t.default),typeof t==`function`&&M(t)?t:null):null};withCommandResolver(e){return this.commandResolver=e,this}withFileImporter(e){return this.importFile=e,this}registerCommand(e,t=!1){if(!M(e))throw Error(`Invalid command, it must extend the Command class.`);let n=e.command;if(!n)throw Error(`Cannot register a command with no name. ${e.name} `);if(!t&&this.commands[n])throw Error(`Command ${n} already registered.`);this.commands[n]=e}async loadCommandsPath(e){for await(let t of this.listCommandsFiles(e))try{let e=await this.commandResolver(t);M(e)&&this.registerCommand(e)}catch(e){throw Error(`Command ${t} failed to load. ${e}`,{cause:e})}}async runCommand(e,t,...n){let r;if(typeof t==`string`){let i=this.commands[t];if(!i){let r=await this.suggestCommand(t);return r?await this.runCommand(e,r,...n):1}r=new i}else r=M(t)?new t:t;return await r.run({ctx:e,logger:this.logger,args:n})??0}async suggestCommand(e){let t=this.getAvailableCommands(),{bestMatch:n,bestMatchIndex:r,ratings:i}=this.stringSimilarity.findBestMatch(e,t),a=i.filter(e=>e.rating>.3).map(e=>e.target);if(n&&(n.rating>0&&a.length<=1||n.rating>.7&&a.length>1)){let n=t[r];return await this.askRunSimilarCommand(e,n)?n:null}if(a.length){this.io.error(`${l.default.bgRed(` ERROR `)} Command ${l.default.yellow(e)} not found.\n`);let t=await this.io.askForSelect(l.default.green(`Did you mean to run one of these commands instead?`),a);if(t)return t}throw new b(e)}async askRunSimilarCommand(e,t){return this.io.error(`${l.default.bgRed(` ERROR `)} Command ${l.default.yellow(e)} not found.\n`),this.io.askForConfirmation(`${l.default.green(`Do you want to run ${l.default.yellow(t)} instead?`)} `)}async*listCommandsFiles(e){let t=d.default.readdirSync(e,{withFileTypes:!0});for(let n of t){let t=f.default.resolve(e,n.name);if(n.isDirectory())yield*this.listCommandsFiles(f.default.resolve(e,n.name));else{if(!t.endsWith(`.ts`)&&!t.endsWith(`.js`)&&!t.endsWith(`.mjs`)&&!t.endsWith(`.cjs`))continue;yield t}}}},P=class e{static parse(t,n={}){let[r,...i]=t.split(/\{(.*?)\}/g).map(e=>e.trim()).filter(Boolean),a={},o={};for(let t of i){let{name:r,isFlag:i,definition:s}=e.parseParamSignature(t,n);i?a[r]=s:o[r]=s}return{command:r,flags:a,args:o}}static parseParamSignature(e,t){let n=e,r=!1,i,a,o,s=!1,c=!1,l=!0;if(n.includes(`:`)){let[e,t]=n.split(`:`);n=e.trim(),i=t.trim()}if(n.includes(`=`)){let[e,t]=n.split(`=`);n=e.trim();let r=t.trim();l=!1,r.length?r===`*`?(c=!0,a=[]):r===`true`?(s=!0,a=!0):r===`false`?(s=!0,a=!1):a=r:a=null}else n.startsWith(`--`)&&(s=!0,l=!1,a=!1);if(n.includes(`|`)){let[e,...t]=n.split(`|`);n=e.trim(),o=t.map(e=>e.trim())}n.startsWith(`--`)&&(r=!0,n=n.slice(2)),n.endsWith(`?`)&&(l=!1,n=n.slice(0,-1)),n.endsWith(`*`)&&(c=!0,l=!0,a=[],n=n.slice(0,-1)),i=i??t[n]??t[`--${n}`];let u,d=r?C:w;return u=s?C.boolean({description:i,alias:o,...a===void 0?{}:{default:a}}):c?d.string({description:i,alias:o,multiple:!0,...l?{required:!0}:{},default:a??[]}):d.string({description:i,alias:o,...l?{required:!0}:{},...a===void 0?{}:{default:a}}),{name:n,isFlag:r,definition:u}}},F=class extends O{static signature=``;static helperDefinitions={};static get command(){return(this.signature??this.signature).split(/\s/)[0]||``}async run(e){let t=this.constructor;if(t.signature&&!Object.prototype.hasOwnProperty.call(t,`_signatureParsed`)){let e=P.parse(t.signature,t.helperDefinitions),n=Object.prototype.hasOwnProperty.call(t,`flags`)?t.flags:{},r=Object.prototype.hasOwnProperty.call(t,`args`)?t.args:{};t.flags={...e.flags,...n},t.args={...e.args,...r},Object.defineProperty(t,`_signatureParsed`,{value:!0})}return super.run(e)}option(e,t=null){return this.parser.flag(e,t)}argument(e,t=null){return this.parser.argument(e,t)}async askForConfirmation(...e){return this.io.askForConfirmation(...e)}async askForInput(...e){return this.io.askForInput(...e)}async askForSelect(...e){return this.io.askForSelect(...e)}newLoader(...e){return this.io.newLoader(...e)}},I=class{logger;constructor(e){this.logger=e}handle(e){if(j(e))return e.pretty(this.logger),-1;throw e}},L=class extends O{static command=`help`;static description=l.default.bold(`Show help information about the CLI and its commands`);constructor(e){super(),this.opts=e}async handle(){let e=this.opts.commandRegistry.getCommands().filter(e=>!e.hidden),t=this.opts.cliName??`Bob CLI`,n=this.opts.cliVersion??`0.0.0`,r=(await Promise.resolve().then(()=>require(`../package-1uMjs68E.cjs`)))?.default?.version??`0.0.0`;this.io.log(`${t} ${l.default.green(n)} (core: ${l.default.yellow(r)})
3
3
 
4
4
  ${l.default.yellow(`Usage`)}:
5
5
  command [options] [arguments]
@@ -1,6 +1,6 @@
1
1
  var e = {
2
2
  name: "bob-core",
3
- version: "3.0.0-alpha.0",
3
+ version: "3.0.0-alpha.2",
4
4
  description: "BOB Core",
5
5
  type: "module",
6
6
  main: "./dist/cjs/src/index.js",
@@ -11,14 +11,12 @@ export declare abstract class CommandWithSignature<C extends ContextDefinition =
11
11
  static helperDefinitions: Record<string, string>;
12
12
  static get command(): string;
13
13
  run(runOpts: CommandRunOption<C>): Promise<number | void>;
14
- /**
15
- * Convenience accessor for a parsed flag value.
16
- */
17
- protected flag<T = string>(key: string): T | null;
18
- protected flag<T = string>(key: string, defaultValue: T): NoInfer<T>;
19
- /**
20
- * Convenience accessor for a parsed argument value.
21
- */
14
+ protected option<T = string>(key: string): T | null;
15
+ protected option<T = string>(key: string, defaultValue: T): NoInfer<T>;
22
16
  protected argument<T = string>(key: string): T | null;
23
17
  protected argument<T = string>(key: string, defaultValue: T): NoInfer<T>;
18
+ askForConfirmation(...opts: Parameters<typeof this.io.askForConfirmation>): ReturnType<typeof this.io.askForConfirmation>;
19
+ askForInput(...opts: Parameters<typeof this.io.askForInput>): ReturnType<typeof this.io.askForInput>;
20
+ askForSelect(...opts: Parameters<typeof this.io.askForSelect>): ReturnType<typeof this.io.askForSelect>;
21
+ newLoader(...opts: Parameters<typeof this.io.newLoader>): ReturnType<typeof this.io.newLoader>;
24
22
  }
@@ -828,7 +828,7 @@ var T = class {
828
828
  static signature = "";
829
829
  static helperDefinitions = {};
830
830
  static get command() {
831
- return this.signature.split(/\s/)[0] || "";
831
+ return (this.signature ?? this.signature).split(/\s/)[0] || "";
832
832
  }
833
833
  async run(e) {
834
834
  let t = this.constructor;
@@ -844,12 +844,24 @@ var T = class {
844
844
  }
845
845
  return super.run(e);
846
846
  }
847
- flag(e, t = null) {
847
+ option(e, t = null) {
848
848
  return this.parser.flag(e, t);
849
849
  }
850
850
  argument(e, t = null) {
851
851
  return this.parser.argument(e, t);
852
852
  }
853
+ async askForConfirmation(...e) {
854
+ return this.io.askForConfirmation(...e);
855
+ }
856
+ async askForInput(...e) {
857
+ return this.io.askForInput(...e);
858
+ }
859
+ async askForSelect(...e) {
860
+ return this.io.askForSelect(...e);
861
+ }
862
+ newLoader(...e) {
863
+ return this.io.newLoader(...e);
864
+ }
853
865
  }, O = class {
854
866
  logger;
855
867
  constructor(e) {
@@ -866,7 +878,7 @@ var T = class {
866
878
  super(), this.opts = e;
867
879
  }
868
880
  async handle() {
869
- let e = this.opts.commandRegistry.getCommands().filter((e) => !e.hidden), n = this.opts.cliName ?? "Bob CLI", r = this.opts.cliVersion ?? "0.0.0", i = (await import("../package-DXx2gXIL.js"))?.default?.version ?? "0.0.0";
881
+ let e = this.opts.commandRegistry.getCommands().filter((e) => !e.hidden), n = this.opts.cliName ?? "Bob CLI", r = this.opts.cliVersion ?? "0.0.0", i = (await import("../package-DfcwA4BR.js"))?.default?.version ?? "0.0.0";
870
882
  this.io.log(`${n} ${t.green(r)} (core: ${t.yellow(i)})
871
883
 
872
884
  ${t.yellow("Usage")}:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bob-core",
3
- "version": "3.0.0-alpha.0",
3
+ "version": "3.0.0-alpha.2",
4
4
  "description": "BOB Core",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/src/index.js",