cleye 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -263,6 +263,21 @@ argv.flags.someString // => "hello" (string)
263
263
  argv.flags.someNumber // => [1, 2] (number[])
264
264
  ```
265
265
 
266
+ #### Inverting boolean flags
267
+ To explicitly set a boolean flag to `false`, pass in the value using the `=` operator:
268
+
269
+ ```sh
270
+ $ my-script --some-boolean=false
271
+ ```
272
+
273
+ Without `=`, the `false` will be parsed as a separate argument:
274
+
275
+ ```sh
276
+ $ my-script --some-boolean false
277
+ # argv.flags.someBoolean => true
278
+ # argv._ => ['false']
279
+ ```
280
+
266
281
  #### Custom flag types & validation
267
282
  Custom flag types can be created to validate flags and narrow types. Simply create a new function that accepts a string and returns the parsed value.
268
283
 
package/dist/index.cjs CHANGED
@@ -1,10 +1,10 @@
1
- "use strict";var B=Object.defineProperty;var s=(t,e)=>B(t,"name",{value:e,configurable:!0});var P=require("type-flag"),S=require("tty"),x=require("terminal-columns");const I=s(t=>t.replaceAll(/[\W_]([a-z\d])?/gi,(e,r)=>r?r.toUpperCase():""),"camelCase"),R=s(t=>t.replaceAll(/\B([A-Z])/g,"-$1").toLowerCase(),"kebabCase"),D={"> 80":[{width:"content-width",paddingLeft:2,paddingRight:8},{width:"auto"}],"> 40":[{width:"auto",paddingLeft:2,paddingRight:8,preprocess:s(t=>t.trim(),"preprocess")},{width:"100%",paddingLeft:2,paddingBottom:1}],"> 0":{stdoutColumns:1e3,columns:[{width:"content-width",paddingLeft:2,paddingRight:8},{width:"content-width"}]}};function L(t){let e=!1;return{type:"table",data:{tableData:Object.keys(t).sort((a,i)=>a.localeCompare(i)).map(a=>{const i=t[a],l="alias"in i;return l&&(e=!0),{name:a,flag:i,flagFormatted:`--${R(a)}`,aliasesEnabled:e,aliasFormatted:l?`-${i.alias}`:void 0}}).map(a=>(a.aliasesEnabled=e,[{type:"flagName",data:a},{type:"flagDescription",data:a}])),tableBreakpoints:D}}}s(L,"renderFlags");const O=s(t=>!t||(t.version??(t.help?t.help.version:void 0)),"getVersion"),j=s(t=>{const e="parent"in t&&t.parent?.name;return(e?`${e} `:"")+t.name},"getName");function T(t){const e=[];t.name&&e.push(j(t));const r=O(t)??("parent"in t&&O(t.parent));if(r&&e.push(`v${r}`),e.length!==0)return{id:"name",type:"text",data:`${e.join(" ")}
1
+ "use strict";var B=Object.defineProperty;var s=(t,e)=>B(t,"name",{value:e,configurable:!0});var P=require("type-flag"),S=require("tty"),E=require("terminal-columns");const I=s(t=>t.replaceAll(/[\W_]([a-z\d])?/gi,(e,r)=>r?r.toUpperCase():""),"camelCase"),R=s(t=>t.replaceAll(/\B([A-Z])/g,"-$1").toLowerCase(),"kebabCase"),D={"> 80":[{width:"content-width",paddingLeft:2,paddingRight:8},{width:"auto"}],"> 40":[{width:"auto",paddingLeft:2,paddingRight:8,preprocess:s(t=>t.trim(),"preprocess")},{width:"100%",paddingLeft:2,paddingBottom:1}],"> 0":{stdoutColumns:1e3,columns:[{width:"content-width",paddingLeft:2,paddingRight:8},{width:"content-width"}]}};function L(t){let e=!1;return{type:"table",data:{tableData:Object.keys(t).sort((a,i)=>a.localeCompare(i)).map(a=>{const i=t[a],l="alias"in i;return l&&(e=!0),{name:a,flag:i,flagFormatted:`--${R(a)}`,aliasesEnabled:e,aliasFormatted:l?`-${i.alias}`:void 0}}).map(a=>(a.aliasesEnabled=e,[{type:"flagName",data:a},{type:"flagDescription",data:a}])),tableBreakpoints:D}}}s(L,"renderFlags");const C=s(t=>!t||(t.version??(t.help?t.help.version:void 0)),"getVersion"),x=s(t=>{const e="parent"in t&&t.parent?.name;return(e?`${e} `:"")+t.name},"getName");function T(t){const e=[];t.name&&e.push(x(t));const r=C(t)??("parent"in t&&C(t.parent));if(r&&e.push(`v${r}`),e.length!==0)return{id:"name",type:"text",data:`${e.join(" ")}
2
2
  `}}s(T,"getNameAndVersion");function k(t){const{help:e}=t;if(!(!e||!e.description))return{id:"description",type:"text",data:`${e.description}
3
3
  `}}s(k,"getDescription");function F(t){const e=t.help||{};if("usage"in e)return e.usage?{id:"usage",type:"section",data:{title:"Usage:",body:Array.isArray(e.usage)?e.usage.join(`
4
- `):e.usage}}:void 0;if(t.name){const r=[],n=[j(t)];if(t.flags&&Object.keys(t.flags).length>0&&n.push("[flags...]"),t.parameters&&t.parameters.length>0){const{parameters:a}=t,i=a.indexOf("--"),l=i!==-1&&a.slice(i+1).some(o=>o.startsWith("<"));n.push(a.map(o=>o!=="--"?o:l?"--":"[--]").join(" "))}if(n.length>1&&r.push(n.join(" ")),"commands"in t&&t.commands?.length&&r.push(`${t.name} <command>`),r.length>0)return{id:"usage",type:"section",data:{title:"Usage:",body:r.join(`
5
- `)}}}}s(F,"getUsage");function _(t){return!("commands"in t)||!t.commands?.length?void 0:{id:"commands",type:"section",data:{title:"Commands:",body:{type:"table",data:{tableData:t.commands.map(n=>[n.options.name,n.options.help?n.options.help.description:""]),tableOptions:[{width:"content-width",paddingLeft:2,paddingRight:8}]}},indentBody:0}}}s(_,"getCommands");function H(t){if(!(!t.flags||Object.keys(t.flags).length===0))return{id:"flags",type:"section",data:{title:"Flags:",body:L(t.flags),indentBody:0}}}s(H,"getFlags");function U(t){const{help:e}=t;if(!e||!e.examples||e.examples.length===0)return;let{examples:r}=e;if(Array.isArray(r)&&(r=r.join(`
4
+ `):e.usage}}:void 0;if(t.name){const r=[],n=[x(t)];if(t.flags&&Object.keys(t.flags).length>0&&n.push("[flags...]"),t.parameters&&t.parameters.length>0){const{parameters:a}=t,i=a.indexOf("--"),l=i!==-1&&a.slice(i+1).some(o=>o.startsWith("<"));n.push(a.map(o=>o!=="--"?o:l?"--":"[--]").join(" "))}if(n.length>1&&r.push(n.join(" ")),"commands"in t&&t.commands?.length&&r.push(`${t.name} <command>`),r.length>0)return{id:"usage",type:"section",data:{title:"Usage:",body:r.join(`
5
+ `)}}}}s(F,"getUsage");function _(t){return!("commands"in t)||!t.commands?.length?void 0:{id:"commands",type:"section",data:{title:"Commands:",body:{type:"table",data:{tableData:t.commands.map(n=>{const{help:a}=n.options;return[n.options.name,typeof a=="object"&&a.description||""]}),tableOptions:[{width:"content-width",paddingLeft:2,paddingRight:8}]}},indentBody:0}}}s(_,"getCommands");function H(t){if(!(!t.flags||Object.keys(t.flags).length===0))return{id:"flags",type:"section",data:{title:"Flags:",body:L(t.flags),indentBody:0}}}s(H,"getFlags");function U(t){const{help:e}=t;if(!e||!e.examples||e.examples.length===0)return;let{examples:r}=e;if(Array.isArray(r)&&(r=r.join(`
6
6
  `)),r)return{id:"examples",type:"section",data:{title:"Examples:",body:r}}}s(U,"getExamples");function V(t){if(!("alias"in t)||!t.alias)return;const{alias:e}=t;return{id:"aliases",type:"section",data:{title:"Aliases:",body:Array.isArray(e)?e.join(", "):e}}}s(V,"getAliases");const J=s(t=>[T,k,F,_,H,U,V].map(e=>e(t)).filter(Boolean),"generateHelp"),M=S.WriteStream.prototype.hasColors();class W{static{s(this,"Renderers")}text(e){return e}bold(e){return M?`\x1B[1m${e}\x1B[22m`:e.toLocaleUpperCase()}indentText({text:e,spaces:r}){return e.replaceAll(/^/gm," ".repeat(r))}heading(e){return this.bold(e)}section({title:e,body:r,indentBody:n=2}){return`${(e?`${this.heading(e)}
7
7
  `:"")+(r?this.indentText({text:this.render(r),spaces:n}):"")}
8
- `}table({tableData:e,tableOptions:r,tableBreakpoints:n}){return x.terminalColumns(e.map(a=>a.map(i=>this.render(i))),n?x.breakpoints(n):r)}flagParameter(e){return e===Boolean?"":e===String?"<string>":e===Number?"<number>":Array.isArray(e)?this.flagParameter(e[0]):"<value>"}flagOperator(e){return" "}flagName(e){const{flag:r,flagFormatted:n,aliasesEnabled:a,aliasFormatted:i}=e;let l="";if(i?l+=`${i}, `:a&&(l+=" "),l+=n,"placeholder"in r&&typeof r.placeholder=="string")l+=`${this.flagOperator(e)}${r.placeholder}`;else{const o=this.flagParameter("type"in r?r.type:r);o&&(l+=`${this.flagOperator(e)}${o}`)}return l}flagDefault(e){return JSON.stringify(e)}flagDescription({flag:e}){let r="description"in e?e.description??"":"";if("default"in e){let{default:n}=e;typeof n=="function"&&(n=n()),n&&(r+=` (default: ${this.flagDefault(n)})`)}return r}render(e){if(typeof e=="string")return e;if(Array.isArray(e))return e.map(r=>this.render(r)).join(`
9
- `);if("type"in e&&this[e.type]){const r=this[e.type];if(typeof r=="function")return r.call(this,e.data)}throw new Error(`Invalid node type: ${JSON.stringify(e)}`)}}const w=s(t=>t.length>0&&!t.includes(" "),"isValidScriptName"),{stringify:f}=JSON,z=/[|\\{}()[\]^$+*?.]/;function b(t){const e=[];let r,n;for(const a of t){if(n)throw new Error(`Invalid parameter: Spread parameter ${f(n)} must be last`);const i=a[0],l=a.at(-1);let o;if(i==="<"&&l===">"&&(o=!0,r))throw new Error(`Invalid parameter: Required parameter ${f(a)} cannot come after optional parameter ${f(r)}`);if(i==="["&&l==="]"&&(o=!1,r=a),o===void 0)throw new Error(`Invalid parameter: ${f(a)}. Must be wrapped in <> (required parameter) or [] (optional parameter)`);let c=a.slice(1,-1);const m=c.slice(-3)==="...";m&&(n=a,c=c.slice(0,-3));const p=c.match(z);if(p)throw new Error(`Invalid parameter: ${f(a)}. Invalid character found ${f(p[0])}`);e.push({name:c,required:o,spread:m})}return e}s(b,"parseParameters");function v(t,e,r,n){for(let a=0;a<e.length;a+=1){const{name:i,required:l,spread:o}=e[a],c=I(i);if(c in t)throw new Error(`Invalid parameter: ${f(i)} is used more than once.`);const m=o?r.slice(a):r[a];if(o&&(a=e.length),l&&(!m||o&&m.length===0))return console.error(`Error: Missing required parameter ${f(i)}
10
- `),n(),process.exit(1);t[c]=m}}s(v,"mapParametersToArguments");function Z(t){return t===void 0||t!==!1}s(Z,"helpEnabled");function q(t,e,r,n){const a={...e.flags},i=e.version&&!("version"in a);i&&(a.version={type:Boolean,description:"Show version"});const{help:l}=e,o=Z(l);o&&!("help"in a)&&(a.help={type:Boolean,alias:"h",description:"Show help"});const c=P.typeFlag(a,n,{ignore:e.ignoreArgv}),m=s(()=>{console.log(e.version)},"showVersion");if(i&&c.flags.version===!0)return m(),process.exit(0);const p=new W,N=o&&l?.render?l.render:d=>p.render(d),h=s(d=>{const u=J({...e,...d?{help:d}:{},flags:a});console.log(N(u,p))},"showHelp");if(o&&c.flags.help===!0)return h(),process.exit(0);if(e.parameters){let{parameters:d}=e,u=c._;const y=d.indexOf("--"),E=d.slice(y+1),g=Object.create(null);if(y>-1&&E.length>0){d=d.slice(0,y);const C=c._["--"];u=u.slice(0,-C.length||void 0),v(g,b(d),u,h),v(g,b(E),C,h)}else v(g,b(d),u,h);Object.assign(c._,g)}const $={...c,showVersion:m,showHelp:h},A={command:t,...$};if(typeof r=="function"){const d=r($);if(d&&"then"in d)return Object.assign(Promise.resolve(d),A)}return A}s(q,"cliBase");function G(t,e){const r=new Map;for(const n of e){const a=[n.options.name],{alias:i}=n.options;i&&(Array.isArray(i)?a.push(...i):a.push(i));for(const l of a){if(r.has(l))throw new Error(`Duplicate command name found: ${f(l)}`);r.set(l,n)}}return r.get(t)}s(G,"getCommand");function K(t,e,r=process.argv.slice(2)){if(!t)throw new Error("Options is required");if("name"in t&&(!t.name||!w(t.name)))throw new Error(`Invalid script name: ${f(t.name)}`);const n=r[0];if(t.commands&&n&&w(n)){const a=G(n,t.commands);if(a)return q(a.options.name,{...a.options,parent:t},a.callback,r.slice(1))}return q(void 0,t,e,r)}s(K,"cli");function Q(t,e){if(!t)throw new Error("Command options are required");const{name:r}=t;if(r===void 0)throw new Error("Command name is required");if(!w(r))throw new Error(`Invalid command name ${JSON.stringify(r)}. Command names must be one word.`);return{options:t,callback:e}}s(Q,"command"),exports.cli=K,exports.command=Q;
8
+ `}table({tableData:e,tableOptions:r,tableBreakpoints:n}){return E.terminalColumns(e.map(a=>a.map(i=>this.render(i))),n?E.breakpoints(n):r)}flagParameter(e){return e===Boolean?"":e===String?"<string>":e===Number?"<number>":Array.isArray(e)?this.flagParameter(e[0]):"<value>"}flagOperator(e){return" "}flagName(e){const{flag:r,flagFormatted:n,aliasesEnabled:a,aliasFormatted:i}=e;let l="";if(i?l+=`${i}, `:a&&(l+=" "),l+=n,"placeholder"in r&&typeof r.placeholder=="string")l+=`${this.flagOperator(e)}${r.placeholder}`;else{const o=this.flagParameter("type"in r?r.type:r);o&&(l+=`${this.flagOperator(e)}${o}`)}return l}flagDefault(e){return JSON.stringify(e)}flagDescription({flag:e}){let r="description"in e?e.description??"":"";if("default"in e){let{default:n}=e;typeof n=="function"&&(n=n()),n&&(r+=` (default: ${this.flagDefault(n)})`)}return r}render(e){if(typeof e=="string")return e;if(Array.isArray(e))return e.map(r=>this.render(r)).join(`
9
+ `);if("type"in e&&this[e.type]){const r=this[e.type];if(typeof r=="function")return r.call(this,e.data)}throw new Error(`Invalid node type: ${JSON.stringify(e)}`)}}const v=s(t=>t.length>0&&!t.includes(" "),"isValidScriptName"),{stringify:f}=JSON,z=/[|\\{}()[\]^$+*?.]/;function O(t){const e=[];let r,n;for(const a of t){if(n)throw new Error(`Invalid parameter: Spread parameter ${f(n)} must be last`);const i=a[0],l=a.at(-1);let o;if(i==="<"&&l===">"&&(o=!0,r))throw new Error(`Invalid parameter: Required parameter ${f(a)} cannot come after optional parameter ${f(r)}`);if(i==="["&&l==="]"&&(o=!1,r=a),o===void 0)throw new Error(`Invalid parameter: ${f(a)}. Must be wrapped in <> (required parameter) or [] (optional parameter)`);let c=a.slice(1,-1);const m=c.slice(-3)==="...";m&&(n=a,c=c.slice(0,-3));const u=c.match(z);if(u)throw new Error(`Invalid parameter: ${f(a)}. Invalid character found ${f(u[0])}`);e.push({name:c,required:o,spread:m})}return e}s(O,"parseParameters");function j(t,e,r,n){for(let a=0;a<e.length;a+=1){const{name:i,required:l,spread:o}=e[a],c=I(i);if(c in t)throw new Error(`Invalid parameter: ${f(i)} is used more than once.`);const m=o?r.slice(a):r[a];if(o&&(a=e.length),l&&(!m||o&&m.length===0))return console.error(`Error: Missing required parameter ${f(i)}
10
+ `),n(),process.exit(1);t[c]=m}}s(j,"mapParametersToArguments");function Z(t){return t!==!1}s(Z,"helpEnabled");function q(t,e,r,n){const a={...e.flags},i=e.version&&!("version"in a);i&&(a.version={type:Boolean,description:"Show version"});const{help:l}=e,o=Z(l);o&&!("help"in a)&&(a.help={type:Boolean,alias:"h",description:"Show help"});const c=P.typeFlag(a,n,{ignore:e.ignoreArgv}),m=s(()=>{console.log(e.version)},"showVersion");if(i&&c.flags.version===!0)return m(),process.exit(0);const u=new W,N=o&&l?.render?l.render:d=>u.render(d),h=s(d=>{const p=J({...e,...d?{help:d}:{},flags:a});console.log(N(p,u))},"showHelp");if(o&&c.flags.help===!0)return h(),process.exit(0);if(e.parameters){let{parameters:d}=e,p=c._;const g=d.indexOf("--"),y=d.slice(g+1),w=Object.create(null);let b=[];g>-1&&y.length>0&&(d=d.slice(0,g),b=c._["--"],p=p.slice(0,-b.length||void 0)),j(w,O(d),p,h),g>-1&&y.length>0&&j(w,O(y),b,h),Object.assign(c._,w)}const $={...c,showVersion:m,showHelp:h},A={command:t,...$};if(typeof r=="function"){const d=r($);if(d&&"then"in d)return Object.assign(Promise.resolve(d),A)}return A}s(q,"cliBase");function G(t,e){const r=new Map;for(const n of e){const a=[n.options.name],{alias:i}=n.options;i&&(Array.isArray(i)?a.push(...i):a.push(i));for(const l of a){if(r.has(l))throw new Error(`Duplicate command name found: ${f(l)}`);r.set(l,n)}}return r.get(t)}s(G,"getCommand");function K(t,e,r=process.argv.slice(2)){if(!t)throw new Error("Options is required");if("name"in t&&(!t.name||!v(t.name)))throw new Error(`Invalid script name: ${f(t.name)}`);const n=r[0];if(t.commands&&n&&v(n)){const a=G(n,t.commands);if(a)return q(a.options.name,{...a.options,parent:t},a.callback,r.slice(1))}return q(void 0,t,e,r)}s(K,"cli");function Q(t,e){if(!t)throw new Error("Command options are required");const{name:r}=t;if(r===void 0)throw new Error("Command name is required");if(!v(r))throw new Error(`Invalid command name ${JSON.stringify(r)}. Command names must be one word.`);return{options:t,callback:e}}s(Q,"command"),exports.cli=K,exports.command=Q;
package/dist/index.d.cts CHANGED
@@ -1,4 +1,5 @@
1
- import { TypeFlagOptions, Flags as Flags$1, TypeFlag } from 'type-flag';
1
+ import { IgnoreFunction, Flags as Flags$1, TypeFlag } from 'type-flag';
2
+ export { TypeFlag } from 'type-flag';
2
3
  import { Options } from 'terminal-columns';
3
4
 
4
5
  type CommandOptions<Parameters = string[]> = {
@@ -30,7 +31,7 @@ type CommandOptions<Parameters = string[]> = {
30
31
  /**
31
32
  * Which argv elements to ignore from parsing
32
33
  */
33
- ignoreArgv?: TypeFlagOptions['ignore'];
34
+ ignoreArgv?: IgnoreFunction;
34
35
  };
35
36
  declare function command<Options extends CommandOptions<[...Parameters]>, Parameters extends string[]>(options: Readonly<Options> & CommandOptions<[...Parameters]>, callback?: CallbackFunction<ParseArgv<Options, Parameters>>): Command<Options, ParseArgv<Options, Parameters, Options['name']>>;
36
37
  type Command<Options extends CommandOptions = CommandOptions, ParsedType = any> = {
@@ -176,7 +177,7 @@ type CliOptions<Commands = Command[], Parameters extends string[] = string[]> =
176
177
  /**
177
178
  * Which argv elements to ignore from parsing
178
179
  */
179
- ignoreArgv?: TypeFlagOptions['ignore'];
180
+ ignoreArgv?: IgnoreFunction;
180
181
  };
181
182
  type AlphabetLowercase = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z';
182
183
  type Numeric = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
@@ -199,11 +200,17 @@ type TypeFlagWrapper<Options extends {
199
200
  type ParseArgv<Options extends {
200
201
  flags?: Flags;
201
202
  }, Parameters extends string[], CommandName extends string | undefined = ''> = (CommandName extends '' ? TypeFlagWrapper<Options, Parameters> : WithCommand<TypeFlagWrapper<Options, Parameters>, CommandName>);
203
+ /**
204
+ * Helper type to reject unknown properties in cli() options.
205
+ * Maps any key not in CliOptions to `never`, causing a type error
206
+ * when excess properties are passed.
207
+ */
208
+ type StrictOptions<T> = T & Record<Exclude<keyof T, keyof CliOptions>, never>;
202
209
 
203
- declare function cli<Options extends CliOptions<undefined, [...Parameters]>, Parameters extends string[]>(options: Options & CliOptions<undefined, [...Parameters]>, callback?: CallbackFunction<ParseArgv<Options, Parameters>>, argv?: string[]): ({
210
+ declare function cli<Options extends CliOptions<undefined, [...Parameters]>, Parameters extends string[]>(options: StrictOptions<Options> & CliOptions<undefined, [...Parameters]>, callback?: CallbackFunction<ParseArgv<Options, Parameters>>, argv?: string[]): ({
204
211
  [Key in keyof ParseArgv<Options, Parameters, undefined>]: ParseArgv<Options, Parameters, undefined>[Key];
205
212
  } & Promise<void>);
206
- declare function cli<Options extends CliOptions<[...Commands], [...Parameters]>, Commands extends Command[], Parameters extends string[]>(options: Options & CliOptions<[...Commands], [...Parameters]>, callback?: CallbackFunction<ParseArgv<Options, Parameters>>, argv?: string[]): (({
213
+ declare function cli<Options extends CliOptions<[...Commands], [...Parameters]>, Commands extends Command[], Parameters extends string[]>(options: StrictOptions<Options> & CliOptions<[...Commands], [...Parameters]>, callback?: CallbackFunction<ParseArgv<Options, Parameters>>, argv?: string[]): (({
207
214
  [Key in keyof ParseArgv<Options, Parameters, undefined>]: ParseArgv<Options, Parameters, undefined>[Key];
208
215
  } | {
209
216
  [KeyA in keyof Commands]: (Commands[KeyA] extends Command ? ({
@@ -212,4 +219,4 @@ declare function cli<Options extends CliOptions<[...Commands], [...Parameters]>,
212
219
  }[number]) & Promise<void>);
213
220
 
214
221
  export { Renderers, cli, command };
215
- export type { Command };
222
+ export type { Command, Flags };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,5 @@
1
- import { TypeFlagOptions, Flags as Flags$1, TypeFlag } from 'type-flag';
1
+ import { IgnoreFunction, Flags as Flags$1, TypeFlag } from 'type-flag';
2
+ export { TypeFlag } from 'type-flag';
2
3
  import { Options } from 'terminal-columns';
3
4
 
4
5
  type CommandOptions<Parameters = string[]> = {
@@ -30,7 +31,7 @@ type CommandOptions<Parameters = string[]> = {
30
31
  /**
31
32
  * Which argv elements to ignore from parsing
32
33
  */
33
- ignoreArgv?: TypeFlagOptions['ignore'];
34
+ ignoreArgv?: IgnoreFunction;
34
35
  };
35
36
  declare function command<Options extends CommandOptions<[...Parameters]>, Parameters extends string[]>(options: Readonly<Options> & CommandOptions<[...Parameters]>, callback?: CallbackFunction<ParseArgv<Options, Parameters>>): Command<Options, ParseArgv<Options, Parameters, Options['name']>>;
36
37
  type Command<Options extends CommandOptions = CommandOptions, ParsedType = any> = {
@@ -176,7 +177,7 @@ type CliOptions<Commands = Command[], Parameters extends string[] = string[]> =
176
177
  /**
177
178
  * Which argv elements to ignore from parsing
178
179
  */
179
- ignoreArgv?: TypeFlagOptions['ignore'];
180
+ ignoreArgv?: IgnoreFunction;
180
181
  };
181
182
  type AlphabetLowercase = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z';
182
183
  type Numeric = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
@@ -199,11 +200,17 @@ type TypeFlagWrapper<Options extends {
199
200
  type ParseArgv<Options extends {
200
201
  flags?: Flags;
201
202
  }, Parameters extends string[], CommandName extends string | undefined = ''> = (CommandName extends '' ? TypeFlagWrapper<Options, Parameters> : WithCommand<TypeFlagWrapper<Options, Parameters>, CommandName>);
203
+ /**
204
+ * Helper type to reject unknown properties in cli() options.
205
+ * Maps any key not in CliOptions to `never`, causing a type error
206
+ * when excess properties are passed.
207
+ */
208
+ type StrictOptions<T> = T & Record<Exclude<keyof T, keyof CliOptions>, never>;
202
209
 
203
- declare function cli<Options extends CliOptions<undefined, [...Parameters]>, Parameters extends string[]>(options: Options & CliOptions<undefined, [...Parameters]>, callback?: CallbackFunction<ParseArgv<Options, Parameters>>, argv?: string[]): ({
210
+ declare function cli<Options extends CliOptions<undefined, [...Parameters]>, Parameters extends string[]>(options: StrictOptions<Options> & CliOptions<undefined, [...Parameters]>, callback?: CallbackFunction<ParseArgv<Options, Parameters>>, argv?: string[]): ({
204
211
  [Key in keyof ParseArgv<Options, Parameters, undefined>]: ParseArgv<Options, Parameters, undefined>[Key];
205
212
  } & Promise<void>);
206
- declare function cli<Options extends CliOptions<[...Commands], [...Parameters]>, Commands extends Command[], Parameters extends string[]>(options: Options & CliOptions<[...Commands], [...Parameters]>, callback?: CallbackFunction<ParseArgv<Options, Parameters>>, argv?: string[]): (({
213
+ declare function cli<Options extends CliOptions<[...Commands], [...Parameters]>, Commands extends Command[], Parameters extends string[]>(options: StrictOptions<Options> & CliOptions<[...Commands], [...Parameters]>, callback?: CallbackFunction<ParseArgv<Options, Parameters>>, argv?: string[]): (({
207
214
  [Key in keyof ParseArgv<Options, Parameters, undefined>]: ParseArgv<Options, Parameters, undefined>[Key];
208
215
  } | {
209
216
  [KeyA in keyof Commands]: (Commands[KeyA] extends Command ? ({
@@ -212,4 +219,4 @@ declare function cli<Options extends CliOptions<[...Commands], [...Parameters]>,
212
219
  }[number]) & Promise<void>);
213
220
 
214
221
  export { Renderers, cli, command };
215
- export type { Command };
222
+ export type { Command, Flags };
package/dist/index.mjs CHANGED
@@ -1,10 +1,10 @@
1
- var B=Object.defineProperty;var s=(t,e)=>B(t,"name",{value:e,configurable:!0});import{typeFlag as P}from"type-flag";import S from"tty";import{terminalColumns as q,breakpoints as I}from"terminal-columns";const R=s(t=>t.replaceAll(/[\W_]([a-z\d])?/gi,(e,r)=>r?r.toUpperCase():""),"camelCase"),D=s(t=>t.replaceAll(/\B([A-Z])/g,"-$1").toLowerCase(),"kebabCase"),L={"> 80":[{width:"content-width",paddingLeft:2,paddingRight:8},{width:"auto"}],"> 40":[{width:"auto",paddingLeft:2,paddingRight:8,preprocess:s(t=>t.trim(),"preprocess")},{width:"100%",paddingLeft:2,paddingBottom:1}],"> 0":{stdoutColumns:1e3,columns:[{width:"content-width",paddingLeft:2,paddingRight:8},{width:"content-width"}]}};function T(t){let e=!1;return{type:"table",data:{tableData:Object.keys(t).sort((a,i)=>a.localeCompare(i)).map(a=>{const i=t[a],o="alias"in i;return o&&(e=!0),{name:a,flag:i,flagFormatted:`--${D(a)}`,aliasesEnabled:e,aliasFormatted:o?`-${i.alias}`:void 0}}).map(a=>(a.aliasesEnabled=e,[{type:"flagName",data:a},{type:"flagDescription",data:a}])),tableBreakpoints:L}}}s(T,"renderFlags");const x=s(t=>!t||(t.version??(t.help?t.help.version:void 0)),"getVersion"),O=s(t=>{const e="parent"in t&&t.parent?.name;return(e?`${e} `:"")+t.name},"getName");function k(t){const e=[];t.name&&e.push(O(t));const r=x(t)??("parent"in t&&x(t.parent));if(r&&e.push(`v${r}`),e.length!==0)return{id:"name",type:"text",data:`${e.join(" ")}
1
+ var B=Object.defineProperty;var s=(t,e)=>B(t,"name",{value:e,configurable:!0});import{typeFlag as P}from"type-flag";import S from"tty";import{terminalColumns as q,breakpoints as I}from"terminal-columns";const R=s(t=>t.replaceAll(/[\W_]([a-z\d])?/gi,(e,r)=>r?r.toUpperCase():""),"camelCase"),D=s(t=>t.replaceAll(/\B([A-Z])/g,"-$1").toLowerCase(),"kebabCase"),L={"> 80":[{width:"content-width",paddingLeft:2,paddingRight:8},{width:"auto"}],"> 40":[{width:"auto",paddingLeft:2,paddingRight:8,preprocess:s(t=>t.trim(),"preprocess")},{width:"100%",paddingLeft:2,paddingBottom:1}],"> 0":{stdoutColumns:1e3,columns:[{width:"content-width",paddingLeft:2,paddingRight:8},{width:"content-width"}]}};function T(t){let e=!1;return{type:"table",data:{tableData:Object.keys(t).sort((a,i)=>a.localeCompare(i)).map(a=>{const i=t[a],o="alias"in i;return o&&(e=!0),{name:a,flag:i,flagFormatted:`--${D(a)}`,aliasesEnabled:e,aliasFormatted:o?`-${i.alias}`:void 0}}).map(a=>(a.aliasesEnabled=e,[{type:"flagName",data:a},{type:"flagDescription",data:a}])),tableBreakpoints:L}}}s(T,"renderFlags");const E=s(t=>!t||(t.version??(t.help?t.help.version:void 0)),"getVersion"),C=s(t=>{const e="parent"in t&&t.parent?.name;return(e?`${e} `:"")+t.name},"getName");function k(t){const e=[];t.name&&e.push(C(t));const r=E(t)??("parent"in t&&E(t.parent));if(r&&e.push(`v${r}`),e.length!==0)return{id:"name",type:"text",data:`${e.join(" ")}
2
2
  `}}s(k,"getNameAndVersion");function _(t){const{help:e}=t;if(!(!e||!e.description))return{id:"description",type:"text",data:`${e.description}
3
3
  `}}s(_,"getDescription");function F(t){const e=t.help||{};if("usage"in e)return e.usage?{id:"usage",type:"section",data:{title:"Usage:",body:Array.isArray(e.usage)?e.usage.join(`
4
- `):e.usage}}:void 0;if(t.name){const r=[],n=[O(t)];if(t.flags&&Object.keys(t.flags).length>0&&n.push("[flags...]"),t.parameters&&t.parameters.length>0){const{parameters:a}=t,i=a.indexOf("--"),o=i!==-1&&a.slice(i+1).some(l=>l.startsWith("<"));n.push(a.map(l=>l!=="--"?l:o?"--":"[--]").join(" "))}if(n.length>1&&r.push(n.join(" ")),"commands"in t&&t.commands?.length&&r.push(`${t.name} <command>`),r.length>0)return{id:"usage",type:"section",data:{title:"Usage:",body:r.join(`
5
- `)}}}}s(F,"getUsage");function H(t){return!("commands"in t)||!t.commands?.length?void 0:{id:"commands",type:"section",data:{title:"Commands:",body:{type:"table",data:{tableData:t.commands.map(n=>[n.options.name,n.options.help?n.options.help.description:""]),tableOptions:[{width:"content-width",paddingLeft:2,paddingRight:8}]}},indentBody:0}}}s(H,"getCommands");function U(t){if(!(!t.flags||Object.keys(t.flags).length===0))return{id:"flags",type:"section",data:{title:"Flags:",body:T(t.flags),indentBody:0}}}s(U,"getFlags");function V(t){const{help:e}=t;if(!e||!e.examples||e.examples.length===0)return;let{examples:r}=e;if(Array.isArray(r)&&(r=r.join(`
4
+ `):e.usage}}:void 0;if(t.name){const r=[],n=[C(t)];if(t.flags&&Object.keys(t.flags).length>0&&n.push("[flags...]"),t.parameters&&t.parameters.length>0){const{parameters:a}=t,i=a.indexOf("--"),o=i!==-1&&a.slice(i+1).some(l=>l.startsWith("<"));n.push(a.map(l=>l!=="--"?l:o?"--":"[--]").join(" "))}if(n.length>1&&r.push(n.join(" ")),"commands"in t&&t.commands?.length&&r.push(`${t.name} <command>`),r.length>0)return{id:"usage",type:"section",data:{title:"Usage:",body:r.join(`
5
+ `)}}}}s(F,"getUsage");function H(t){return!("commands"in t)||!t.commands?.length?void 0:{id:"commands",type:"section",data:{title:"Commands:",body:{type:"table",data:{tableData:t.commands.map(n=>{const{help:a}=n.options;return[n.options.name,typeof a=="object"&&a.description||""]}),tableOptions:[{width:"content-width",paddingLeft:2,paddingRight:8}]}},indentBody:0}}}s(H,"getCommands");function U(t){if(!(!t.flags||Object.keys(t.flags).length===0))return{id:"flags",type:"section",data:{title:"Flags:",body:T(t.flags),indentBody:0}}}s(U,"getFlags");function V(t){const{help:e}=t;if(!e||!e.examples||e.examples.length===0)return;let{examples:r}=e;if(Array.isArray(r)&&(r=r.join(`
6
6
  `)),r)return{id:"examples",type:"section",data:{title:"Examples:",body:r}}}s(V,"getExamples");function J(t){if(!("alias"in t)||!t.alias)return;const{alias:e}=t;return{id:"aliases",type:"section",data:{title:"Aliases:",body:Array.isArray(e)?e.join(", "):e}}}s(J,"getAliases");const M=s(t=>[k,_,F,H,U,V,J].map(e=>e(t)).filter(Boolean),"generateHelp"),W=S.WriteStream.prototype.hasColors();class z{static{s(this,"Renderers")}text(e){return e}bold(e){return W?`\x1B[1m${e}\x1B[22m`:e.toLocaleUpperCase()}indentText({text:e,spaces:r}){return e.replaceAll(/^/gm," ".repeat(r))}heading(e){return this.bold(e)}section({title:e,body:r,indentBody:n=2}){return`${(e?`${this.heading(e)}
7
7
  `:"")+(r?this.indentText({text:this.render(r),spaces:n}):"")}
8
8
  `}table({tableData:e,tableOptions:r,tableBreakpoints:n}){return q(e.map(a=>a.map(i=>this.render(i))),n?I(n):r)}flagParameter(e){return e===Boolean?"":e===String?"<string>":e===Number?"<number>":Array.isArray(e)?this.flagParameter(e[0]):"<value>"}flagOperator(e){return" "}flagName(e){const{flag:r,flagFormatted:n,aliasesEnabled:a,aliasFormatted:i}=e;let o="";if(i?o+=`${i}, `:a&&(o+=" "),o+=n,"placeholder"in r&&typeof r.placeholder=="string")o+=`${this.flagOperator(e)}${r.placeholder}`;else{const l=this.flagParameter("type"in r?r.type:r);l&&(o+=`${this.flagOperator(e)}${l}`)}return o}flagDefault(e){return JSON.stringify(e)}flagDescription({flag:e}){let r="description"in e?e.description??"":"";if("default"in e){let{default:n}=e;typeof n=="function"&&(n=n()),n&&(r+=` (default: ${this.flagDefault(n)})`)}return r}render(e){if(typeof e=="string")return e;if(Array.isArray(e))return e.map(r=>this.render(r)).join(`
9
- `);if("type"in e&&this[e.type]){const r=this[e.type];if(typeof r=="function")return r.call(this,e.data)}throw new Error(`Invalid node type: ${JSON.stringify(e)}`)}}const w=s(t=>t.length>0&&!t.includes(" "),"isValidScriptName"),{stringify:f}=JSON,Z=/[|\\{}()[\]^$+*?.]/;function b(t){const e=[];let r,n;for(const a of t){if(n)throw new Error(`Invalid parameter: Spread parameter ${f(n)} must be last`);const i=a[0],o=a.at(-1);let l;if(i==="<"&&o===">"&&(l=!0,r))throw new Error(`Invalid parameter: Required parameter ${f(a)} cannot come after optional parameter ${f(r)}`);if(i==="["&&o==="]"&&(l=!1,r=a),l===void 0)throw new Error(`Invalid parameter: ${f(a)}. Must be wrapped in <> (required parameter) or [] (optional parameter)`);let c=a.slice(1,-1);const m=c.slice(-3)==="...";m&&(n=a,c=c.slice(0,-3));const p=c.match(Z);if(p)throw new Error(`Invalid parameter: ${f(a)}. Invalid character found ${f(p[0])}`);e.push({name:c,required:l,spread:m})}return e}s(b,"parseParameters");function v(t,e,r,n){for(let a=0;a<e.length;a+=1){const{name:i,required:o,spread:l}=e[a],c=R(i);if(c in t)throw new Error(`Invalid parameter: ${f(i)} is used more than once.`);const m=l?r.slice(a):r[a];if(l&&(a=e.length),o&&(!m||l&&m.length===0))return console.error(`Error: Missing required parameter ${f(i)}
10
- `),n(),process.exit(1);t[c]=m}}s(v,"mapParametersToArguments");function G(t){return t===void 0||t!==!1}s(G,"helpEnabled");function j(t,e,r,n){const a={...e.flags},i=e.version&&!("version"in a);i&&(a.version={type:Boolean,description:"Show version"});const{help:o}=e,l=G(o);l&&!("help"in a)&&(a.help={type:Boolean,alias:"h",description:"Show help"});const c=P(a,n,{ignore:e.ignoreArgv}),m=s(()=>{console.log(e.version)},"showVersion");if(i&&c.flags.version===!0)return m(),process.exit(0);const p=new z,N=l&&o?.render?o.render:d=>p.render(d),h=s(d=>{const u=M({...e,...d?{help:d}:{},flags:a});console.log(N(u,p))},"showHelp");if(l&&c.flags.help===!0)return h(),process.exit(0);if(e.parameters){let{parameters:d}=e,u=c._;const y=d.indexOf("--"),E=d.slice(y+1),g=Object.create(null);if(y>-1&&E.length>0){d=d.slice(0,y);const C=c._["--"];u=u.slice(0,-C.length||void 0),v(g,b(d),u,h),v(g,b(E),C,h)}else v(g,b(d),u,h);Object.assign(c._,g)}const $={...c,showVersion:m,showHelp:h},A={command:t,...$};if(typeof r=="function"){const d=r($);if(d&&"then"in d)return Object.assign(Promise.resolve(d),A)}return A}s(j,"cliBase");function K(t,e){const r=new Map;for(const n of e){const a=[n.options.name],{alias:i}=n.options;i&&(Array.isArray(i)?a.push(...i):a.push(i));for(const o of a){if(r.has(o))throw new Error(`Duplicate command name found: ${f(o)}`);r.set(o,n)}}return r.get(t)}s(K,"getCommand");function Q(t,e,r=process.argv.slice(2)){if(!t)throw new Error("Options is required");if("name"in t&&(!t.name||!w(t.name)))throw new Error(`Invalid script name: ${f(t.name)}`);const n=r[0];if(t.commands&&n&&w(n)){const a=K(n,t.commands);if(a)return j(a.options.name,{...a.options,parent:t},a.callback,r.slice(1))}return j(void 0,t,e,r)}s(Q,"cli");function X(t,e){if(!t)throw new Error("Command options are required");const{name:r}=t;if(r===void 0)throw new Error("Command name is required");if(!w(r))throw new Error(`Invalid command name ${JSON.stringify(r)}. Command names must be one word.`);return{options:t,callback:e}}s(X,"command");export{Q as cli,X as command};
9
+ `);if("type"in e&&this[e.type]){const r=this[e.type];if(typeof r=="function")return r.call(this,e.data)}throw new Error(`Invalid node type: ${JSON.stringify(e)}`)}}const $=s(t=>t.length>0&&!t.includes(" "),"isValidScriptName"),{stringify:f}=JSON,Z=/[|\\{}()[\]^$+*?.]/;function x(t){const e=[];let r,n;for(const a of t){if(n)throw new Error(`Invalid parameter: Spread parameter ${f(n)} must be last`);const i=a[0],o=a.at(-1);let l;if(i==="<"&&o===">"&&(l=!0,r))throw new Error(`Invalid parameter: Required parameter ${f(a)} cannot come after optional parameter ${f(r)}`);if(i==="["&&o==="]"&&(l=!1,r=a),l===void 0)throw new Error(`Invalid parameter: ${f(a)}. Must be wrapped in <> (required parameter) or [] (optional parameter)`);let c=a.slice(1,-1);const m=c.slice(-3)==="...";m&&(n=a,c=c.slice(0,-3));const u=c.match(Z);if(u)throw new Error(`Invalid parameter: ${f(a)}. Invalid character found ${f(u[0])}`);e.push({name:c,required:l,spread:m})}return e}s(x,"parseParameters");function O(t,e,r,n){for(let a=0;a<e.length;a+=1){const{name:i,required:o,spread:l}=e[a],c=R(i);if(c in t)throw new Error(`Invalid parameter: ${f(i)} is used more than once.`);const m=l?r.slice(a):r[a];if(l&&(a=e.length),o&&(!m||l&&m.length===0))return console.error(`Error: Missing required parameter ${f(i)}
10
+ `),n(),process.exit(1);t[c]=m}}s(O,"mapParametersToArguments");function G(t){return t!==!1}s(G,"helpEnabled");function j(t,e,r,n){const a={...e.flags},i=e.version&&!("version"in a);i&&(a.version={type:Boolean,description:"Show version"});const{help:o}=e,l=G(o);l&&!("help"in a)&&(a.help={type:Boolean,alias:"h",description:"Show help"});const c=P(a,n,{ignore:e.ignoreArgv}),m=s(()=>{console.log(e.version)},"showVersion");if(i&&c.flags.version===!0)return m(),process.exit(0);const u=new z,N=l&&o?.render?o.render:d=>u.render(d),h=s(d=>{const p=M({...e,...d?{help:d}:{},flags:a});console.log(N(p,u))},"showHelp");if(l&&c.flags.help===!0)return h(),process.exit(0);if(e.parameters){let{parameters:d}=e,p=c._;const g=d.indexOf("--"),y=d.slice(g+1),w=Object.create(null);let b=[];g>-1&&y.length>0&&(d=d.slice(0,g),b=c._["--"],p=p.slice(0,-b.length||void 0)),O(w,x(d),p,h),g>-1&&y.length>0&&O(w,x(y),b,h),Object.assign(c._,w)}const v={...c,showVersion:m,showHelp:h},A={command:t,...v};if(typeof r=="function"){const d=r(v);if(d&&"then"in d)return Object.assign(Promise.resolve(d),A)}return A}s(j,"cliBase");function K(t,e){const r=new Map;for(const n of e){const a=[n.options.name],{alias:i}=n.options;i&&(Array.isArray(i)?a.push(...i):a.push(i));for(const o of a){if(r.has(o))throw new Error(`Duplicate command name found: ${f(o)}`);r.set(o,n)}}return r.get(t)}s(K,"getCommand");function Q(t,e,r=process.argv.slice(2)){if(!t)throw new Error("Options is required");if("name"in t&&(!t.name||!$(t.name)))throw new Error(`Invalid script name: ${f(t.name)}`);const n=r[0];if(t.commands&&n&&$(n)){const a=K(n,t.commands);if(a)return j(a.options.name,{...a.options,parent:t},a.callback,r.slice(1))}return j(void 0,t,e,r)}s(Q,"cli");function X(t,e){if(!t)throw new Error("Command options are required");const{name:r}=t;if(r===void 0)throw new Error("Command name is required");if(!$(r))throw new Error(`Invalid command name ${JSON.stringify(r)}. Command names must be one word.`);return{options:t,callback:e}}s(X,"command");export{Q as cli,X as command};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cleye",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "The intuitive CLI development tool",
5
5
  "keywords": [
6
6
  "cli",
@@ -43,6 +43,6 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "terminal-columns": "^2.0.0",
46
- "type-flag": "^4.0.1"
46
+ "type-flag": "^4.0.3"
47
47
  }
48
48
  }