@thi.ng/args
Advanced tools
Comparing version 0.3.1 to 0.4.0
31
api.d.ts
import type { Fn, IDeref, IObjectOf } from "@thi.ng/api"; | ||
export interface ArgSpecBase { | ||
/** | ||
* Shorthand for given arg/option | ||
*/ | ||
alias?: string; | ||
/** | ||
* Description (for usage only) | ||
*/ | ||
desc?: string; | ||
/** | ||
* Type hint (for usage only) | ||
*/ | ||
hint?: string; | ||
/** | ||
* Custom string representation of default value (e.g. a hex value) | ||
*/ | ||
defaultHint?: string; | ||
/** | ||
* Predicate function called when this arg is being parsed. Function MUST | ||
* return true for parsing to continue. | ||
*/ | ||
fn?: Fn<string, boolean>; | ||
/** | ||
* Group ID this arg belongs to. By default args belong to a "main" group. | ||
* {@link flag} args are associated with the "flags" group (by default). | ||
* | ||
* See {@link UsageOpts.groups} for more details. | ||
*/ | ||
group?: string; | ||
} | ||
@@ -109,2 +132,10 @@ export declare type ArgSpecRestrict<T> = undefined extends T ? {} : { | ||
suffix: string; | ||
/** | ||
* Defines output order of arg groups. By default args belong to either | ||
* "main" or "flag" groups. Each group's args are output in alphabetical | ||
* order. Groups are separated by an empty line. | ||
* | ||
* @defaultValue `["flags", "main"]` | ||
*/ | ||
groups: string[]; | ||
} | ||
@@ -111,0 +142,0 @@ /** |
@@ -12,2 +12,3 @@ import type { Fn } from "@thi.ng/api"; | ||
default: boolean; | ||
group: string; | ||
}; | ||
@@ -22,2 +23,3 @@ /** | ||
hint: string; | ||
group: string; | ||
}; | ||
@@ -37,2 +39,3 @@ /** | ||
multi: true; | ||
group: string; | ||
}; | ||
@@ -48,2 +51,3 @@ /** | ||
hint: string; | ||
group: string; | ||
}; | ||
@@ -59,2 +63,3 @@ /** | ||
hint: string; | ||
group: string; | ||
}; | ||
@@ -70,2 +75,3 @@ /** | ||
hint: string; | ||
group: string; | ||
}; | ||
@@ -85,2 +91,3 @@ /** | ||
multi: true; | ||
group: string; | ||
}; | ||
@@ -100,2 +107,3 @@ /** | ||
multi: true; | ||
group: string; | ||
}; | ||
@@ -115,2 +123,3 @@ /** | ||
multi: true; | ||
group: string; | ||
}; | ||
@@ -126,2 +135,3 @@ /** | ||
hint: string; | ||
group: string; | ||
}; | ||
@@ -138,2 +148,3 @@ /** | ||
hint: string; | ||
group: string; | ||
} & { | ||
@@ -156,2 +167,3 @@ desc: string; | ||
multi: true; | ||
group: string; | ||
} & { | ||
@@ -176,2 +188,3 @@ desc: string; | ||
multi: true; | ||
group: string; | ||
}; | ||
@@ -207,2 +220,3 @@ /** | ||
hint: string; | ||
group: string; | ||
}; | ||
@@ -219,3 +233,4 @@ /** | ||
hint: string; | ||
group: string; | ||
}; | ||
//# sourceMappingURL=args.d.ts.map |
16
args.js
import { repeat } from "@thi.ng/strings"; | ||
import { coerceFloat, coerceFloats, coerceHexInt, coerceHexInts, coerceInt, coerceInts, coerceJson, coerceKV, coerceOneOf, coerceTuple, } from "./coerce"; | ||
const $single = (coerce, hint) => (spec) => (Object.assign({ coerce, | ||
hint }, spec)); | ||
const $multi = (coerce, hint) => (spec) => (Object.assign({ hint: $hint(hint, spec.delim), multi: true, coerce }, spec)); | ||
hint, group: "main" }, spec)); | ||
const $multi = (coerce, hint) => (spec) => (Object.assign({ hint: $hint(hint, spec.delim), multi: true, coerce, group: "main" }, spec)); | ||
const $hint = (hint, delim) => hint + (delim ? `[${delim}..]` : ""); | ||
@@ -13,3 +13,3 @@ /** | ||
*/ | ||
export const flag = (spec) => (Object.assign({ flag: true, default: false }, spec)); | ||
export const flag = (spec) => (Object.assign({ flag: true, default: false, group: "flags" }, spec)); | ||
/** | ||
@@ -80,3 +80,3 @@ * Returns a full {@link ArgSpec} for a string value arg. | ||
*/ | ||
export const json = (spec) => (Object.assign({ coerce: coerceJson, hint: "JSON" }, spec)); | ||
export const json = (spec) => (Object.assign({ coerce: coerceJson, hint: "JSON", group: "main" }, spec)); | ||
const $desc = (opts, prefix) => `${prefix ? prefix + ": " : ""}${opts.map((x) => `'${x}'`).join(", ")}`; | ||
@@ -90,3 +90,3 @@ /** | ||
*/ | ||
export const oneOf = (opts, spec) => (Object.assign(Object.assign({ coerce: coerceOneOf(opts), hint: "ID" }, spec), { desc: $desc(opts, spec.desc) })); | ||
export const oneOf = (opts, spec) => (Object.assign(Object.assign({ coerce: coerceOneOf(opts), hint: "ID", group: "main" }, spec), { desc: $desc(opts, spec.desc) })); | ||
/** | ||
@@ -100,3 +100,3 @@ * Multi-arg version of {@link oneOf}. Returns full {@link ArgSpec} for multiple | ||
*/ | ||
export const oneOfMulti = (opts, spec) => (Object.assign(Object.assign({ coerce: (xs) => xs.map(coerceOneOf(opts)), hint: $hint("ID", spec.delim), multi: true }, spec), { desc: $desc(opts, spec.desc) })); | ||
export const oneOfMulti = (opts, spec) => (Object.assign(Object.assign({ coerce: (xs) => xs.map(coerceOneOf(opts)), hint: $hint("ID", spec.delim), multi: true, group: "main" }, spec), { desc: $desc(opts, spec.desc) })); | ||
/** | ||
@@ -114,3 +114,3 @@ * Returns a full {@link ArgSpec} for multiple `key=value` pair args, coerced | ||
*/ | ||
export const kvPairs = (spec, delim = "=", strict) => (Object.assign({ coerce: coerceKV(delim, strict), hint: `key${delim}val`, multi: true }, spec)); | ||
export const kvPairs = (spec, delim = "=", strict) => (Object.assign({ coerce: coerceKV(delim, strict), hint: `key${delim}val`, multi: true, group: "main" }, spec)); | ||
/** | ||
@@ -142,3 +142,3 @@ * Returns a full {@link ArgSpec} for a fixed `size` tuple extracted from a | ||
*/ | ||
export const tuple = (coerce, size, spec, delim = ",") => (Object.assign({ coerce: coerceTuple(coerce, size, delim), hint: [...repeat("N", size)].join(delim) }, spec)); | ||
export const tuple = (coerce, size, spec, delim = ",") => (Object.assign({ coerce: coerceTuple(coerce, size, delim), hint: [...repeat("N", size)].join(delim), group: "main" }, spec)); | ||
/** | ||
@@ -145,0 +145,0 @@ * Syntax sugar for `tuple(coerceInt, size, {...}, delim)`. |
@@ -6,2 +6,14 @@ # Change Log | ||
# [0.4.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/args@0.3.1...@thi.ng/args@0.4.0) (2021-03-22) | ||
### Features | ||
* **args:** add arg groups, segment usage output ([ebf5197](https://github.com/thi-ng/umbrella/commit/ebf51974e4e1e1d5288af9ad420d4211addd95ad)) | ||
* **args:** support arbitrary length aliases ([1cfdf49](https://github.com/thi-ng/umbrella/commit/1cfdf49a53cca2f80836caf428e220e90f687ad1)) | ||
## [0.3.1](https://github.com/thi-ng/umbrella/compare/@thi.ng/args@0.3.0...@thi.ng/args@0.3.1) (2021-03-21) | ||
@@ -8,0 +20,0 @@ |
@@ -54,6 +54,6 @@ 'use strict'; | ||
const $single = (coerce, hint) => (spec) => (Object.assign({ coerce, | ||
hint }, spec)); | ||
const $multi = (coerce, hint) => (spec) => (Object.assign({ hint: $hint(hint, spec.delim), multi: true, coerce }, spec)); | ||
hint, group: "main" }, spec)); | ||
const $multi = (coerce, hint) => (spec) => (Object.assign({ hint: $hint(hint, spec.delim), multi: true, coerce, group: "main" }, spec)); | ||
const $hint = (hint, delim) => hint + (delim ? `[${delim}..]` : ""); | ||
const flag = (spec) => (Object.assign({ flag: true, default: false }, spec)); | ||
const flag = (spec) => (Object.assign({ flag: true, default: false, group: "flags" }, spec)); | ||
const string = $single((x) => x, "STR"); | ||
@@ -67,12 +67,12 @@ const strings = $multi((x) => x, "STR"); | ||
const ints = $multi(coerceInts, "INT"); | ||
const json = (spec) => (Object.assign({ coerce: coerceJson, hint: "JSON" }, spec)); | ||
const json = (spec) => (Object.assign({ coerce: coerceJson, hint: "JSON", group: "main" }, spec)); | ||
const $desc = (opts, prefix) => `${prefix ? prefix + ": " : ""}${opts.map((x) => `'${x}'`).join(", ")}`; | ||
const oneOf = (opts, spec) => (Object.assign(Object.assign({ coerce: coerceOneOf(opts), hint: "ID" }, spec), { desc: $desc(opts, spec.desc) })); | ||
const oneOfMulti = (opts, spec) => (Object.assign(Object.assign({ coerce: (xs) => xs.map(coerceOneOf(opts)), hint: $hint("ID", spec.delim), multi: true }, spec), { desc: $desc(opts, spec.desc) })); | ||
const kvPairs = (spec, delim = "=", strict) => (Object.assign({ coerce: coerceKV(delim, strict), hint: `key${delim}val`, multi: true }, spec)); | ||
const tuple = (coerce, size, spec, delim = ",") => (Object.assign({ coerce: coerceTuple(coerce, size, delim), hint: [...strings$1.repeat("N", size)].join(delim) }, spec)); | ||
const oneOf = (opts, spec) => (Object.assign(Object.assign({ coerce: coerceOneOf(opts), hint: "ID", group: "main" }, spec), { desc: $desc(opts, spec.desc) })); | ||
const oneOfMulti = (opts, spec) => (Object.assign(Object.assign({ coerce: (xs) => xs.map(coerceOneOf(opts)), hint: $hint("ID", spec.delim), multi: true, group: "main" }, spec), { desc: $desc(opts, spec.desc) })); | ||
const kvPairs = (spec, delim = "=", strict) => (Object.assign({ coerce: coerceKV(delim, strict), hint: `key${delim}val`, multi: true, group: "main" }, spec)); | ||
const tuple = (coerce, size, spec, delim = ",") => (Object.assign({ coerce: coerceTuple(coerce, size, delim), hint: [...strings$1.repeat("N", size)].join(delim), group: "main" }, spec)); | ||
const size = (size, spec, delim = "x") => tuple(coerceInt, size, spec, delim); | ||
const usage = (specs, opts = {}) => { | ||
opts = Object.assign({ lineWidth: 80, paramWidth: 32, showDefaults: true, prefix: "", suffix: "" }, opts); | ||
opts = Object.assign({ lineWidth: 80, paramWidth: 32, showDefaults: true, prefix: "", suffix: "", groups: ["flags", "main"] }, opts); | ||
const theme = opts.color !== false | ||
@@ -82,33 +82,34 @@ ? Object.assign(Object.assign({}, DEFAULT_THEME), opts.color) : {}; | ||
const ansi = (x, col) => col != null ? `\x1b[${col}m${x}\x1b[0m` : x; | ||
const format = (ids) => ids.map((id) => { | ||
const spec = specs[id]; | ||
const hint = spec.hint ? ansi(" " + spec.hint, theme.hint) : ""; | ||
const name = ansi(`--${strings$1.kebab(id)}`, theme.param); | ||
const alias = spec.alias | ||
? `${ansi("-" + spec.alias, theme.param)}${hint}, ` | ||
: ""; | ||
const params = `${alias}${name}${hint}`; | ||
const isRequired = spec.optional === false && spec.default === undefined; | ||
const prefixes = []; | ||
isRequired && prefixes.push("required"); | ||
spec.multi && prefixes.push("multiple"); | ||
const prefix = prefixes.length | ||
? ansi(`[${prefixes.join(", ")}] `, isRequired ? theme.required : theme.multi) | ||
: ""; | ||
const defaults = opts.showDefaults && spec.default !== undefined | ||
? ansi(` (default: ${strings$1.stringify()(spec.defaultHint != undefined | ||
? spec.defaultHint | ||
: spec.default)})`, theme.default) | ||
: ""; | ||
return (strings$1.padRight(opts.paramWidth)(params, strings$1.stripAnsi(params).length) + | ||
strings$1.wordWrapLines(prefix + (spec.desc || "") + defaults, opts.lineWidth - opts.paramWidth) | ||
.map((l, i) => (i > 0 ? indent : "") + l) | ||
.join("\n")); | ||
}); | ||
const sortedIDs = Object.keys(specs).sort(); | ||
const groups = opts.groups | ||
? opts.groups.map((gid) => sortedIDs.filter((id) => specs[id].group === gid)) | ||
: [sortedIDs]; | ||
return [ | ||
opts.prefix, | ||
...Object.keys(specs) | ||
.sort() | ||
.map((id) => { | ||
const spec = specs[id]; | ||
const hint = spec.hint | ||
? ansi(" " + spec.hint, theme.hint) | ||
: ""; | ||
const name = ansi(`--${strings$1.kebab(id)}`, theme.param); | ||
const alias = spec.alias | ||
? `${ansi("-" + spec.alias, theme.param)}${hint}, ` | ||
: ""; | ||
const params = `${alias}${name}${hint}`; | ||
const isRequired = spec.optional === false && spec.default === undefined; | ||
const prefixes = []; | ||
isRequired && prefixes.push("required"); | ||
spec.multi && prefixes.push("multiple"); | ||
const prefix = prefixes.length | ||
? ansi(`[${prefixes.join(", ")}] `, isRequired ? theme.required : theme.multi) | ||
: ""; | ||
const defaults = opts.showDefaults && spec.default !== undefined | ||
? ansi(` (default: ${strings$1.stringify()(spec.defaultHint != undefined | ||
? spec.defaultHint | ||
: spec.default)})`, theme.default) | ||
: ""; | ||
return (strings$1.padRight(opts.paramWidth)(params, strings$1.stripAnsi(params).length) + | ||
strings$1.wordWrapLines(prefix + (spec.desc || "") + defaults, opts.lineWidth - opts.paramWidth) | ||
.map((l, i) => (i > 0 ? indent : "") + l) | ||
.join("\n")); | ||
}), | ||
...groups.map((ids) => format(ids).join("\n") + "\n"), | ||
opts.suffix, | ||
@@ -175,3 +176,3 @@ ].join("\n"); | ||
else { | ||
id = aliases[a[1]]; | ||
id = aliases[a.substr(1)]; | ||
!id && errors.illegalArgs(`unknown option: ${a}`); | ||
@@ -178,0 +179,0 @@ } |
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@thi.ng/strings"),require("@thi.ng/checks"),require("@thi.ng/errors")):"function"==typeof define&&define.amd?define(["exports","@thi.ng/strings","@thi.ng/checks","@thi.ng/errors"],t):t(((e="undefined"!=typeof globalThis?globalThis:e||self).thi=e.thi||{},e.thi.ng=e.thi.ng||{},e.thi.ng.args={}),e.thi.ng.strings,e.thi.ng.checks,e.thi.ng.errors)}(this,(function(e,t,s,i){"use strict";const n={default:95,hint:90,multi:90,param:96,required:33};class r{constructor(e){this.value=e}deref(){return this.value}}const a=e=>s.isNumericFloat(e)?parseFloat(e):i.illegalArgs(`not a numeric value: ${e}`),l=e=>e.map(a),o=e=>s.isHex(e)?parseInt(e,16):i.illegalArgs(`not a hex value: ${e}`),c=e=>e.map(o),u=e=>s.isNumericInt(e)?parseInt(e):i.illegalArgs(`not an integer: ${e}`),g=e=>e.map(u),h=e=>JSON.parse(e),d=e=>t=>e.includes(t)?t:i.illegalArgs(`invalid option: ${t}`),p=(e="=",t=!1)=>s=>s.reduce(((s,n)=>{const r=n.indexOf(e);return t&&r<1&&i.illegalArgs(`got '${n}', but expected a 'key${e}value' pair`),r>0?s[n.substr(0,r)]=n.substr(r+1):s[n]="true",s}),{}),f=(e,t,s=",")=>n=>{const a=n.split(s);return a.length!==t&&i.illegalArgs(`got '${n}', but expected a tuple of ${t} values`),new r(a.map(e))},m=(e,t)=>s=>Object.assign({coerce:e,hint:t},s),b=(e,t)=>s=>Object.assign({hint:$(t,s.delim),multi:!0,coerce:e},s),$=(e,t)=>e+(t?`[${t}..]`:""),O=m((e=>e),"STR"),j=b((e=>e),"STR"),v=m(a,"NUM"),x=m(o,"HEX"),A=m(u,"INT"),y=b(l,"NUM"),k=b(c,"HEX"),I=b(g,"INT"),w=(e,t)=>`${t?t+": ":""}${e.map((e=>`'${e}'`)).join(", ")}`,T=(e,s,i,n=",")=>Object.assign({coerce:f(e,s,n),hint:[...t.repeat("N",s)].join(n)},i),N=(e,s={})=>{const i=!1!==(s=Object.assign({lineWidth:80,paramWidth:32,showDefaults:!0,prefix:"",suffix:""},s)).color?Object.assign(Object.assign({},n),s.color):{},r=t.repeat(" ",s.paramWidth),a=(e,t)=>null!=t?`[${t}m${e}[0m`:e;return[s.prefix,...Object.keys(e).sort().map((n=>{const l=e[n],o=l.hint?a(" "+l.hint,i.hint):"",c=a(`--${t.kebab(n)}`,i.param),u=`${l.alias?`${a("-"+l.alias,i.param)}${o}, `:""}${c}${o}`,g=!1===l.optional&&void 0===l.default,h=[];g&&h.push("required"),l.multi&&h.push("multiple");const d=h.length?a(`[${h.join(", ")}] `,g?i.required:i.multi):"",p=s.showDefaults&&void 0!==l.default?a(` (default: ${t.stringify()(null!=l.defaultHint?l.defaultHint:l.default)})`,i.default):"";return t.padRight(s.paramWidth)(u,t.stripAnsi(u).length)+t.wordWrapLines(d+(l.desc||"")+p,s.lineWidth-s.paramWidth).map(((e,t)=>(t>0?r:"")+e)).join("\n")})),s.suffix].join("\n")},H=(e,t,s)=>{const n=W(e),r={};let a,l,o=s.start;for(;o<t.length;){const i=t[o];if(a){if(E(l,r,a,i))break;a=null,o++}else{if(s.help.includes(i))return void console.log(N(e,s.usageOpts));const t=q(e,n,r,i);if(a=t.id,l=t.spec,o+=~~(t.state<2),t.state)break}}return a&&i.illegalArgs(`missing value for: --${a}`),{result:D(e,r),index:o,rest:t.slice(o),done:o>=t.length}},W=e=>Object.entries(e).reduce(((e,[t,s])=>s.alias?(e[s.alias]=t,e):e),{}),q=(e,s,n,r)=>{if("-"===r[0]){let a;if("-"===r[1]){if("--"===r)return{state:1};a=t.camel(r.substr(2))}else a=s[r[1]],!a&&i.illegalArgs(`unknown option: ${r}`);const l=e[a];return!l&&i.illegalArgs(a),l.flag&&(n[a]=!0,a=void 0,l.fn&&!l.fn("true"))?{state:1,spec:l}:{state:0,id:a,spec:l}}return{state:2}},E=(e,t,n,r)=>(/^-[a-z]/i.test(r)&&i.illegalArgs(`missing value for: --${n}`),e.multi?s.isArray(t[n])?t[n].push(r):t[n]=[r]:t[n]=r,e.fn&&!e.fn(r)),D=(e,t)=>{let s;for(let n in e)s=e[n],void 0===t[n]?void 0!==s.default?t[n]=s.default:!1===s.optional&&i.illegalArgs(`missing arg: --${n}`):s.coerce&&F(s,t,n);return t},F=(e,t,s)=>{try{e.multi&&e.delim&&(t[s]=t[s].reduce(((t,s)=>(t.push(...s.split(e.delim)),t)),[])),t[s]=e.coerce(t[s])}catch(e){throw new Error(`arg --${s}: ${e.message}`)}};e.DEFAULT_THEME=n,e.Tuple=r,e.coerceFloat=a,e.coerceFloats=l,e.coerceHexInt=o,e.coerceHexInts=c,e.coerceInt=u,e.coerceInts=g,e.coerceJson=h,e.coerceKV=p,e.coerceOneOf=d,e.coerceString=e=>e,e.coerceTuple=f,e.flag=e=>Object.assign({flag:!0,default:!1},e),e.float=v,e.floats=y,e.hex=x,e.hexes=k,e.int=A,e.ints=I,e.json=e=>Object.assign({coerce:h,hint:"JSON"},e),e.kvPairs=(e,t="=",s)=>Object.assign({coerce:p(t,s),hint:`key${t}val`,multi:!0},e),e.oneOf=(e,t)=>Object.assign(Object.assign({coerce:d(e),hint:"ID"},t),{desc:w(e,t.desc)}),e.oneOfMulti=(e,t)=>Object.assign(Object.assign({coerce:t=>t.map(d(e)),hint:$("ID",t.delim),multi:!0},t),{desc:w(e,t.desc)}),e.parse=(e,t,s)=>{s=Object.assign({start:2,showUsage:!0,help:["--help","-h"]},s);try{return H(e,t,s)}catch(t){throw s.showUsage&&console.log(t.message+"\n\n"+N(e,s.usageOpts)),t}},e.size=(e,t,s="x")=>T(u,e,t,s),e.string=O,e.strings=j,e.tuple=T,e.usage=N,Object.defineProperty(e,"__esModule",{value:!0})})); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@thi.ng/strings"),require("@thi.ng/checks"),require("@thi.ng/errors")):"function"==typeof define&&define.amd?define(["exports","@thi.ng/strings","@thi.ng/checks","@thi.ng/errors"],t):t(((e="undefined"!=typeof globalThis?globalThis:e||self).thi=e.thi||{},e.thi.ng=e.thi.ng||{},e.thi.ng.args={}),e.thi.ng.strings,e.thi.ng.checks,e.thi.ng.errors)}(this,(function(e,t,s,i){"use strict";const r={default:95,hint:90,multi:90,param:96,required:33};class n{constructor(e){this.value=e}deref(){return this.value}}const a=e=>s.isNumericFloat(e)?parseFloat(e):i.illegalArgs(`not a numeric value: ${e}`),l=e=>e.map(a),o=e=>s.isHex(e)?parseInt(e,16):i.illegalArgs(`not a hex value: ${e}`),c=e=>e.map(o),u=e=>s.isNumericInt(e)?parseInt(e):i.illegalArgs(`not an integer: ${e}`),g=e=>e.map(u),p=e=>JSON.parse(e),h=e=>t=>e.includes(t)?t:i.illegalArgs(`invalid option: ${t}`),f=(e="=",t=!1)=>s=>s.reduce(((s,r)=>{const n=r.indexOf(e);return t&&n<1&&i.illegalArgs(`got '${r}', but expected a 'key${e}value' pair`),n>0?s[r.substr(0,n)]=r.substr(n+1):s[r]="true",s}),{}),d=(e,t,s=",")=>r=>{const a=r.split(s);return a.length!==t&&i.illegalArgs(`got '${r}', but expected a tuple of ${t} values`),new n(a.map(e))},m=(e,t)=>s=>Object.assign({coerce:e,hint:t,group:"main"},s),b=(e,t)=>s=>Object.assign({hint:$(t,s.delim),multi:!0,coerce:e,group:"main"},s),$=(e,t)=>e+(t?`[${t}..]`:""),O=m((e=>e),"STR"),j=b((e=>e),"STR"),v=m(a,"NUM"),x=m(o,"HEX"),A=m(u,"INT"),y=b(l,"NUM"),k=b(c,"HEX"),I=b(g,"INT"),w=(e,t)=>`${t?t+": ":""}${e.map((e=>`'${e}'`)).join(", ")}`,T=(e,s,i,r=",")=>Object.assign({coerce:d(e,s,r),hint:[...t.repeat("N",s)].join(r),group:"main"},i),N=(e,s={})=>{const i=!1!==(s=Object.assign({lineWidth:80,paramWidth:32,showDefaults:!0,prefix:"",suffix:"",groups:["flags","main"]},s)).color?Object.assign(Object.assign({},r),s.color):{},n=t.repeat(" ",s.paramWidth),a=(e,t)=>null!=t?`[${t}m${e}[0m`:e,l=Object.keys(e).sort(),o=s.groups?s.groups.map((t=>l.filter((s=>e[s].group===t)))):[l];return[s.prefix,...o.map((r=>(r=>r.map((r=>{const l=e[r],o=l.hint?a(" "+l.hint,i.hint):"",c=a(`--${t.kebab(r)}`,i.param),u=`${l.alias?`${a("-"+l.alias,i.param)}${o}, `:""}${c}${o}`,g=!1===l.optional&&void 0===l.default,p=[];g&&p.push("required"),l.multi&&p.push("multiple");const h=p.length?a(`[${p.join(", ")}] `,g?i.required:i.multi):"",f=s.showDefaults&&void 0!==l.default?a(` (default: ${t.stringify()(null!=l.defaultHint?l.defaultHint:l.default)})`,i.default):"";return t.padRight(s.paramWidth)(u,t.stripAnsi(u).length)+t.wordWrapLines(h+(l.desc||"")+f,s.lineWidth-s.paramWidth).map(((e,t)=>(t>0?n:"")+e)).join("\n")})))(r).join("\n")+"\n")),s.suffix].join("\n")},H=(e,t,s)=>{const r=W(e),n={};let a,l,o=s.start;for(;o<t.length;){const i=t[o];if(a){if(E(l,n,a,i))break;a=null,o++}else{if(s.help.includes(i))return void console.log(N(e,s.usageOpts));const t=q(e,r,n,i);if(a=t.id,l=t.spec,o+=~~(t.state<2),t.state)break}}return a&&i.illegalArgs(`missing value for: --${a}`),{result:D(e,n),index:o,rest:t.slice(o),done:o>=t.length}},W=e=>Object.entries(e).reduce(((e,[t,s])=>s.alias?(e[s.alias]=t,e):e),{}),q=(e,s,r,n)=>{if("-"===n[0]){let a;if("-"===n[1]){if("--"===n)return{state:1};a=t.camel(n.substr(2))}else a=s[n.substr(1)],!a&&i.illegalArgs(`unknown option: ${n}`);const l=e[a];return!l&&i.illegalArgs(a),l.flag&&(r[a]=!0,a=void 0,l.fn&&!l.fn("true"))?{state:1,spec:l}:{state:0,id:a,spec:l}}return{state:2}},E=(e,t,r,n)=>(/^-[a-z]/i.test(n)&&i.illegalArgs(`missing value for: --${r}`),e.multi?s.isArray(t[r])?t[r].push(n):t[r]=[n]:t[r]=n,e.fn&&!e.fn(n)),D=(e,t)=>{let s;for(let r in e)s=e[r],void 0===t[r]?void 0!==s.default?t[r]=s.default:!1===s.optional&&i.illegalArgs(`missing arg: --${r}`):s.coerce&&F(s,t,r);return t},F=(e,t,s)=>{try{e.multi&&e.delim&&(t[s]=t[s].reduce(((t,s)=>(t.push(...s.split(e.delim)),t)),[])),t[s]=e.coerce(t[s])}catch(e){throw new Error(`arg --${s}: ${e.message}`)}};e.DEFAULT_THEME=r,e.Tuple=n,e.coerceFloat=a,e.coerceFloats=l,e.coerceHexInt=o,e.coerceHexInts=c,e.coerceInt=u,e.coerceInts=g,e.coerceJson=p,e.coerceKV=f,e.coerceOneOf=h,e.coerceString=e=>e,e.coerceTuple=d,e.flag=e=>Object.assign({flag:!0,default:!1,group:"flags"},e),e.float=v,e.floats=y,e.hex=x,e.hexes=k,e.int=A,e.ints=I,e.json=e=>Object.assign({coerce:p,hint:"JSON",group:"main"},e),e.kvPairs=(e,t="=",s)=>Object.assign({coerce:f(t,s),hint:`key${t}val`,multi:!0,group:"main"},e),e.oneOf=(e,t)=>Object.assign(Object.assign({coerce:h(e),hint:"ID",group:"main"},t),{desc:w(e,t.desc)}),e.oneOfMulti=(e,t)=>Object.assign(Object.assign({coerce:t=>t.map(h(e)),hint:$("ID",t.delim),multi:!0,group:"main"},t),{desc:w(e,t.desc)}),e.parse=(e,t,s)=>{s=Object.assign({start:2,showUsage:!0,help:["--help","-h"]},s);try{return H(e,t,s)}catch(t){throw s.showUsage&&console.log(t.message+"\n\n"+N(e,s.usageOpts)),t}},e.size=(e,t,s="x")=>T(u,e,t,s),e.string=O,e.strings=j,e.tuple=T,e.usage=N,Object.defineProperty(e,"__esModule",{value:!0})})); |
{ | ||
"name": "@thi.ng/args", | ||
"version": "0.3.1", | ||
"version": "0.4.0", | ||
"description": "Declarative, functional & typechecked CLI argument/options parser, value coercions etc.", | ||
@@ -86,3 +86,3 @@ "module": "./index.js", | ||
}, | ||
"gitHead": "578bc1ab7886b3ab41a363bce8271ddf01654898" | ||
"gitHead": "feb86e519d19f661b6db6f2adb3a54f6e1e55f80" | ||
} |
@@ -63,3 +63,3 @@ import { isArray } from "@thi.ng/checks"; | ||
else { | ||
id = aliases[a[1]]; | ||
id = aliases[a.substr(1)]; | ||
!id && illegalArgs(`unknown option: ${a}`); | ||
@@ -66,0 +66,0 @@ } |
@@ -64,3 +64,3 @@ <!-- This file is generated - DO NOT EDIT! --> | ||
Package sizes (gzipped, pre-treeshake): ESM: 2.03 KB / CJS: 2.16 KB / UMD: 2.10 KB | ||
Package sizes (gzipped, pre-treeshake): ESM: 2.14 KB / CJS: 2.27 KB / UMD: 2.23 KB | ||
@@ -146,9 +146,21 @@ ## Dependencies | ||
By default uses ANSI colors (see | ||
[`UsageOpts`](https://github.com/thi-ng/umbrella/blob/develop/packages/args/src/api.ts)), | ||
`--help` is always available as built-in: | ||
Usage information can be generated via `usage()` and is automatically triggered | ||
via the special `--help` option (configurable, see | ||
[ParseOpts](https://docs.thi.ng/umbrella/args/interfaces/parseopts.html)). | ||
Each arg can be associated with arbitrary group IDs, which are then used to | ||
segment usage output. By default, `flag()` args are assigned to a `"flags"` | ||
group, all others to `"main"`. The default output order too is `["flags", | ||
"main"]`, but can be configured via a `group` option given an arg spec or | ||
factory function. | ||
By default, ANSI colors are used to format the result string of `usage()`, but | ||
can be disabled (see | ||
[`UsageOpts`](https://docs.thi.ng/umbrella/args/interfaces/usageopts.html)). | ||
```text | ||
ts-node index.ts --help | ||
-f, --force Force operation | ||
--bg HEX Background color | ||
@@ -158,3 +170,2 @@ -c PATH, --config-path PATH Config file path (CLI args always take | ||
-D key=val, --define key=val [multiple] Define dict entry | ||
-f, --force Force operation | ||
--size WxH Target size | ||
@@ -161,0 +172,0 @@ -t ID, --type ID [required] Image type: 'png', 'jpg', 'gif', |
61
usage.js
import { kebab, padRight, repeat, stringify, stripAnsi, wordWrapLines, } from "@thi.ng/strings"; | ||
import { DEFAULT_THEME } from "./api"; | ||
export const usage = (specs, opts = {}) => { | ||
opts = Object.assign({ lineWidth: 80, paramWidth: 32, showDefaults: true, prefix: "", suffix: "" }, opts); | ||
opts = Object.assign({ lineWidth: 80, paramWidth: 32, showDefaults: true, prefix: "", suffix: "", groups: ["flags", "main"] }, opts); | ||
const theme = opts.color !== false | ||
@@ -9,35 +9,36 @@ ? Object.assign(Object.assign({}, DEFAULT_THEME), opts.color) : {}; | ||
const ansi = (x, col) => col != null ? `\x1b[${col}m${x}\x1b[0m` : x; | ||
const format = (ids) => ids.map((id) => { | ||
const spec = specs[id]; | ||
const hint = spec.hint ? ansi(" " + spec.hint, theme.hint) : ""; | ||
const name = ansi(`--${kebab(id)}`, theme.param); | ||
const alias = spec.alias | ||
? `${ansi("-" + spec.alias, theme.param)}${hint}, ` | ||
: ""; | ||
const params = `${alias}${name}${hint}`; | ||
const isRequired = spec.optional === false && spec.default === undefined; | ||
const prefixes = []; | ||
isRequired && prefixes.push("required"); | ||
spec.multi && prefixes.push("multiple"); | ||
const prefix = prefixes.length | ||
? ansi(`[${prefixes.join(", ")}] `, isRequired ? theme.required : theme.multi) | ||
: ""; | ||
const defaults = opts.showDefaults && spec.default !== undefined | ||
? ansi(` (default: ${stringify()(spec.defaultHint != undefined | ||
? spec.defaultHint | ||
: spec.default)})`, theme.default) | ||
: ""; | ||
return (padRight(opts.paramWidth)(params, stripAnsi(params).length) + | ||
wordWrapLines(prefix + (spec.desc || "") + defaults, opts.lineWidth - opts.paramWidth) | ||
.map((l, i) => (i > 0 ? indent : "") + l) | ||
.join("\n")); | ||
}); | ||
const sortedIDs = Object.keys(specs).sort(); | ||
const groups = opts.groups | ||
? opts.groups.map((gid) => sortedIDs.filter((id) => specs[id].group === gid)) | ||
: [sortedIDs]; | ||
return [ | ||
opts.prefix, | ||
...Object.keys(specs) | ||
.sort() | ||
.map((id) => { | ||
const spec = specs[id]; | ||
const hint = spec.hint | ||
? ansi(" " + spec.hint, theme.hint) | ||
: ""; | ||
const name = ansi(`--${kebab(id)}`, theme.param); | ||
const alias = spec.alias | ||
? `${ansi("-" + spec.alias, theme.param)}${hint}, ` | ||
: ""; | ||
const params = `${alias}${name}${hint}`; | ||
const isRequired = spec.optional === false && spec.default === undefined; | ||
const prefixes = []; | ||
isRequired && prefixes.push("required"); | ||
spec.multi && prefixes.push("multiple"); | ||
const prefix = prefixes.length | ||
? ansi(`[${prefixes.join(", ")}] `, isRequired ? theme.required : theme.multi) | ||
: ""; | ||
const defaults = opts.showDefaults && spec.default !== undefined | ||
? ansi(` (default: ${stringify()(spec.defaultHint != undefined | ||
? spec.defaultHint | ||
: spec.default)})`, theme.default) | ||
: ""; | ||
return (padRight(opts.paramWidth)(params, stripAnsi(params).length) + | ||
wordWrapLines(prefix + (spec.desc || "") + defaults, opts.lineWidth - opts.paramWidth) | ||
.map((l, i) => (i > 0 ? indent : "") + l) | ||
.join("\n")); | ||
}), | ||
...groups.map((ids) => format(ids).join("\n") + "\n"), | ||
opts.suffix, | ||
].join("\n"); | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
89539
1013
222