@thi.ng/args
Advanced tools
Comparing version 0.1.0 to 0.2.0
13
api.d.ts
@@ -6,2 +6,3 @@ import type { Fn, IDeref, IObjectOf } from "@thi.ng/api"; | ||
hint?: string; | ||
defaultHint?: string; | ||
fn?: Fn<string, boolean>; | ||
@@ -85,4 +86,16 @@ } | ||
color: Partial<ColorTheme> | false; | ||
/** | ||
* If true (default), display argument default values. | ||
* | ||
* @defaultValue true | ||
*/ | ||
showDefaults: boolean; | ||
} | ||
/** | ||
* Color theme for {@link usage}. Each item is an ANSI color code: | ||
* | ||
* https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit | ||
*/ | ||
export interface ColorTheme { | ||
default: number; | ||
hint: number; | ||
@@ -89,0 +102,0 @@ multi: number; |
export const DEFAULT_THEME = { | ||
default: 95, | ||
hint: 90, | ||
@@ -3,0 +4,0 @@ multi: 90, |
@@ -6,2 +6,13 @@ # Change Log | ||
# [0.2.0](https://github.com/thi-ng/umbrella/compare/@thi.ng/args@0.1.0...@thi.ng/args@0.2.0) (2021-01-13) | ||
### Features | ||
* **args:** add defaultHint opt, update usage() ([f8a4146](https://github.com/thi-ng/umbrella/commit/f8a414605a0d5c93fcef83ab931911c6c2f39f7d)) | ||
# 0.1.0 (2021-01-10) | ||
@@ -8,0 +19,0 @@ |
185
lib/index.js
@@ -10,2 +10,3 @@ 'use strict'; | ||
const DEFAULT_THEME = { | ||
default: 95, | ||
hint: 90, | ||
@@ -75,3 +76,3 @@ multi: 90, | ||
const usage = (specs, opts = {}) => { | ||
opts = Object.assign({ lineWidth: 80, paramWidth: 32 }, opts); | ||
opts = Object.assign({ lineWidth: 80, paramWidth: 32, showDefaults: true }, opts); | ||
const theme = opts.color !== false | ||
@@ -98,4 +99,9 @@ ? Object.assign(Object.assign({}, DEFAULT_THEME), opts.color) : {}; | ||
: ""; | ||
const defaults = opts.showDefaults && spec.default | ||
? 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 || ""), opts.lineWidth - opts.paramWidth) | ||
strings$1.wordWrapLines(prefix + (spec.desc || "") + defaults, opts.lineWidth - opts.paramWidth) | ||
.map((l, i) => (i > 0 ? indent : "") + l) | ||
@@ -107,94 +113,113 @@ .join("\n")); | ||
const HELP = "--help"; | ||
const parse = (specs, argv, opts) => { | ||
opts = Object.assign({ start: 2, showUsage: true }, opts); | ||
try { | ||
return parseOpts(specs, argv, opts); | ||
} | ||
catch (e) { | ||
if (opts.showUsage) { | ||
console.log(e.message + "\n\n" + usage(specs, opts.usageOpts)); | ||
} | ||
throw e; | ||
} | ||
}; | ||
const parseOpts = (specs, argv, opts) => { | ||
const aliases = aliasIndex(specs); | ||
const acc = {}; | ||
const aliases = Object.entries(specs).reduce((acc, [k, v]) => (v.alias ? ((acc[v.alias] = k), acc) : acc), {}); | ||
let id; | ||
let spec; | ||
let i = opts.start; | ||
try { | ||
for (; i < argv.length;) { | ||
const a = argv[i]; | ||
if (!id) { | ||
if (a[0] === "-") { | ||
if (a[1] === "-") { | ||
if (a === "--") { | ||
i++; | ||
break; | ||
} | ||
id = strings$1.camel(a.substr(2)); | ||
} | ||
else { | ||
id = aliases[a[1]]; | ||
!id && errors.illegalArgs(`unknown alias: ${a}`); | ||
} | ||
if (id === "help") { | ||
console.log(usage(specs, opts.usageOpts)); | ||
return; | ||
} | ||
spec = specs[id]; | ||
!spec && errors.illegalArgs(id); | ||
i++; | ||
if (spec.flag) { | ||
acc[id] = true; | ||
id = null; | ||
if (spec.fn && !spec.fn("true")) | ||
break; | ||
} | ||
} | ||
else | ||
break; | ||
for (; i < argv.length;) { | ||
const a = argv[i]; | ||
if (!id) { | ||
if (a === HELP) { | ||
console.log(usage(specs, opts.usageOpts)); | ||
return; | ||
} | ||
else { | ||
/^-[a-z]/i.test(a) && errors.illegalArgs(`missing value for: --${id}`); | ||
if (spec.multi) { | ||
checks.isArray(acc[id]) ? acc[id].push(a) : (acc[id] = [a]); | ||
} | ||
else { | ||
acc[id] = a; | ||
} | ||
id = null; | ||
i++; | ||
if (spec.fn && !spec.fn(a)) | ||
break; | ||
} | ||
const state = parseKey(specs, aliases, acc, a); | ||
id = state.id; | ||
spec = state.spec; | ||
i = i + ~~(state.state < 2); | ||
if (state.state) | ||
break; | ||
} | ||
id && errors.illegalArgs(`missing value for: --${id}`); | ||
for (id in specs) { | ||
spec = specs[id]; | ||
if (acc[id] === undefined) { | ||
if (spec.default !== undefined) { | ||
acc[id] = spec.default; | ||
} | ||
else if (spec.optional === false) { | ||
errors.illegalArgs(`missing arg: --${id}`); | ||
} | ||
else { | ||
if (parseValue(spec, acc, id, a)) | ||
break; | ||
id = null; | ||
i++; | ||
} | ||
} | ||
id && errors.illegalArgs(`missing value for: --${id}`); | ||
return { | ||
result: processResults(specs, acc), | ||
index: i, | ||
rest: argv.slice(i), | ||
done: i >= argv.length, | ||
}; | ||
}; | ||
const aliasIndex = (specs) => Object.entries(specs).reduce((acc, [k, v]) => (v.alias ? ((acc[v.alias] = k), acc) : acc), {}); | ||
const parseKey = (specs, aliases, acc, a) => { | ||
if (a[0] === "-") { | ||
let id; | ||
if (a[1] === "-") { | ||
if (a === "--") | ||
return { state: 1 }; | ||
id = strings$1.camel(a.substr(2)); | ||
} | ||
else { | ||
id = aliases[a[1]]; | ||
!id && errors.illegalArgs(`unknown option: ${a}`); | ||
} | ||
const spec = specs[id]; | ||
!spec && errors.illegalArgs(id); | ||
if (spec.flag) { | ||
acc[id] = true; | ||
id = undefined; | ||
if (spec.fn && !spec.fn("true")) | ||
return { state: 1, spec }; | ||
} | ||
return { state: 0, id, spec }; | ||
} | ||
return { state: 2 }; | ||
}; | ||
const parseValue = (spec, acc, id, a) => { | ||
/^-[a-z]/i.test(a) && errors.illegalArgs(`missing value for: --${id}`); | ||
if (spec.multi) { | ||
checks.isArray(acc[id]) ? acc[id].push(a) : (acc[id] = [a]); | ||
} | ||
else { | ||
acc[id] = a; | ||
} | ||
return spec.fn && !spec.fn(a); | ||
}; | ||
const processResults = (specs, acc) => { | ||
let spec; | ||
for (let id in specs) { | ||
spec = specs[id]; | ||
if (acc[id] === undefined) { | ||
if (spec.default !== undefined) { | ||
acc[id] = spec.default; | ||
} | ||
else { | ||
if (spec.coerce) { | ||
try { | ||
if (spec.multi && spec.delim) { | ||
acc[id] = acc[id].reduce((acc, x) => (acc.push(...x.split(spec.delim)), acc), []); | ||
} | ||
acc[id] = spec.coerce(acc[id]); | ||
} | ||
catch (e) { | ||
throw new Error(`arg --${id}: ${e.message}`); | ||
} | ||
} | ||
else if (spec.optional === false) { | ||
errors.illegalArgs(`missing arg: --${id}`); | ||
} | ||
} | ||
return { | ||
result: acc, | ||
index: i, | ||
rest: argv.slice(i), | ||
done: i >= argv.length, | ||
}; | ||
else if (spec.coerce) { | ||
coerceValue(spec, acc, id); | ||
} | ||
} | ||
catch (e) { | ||
if (opts.showUsage) { | ||
console.log(e.message + "\n\n" + usage(specs, opts.usageOpts)); | ||
return acc; | ||
}; | ||
const coerceValue = (spec, acc, id) => { | ||
try { | ||
if (spec.multi && spec.delim) { | ||
acc[id] = acc[id].reduce((acc, x) => (acc.push(...x.split(spec.delim)), acc), []); | ||
} | ||
throw e; | ||
acc[id] = spec.coerce(acc[id]); | ||
} | ||
catch (e) { | ||
throw new Error(`arg --${id}: ${e.message}`); | ||
} | ||
}; | ||
@@ -201,0 +226,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,i,s){"use strict";const r={hint:90,multi:90,param:96,required:33};class n{constructor(e){this.value=e}deref(){return this.value}}const a=e=>i.isNumericFloat(e)?parseFloat(e):s.illegalArgs(`not a numeric value: ${e}`),l=e=>e.map(a),c=e=>i.isHex(e)?parseInt(e,16):s.illegalArgs(`not a hex value: ${e}`),o=e=>e.map(c),g=e=>i.isNumericInt(e)?parseInt(e):s.illegalArgs(`not an integer: ${e}`),u=e=>e.map(g),h=e=>JSON.parse(e),p=e=>t=>e.includes(t)?t:s.illegalArgs(`invalid option: ${t}`),d=(e="=",t=!1)=>i=>i.reduce(((i,r)=>{const n=r.indexOf(e);return t&&n<1&&s.illegalArgs(`got '${r}', but expected a 'key${e}value' pair`),n>0?i[r.substr(0,n)]=r.substr(n+1):i[r]="true",i}),{}),f=(e,t,i=",")=>r=>{const a=r.split(i);return a.length!==t&&s.illegalArgs(`got '${r}', but expected a tuple of ${t} values`),new n(a.map(e))},m=(e,t)=>i=>Object.assign({coerce:e,hint:t},i),b=(e,t)=>i=>Object.assign({hint:$(t,i.delim),multi:!0,coerce:e},i),$=(e,t)=>e+(t?`[${t}..]`:""),O=m((e=>e),"STR"),j=b((e=>e),"STR"),v=m(a,"NUM"),x=m(c,"HEX"),A=m(g,"INT"),k=b(l,"NUM"),y=b(o,"HEX"),I=b(u,"INT"),T=(e,t)=>`${t?t+": ":""}${e.map((e=>`'${e}'`)).join(", ")}`,N=(e,i,s,r=",")=>Object.assign({coerce:f(e,i,r),hint:[...t.repeat("N",i)].join(r)},s),w=(e,i={})=>{const s=!1!==(i=Object.assign({lineWidth:80,paramWidth:32},i)).color?Object.assign(Object.assign({},r),i.color):{},n=t.repeat(" ",i.paramWidth),a=(e,t)=>null!=t?`[${t}m${e}[0m`:e;return Object.keys(e).sort().map((r=>{const l=e[r],c=l.hint?a(" "+l.hint,s.hint):"",o=a(`--${t.kebab(r)}`,s.param),g=`${l.alias?`${a("-"+l.alias,s.param)}${c}, `:""}${o}${c}`,u=!1===l.optional&&void 0===l.default,h=[];u&&h.push("required"),l.multi&&h.push("multiple");const p=h.length?a(`[${h.join(", ")}] `,u?s.required:s.multi):"";return t.padRight(i.paramWidth)(g,t.stripAnsi(g).length)+t.wordWrapLines(p+(l.desc||""),i.lineWidth-i.paramWidth).map(((e,t)=>(t>0?n:"")+e)).join("\n")})).join("\n")};e.DEFAULT_THEME=r,e.Tuple=n,e.coerceFloat=a,e.coerceFloats=l,e.coerceHexInt=c,e.coerceHexInts=o,e.coerceInt=g,e.coerceInts=u,e.coerceJson=h,e.coerceKV=d,e.coerceOneOf=p,e.coerceString=e=>e,e.coerceTuple=f,e.flag=e=>Object.assign({flag:!0,default:!1},e),e.float=v,e.floats=k,e.hex=x,e.hexes=y,e.int=A,e.ints=I,e.json=e=>Object.assign({coerce:h,hint:"JSON"},e),e.kvPairs=(e,t="=",i)=>Object.assign({coerce:d(t,i),hint:`key${t}val`,multi:!0},e),e.oneOf=(e,t)=>Object.assign(Object.assign({coerce:p(e),hint:"ID"},t),{desc:T(e,t.desc)}),e.oneOfMulti=(e,t)=>Object.assign(Object.assign({coerce:t=>t.map(p(e)),hint:$("ID",t.delim),multi:!0},t),{desc:T(e,t.desc)}),e.parse=(e,r,n)=>{n=Object.assign({start:2,showUsage:!0},n);const a={},l=Object.entries(e).reduce(((e,[t,i])=>i.alias?(e[i.alias]=t,e):e),{});let c,o,g=n.start;try{for(;g<r.length;){const u=r[g];if(c){if(/^-[a-z]/i.test(u)&&s.illegalArgs(`missing value for: --${c}`),o.multi?i.isArray(a[c])?a[c].push(u):a[c]=[u]:a[c]=u,c=null,g++,o.fn&&!o.fn(u))break}else{if("-"!==u[0])break;if("-"===u[1]){if("--"===u){g++;break}c=t.camel(u.substr(2))}else c=l[u[1]],!c&&s.illegalArgs(`unknown alias: ${u}`);if("help"===c)return void console.log(w(e,n.usageOpts));if(o=e[c],!o&&s.illegalArgs(c),g++,o.flag&&(a[c]=!0,c=null,o.fn&&!o.fn("true")))break}}for(c in c&&s.illegalArgs(`missing value for: --${c}`),e)if(o=e[c],void 0===a[c])void 0!==o.default?a[c]=o.default:!1===o.optional&&s.illegalArgs(`missing arg: --${c}`);else if(o.coerce)try{o.multi&&o.delim&&(a[c]=a[c].reduce(((e,t)=>(e.push(...t.split(o.delim)),e)),[])),a[c]=o.coerce(a[c])}catch(e){throw new Error(`arg --${c}: ${e.message}`)}return{result:a,index:g,rest:r.slice(g),done:g>=r.length}}catch(t){throw n.showUsage&&console.log(t.message+"\n\n"+w(e,n.usageOpts)),t}},e.size=(e,t,i="x")=>N(g,e,t,i),e.string=O,e.strings=j,e.tuple=N,e.usage=w,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 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},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 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&&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")})).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("--help"===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},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.1.0", | ||
"version": "0.2.0", | ||
"description": "Declarative, functional & typechecked CLI argument/options parser, value coercions etc.", | ||
@@ -55,3 +55,3 @@ "module": "./index.js", | ||
"@thi.ng/errors": "^1.2.26", | ||
"@thi.ng/strings": "^1.13.0" | ||
"@thi.ng/strings": "^1.14.0" | ||
}, | ||
@@ -65,5 +65,7 @@ "files": [ | ||
"argument", | ||
"ansi", | ||
"cli", | ||
"coerce", | ||
"convert", | ||
"color", | ||
"conversion", | ||
"declarative", | ||
@@ -86,3 +88,3 @@ "functional", | ||
}, | ||
"gitHead": "ec0b1d686c9d5f8f73e2c170b9915c2dd875903f" | ||
"gitHead": "97c3f9d114dbea8ba4e33f69f631de5c8fd30eda" | ||
} |
178
parse.js
@@ -5,94 +5,116 @@ import { isArray } from "@thi.ng/checks"; | ||
import { usage } from "./usage"; | ||
const HELP = "--help"; | ||
export const parse = (specs, argv, opts) => { | ||
opts = Object.assign({ start: 2, showUsage: true }, opts); | ||
try { | ||
return parseOpts(specs, argv, opts); | ||
} | ||
catch (e) { | ||
if (opts.showUsage) { | ||
console.log(e.message + "\n\n" + usage(specs, opts.usageOpts)); | ||
} | ||
throw e; | ||
} | ||
}; | ||
const parseOpts = (specs, argv, opts) => { | ||
const aliases = aliasIndex(specs); | ||
const acc = {}; | ||
const aliases = Object.entries(specs).reduce((acc, [k, v]) => (v.alias ? ((acc[v.alias] = k), acc) : acc), {}); | ||
let id; | ||
let spec; | ||
let i = opts.start; | ||
try { | ||
for (; i < argv.length;) { | ||
const a = argv[i]; | ||
if (!id) { | ||
if (a[0] === "-") { | ||
if (a[1] === "-") { | ||
if (a === "--") { | ||
i++; | ||
break; | ||
} | ||
id = camel(a.substr(2)); | ||
} | ||
else { | ||
id = aliases[a[1]]; | ||
!id && illegalArgs(`unknown alias: ${a}`); | ||
} | ||
if (id === "help") { | ||
console.log(usage(specs, opts.usageOpts)); | ||
return; | ||
} | ||
spec = specs[id]; | ||
!spec && illegalArgs(id); | ||
i++; | ||
if (spec.flag) { | ||
acc[id] = true; | ||
id = null; | ||
if (spec.fn && !spec.fn("true")) | ||
break; | ||
} | ||
} | ||
else | ||
break; | ||
for (; i < argv.length;) { | ||
const a = argv[i]; | ||
if (!id) { | ||
if (a === HELP) { | ||
console.log(usage(specs, opts.usageOpts)); | ||
return; | ||
} | ||
else { | ||
/^-[a-z]/i.test(a) && illegalArgs(`missing value for: --${id}`); | ||
if (spec.multi) { | ||
isArray(acc[id]) ? acc[id].push(a) : (acc[id] = [a]); | ||
} | ||
else { | ||
acc[id] = a; | ||
} | ||
id = null; | ||
i++; | ||
if (spec.fn && !spec.fn(a)) | ||
break; | ||
} | ||
const state = parseKey(specs, aliases, acc, a); | ||
id = state.id; | ||
spec = state.spec; | ||
i = i + ~~(state.state < 2); | ||
if (state.state) | ||
break; | ||
} | ||
id && illegalArgs(`missing value for: --${id}`); | ||
for (id in specs) { | ||
spec = specs[id]; | ||
if (acc[id] === undefined) { | ||
if (spec.default !== undefined) { | ||
acc[id] = spec.default; | ||
} | ||
else if (spec.optional === false) { | ||
illegalArgs(`missing arg: --${id}`); | ||
} | ||
else { | ||
if (parseValue(spec, acc, id, a)) | ||
break; | ||
id = null; | ||
i++; | ||
} | ||
} | ||
id && illegalArgs(`missing value for: --${id}`); | ||
return { | ||
result: processResults(specs, acc), | ||
index: i, | ||
rest: argv.slice(i), | ||
done: i >= argv.length, | ||
}; | ||
}; | ||
const aliasIndex = (specs) => Object.entries(specs).reduce((acc, [k, v]) => (v.alias ? ((acc[v.alias] = k), acc) : acc), {}); | ||
const parseKey = (specs, aliases, acc, a) => { | ||
if (a[0] === "-") { | ||
let id; | ||
if (a[1] === "-") { | ||
// terminator arg, stop parsing | ||
if (a === "--") | ||
return { state: 1 }; | ||
id = camel(a.substr(2)); | ||
} | ||
else { | ||
id = aliases[a[1]]; | ||
!id && illegalArgs(`unknown option: ${a}`); | ||
} | ||
const spec = specs[id]; | ||
!spec && illegalArgs(id); | ||
if (spec.flag) { | ||
acc[id] = true; | ||
id = undefined; | ||
// stop parsing if fn returns false | ||
if (spec.fn && !spec.fn("true")) | ||
return { state: 1, spec }; | ||
} | ||
return { state: 0, id, spec }; | ||
} | ||
// no option arg, stop parsing | ||
return { state: 2 }; | ||
}; | ||
const parseValue = (spec, acc, id, a) => { | ||
/^-[a-z]/i.test(a) && illegalArgs(`missing value for: --${id}`); | ||
if (spec.multi) { | ||
isArray(acc[id]) ? acc[id].push(a) : (acc[id] = [a]); | ||
} | ||
else { | ||
acc[id] = a; | ||
} | ||
return spec.fn && !spec.fn(a); | ||
}; | ||
const processResults = (specs, acc) => { | ||
let spec; | ||
for (let id in specs) { | ||
spec = specs[id]; | ||
if (acc[id] === undefined) { | ||
if (spec.default !== undefined) { | ||
acc[id] = spec.default; | ||
} | ||
else { | ||
if (spec.coerce) { | ||
try { | ||
if (spec.multi && spec.delim) { | ||
acc[id] = acc[id].reduce((acc, x) => (acc.push(...x.split(spec.delim)), acc), []); | ||
} | ||
acc[id] = spec.coerce(acc[id]); | ||
} | ||
catch (e) { | ||
throw new Error(`arg --${id}: ${e.message}`); | ||
} | ||
} | ||
else if (spec.optional === false) { | ||
illegalArgs(`missing arg: --${id}`); | ||
} | ||
} | ||
return { | ||
result: acc, | ||
index: i, | ||
rest: argv.slice(i), | ||
done: i >= argv.length, | ||
}; | ||
else if (spec.coerce) { | ||
coerceValue(spec, acc, id); | ||
} | ||
} | ||
catch (e) { | ||
if (opts.showUsage) { | ||
console.log(e.message + "\n\n" + usage(specs, opts.usageOpts)); | ||
return acc; | ||
}; | ||
const coerceValue = (spec, acc, id) => { | ||
try { | ||
if (spec.multi && spec.delim) { | ||
acc[id] = acc[id].reduce((acc, x) => (acc.push(...x.split(spec.delim)), acc), []); | ||
} | ||
throw e; | ||
acc[id] = spec.coerce(acc[id]); | ||
} | ||
catch (e) { | ||
throw new Error(`arg --${id}: ${e.message}`); | ||
} | ||
}; |
11
usage.js
@@ -1,5 +0,5 @@ | ||
import { kebab, padRight, repeat, stripAnsi, wordWrapLines, } from "@thi.ng/strings"; | ||
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 }, opts); | ||
opts = Object.assign({ lineWidth: 80, paramWidth: 32, showDefaults: true }, opts); | ||
const theme = opts.color !== false | ||
@@ -26,4 +26,9 @@ ? Object.assign(Object.assign({}, DEFAULT_THEME), opts.color) : {}; | ||
: ""; | ||
const defaults = opts.showDefaults && spec.default | ||
? ansi(` (default: ${stringify()(spec.defaultHint != undefined | ||
? spec.defaultHint | ||
: spec.default)})`, theme.default) | ||
: ""; | ||
return (padRight(opts.paramWidth)(params, stripAnsi(params).length) + | ||
wordWrapLines(prefix + (spec.desc || ""), opts.lineWidth - opts.paramWidth) | ||
wordWrapLines(prefix + (spec.desc || "") + defaults, opts.lineWidth - opts.paramWidth) | ||
.map((l, i) => (i > 0 ? indent : "") + l) | ||
@@ -30,0 +35,0 @@ .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
84856
1001
Updated@thi.ng/strings@^1.14.0