Comparing version 0.6.0 to 0.8.2
// @bun | ||
var _={kebab:/([a-z0-9]|(?=[A-Z]))([A-Z])/g,camel:/-+([^-])|-+$/g,arrayType:/(^array|\[\])$/,validTypes:/^((array|count)|(boolean|string|number|float|int|hex)(\[\])?)$/,paramTokens:/^(?<STOP>--)$|^-(?<LONG>-+)?(?<NO>no-)?(?<KEY>[^=\s]+?)(?<KEYNUM>[\d]*)(?<ASSIGN>=(?<VAL>.*))?$/};function d(x,R){R=R||{output:{_:[]},validate:[],mandatory:[],complexDefault:{},conf:{error:(T)=>{throw T},panic:(T)=>{throw T},allowUnknown:!0,autoCamelKebabCase:!0,allowNegatingFlags:!0,allowKeyNumValues:!0,allowAssign:!0},params:{}};const{mandatory:h,validate:v,complexDefault:b,output:Z,conf:q,params:z}=R;x.reverse();while(x.length){let T=""+x.pop();if(T.charCodeAt(0)!==45){Z._.push(T);continue}const J=T.match(_.paramTokens);if(J===void 0)return q.panic("Grup not returned");let{STOP:D,LONG:W,NO:C,KEY:$,KEYNUM:Q,ASSIGN:F,VAL:w}=J?.groups||{STOP:"",LONG:"",NO:"",KEY:"",KEYNUM:"",ASSIGN:"",VAL:""};if(D){Z._=Z._.concat(x.reverse());break}if(C&&!q.allowNegatingFlags)$=(C?C:"")+$,C="";if(Q)if(!q.allowKeyNumValues||W||F)$=$+(Q?Q:""),Q="";else{if(!W&&1<$.length)return q.error(`Unsupported format: '${T}'. Did you miss a dash before that?`);w=F=Q}if(!W&&1<$.length){const H=$.split("").map((X)=>(C?"-no-":"-")+X);H[H.length-1]=H[H.length-1]+(F?F:""),x=x.concat(H.reverse());continue}if(!$){Z._.push(T);continue}if(!z[$]){if(!q.allowUnknown)return q.error(`Unspecified parameters like '${$}' not allowed.`);if(q.autoCamelKebabCase)$=$.replace(_.camel,function(H,X){return X.toUpperCase()});if(F){if(!w){if(x.length===0)return q.error(`No data provided for '${$}'`);w=x.pop()||""}Z[$]=+w==w?+w:w}else Z[$]=!C;continue}if(z[$].type==="boolean"){if(F)return q.error(`You asked for the parameter '${$}' to be boolean but you are trying to assign a value: '${T}'`);Z[z[$].key]=!C;continue}if(C)return q.error(`Can't negate '${$}' as the type is set to '${z[$].type}'`);if(z[$].type==="count"){Z[$]++;continue}if(x.length===0)return q.error(`No data provided for '${$}'`);w||=x.pop()||"";let B=0;switch(z[$].type){case"string":Z[z[$].key]=w;continue;case"array":case"string[]":Z[z[$].key].push(w);continue;case"number":case"float":case"number[]":case"float[]":B=+w;break;case"int":case"int[]":debugger;if(B=+w|0,""+B!==w)B=NaN;break;case"hex":case"hex[]":B=parseInt(w,16);break;default:return q.panic(`The parameter '${$}' is configured with an invalid type: '${z[$].type}'`)}if(isNaN(B)||!isFinite(B))return q.error(`The value of '${$}' is not a valid ${z[$].type}: '${w}'`);if(Array.isArray(Z[z[$].key]))Z[z[$].key].push(B);else Z[z[$].key]=B}for(let T in b){if(!z.hasOwnProperty(T))continue;if(Z[T]===void 0||!Z[T].length)Z[T]=b[T]}for(let T of v){let J="";if(typeof z[T].valid==="function"){if(z[T].valid(Z[T]))continue}else{if(!Array.isArray(z[T].valid))return q.panic(`The "valid" property of the '${T}' parameter must be a function or an array of valid values`);if(z[T].valid.includes(Z[T]))continue;J=". Please use one of the following values: "+JSON.stringify(z[T].valid)}return q.error(`The value provided for parameter '${T}' is not valid: '${Z[T]}'`+J)}for(let T of h)if(Z[T]===void 0)return q.error(`The parameter '${T}' is mandatory.`+(z[T].alias.length?` You can also provide an alias: ${z[T].alias.join(", ")}`:""));return Z}export{d as default}; | ||
var C={isCamel:/[a-z0-9][A-Z]/,isKebab:/\w-\w+/,camel2kebab:/([a-z0-9]|(?=[A-Z]))([A-Z])/g,kebab2camel:/-+([^-])|-+$/g,isArrayType:/(^array|\[\])$/,validTypes:/^((array|count|json|split)|(boolean|string|number|float|int|hex)(\[\])?)$/,paramTokens:/^(?<STOP>--)$|^-(?<LONG>-+)?(?<NO>no-)?(?<KEY>[^=\s]+?)(?<KEYNUM>[\d]*)(?<ASSIGN>=(?<VAL>.*))?$/,listDeviders:/[,\s]+-?-?|^--?/,isHex:/^(0x)?[A-Fa-f0-9]+$/,isHexPrefix:/^(0x)[A-Fa-f0-9]+$/,truncate:/^(.{40}).*$/,boolStringTrue:/^(true|yes|on)$/i,boolstringfalse:/^(false|no|off)$/i};function O(F){const b={};for(let f in F){const I=f.split(".");let J=b;I.forEach((x,M)=>{if(!J[x])J[x]={};if(M===I.length-1)J[x]=F[f];else J=J[x]})}return b}function h(F,b){b=b||{output:{_:[]},validate:[],mandatory:[],conflict:[],complexDefault:{},conf:{error:($)=>{throw $},panic:($)=>{throw $},allowUnknown:!0,autoCamelKebabCase:!0,allowNegatingFlags:!0,allowKeyNumValues:!0,allowAssign:!0,outputAlias:!1},params:{}};const{mandatory:f,validate:I,complexDefault:J,output:x,conf:M,params:R,conflict:S}=b,U=[],{error:q,panic:i,allowUnknown:d,autoCamelKebabCase:j,allowNegatingFlags:A,allowKeyNumValues:N,allowAssign:V}=M,v=x._.push.bind(x._),n=Object.prototype.hasOwnProperty;F.reverse();while(F.length){let $=""+F.pop();if($.charCodeAt(0)!==45){v($);continue}const H=$.match(C.paramTokens);if(!H)return i("Group not returned");let{STOP:W,LONG:w,NO:B,KEY:Z,KEYNUM:G,ASSIGN:T,VAL:z}=H.groups;if(W){x._=x._.concat(F.reverse());break}if(B&&!A)Z=(B||"")+Z,B="";if(G)if(!N||w||T)Z+=G,G="";else{if(!w&&1<Z.length)return q(`Unsupported format: '${$}'. Did you miss a dash at the beginning?`);z=T=G}if(!w&&1<Z.length){const _=Z.split("").map((P)=>(B?"-no-":"-")+P);_[_.length-1]+=T||"",F=F.concat(_.reverse());continue}if(!Z){v($);continue}if(!R[Z]){if(!d)return q(`Unknown parameter '${Z}' not allowed.`);if(j&&C.isKebab.test(Z))Z=Z.replace(C.kebab2camel,(_,P)=>P.toUpperCase());if(T){if(!z){if(F.length===0)return q(`No data provided for '${Z}'`);z=F.pop()||""}x[Z]=+z+""===z?+z:z}else x[Z]=!B;U.push(Z);continue}const D=R[Z].key,X=R[D].type;if(!z&&!(X==="count"||X==="boolean"&&!T)){if(F.length===0)return q(`No data provided for '${Z}'`);z||=F.pop()||""}if(X==="boolean"){let _=!B;if(T)if(B)return q(`The parameter '${Z}' can't be negated AND assigned at the same time`);else if(M.allowBoolString&&C.boolStringTrue.test(z))_=!0;else if(M.allowBoolString&&C.boolstringfalse.test(z))_=!1;else return q(`The parameter '${Z}' is a boolean (a flag) and can't be assigned a value like '${$}'`);x[D]=_,U.push(D);continue}if(B)return q(`Can't negate '${Z}' as the type is set to '${X}'`);if(X==="count"){x[D]++,U.push(D);continue}let Q=0;switch(X){case"string":x[D]=z;continue;case"array":case"string[]":x[D].push(z);continue;case"number":case"float":case"number[]":case"float[]":Q=+z;break;case"int":case"int[]":if(Q=+z|0,Q+""!==z&&!C.isHexPrefix.test(z))Q=NaN;break;case"hex":case"hex[]":if(C.isHex.test(z))Q=parseInt(z,16);else Q=NaN;break;default:return i(`Parameter '${Z}' configuration has an invalid type: '${X}'`)}if(isNaN(Q)||!isFinite(Q))return q(`The value of '${Z}' is not a valid ${X}: '${z}'`);if(Array.isArray(x[D]))x[D].push(Q);else x[D]=Q}for(let[$,H]of Object.entries(J)){if(!n.call(R,$))continue;if(x[$]===void 0||!x[$].length)x[$]=H}for(let $ of I){const H=R[$];let W="";if(typeof H.valid==="function"){if(H.valid(x[$]))continue}else{if(!Array.isArray(H.valid))return i(`The "valid" property of '${$}' parameter must be a function or an array of valid values`);if(H.valid.includes(x[$]))continue;W=". Please use one of the following values: "+JSON.stringify(H.valid)}return q(`The value provided for the parameter '${$}' is not valid: '${x[$]}'`+W)}for(let $ of f)if(x[$]===void 0)return q(`The parameter '${$}' is mandatory.${R[$]?.alias?.length?` You can also use an alias: ${R[$].alias.join(", ")}`:""}`);for(let $ of S){if(!U.includes($))continue;const H=R[$]?.conflict?.find((W)=>U.includes(W));if(H)return q(`The parameter '${$}' conflicts with '${H}'`)}if(M.outputAlias){const $={};for(let H in x){if(H==="_"||!Object.prototype.hasOwnProperty.call(x,H))continue;const W=x[H];$[H]=W;const w=R[H].alias;if(!w)continue;for(let B of w)$[B]=W}Object.assign(x,$)}if(M.outputInflate)return O(x);return x}export{h as default}; |
// @bun | ||
var R={kebab:/([a-z0-9]|(?=[A-Z]))([A-Z])/g,camel:/-+([^-])|-+$/g};function T(H,W){W=W||{output:{_:[]},validate:[],mandatory:[],complexDefault:{},conf:{error:(q)=>{throw q},panic:(q)=>{throw q},allowUnknown:!0,autoCamelKebabCase:!0,allowNegatingFlags:!0,allowKeyNumValues:!0,allowAssign:!0},params:{}};const{mandatory:_,validate:$,output:z,conf:F,params:B,complexDefault:Z}=W;H.reverse();while(H.length){let q=""+H.pop();if(q.charCodeAt(0)!==45){z._.push(q);continue}let J=!1,w="",C="",U=!1;if(q.charCodeAt(1)===45)J=!0,w=q.slice(2);else w=q.slice(1);if(J&&!w){z._=z._.concat(H.reverse());break}if(!w){z._.push(q);continue}if(F.allowAssign){let Q=w.indexOf("=");if(-1<Q)U=!0,C=w.slice(Q+1),w=w.slice(0,Q)}if(!J&&w.length!==1){if(U)return F.error(`Unsupported format: '${q}'`);const Q=w.split("").map((X)=>"-"+X);H=H.concat(Q.reverse());continue}if(!B[w]){if(!F.allowUnknown)return F.error(`'${w}' not allowed`);if(F.autoCamelKebabCase)w=w.replace(R.camel,function(Q,X){return X.toUpperCase()});if(U){if(!C){if(H.length===0)return F.error(`No data provided for '${w}'`);C=H.pop()||""}z[w]=+C==C?+C:C}else z[w]=!0;continue}if(B[w].type==="boolean"){if(U)return F.error(`'${w}' is boolean, so can't assign: '${q}'`);z[B[w].key]=!0;continue}if(B[w].type==="count"){if(U)return F.error(`'${w}' is count, so can't assign: '${q}'`);z[w]++;continue}if(!C){if(H.length===0)return F.error(`No data for '${w}'`);C=H.pop()||""}let M=0;switch(B[w].type){case"string":z[B[w].key]=C;continue;case"array":case"string[]":z[B[w].key].push(C);continue;case"number":case"float":case"number[]":case"float[]":M=+C;break;case"int":case"int[]":if(M=+C|0,""+M!==C)M=NaN;break;case"hex":case"hex[]":M=parseInt(C,16);break;default:return F.panic(`'${w}' got invalid type: '${B[w].type}'`)}if(isNaN(M)||!isFinite(M))return F.error(`'${w}' not a valid ${B[w].type}: '${C}'`);if(Array.isArray(z[B[w].key]))z[B[w].key].push(M);else z[B[w].key]=M}for(let q of $){let J="";if(typeof B[q].valid==="function"){if(B[q].valid(z[q]))continue}else{if(!Array.isArray(B[q].valid))return F.panic(`"valid" property of '${q}' must be function or array`);if(B[q].valid.includes(z[q]))continue;J=". Valid values: "+JSON.stringify(B[q].valid)}return F.error(`Invalid value for '${q}': '${z[q]}'`+J)}for(let q of _)if(z[q]===void 0)return F.error(`'${q.length>1?"--":"-"}${q}' is mandatory`+(B[q].alias.length?`. Or use an alias: ${B[q].alias.map((J)=>(J.length>1?"--":"-")+J).join(", ")}`:""));for(let q in Z){if(!B.hasOwnProperty(q))continue;if(z[q]===void 0||!z[q].length)z[q]=Z[q]}return z}export{R as re,T as default}; | ||
var U={isCamel:/[a-z0-9][A-Z]/,isKebab:/\w-\w+/,camel2kebab:/([a-z0-9]|(?=[A-Z]))([A-Z])/g,kebab2camel:/-+([^-])|-+$/g,isArrayType:/(^array|\[\])$/,validTypes:/^((array|count|json|split)|(boolean|string|number|float|int|hex)(\[\])?)$/,paramTokens:/^(?<STOP>--)$|^-(?<LONG>-+)?(?<NO>no-)?(?<KEY>[^=\s]+?)(?<KEYNUM>[\d]*)(?<ASSIGN>=(?<VAL>.*))?$/,listDeviders:/[,\s]+-?-?|^--?/,isHex:/^(0x)?[A-Fa-f0-9]+$/,isHexPrefix:/^(0x)[A-Fa-f0-9]+$/,truncate:/^(.{40}).*$/,boolStringTrue:/^(true|yes|on)$/i,boolstringfalse:/^(false|no|off)$/i};function J(w,C){C=C||{output:{_:[]},validate:[],mandatory:[],conflict:[],complexDefault:{},conf:{error:($)=>{throw $},panic:($)=>{throw $},allowUnknown:!0,autoCamelKebabCase:!0,allowNegatingFlags:!0,allowKeyNumValues:!0,allowAssign:!0},params:{}};const{mandatory:q,validate:B,output:b,conf:Z,params:x,complexDefault:d}=C;w.reverse();while(w.length){let $=""+w.pop();if($.charCodeAt(0)!==45){b._.push($);continue}let F=!1,i="",T="",l=!1;if($.charCodeAt(1)===45)F=!0,i=$.slice(2);else i=$.slice(1);if(F&&!i){b._=b._.concat(w.reverse());break}if(!i){b._.push($);continue}if(Z.allowAssign){const H=i.indexOf("=");if(-1<H)l=!0,T=i.slice(H+1),i=i.slice(0,H)}if(!F&&i.length!==1){if(l)return Z.error(`Unsupported format: '${$}'`);const H=i.split("").map((M)=>"-"+M);w=w.concat(H.reverse());continue}if(!x[i]){if(!Z.allowUnknown)return Z.error(`Unknown parameter '${i}' not allowed`);if(Z.autoCamelKebabCase)i=i.replace(U.kebab2camel,function(H,M){return M.toUpperCase()});if(l){if(!T){if(w.length===0)return Z.error(`No data provided for '${i}'`);T=w.pop()||""}b[i]=+T+""===T?+T:T}else b[i]=!0;continue}if(x[x[i].key].type==="boolean"){if(l)return Z.error(`'${i}' is boolean, so can't assign: '${$}'`);b[x[i].key]=!0;continue}if(x[x[i].key].type==="count"){if(l)return Z.error(`'${i}' counting, so can't assign: '${$}'`);b[i]++;continue}if(!T){if(w.length===0)return Z.error(`No data for '${i}'`);T=w.pop()||""}let z=0;switch(x[x[i].key].type){case"string":b[x[i].key]=T;continue;case"array":case"string[]":b[x[i].key].push(T);continue;case"number":case"float":case"number[]":case"float[]":z=+T;break;case"int":case"int[]":if(z=+T|0,z+""!==T)z=NaN;break;case"hex":case"hex[]":if(U.isHex.test(T))z=parseInt(T,16);else z=NaN;break;default:return Z.panic(`'${i}' got invalid type: '${x[x[i].key].type}'`)}if(isNaN(z)||!isFinite(z))return Z.error(`'${i}' value is not a valid ${x[x[i].key].type}: '${T}'`);if(Array.isArray(b[x[i].key]))b[x[i].key].push(z);else b[x[i].key]=z}for(let $ of B){let F="";if(typeof x[$].valid==="function"){if(x[$].valid(b[$]))continue}else{if(!Array.isArray(x[$].valid))return Z.panic(`"valid" property of '${$}' must be function or array`);if(x[$].valid.includes(b[$]))continue;F=". Valid values: "+JSON.stringify(x[$].valid)}return Z.error(`Invalid value for '${$}': '${b[$]}'`+F)}for(let $ of q)if(b[$]===void 0)return Z.error(`'${$.length>1?"--":"-"}${$}' is mandatory`+(x[$]?.alias?.length?`. Or use an alias: ${x[$].alias.map((F)=>(F.length>1?"--":"-")+F).join(", ")}`:""));for(let $ in d){if(!x.hasOwnProperty($))continue;if(b[$]===void 0||!b[$].length)b[$]=d[$]}return b}export{J as default}; |
#!/usr/bin/env node | ||
// @bun | ||
var Q={kebab:/([a-z0-9]|(?=[A-Z]))([A-Z])/g,camel:/-+([^-])|-+$/g,arrayType:/(^array|\[\])$/,validTypes:/^((array|count)|(boolean|string|number|float|int|hex)(\[\])?)$/,paramTokens:/^(?<STOP>--)$|^-(?<LONG>-+)?(?<NO>no-)?(?<KEY>[^=\s]+?)(?<KEYNUM>[\d]*)(?<ASSIGN>=(?<VAL>.*))?$/};function i(C,w){w=w||{output:{_:[]},validate:[],mandatory:[],complexDefault:{},conf:{error:(M)=>{throw M},panic:(M)=>{throw M},allowUnknown:!0,autoCamelKebabCase:!0,allowNegatingFlags:!0,allowKeyNumValues:!0,allowAssign:!0},params:{}};const{mandatory:I,validate:h,complexDefault:q,output:J,conf:Z,params:$}=w;C.reverse();while(C.length){let M=""+C.pop();if(M.charCodeAt(0)!==45){J._.push(M);continue}const B=M.match(Q.paramTokens);if(B===void 0)return Z.panic("Grup not returned");let{STOP:O,LONG:T,NO:H,KEY:x,KEYNUM:X,ASSIGN:R,VAL:z}=B?.groups||{STOP:"",LONG:"",NO:"",KEY:"",KEYNUM:"",ASSIGN:"",VAL:""};if(O){J._=J._.concat(C.reverse());break}if(H&&!Z.allowNegatingFlags)x=(H?H:"")+x,H="";if(X)if(!Z.allowKeyNumValues||T||R)x=x+(X?X:""),X="";else{if(!T&&1<x.length)return Z.error(`Unsupported format: '${M}'. Did you miss a dash before that?`);z=R=X}if(!T&&1<x.length){const W=x.split("").map((_)=>(H?"-no-":"-")+_);W[W.length-1]=W[W.length-1]+(R?R:""),C=C.concat(W.reverse());continue}if(!x){J._.push(M);continue}if(!$[x]){if(!Z.allowUnknown)return Z.error(`Unspecified parameters like '${x}' not allowed.`);if(Z.autoCamelKebabCase)x=x.replace(Q.camel,function(W,_){return _.toUpperCase()});if(R){if(!z){if(C.length===0)return Z.error(`No data provided for '${x}'`);z=C.pop()||""}J[x]=+z==z?+z:z}else J[x]=!H;continue}if($[x].type==="boolean"){if(R)return Z.error(`You asked for the parameter '${x}' to be boolean but you are trying to assign a value: '${M}'`);J[$[x].key]=!H;continue}if(H)return Z.error(`Can't negate '${x}' as the type is set to '${$[x].type}'`);if($[x].type==="count"){J[x]++;continue}if(C.length===0)return Z.error(`No data provided for '${x}'`);z||=C.pop()||"";let F=0;switch($[x].type){case"string":J[$[x].key]=z;continue;case"array":case"string[]":J[$[x].key].push(z);continue;case"number":case"float":case"number[]":case"float[]":F=+z;break;case"int":case"int[]":debugger;if(F=+z|0,""+F!==z)F=NaN;break;case"hex":case"hex[]":F=parseInt(z,16);break;default:return Z.panic(`The parameter '${x}' is configured with an invalid type: '${$[x].type}'`)}if(isNaN(F)||!isFinite(F))return Z.error(`The value of '${x}' is not a valid ${$[x].type}: '${z}'`);if(Array.isArray(J[$[x].key]))J[$[x].key].push(F);else J[$[x].key]=F}for(let M in q){if(!$.hasOwnProperty(M))continue;if(J[M]===void 0||!J[M].length)J[M]=q[M]}for(let M of h){let B="";if(typeof $[M].valid==="function"){if($[M].valid(J[M]))continue}else{if(!Array.isArray($[M].valid))return Z.panic(`The "valid" property of the '${M}' parameter must be a function or an array of valid values`);if($[M].valid.includes(J[M]))continue;B=". Please use one of the following values: "+JSON.stringify($[M].valid)}return Z.error(`The value provided for parameter '${M}' is not valid: '${J[M]}'`+B)}for(let M of I)if(J[M]===void 0)return Z.error(`The parameter '${M}' is mandatory.`+($[M].alias.length?` You can also provide an alias: ${$[M].alias.join(", ")}`:""));return J}function j(C,w){return A(P(C,w))}function P(C,w={}){const I=[],h=[];let q={},J={_:[]};const Z={...d,...w.strict?V:{},...w};for(let $ in C){if(!C.hasOwnProperty($))continue;let M=C[$];if(M===null||typeof M!=="object"||Array.isArray(M))M={default:M,type:D(M)};if(M.key=$,M.alias=M.alias||[],M.valid!==void 0){if(h.push($),M.default===void 0&&Array.isArray(M.valid)){if(!M.valid.length)return Z.panic(`Empty array found for valid values of '${$}'`);if(M.type===void 0)M.type=D(M.valid[0]);M.default=M.valid[0]}}if(M.type=M.type?.toLowerCase()||D(M.default)||"boolean",M.default!==void 0)if(Array.isArray(M.default))q[$]=M.default;else if(M.type=="count")return Z.error(`Default parameters like '${M.default}' are not allowed on parameters like '${$}' with the type '${M.type}'`);else J[$]=M.default;if(M.type=="count")J[$]=0;if(!M.type.match(Q.validTypes))Z.error(`Invalid type '${M.type}' for parameter '${$}'`);if(M.type.match(Q.arrayType))J[$]=[];if(M.mandatory)I.push($);if(Z.autoCamelKebabCase){let B=$.replace(Q.kebab,"$1-$2").toLowerCase();if(B!==$)M.alias=[B].concat(M.alias||[])}if(M.alias!==void 0&&!Array.isArray(M.alias))M.alias=[M.alias];if(M.alias)M.alias.forEach((B)=>{if(C[B]===void 0)C[B]={type:C[$].type,key:$}})}return{output:J,validate:h,mandatory:I,complexDefault:q,conf:Z,params:C}}function D(C){if(C===null||C===void 0)return;let w=typeof C,I=Array.isArray(C);if(I&&C.length>0)w=typeof C[0];switch(w){case"boolean":case"number":return w+(I?"[]":"");default:return"string"+(I?"[]":"")}}function A(C,w=1){let I="{\n";for(let[h,q]of Object.entries(C)){if(I+=`${" ".repeat(w)}"${h}": `,typeof q==="function")I+=q.toString();else if(typeof q==="object"&&!Array.isArray(q))I+=A(q,w+1);else I+=JSON.stringify(q);I+=",\n"}return I+=" ".repeat(w-1)+"}",I}var d={error:(C)=>{throw C},panic:(C)=>{throw C},allowUnknown:!0,autoCamelKebabCase:!0,allowNegatingFlags:!0,allowKeyNumValues:!0,allowAssign:!0},V={allowUnknown:!1,autoCamelKebabCase:!1,allowNegatingFlags:!1,allowKeyNumValues:!1};function U(C={width:100,format:"cli",preIntro:"",showIntro:!0,showOutro:!0,postOutro:""},w={},I){debugger;let h={};if(C.showIntro&&w.intro)h.intro=w.intro;if(h.params=JSON.parse(JSON.stringify(I)),C.showOutro&&w.outro)h.outro=w.outro;if(C.format==="json")return h;if(C.format==="cli")return JSON.stringify(h,null,2);if(C.format==="markdown")return"md not supported yet"}function b(C,w,I,h){if(!I&&!h)return C(w);if(I)S=JSON.stringify(I);if(h)G={...h};return C(w,P(I||{},h||{}))}function g(C={},w={},I){return U({preIntro:"",showIntro:!0,showOutro:!0,postOutro:"",format:"cli",width:100,...C},{...G,...w},I||JSON.parse(S))}var S,G;function L(C,w,I){return b(i,C,w,I)}export{j as precompileConfig,L as default,P as compileConfig,g as argInfo}; | ||
var W={isCamel:/[a-z0-9][A-Z]/,isKebab:/\w-\w+/,camel2kebab:/([a-z0-9]|(?=[A-Z]))([A-Z])/g,kebab2camel:/-+([^-])|-+$/g,isArrayType:/(^array|\[\])$/,validTypes:/^((array|count|json|split)|(boolean|string|number|float|int|hex)(\[\])?)$/,paramTokens:/^(?<STOP>--)$|^-(?<LONG>-+)?(?<NO>no-)?(?<KEY>[^=\s]+?)(?<KEYNUM>[\d]*)(?<ASSIGN>=(?<VAL>.*))?$/,listDeviders:/[,\s]+-?-?|^--?/,isHex:/^(0x)?[A-Fa-f0-9]+$/,isHexPrefix:/^(0x)[A-Fa-f0-9]+$/,truncate:/^(.{40}).*$/,boolStringTrue:/^(true|yes|on)$/i,boolstringfalse:/^(false|no|off)$/i};function c(M){const z={};for(let H in M){const q=H.split(".");let Q=z;q.forEach((C,J)=>{if(!Q[C])Q[C]={};if(J===q.length-1)Q[C]=M[H];else Q=Q[C]})}return z}function d(M,z){z=z||{output:{_:[]},validate:[],mandatory:[],conflict:[],complexDefault:{},conf:{error:($)=>{throw $},panic:($)=>{throw $},allowUnknown:!0,autoCamelKebabCase:!0,allowNegatingFlags:!0,allowKeyNumValues:!0,allowAssign:!0,outputAlias:!1},params:{}};const{mandatory:H,validate:q,complexDefault:Q,output:C,conf:J,params:X,conflict:i}=z,A=[],{error:Z,panic:x,allowUnknown:U,autoCamelKebabCase:v,allowNegatingFlags:L,allowKeyNumValues:K,allowAssign:m}=J,h=C._.push.bind(C._),n=Object.prototype.hasOwnProperty;M.reverse();while(M.length){let $=""+M.pop();if($.charCodeAt(0)!==45){h($);continue}const I=$.match(W.paramTokens);if(!I)return x("Group not returned");let{STOP:P,LONG:T,NO:D,KEY:F,KEYNUM:f,ASSIGN:_,VAL:B}=I.groups;if(P){C._=C._.concat(M.reverse());break}if(D&&!L)F=(D||"")+F,D="";if(f)if(!K||T||_)F+=f,f="";else{if(!T&&1<F.length)return Z(`Unsupported format: '${$}'. Did you miss a dash at the beginning?`);B=_=f}if(!T&&1<F.length){const S=F.split("").map((j)=>(D?"-no-":"-")+j);S[S.length-1]+=_||"",M=M.concat(S.reverse());continue}if(!F){h($);continue}if(!X[F]){if(!U)return Z(`Unknown parameter '${F}' not allowed.`);if(v&&W.isKebab.test(F))F=F.replace(W.kebab2camel,(S,j)=>j.toUpperCase());if(_){if(!B){if(M.length===0)return Z(`No data provided for '${F}'`);B=M.pop()||""}C[F]=+B+""===B?+B:B}else C[F]=!D;A.push(F);continue}const R=X[F].key,G=X[R].type;if(!B&&!(G==="count"||G==="boolean"&&!_)){if(M.length===0)return Z(`No data provided for '${F}'`);B||=M.pop()||""}if(G==="boolean"){let S=!D;if(_)if(D)return Z(`The parameter '${F}' can't be negated AND assigned at the same time`);else if(J.allowBoolString&&W.boolStringTrue.test(B))S=!0;else if(J.allowBoolString&&W.boolstringfalse.test(B))S=!1;else return Z(`The parameter '${F}' is a boolean (a flag) and can't be assigned a value like '${$}'`);C[R]=S,A.push(R);continue}if(D)return Z(`Can't negate '${F}' as the type is set to '${G}'`);if(G==="count"){C[R]++,A.push(R);continue}let w=0;switch(G){case"string":C[R]=B;continue;case"array":case"string[]":C[R].push(B);continue;case"number":case"float":case"number[]":case"float[]":w=+B;break;case"int":case"int[]":if(w=+B|0,w+""!==B&&!W.isHexPrefix.test(B))w=NaN;break;case"hex":case"hex[]":if(W.isHex.test(B))w=parseInt(B,16);else w=NaN;break;default:return x(`Parameter '${F}' configuration has an invalid type: '${G}'`)}if(isNaN(w)||!isFinite(w))return Z(`The value of '${F}' is not a valid ${G}: '${B}'`);if(Array.isArray(C[R]))C[R].push(w);else C[R]=w}for(let[$,I]of Object.entries(Q)){if(!n.call(X,$))continue;if(C[$]===void 0||!C[$].length)C[$]=I}for(let $ of q){const I=X[$];let P="";if(typeof I.valid==="function"){if(I.valid(C[$]))continue}else{if(!Array.isArray(I.valid))return x(`The "valid" property of '${$}' parameter must be a function or an array of valid values`);if(I.valid.includes(C[$]))continue;P=". Please use one of the following values: "+JSON.stringify(I.valid)}return Z(`The value provided for the parameter '${$}' is not valid: '${C[$]}'`+P)}for(let $ of H)if(C[$]===void 0)return Z(`The parameter '${$}' is mandatory.${X[$]?.alias?.length?` You can also use an alias: ${X[$].alias.join(", ")}`:""}`);for(let $ of i){if(!A.includes($))continue;const I=X[$]?.conflict?.find((P)=>A.includes(P));if(I)return Z(`The parameter '${$}' conflicts with '${I}'`)}if(J.outputAlias){const $={};for(let I in C){if(I==="_"||!Object.prototype.hasOwnProperty.call(C,I))continue;const P=C[I];$[I]=P;const T=X[I].alias;if(!T)continue;for(let D of T)$[D]=P}Object.assign(C,$)}if(J.outputInflate)return c(C);return C}function o(M,z){return V(b(M,z))}function b(M,z={}){const H=[],q=[],Q=[],C={},J={_:[]},X={error:(Z)=>{throw Z},panic:(Z)=>{throw Z},autoCamelKebabCase:!0,allowUnknown:!0,allowNegatingFlags:!0,allowKeyNumValues:!0,allowAssign:!0,allowBoolString:!0,outputAlias:!1,outputInflate:!1,intro:"",outro:"",...z.strict?k:{},...z},{panic:i}=X,A=Object.prototype.hasOwnProperty;for(let Z in M){if(!A.call(M,Z))continue;let x=M[Z];if(x===null||typeof x!=="object"||Array.isArray(x))x={default:x,type:N(x)};if(x.key=Z,x.conflict){if(x.conflict=Array.isArray(x.conflict)?x.conflict:String(x.conflict).split(W.listDeviders),x.conflict.length)Q.push(Z)}if(x.valid!==void 0){if(q.push(Z),x.default===void 0&&Array.isArray(x.valid)){if(!x.valid.length)return i(`Empty array found for valid values of '${Z}'`);if(x.type===void 0)x.type=N(x.valid[0]);x.default=x.valid[0]}}if(x.type=x.type?.toLowerCase()||N(x.default)||"boolean",x.default!==void 0)if(Array.isArray(x.default))C[Z]=x.default;else if(x.type=="count")return i(`Default parameter '${x.default}' is not allowed for '${Z}' because of its type '${x.type}'`);else J[Z]=x.default;if(x.type=="count")J[Z]=0;if(!W.validTypes.test(x.type))i(`Invalid type '${x.type}' for parameter '${Z}'`);if(W.isArrayType.test(x.type))J[Z]=[];if(x.mandatory)H.push(Z);if(x.alias)x.alias=Array.isArray(x.alias)?x.alias:String(x.alias).split(W.listDeviders).filter(Boolean);if(X.autoCamelKebabCase&&W.isCamel.test(Z)){const U=Z.replace(W.camel2kebab,"$1-$2").toLowerCase();if(U!==Z)x.alias=x.alias?[U,...x.alias]:[U]}if(x.alias){for(let U of x.alias)if(M[U]===void 0)M[U]={key:Z}}M[Z]=x}return{output:J,validate:q,conflict:Q,mandatory:H,complexDefault:C,conf:X,params:M}}function N(M){if(M===null||M===void 0)return;const z=typeof M,H=Array.isArray(M);switch(z){case"boolean":case"number":return z+(H?"[]":"");default:return"string"+(H?"[]":"")}}function V(M,z=1){let H="{\n";for(let[q,Q]of Object.entries(M)){if(H+=`${" ".repeat(z)}"${q}": `,typeof Q==="function"||Q instanceof RegExp)H+=Q.toString();else if(typeof Q==="object"&&!Array.isArray(Q))H+=V(Q,z+1);else H+=JSON.stringify(Q);H+=",\n"}return H+=" ".repeat(z-1)+"}",H}var k={allowUnknown:!1,allowNegatingFlags:!1,allowKeyNumValues:!1,allowAssign:!1,allowBoolString:!1};function O(M={width:100,format:"cli",preIntro:"",showIntro:!0,showOutro:!0,postOutro:""},z={},H){debugger;let q={};if(M.showIntro&&z.intro)q.intro=z.intro;if(q.params=JSON.parse(JSON.stringify(H)),M.showOutro&&z.outro)q.outro=z.outro;if(M.format==="json")return q;if(M.format==="cli")return JSON.stringify(q,null,2);if(M.format==="markdown")return"md not supported yet"}function E(M,z,H,q){if(!H&&!q)return M(z);if(H)Y={...H};if(q)g={...q};return M(z,b(H||{},q||{}))}function l(M={},z={},H){return O({preIntro:"",showIntro:!0,showOutro:!0,postOutro:"",format:"cli",width:100,...M},{...g,...z},{...Y,...H})}var Y,g;function y(M,z,H){return E(d,M,z,H)}export{o as precompileConfig,y as default,b as compileConfig,l as argInfo,d as argEngine}; |
#!/usr/bin/env node | ||
// @bun | ||
var D={kebab:/([a-z0-9]|(?=[A-Z]))([A-Z])/g,camel:/-+([^-])|-+$/g};function R(C,I){I=I||{output:{_:[]},validate:[],mandatory:[],complexDefault:{},conf:{error:(M)=>{throw M},panic:(M)=>{throw M},allowUnknown:!0,autoCamelKebabCase:!0,allowNegatingFlags:!0,allowKeyNumValues:!0,allowAssign:!0},params:{}};const{mandatory:w,validate:U,output:x,conf:Z,params:J,complexDefault:z}=I;C.reverse();while(C.length){let M=""+C.pop();if(M.charCodeAt(0)!==45){x._.push(M);continue}let B=!1,$="",q="",Q=!1;if(M.charCodeAt(1)===45)B=!0,$=M.slice(2);else $=M.slice(1);if(B&&!$){x._=x._.concat(C.reverse());break}if(!$){x._.push(M);continue}if(Z.allowAssign){let H=$.indexOf("=");if(-1<H)Q=!0,q=$.slice(H+1),$=$.slice(0,H)}if(!B&&$.length!==1){if(Q)return Z.error(`Unsupported format: '${M}'`);const H=$.split("").map((P)=>"-"+P);C=C.concat(H.reverse());continue}if(!J[$]){if(!Z.allowUnknown)return Z.error(`'${$}' not allowed`);if(Z.autoCamelKebabCase)$=$.replace(D.camel,function(H,P){return P.toUpperCase()});if(Q){if(!q){if(C.length===0)return Z.error(`No data provided for '${$}'`);q=C.pop()||""}x[$]=+q==q?+q:q}else x[$]=!0;continue}if(J[$].type==="boolean"){if(Q)return Z.error(`'${$}' is boolean, so can't assign: '${M}'`);x[J[$].key]=!0;continue}if(J[$].type==="count"){if(Q)return Z.error(`'${$}' is count, so can't assign: '${M}'`);x[$]++;continue}if(!q){if(C.length===0)return Z.error(`No data for '${$}'`);q=C.pop()||""}let F=0;switch(J[$].type){case"string":x[J[$].key]=q;continue;case"array":case"string[]":x[J[$].key].push(q);continue;case"number":case"float":case"number[]":case"float[]":F=+q;break;case"int":case"int[]":if(F=+q|0,""+F!==q)F=NaN;break;case"hex":case"hex[]":F=parseInt(q,16);break;default:return Z.panic(`'${$}' got invalid type: '${J[$].type}'`)}if(isNaN(F)||!isFinite(F))return Z.error(`'${$}' not a valid ${J[$].type}: '${q}'`);if(Array.isArray(x[J[$].key]))x[J[$].key].push(F);else x[J[$].key]=F}for(let M of U){let B="";if(typeof J[M].valid==="function"){if(J[M].valid(x[M]))continue}else{if(!Array.isArray(J[M].valid))return Z.panic(`"valid" property of '${M}' must be function or array`);if(J[M].valid.includes(x[M]))continue;B=". Valid values: "+JSON.stringify(J[M].valid)}return Z.error(`Invalid value for '${M}': '${x[M]}'`+B)}for(let M of w)if(x[M]===void 0)return Z.error(`'${M.length>1?"--":"-"}${M}' is mandatory`+(J[M].alias.length?`. Or use an alias: ${J[M].alias.map((B)=>(B.length>1?"--":"-")+B).join(", ")}`:""));for(let M in z){if(!J.hasOwnProperty(M))continue;if(x[M]===void 0||!x[M].length)x[M]=z[M]}return x}var W={kebab:/([a-z0-9]|(?=[A-Z]))([A-Z])/g,camel:/-+([^-])|-+$/g,arrayType:/(^array|\[\])$/,validTypes:/^((array|count)|(boolean|string|number|float|int|hex)(\[\])?)$/,paramTokens:/^(?<STOP>--)$|^-(?<LONG>-+)?(?<NO>no-)?(?<KEY>[^=\s]+?)(?<KEYNUM>[\d]*)(?<ASSIGN>=(?<VAL>.*))?$/};function G(C,I){return _(X(C,I))}function X(C,I={}){const w=[],U=[];let x={},Z={_:[]};const J={...S,...I.strict?A:{},...I};for(let z in C){if(!C.hasOwnProperty(z))continue;let M=C[z];if(M===null||typeof M!=="object"||Array.isArray(M))M={default:M,type:N(M)};if(M.key=z,M.alias=M.alias||[],M.valid!==void 0){if(U.push(z),M.default===void 0&&Array.isArray(M.valid)){if(!M.valid.length)return J.panic(`Empty array found for valid values of '${z}'`);if(M.type===void 0)M.type=N(M.valid[0]);M.default=M.valid[0]}}if(M.type=M.type?.toLowerCase()||N(M.default)||"boolean",M.default!==void 0)if(Array.isArray(M.default))x[z]=M.default;else if(M.type=="count")return J.error(`Default parameters like '${M.default}' are not allowed on parameters like '${z}' with the type '${M.type}'`);else Z[z]=M.default;if(M.type=="count")Z[z]=0;if(!M.type.match(W.validTypes))J.error(`Invalid type '${M.type}' for parameter '${z}'`);if(M.type.match(W.arrayType))Z[z]=[];if(M.mandatory)w.push(z);if(J.autoCamelKebabCase){let B=z.replace(W.kebab,"$1-$2").toLowerCase();if(B!==z)M.alias=[B].concat(M.alias||[])}if(M.alias!==void 0&&!Array.isArray(M.alias))M.alias=[M.alias];if(M.alias)M.alias.forEach((B)=>{if(C[B]===void 0)C[B]={type:C[z].type,key:z}})}return{output:Z,validate:U,mandatory:w,complexDefault:x,conf:J,params:C}}function N(C){if(C===null||C===void 0)return;let I=typeof C,w=Array.isArray(C);if(w&&C.length>0)I=typeof C[0];switch(I){case"boolean":case"number":return I+(w?"[]":"");default:return"string"+(w?"[]":"")}}function _(C,I=1){let w="{\n";for(let[U,x]of Object.entries(C)){if(w+=`${" ".repeat(I)}"${U}": `,typeof x==="function")w+=x.toString();else if(typeof x==="object"&&!Array.isArray(x))w+=_(x,I+1);else w+=JSON.stringify(x);w+=",\n"}return w+=" ".repeat(I-1)+"}",w}var S={error:(C)=>{throw C},panic:(C)=>{throw C},allowUnknown:!0,autoCamelKebabCase:!0,allowNegatingFlags:!0,allowKeyNumValues:!0,allowAssign:!0},A={allowUnknown:!1,autoCamelKebabCase:!1,allowNegatingFlags:!1,allowKeyNumValues:!1};function T(C={width:100,format:"cli",preIntro:"",showIntro:!0,showOutro:!0,postOutro:""},I={},w){debugger;let U={};if(C.showIntro&&I.intro)U.intro=I.intro;if(U.params=JSON.parse(JSON.stringify(w)),C.showOutro&&I.outro)U.outro=I.outro;if(C.format==="json")return U;if(C.format==="cli")return JSON.stringify(U,null,2);if(C.format==="markdown")return"md not supported yet"}function O(C,I,w,U){if(!w&&!U)return C(I);if(w)h=JSON.stringify(w);if(U)i={...U};return C(I,X(w||{},U||{}))}function b(C={},I={},w){return T({preIntro:"",showIntro:!0,showOutro:!0,postOutro:"",format:"cli",width:100,...C},{...i,...I},w||JSON.parse(h))}var h,i;function d(C,I,w){return O(R,C,I,w)}export{G as precompileConfig,d as default,X as compileConfig,b as argInfo}; | ||
var J={isCamel:/[a-z0-9][A-Z]/,isKebab:/\w-\w+/,camel2kebab:/([a-z0-9]|(?=[A-Z]))([A-Z])/g,kebab2camel:/-+([^-])|-+$/g,isArrayType:/(^array|\[\])$/,validTypes:/^((array|count|json|split)|(boolean|string|number|float|int|hex)(\[\])?)$/,paramTokens:/^(?<STOP>--)$|^-(?<LONG>-+)?(?<NO>no-)?(?<KEY>[^=\s]+?)(?<KEYNUM>[\d]*)(?<ASSIGN>=(?<VAL>.*))?$/,listDeviders:/[,\s]+-?-?|^--?/,isHex:/^(0x)?[A-Fa-f0-9]+$/,isHexPrefix:/^(0x)[A-Fa-f0-9]+$/,truncate:/^(.{40}).*$/,boolStringTrue:/^(true|yes|on)$/i,boolstringfalse:/^(false|no|off)$/i};function T(x,w){w=w||{output:{_:[]},validate:[],mandatory:[],conflict:[],complexDefault:{},conf:{error:(C)=>{throw C},panic:(C)=>{throw C},allowUnknown:!0,autoCamelKebabCase:!0,allowNegatingFlags:!0,allowKeyNumValues:!0,allowAssign:!0},params:{}};const{mandatory:z,validate:F,output:i,conf:H,params:Z,complexDefault:Q}=w;x.reverse();while(x.length){let C=""+x.pop();if(C.charCodeAt(0)!==45){i._.push(C);continue}let q=!1,$="",M="",I=!1;if(C.charCodeAt(1)===45)q=!0,$=C.slice(2);else $=C.slice(1);if(q&&!$){i._=i._.concat(x.reverse());break}if(!$){i._.push(C);continue}if(H.allowAssign){const W=$.indexOf("=");if(-1<W)I=!0,M=$.slice(W+1),$=$.slice(0,W)}if(!q&&$.length!==1){if(I)return H.error(`Unsupported format: '${C}'`);const W=$.split("").map((A)=>"-"+A);x=x.concat(W.reverse());continue}if(!Z[$]){if(!H.allowUnknown)return H.error(`Unknown parameter '${$}' not allowed`);if(H.autoCamelKebabCase)$=$.replace(J.kebab2camel,function(W,A){return A.toUpperCase()});if(I){if(!M){if(x.length===0)return H.error(`No data provided for '${$}'`);M=x.pop()||""}i[$]=+M+""===M?+M:M}else i[$]=!0;continue}if(Z[Z[$].key].type==="boolean"){if(I)return H.error(`'${$}' is boolean, so can't assign: '${C}'`);i[Z[$].key]=!0;continue}if(Z[Z[$].key].type==="count"){if(I)return H.error(`'${$}' counting, so can't assign: '${C}'`);i[$]++;continue}if(!M){if(x.length===0)return H.error(`No data for '${$}'`);M=x.pop()||""}let B=0;switch(Z[Z[$].key].type){case"string":i[Z[$].key]=M;continue;case"array":case"string[]":i[Z[$].key].push(M);continue;case"number":case"float":case"number[]":case"float[]":B=+M;break;case"int":case"int[]":if(B=+M|0,B+""!==M)B=NaN;break;case"hex":case"hex[]":if(J.isHex.test(M))B=parseInt(M,16);else B=NaN;break;default:return H.panic(`'${$}' got invalid type: '${Z[Z[$].key].type}'`)}if(isNaN(B)||!isFinite(B))return H.error(`'${$}' value is not a valid ${Z[Z[$].key].type}: '${M}'`);if(Array.isArray(i[Z[$].key]))i[Z[$].key].push(B);else i[Z[$].key]=B}for(let C of F){let q="";if(typeof Z[C].valid==="function"){if(Z[C].valid(i[C]))continue}else{if(!Array.isArray(Z[C].valid))return H.panic(`"valid" property of '${C}' must be function or array`);if(Z[C].valid.includes(i[C]))continue;q=". Valid values: "+JSON.stringify(Z[C].valid)}return H.error(`Invalid value for '${C}': '${i[C]}'`+q)}for(let C of z)if(i[C]===void 0)return H.error(`'${C.length>1?"--":"-"}${C}' is mandatory`+(Z[C]?.alias?.length?`. Or use an alias: ${Z[C].alias.map((q)=>(q.length>1?"--":"-")+q).join(", ")}`:""));for(let C in Q){if(!Z.hasOwnProperty(C))continue;if(i[C]===void 0||!i[C].length)i[C]=Q[C]}return i}function h(x,w){return P(X(x,w))}function X(x,w={}){const z=[],F=[],i=[],H={},Z={_:[]},Q={error:($)=>{throw $},panic:($)=>{throw $},autoCamelKebabCase:!0,allowUnknown:!0,allowNegatingFlags:!0,allowKeyNumValues:!0,allowAssign:!0,allowBoolString:!0,outputAlias:!1,outputInflate:!1,intro:"",outro:"",...w.strict?S:{},...w},{panic:C}=Q,q=Object.prototype.hasOwnProperty;for(let $ in x){if(!q.call(x,$))continue;let M=x[$];if(M===null||typeof M!=="object"||Array.isArray(M))M={default:M,type:U(M)};if(M.key=$,M.conflict){if(M.conflict=Array.isArray(M.conflict)?M.conflict:String(M.conflict).split(J.listDeviders),M.conflict.length)i.push($)}if(M.valid!==void 0){if(F.push($),M.default===void 0&&Array.isArray(M.valid)){if(!M.valid.length)return C(`Empty array found for valid values of '${$}'`);if(M.type===void 0)M.type=U(M.valid[0]);M.default=M.valid[0]}}if(M.type=M.type?.toLowerCase()||U(M.default)||"boolean",M.default!==void 0)if(Array.isArray(M.default))H[$]=M.default;else if(M.type=="count")return C(`Default parameter '${M.default}' is not allowed for '${$}' because of its type '${M.type}'`);else Z[$]=M.default;if(M.type=="count")Z[$]=0;if(!J.validTypes.test(M.type))C(`Invalid type '${M.type}' for parameter '${$}'`);if(J.isArrayType.test(M.type))Z[$]=[];if(M.mandatory)z.push($);if(M.alias)M.alias=Array.isArray(M.alias)?M.alias:String(M.alias).split(J.listDeviders).filter(Boolean);if(Q.autoCamelKebabCase&&J.isCamel.test($)){const I=$.replace(J.camel2kebab,"$1-$2").toLowerCase();if(I!==$)M.alias=M.alias?[I,...M.alias]:[I]}if(M.alias){for(let I of M.alias)if(x[I]===void 0)x[I]={key:$}}x[$]=M}return{output:Z,validate:F,conflict:i,mandatory:z,complexDefault:H,conf:Q,params:x}}function U(x){if(x===null||x===void 0)return;const w=typeof x,z=Array.isArray(x);switch(w){case"boolean":case"number":return w+(z?"[]":"");default:return"string"+(z?"[]":"")}}function P(x,w=1){let z="{\n";for(let[F,i]of Object.entries(x)){if(z+=`${" ".repeat(w)}"${F}": `,typeof i==="function"||i instanceof RegExp)z+=i.toString();else if(typeof i==="object"&&!Array.isArray(i))z+=P(i,w+1);else z+=JSON.stringify(i);z+=",\n"}return z+=" ".repeat(w-1)+"}",z}var S={allowUnknown:!1,allowNegatingFlags:!1,allowKeyNumValues:!1,allowAssign:!1,allowBoolString:!1};function D(x={width:100,format:"cli",preIntro:"",showIntro:!0,showOutro:!0,postOutro:""},w={},z){debugger;let F={};if(x.showIntro&&w.intro)F.intro=w.intro;if(F.params=JSON.parse(JSON.stringify(z)),x.showOutro&&w.outro)F.outro=w.outro;if(x.format==="json")return F;if(x.format==="cli")return JSON.stringify(F,null,2);if(x.format==="markdown")return"md not supported yet"}function b(x,w,z,F){if(!z&&!F)return x(w);if(z)R={...z};if(F)N={...F};return x(w,X(z||{},F||{}))}function G(x={},w={},z){return D({preIntro:"",showIntro:!0,showOutro:!0,postOutro:"",format:"cli",width:100,...x},{...N,...w},{...R,...z})}var R,N;function O(x,w,z){return b(T,x,w,z)}export{h as precompileConfig,O as default,X as compileConfig,G as argInfo}; |
{ | ||
"name": "argmate", | ||
"version": "0.6.0", | ||
"version": "0.8.2", | ||
"author": "Mathias Wulff", | ||
"description": "CLI parameter parsing. Zero dependencies. Fast. Convenient features for better DX", | ||
"description": "Fast CLI parameter parsing. Zero dependencies. Good DX. Pre-compile for turbo speed.", | ||
"license": "CC-BY-SA-4.0", | ||
@@ -11,2 +11,6 @@ "repository": { | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/mathiasrw/argmate/issues" | ||
}, | ||
"homepage": "https://github.com/mathiasrw/argmate#readme", | ||
"keywords": [ | ||
@@ -27,5 +31,10 @@ "CLI", | ||
], | ||
"main": "dist/argMate.mjs", | ||
"module": "dist/argMate.js", | ||
"type": "module", | ||
"types": "src/types.d.ts", | ||
"main": "dist/argMate.js", | ||
"exports": { | ||
"import": "./dist/argMate.js", | ||
"macro": "./dist/argMate.macro.js" | ||
}, | ||
"scripts": { | ||
@@ -45,3 +54,4 @@ "prebuild": "rm -fr dist/", | ||
"prerelease": "yarn && yarn format && yarn test", | ||
"postrelease": "npm publish && git push && git push --tags && echo \"Successfully released version $npm_package_version\"" | ||
"postrelease": "npm publish && git push && git push --tags && echo \"Successfully released version $npm_package_version\"", | ||
"prepare": "husky" | ||
}, | ||
@@ -52,11 +62,6 @@ "dependencies": {}, | ||
"columnify": "^1.6.0", | ||
"husky": "^8.0.3", | ||
"husky": "^9.1.4", | ||
"prettier": "3.3.3", | ||
"rexreplace": "^7.1.3" | ||
}, | ||
"peerDependencies": {}, | ||
"bugs": { | ||
"url": "https://github.com/mathiasrw/argmate/issues" | ||
}, | ||
"homepage": "https://github.com/mathiasrw/argmate#readme" | ||
} | ||
} |
204
README.md
@@ -14,3 +14,3 @@ | ||
> _Your go-to companion for lightning-fast CLI parameter parsing, enhanced with convenient features to make your development experience much smoother._ | ||
> _Your go-to mate for CLI parameter parsing. Friendly, faster than a cut snake, and with added sprinkles of convenience to make your development experience a breeze. Only 6KB and zero dependencies - cheers!_ | ||
@@ -25,3 +25,3 @@ While developing tools like [AlaSQL](https://www.npmjs.com/package/alasql) and [RexReplace](https://www.npmjs.com/package/rexreplace), I've often been torn between two types of CLI parsers. On one hand, there are feature-rich options like [yargs](https://www.npmjs.com/package/yargs) and [commander](https://www.npmjs.com/package/commander). Despite their heavy startup time, these parsers provide useful features like easy defaults, smooth validation, and well-structured CLI help text output. On the other hand, simpler alternatives like [nopt](https://www.npmjs.com/package/nopt) and [mri](https://www.npmjs.com/package/mri) excel in performance but lack in development experience. After uncovering yet another performance hit from using a heavyweight parser, I decided to solve this issue once and for all. | ||
minimist 706,265 ops/sec ±1.05% (94 runs sampled) 13x | ||
yargs-parser 67,417 ops/sec ±0.39% (97 runs sampled) 135x | ||
yargs-parser 67,417 ops/sec ±0.39% (97 runs sampled) 135x | ||
``` | ||
@@ -49,6 +49,6 @@ | ||
ArgMate follows traditional CLI notations similar to yargs and mri. Here are some simple examples: | ||
ArgMate follows traditional CLI notations - similar to yargs and mri. Here are some simple examples: | ||
```js | ||
import ArgMate from 'ArgMate'; | ||
import argMate from 'argmate'; | ||
@@ -59,28 +59,104 @@ let argv; | ||
// Non-parameters are stored in the `_` property of the output | ||
argv = ArgMate(['--foo', 'bar']); | ||
// {_: ['bar'], foo: true} | ||
argv = argMate(['--foo', 'bar', '-i']); | ||
// {_: ['bar'], foo: true, i: true} | ||
// Use the `=` notation for assignment, with or without seperation to the value | ||
// Type is inferred from the value (string or number) | ||
argv = ArgMate(['--foo=', 'bar']); | ||
// {_: [], foo: 'bar'} | ||
argv = ArgMate(['-i=123']); | ||
// {_: [], i: 123} | ||
argv = argMate(['--foo=', 'bar', '-i=123']); | ||
// {_: [], foo: 'bar', i: 123} | ||
// Setting a default value makes the parser treat it as a parameter that must be assigned | ||
// The type is guessed based on the default value | ||
argv = ArgMate(['--foo', 'bar2'], { foo: 'bar' }); | ||
// {_: [], foo: 'bar2'} | ||
argv = argMate(['--foo', 'bar2'], { foo: 'bar', i: 42 }); | ||
// {_: [], foo: 'bar2', i: 42} | ||
// Specify the type explicitly to avoid the guessing game and improving performance | ||
argv = ArgMate(['--foo', 'bar'], { foo: { type: 'string' } }); | ||
// {_: [], foo: 'bar'} | ||
// Example of parsing actual command-line arguments | ||
// Running `node index.js --foo=bar -X .md` | ||
// Assuming the following code is in index.js: | ||
argv = ArgMate(process.argv.slice(2)); | ||
// Example running params from CLI `node index.js --foo=bar -X .md` | ||
argv = argMate(process.argv.slice(2)); | ||
// { _: ['.md'], foo: "bar", X: true } | ||
``` | ||
### Default values and limiting input to known parameters | ||
You can provide default values and enforce that no unknown parameters are allowed: | ||
```js | ||
import argMate from 'argmate'; | ||
const args = process.argv.slice(2); | ||
// Define parameter types and default values | ||
const params = { | ||
foo: 10, // --foo is expected to be an integer, default: 10 | ||
bar: false // --bar is expected to be a boolean, default: false | ||
}; | ||
const config = { | ||
allowUnknown: false // Only allow specified parameters (--foo and --bar) | ||
}; | ||
const argv = argMate(args, params, config); | ||
``` | ||
Same example but a bit shorter | ||
```js | ||
import argMate from 'argmate'; | ||
const argv = argMate(process.argv.slice(2), | ||
{ | ||
foo: 10, | ||
bar: false | ||
}, { | ||
allowUnknown: false | ||
}); | ||
``` | ||
### Real world example | ||
Here's a more comprehensive example demonstrating additional features: | ||
```javascript | ||
import argMate, { argInfo } from 'argmate'; | ||
const args = process.argv.slice(2); | ||
const params = { | ||
start: { | ||
default: 0, | ||
alias: ['s'] | ||
}, | ||
steps: { | ||
type: 'number', | ||
mandatory: true, | ||
alias: ['l', 'loops'], | ||
valid: v => v > 0 // Validate the input | ||
}, | ||
help: { | ||
alias: ['h'] | ||
} | ||
}; | ||
const config = { | ||
allowUnknown: false, | ||
error: msg => { | ||
console.error('Error:', msg); | ||
process.exit(1); | ||
} | ||
}; | ||
const argv = argMate(args, params, config); | ||
// Display help and exit if the help flag is set | ||
if (argv.help) { | ||
console.log(argInfo()); | ||
process.exit(0); | ||
} | ||
// Use the parsed arguments | ||
for (let i = argv.start; i < argv.start + argv.steps; i++) { | ||
console.log(i); | ||
} | ||
``` | ||
### Enforcing parameter types and limiting allowed values | ||
@@ -91,3 +167,3 @@ | ||
```js | ||
import ArgMate from 'ArgMate'; | ||
import argMate from 'argmate'; | ||
@@ -106,3 +182,3 @@ const args = process.argv.slice(2); | ||
const argv = ArgMate(args, params, config); | ||
const argv = argMate(args, params, config); | ||
``` | ||
@@ -113,3 +189,3 @@ | ||
```js | ||
import ArgMate from 'ArgMate'; | ||
import argMate from 'argmate'; | ||
@@ -130,3 +206,3 @@ const argv = ArgMate(process.argv.slice(2), | ||
```javascript | ||
import ArgMate, { argInfo } from 'ArgMate'; | ||
import argMate, { argInfo } from 'argmate'; | ||
@@ -159,3 +235,3 @@ const args = process.argv.slice(2); | ||
const argv = ArgMate(args, params, config); | ||
const argv = argMate(args, params, config); | ||
@@ -179,13 +255,16 @@ // Display help and exit if the help flag is set | ||
the second parameter for argMate is a a configuration object defining the parameters you expect and their propeties | ||
```js | ||
const params = { | ||
// The object returned from argMate will only have propety names provided in this object (foo in this example) | ||
// The object returned from argMate will only have propety names provided in this object (foo in this example) But see outputAlias config below | ||
foo: { | ||
type: 'string', // boolean | string/number | float | int | hex | array7string[] | number[]/float[] | int[] | hex[]. Optional. Defaults to boolean. | ||
type: 'string', // boolean | string | number | float | int | hex | array | string[] | number[] | float[] | int[] | hex[]. Optional. Defaults to boolean. | ||
default: 'val', // The default value for the parameter. If the type is not specified, the type will be determined from this field. Optional. | ||
mandatory: true, // Calls config.error if the value is not provided. No effect if used in combination with "default". | ||
alias: [], // Other values to be treated as this parameter. Also accepts a string with a single value. | ||
// If you camelCase the property name, it will treat kebab-case of the word as an alias (so fooBar will automaticly have foo-bar as alias) | ||
conflict: [], // Other keys to be treated as conflicting. Also accepts a single string. | ||
valid: () => {}, // Function to check if the value is valid (will call config.error if not valid) | ||
// If you camelCase the property name, it will treat kebab-case of the word as an alias (so fooBar will automaticly have foo-bar as alias). Can also be a comma seperated string | ||
conflict: [], // Other keys to be treated as conflicting. Also accepts a single string. Can also be a comma seperated string. | ||
valid: () => {}|[], // Function to check if the value is valid (will call config.error if not valid). Can also be an array of valid values (case sensitive). If you want case insensitive make a function with a regex valid:v=>/foo|bar/i.test(v) will accept both Foo and BAR. | ||
transform: // function that will transform the value. Example: trim values by using transform:v=>v.trim(); | ||
describe: 'Description here', // A description of the parameter. Will be used for the help text (see below). | ||
@@ -199,12 +278,21 @@ }, | ||
```js | ||
// THe default values of all possible porperties of the config object | ||
const config = { | ||
error: msg => {}, // Function to be called when a problem has been detected in the parsing. Defaults to throwing an informative exception (should probably be changed to something more friendly) | ||
panic: msg => {}, // Function to be called when there is a panic in the engine. Defaults to throwing an informative exception. (Mostly used for development and should probably not be changed.) | ||
allowUnknown: true, // Specify if parameters not described in "params" are allowed. If violated, config.error will be called. | ||
no: true, // Specify if boolean flags with "no-" as the first part will be treated as a negation. If so, --no-foo will result in {'_':[], 'foo': false}. Works well with default: true; | ||
intro: 'Intro Text', // Text to add above the information about each parameter in the help text. | ||
outro: 'Outro Text', // Text to add below the information about each parameter in the help text. | ||
error: msg => {throw msg}, // This function will be called when there is a problem with input data (foreample if you try to assign a value to a parameter you have defined as boolean). Defaults to throwing the error messages. | ||
panic: msg => {throw msg}, // This function will be called when there is a problem with the configuration of the parameters. YOu should only encounter these during development. Defaults to throwing the error messages. | ||
allowUnknown: true, // Allows you to provie parameters not defined in the config objecet | ||
allowNegatingFlags: true, // Will let you prepend boolean parameters with "no-" provide the value as false. If so, --no-foo will result in {'_':[], 'foo': false}. | ||
allowKeyNumValues: true // Allows you to use ultra short notations like '-r255' to set -r = 255 | ||
allowAssign: true // Allow the use of = after a parameter to indicate that the next value should to be assigned as a value. Works both for the value as part of the same parameter (-p=2) or the value in the next argument (-p= 2) | ||
allowBoolString: true // Let you assign boolean parameters from strings like true|yes|on|false|no|off | ||
strict: false // Will set all allow* propeties to false. Individual paramters can overwrite this by also being provided. | ||
autoCamelKebabCase: true // Let you treat input like 'foo-bar' as 'fooBar' | ||
outputAlias: false // If set to true the returned data object will contain one property per parameter plus one for each alias. (Normally --foo with -f as alias will only come as {foo:...}. If this option is set to true it will output {foo:..., f: ...}) | ||
outputInflate:false // Will expand keys with dots in them into nested objects (--a.b=22 will result in {a:{b:22}}) | ||
intro: 'Intro Text', // Text that goes above the information about each parameter in the help text. | ||
outro: 'Outro Text', // Text that goes below the information about each parameter in the help text. | ||
}; | ||
``` | ||
### Help Text | ||
@@ -240,5 +328,49 @@ | ||
## Notes | ||
- Demonstrate how to use macros to pregenerate engineConfig to make things even faster. manual or via https://bun.sh/docs/bundler/macros - https://bun.sh/docs/bundler/macros#export-condition-macro | ||
- If you provide array kind of types (like string[]) you can trust the value is alwas an array. If no values provided the array is emptly. | ||
- If you dont specify, you get some help, but not consistency. If you specify you know exactly what you get. | ||
- Defaults to consider unknown params as flags. IF you want unknown things to be assigned you add a = behind the flag. | ||
- undefined parameters will default to being a boolean. If you want to assign values you need to A) define a type (or a default value) in the config obj, or B) add "=" to the parameter in the inputs | ||
- If you provide the same alias to two parameters, the alias will stay with the first parameter you define. | ||
- for defined params you need to provide int, number or float as type for it to be a number in the resulting data object | ||
expect( | ||
argMate(['--host', 'localhost', '--port', '555'], { | ||
host: '', | ||
port: 0, | ||
}) | ||
).toEqual({ | ||
host: 'localhost', | ||
port: 555, | ||
_: [], | ||
}); | ||
- but if you have not defined the param and provide is as assigned then numbers will be identified and provided as value | ||
expect(argMate(['--host=', 'localhost', '--port=', '555'], {})).toEqual({ | ||
host: 'localhost', | ||
port: 555, | ||
_: [], | ||
}); | ||
expect(argMate(['--host=localhost', '--port=55.5'], {})).toEqual({ | ||
host: 'localhost', | ||
port: 55.5, | ||
_: [], | ||
}); | ||
### lite quirks | ||
- Lite will not convert your 0x prepended hexvalues to int | ||
### ideas | ||
- ? Flag to outoconvert _ values to int when convertable? (like deno) | ||
- We do not support autoconverting magic strings like "true" and "false" | ||
- maybe we should have an option to convert magic strings... | ||
- ? input type json thet is parsed and added as data? | ||
- ? Commaseperated list to array? | ||
--- | ||
@@ -245,0 +377,0 @@ |
// @ts-ignore | ||
import {ArgMateParams, ArgMateConfig, ArgProcessObj} from './types.js'; | ||
// @ts-ignore | ||
//import use from './strip.macro.js' with { type: 'macro' }; | ||
interface ArgMateConfigMandatory extends ArgMateConfig { | ||
@@ -40,2 +44,3 @@ error: (msg: string) => void; | ||
mandatory: [], | ||
conflict: [], | ||
complexDefault: {}, | ||
@@ -54,2 +59,3 @@ conf: { | ||
allowAssign: true, | ||
outputAlias: false, | ||
}, | ||
@@ -59,6 +65,22 @@ params: {}, | ||
const {mandatory, validate, complexDefault, output, conf, params} = argProcessObj; | ||
const {mandatory, validate, complexDefault, output, conf, params, conflict} = argProcessObj; | ||
args.reverse(); // Reverse, pop, push, reverse 8.77 times faster than unshft, shift | ||
const inputLog: string[] = []; | ||
// Optimization: Cache frequently used methods and properties | ||
const { | ||
error, | ||
panic, | ||
allowUnknown, | ||
autoCamelKebabCase, | ||
allowNegatingFlags, | ||
allowKeyNumValues, | ||
allowAssign, | ||
} = conf; | ||
const outputPush = output['_'].push.bind(output['_']); | ||
const hasOwnProperty = Object.prototype.hasOwnProperty; | ||
// Reverse, pop, push, reverse 8.77 times faster than unshft, shift | ||
args.reverse(); | ||
while (args.length) { | ||
@@ -68,3 +90,3 @@ let arg: string = '' + args.pop(); | ||
if (arg.charCodeAt(0) !== 45) { | ||
output['_'].push(arg); | ||
outputPush(arg); | ||
continue; | ||
@@ -75,13 +97,5 @@ } | ||
if (undefined === token) return conf.panic('Grup not returned'); | ||
if (!token) return panic('Group not returned'); | ||
let {STOP, LONG, NO, KEY, KEYNUM, ASSIGN, VAL} = token?.groups || { | ||
STOP: '', | ||
LONG: '', | ||
NO: '', | ||
KEY: '', | ||
KEYNUM: '', | ||
ASSIGN: '', | ||
VAL: '', | ||
}; | ||
let {STOP, LONG, NO, KEY, KEYNUM, ASSIGN, VAL} = token.groups as {[key: string]: string}; | ||
@@ -93,4 +107,4 @@ if (STOP) { | ||
if (NO && !conf.allowNegatingFlags) { | ||
KEY = (NO ? NO : '') + KEY; | ||
if (NO && !allowNegatingFlags) { | ||
KEY = (NO || '') + KEY; | ||
NO = ''; | ||
@@ -100,9 +114,9 @@ } | ||
if (KEYNUM) { | ||
if (!conf.allowKeyNumValues || LONG || ASSIGN) { | ||
KEY = KEY + (KEYNUM ? KEYNUM : ''); | ||
if (!allowKeyNumValues || LONG || ASSIGN) { | ||
KEY += KEYNUM; | ||
KEYNUM = ''; | ||
} else { | ||
if (!LONG && 1 < KEY.length) { | ||
return conf.error( | ||
`Unsupported format: '${arg}'. Did you miss a dash before that?` | ||
return error( | ||
`Unsupported format: '${arg}'. Did you miss a dash at the beginning?` | ||
); | ||
@@ -116,3 +130,3 @@ } | ||
const multi = KEY.split('').map(v => (NO ? '-no-' : '-') + v); | ||
multi[multi.length - 1] = multi[multi.length - 1] + (ASSIGN ? ASSIGN : ''); | ||
multi[multi.length - 1] += ASSIGN || ''; | ||
args = args.concat(multi.reverse()); | ||
@@ -123,15 +137,12 @@ continue; | ||
if (!KEY) { | ||
output['_'].push(arg); | ||
outputPush(arg); | ||
continue; | ||
} | ||
// Key not defined as a parameter | ||
// Key is not a defined parameter | ||
if (!params[KEY]) { | ||
if (!conf.allowUnknown) | ||
return conf.error(`Unspecified parameters like '${KEY}' not allowed.`); | ||
if (!allowUnknown) return error(`Unknown parameter '${KEY}' not allowed.`); | ||
if (conf.autoCamelKebabCase) { | ||
KEY = KEY.replace(re.camel, function (match, letter) { | ||
return letter.toUpperCase(); | ||
}); | ||
if (autoCamelKebabCase && re.isKebab.test(KEY)) { | ||
KEY = KEY.replace(re.kebab2camel, (_, letter) => letter.toUpperCase()); | ||
} | ||
@@ -141,19 +152,44 @@ | ||
if (!VAL) { | ||
if (args.length === 0) return conf.error(`No data provided for '${KEY}'`); | ||
if (args.length === 0) return error(`No data provided for '${KEY}'`); | ||
VAL = args.pop() || ''; | ||
} | ||
// @ts-ignore | ||
output[KEY] = +VAL == VAL ? +VAL : VAL; | ||
output[KEY] = +VAL + '' === VAL ? +VAL : VAL; | ||
} else { | ||
output[KEY] = !NO; | ||
} | ||
inputLog.push(KEY); | ||
continue; | ||
} | ||
if ('boolean' === params[KEY].type) { | ||
if (ASSIGN) | ||
return conf.error( | ||
`You asked for the parameter '${KEY}' to be boolean but you are trying to assign a value: '${arg}'` | ||
); | ||
output[params[KEY].key] = !NO; | ||
const theKey = params[KEY].key; | ||
const theType = params[theKey].type; | ||
if (!VAL && !('count' === theType || ('boolean' === theType && !ASSIGN))) { | ||
if (0 === args.length) { | ||
return error(`No data provided for '${KEY}'`); | ||
} | ||
VAL ||= args.pop() || ''; | ||
} | ||
if ('boolean' === theType) { | ||
let result = !NO; | ||
if (ASSIGN) { | ||
if (NO) { | ||
return error( | ||
`The parameter '${KEY}' can't be negated AND assigned at the same time` | ||
); | ||
} else if (conf.allowBoolString && re.boolStringTrue.test(VAL)) { | ||
result = true; | ||
} else if (conf.allowBoolString && re.boolstringfalse.test(VAL)) { | ||
result = false; | ||
} else { | ||
return error( | ||
`The parameter '${KEY}' is a boolean (a flag) and can't be assigned a value like '${arg}'` | ||
); | ||
} | ||
} | ||
output[theKey] = result; | ||
inputLog.push(theKey); | ||
continue; | ||
@@ -163,19 +199,20 @@ } | ||
if (NO) { | ||
return conf.error(`Can't negate '${KEY}' as the type is set to '${params[KEY].type}'`); | ||
return error(`Can't negate '${KEY}' as the type is set to '${theType}'`); | ||
} | ||
if ('count' === params[KEY].type) { | ||
output[KEY]++; | ||
if ('count' === theType) { | ||
output[theKey]++; | ||
inputLog.push(theKey); | ||
continue; | ||
} | ||
if (0 === args.length) return conf.error(`No data provided for '${KEY}'`); | ||
//if(params[KEY].split) { | ||
//VAL = VAL.split(params[KEY].split).filter(Boolean); | ||
//} | ||
VAL ||= args.pop() || ''; | ||
let data = 0; | ||
let num = 0; | ||
switch (params[KEY].type) { | ||
switch (theType) { | ||
case 'string': | ||
output[params[KEY].key] = VAL; | ||
output[theKey] = VAL; | ||
continue; | ||
@@ -185,3 +222,3 @@ | ||
case 'string[]': | ||
output[params[KEY].key].push(VAL); | ||
output[theKey].push(VAL); | ||
continue; | ||
@@ -193,3 +230,3 @@ | ||
case 'float[]': | ||
num = +VAL; | ||
data = +VAL; | ||
break; | ||
@@ -199,6 +236,4 @@ | ||
case 'int[]': | ||
debugger; | ||
num = +VAL | 0; | ||
if ('' + num !== VAL) num = NaN; | ||
data = +VAL | 0; | ||
if (data + '' !== VAL && !re.isHexPrefix.test(VAL)) data = NaN; | ||
break; | ||
@@ -208,58 +243,120 @@ | ||
case 'hex[]': | ||
num = parseInt(VAL, 16); | ||
if (re.isHex.test(VAL)) { | ||
data = parseInt(VAL, 16); | ||
} else { | ||
data = NaN; | ||
} | ||
break; | ||
/* | ||
case 'json': | ||
console.log(VAL); | ||
try { | ||
data = JSON.parse(VAL); | ||
} catch (e) { | ||
data = NaN; // I know - a bit cheeky... | ||
VAL = e.message; // VAL.replace(re.truncate, '$1...'); | ||
} | ||
break; | ||
*/ | ||
default: | ||
return conf.panic( | ||
`The parameter '${KEY}' is configured with an invalid type: '${params[KEY].type}'` | ||
); | ||
return panic(`Parameter '${KEY}' configuration has an invalid type: '${theType}'`); | ||
} | ||
if (isNaN(num) || !isFinite(num)) | ||
return conf.error(`The value of '${KEY}' is not a valid ${params[KEY].type}: '${VAL}'`); | ||
if (Array.isArray(output[params[KEY].key])) { | ||
output[params[KEY].key].push(num); | ||
if (isNaN(data) || !isFinite(data)) | ||
return error(`The value of '${KEY}' is not a valid ${theType}: '${VAL}'`); | ||
if (Array.isArray(output[theKey])) { | ||
output[theKey].push(data); | ||
} else { | ||
output[params[KEY].key] = num; | ||
output[theKey] = data; | ||
} | ||
} | ||
for (let key in complexDefault) { | ||
if (!params.hasOwnProperty(key)) continue; | ||
for (const [key, value] of Object.entries(complexDefault)) { | ||
if (!hasOwnProperty.call(params, key)) continue; | ||
if (undefined === output[key] || !output[key].length) { | ||
output[key] = complexDefault[key]; | ||
output[key] = value; | ||
} | ||
} | ||
for (let key of validate) { | ||
for (const key of validate) { | ||
const param = params[key]; | ||
let help = ''; | ||
if ('function' === typeof params[key].valid) { | ||
if (params[key].valid(output[key])) continue; | ||
if ('function' === typeof param.valid) { | ||
if (param.valid(output[key])) continue; | ||
} else { | ||
if (!Array.isArray(params[key].valid)) | ||
return conf.panic( | ||
`The "valid" property of the '${key}' parameter must be a function or an array of valid values` | ||
if (!Array.isArray(param.valid)) | ||
return panic( | ||
`The "valid" property of '${key}' parameter must be a function or an array of valid values` | ||
); | ||
if (params[key].valid.includes(output[key])) continue; | ||
help = '. Please use one of the following values: ' + JSON.stringify(params[key].valid); | ||
if (param.valid.includes(output[key])) continue; | ||
help = '. Please use one of the following values: ' + JSON.stringify(param.valid); | ||
} | ||
return conf.error( | ||
`The value provided for parameter '${key}' is not valid: '${output[key]}'` + help | ||
return error( | ||
`The value provided for the parameter '${key}' is not valid: '${output[key]}'` + help | ||
); | ||
} | ||
for (let key of mandatory) { | ||
for (const key of mandatory) { | ||
if (undefined === output[key]) | ||
return conf.error( | ||
`The parameter '${key}' is mandatory.` + | ||
(params[key].alias.length | ||
? ` You can also provide an alias: ${params[key].alias.join(', ')}` | ||
: '') | ||
return error( | ||
`The parameter '${key}' is mandatory.${params[key]?.alias?.length ? ` You can also use an alias: ${params[key].alias.join(', ')}` : ''}` | ||
); | ||
} | ||
// todo: check for conflict | ||
for (const key of conflict) { | ||
if (!inputLog.includes(key)) continue; | ||
const conflicting = params[key]?.conflict?.find(value => inputLog.includes(value)); | ||
if (conflicting) { | ||
return error(`The parameter '${key}' conflicts with '${conflicting}'`); | ||
} | ||
} | ||
if (conf.outputAlias) { | ||
const tempOutput = {}; | ||
for (const key in output) { | ||
if ('_' === key || !Object.prototype.hasOwnProperty.call(output, key)) continue; | ||
const result = output[key]; | ||
tempOutput[key] = result; | ||
const alias = params[key].alias; | ||
if (!alias) continue; | ||
for (const a of alias) { | ||
tempOutput[a] = result; | ||
} | ||
} | ||
Object.assign(output, tempOutput); | ||
} | ||
if (conf.outputInflate) { | ||
return inflate(output); | ||
} | ||
return output; | ||
} | ||
function inflate(flatObj) { | ||
const result = {}; | ||
for (const key in flatObj) { | ||
const keys = key.split('.'); | ||
let currentLevel = result; | ||
keys.forEach((k, i) => { | ||
if (!currentLevel[k]) { | ||
currentLevel[k] = {}; | ||
} | ||
if (i === keys.length - 1) { | ||
currentLevel[k] = flatObj[key]; | ||
} else { | ||
currentLevel = currentLevel[k]; | ||
} | ||
}); | ||
} | ||
return result; | ||
} |
@@ -8,6 +8,4 @@ // @ts-ignore | ||
export const re = { | ||
kebab: /([a-z0-9]|(?=[A-Z]))([A-Z])/g, | ||
camel: /-+([^-])|-+$/g, | ||
}; | ||
// @ts-ignore | ||
import {re} from './common.js'; | ||
@@ -34,2 +32,3 @@ /* | ||
array of value as default | ||
# conflicting values | ||
*/ | ||
@@ -44,2 +43,3 @@ | ||
mandatory: [], | ||
conflict: [], | ||
complexDefault: {}, | ||
@@ -97,3 +97,3 @@ conf: { | ||
if (conf.allowAssign) { | ||
let i = KEY.indexOf('='); | ||
const i = KEY.indexOf('='); | ||
if (-1 < i) { | ||
@@ -114,6 +114,6 @@ ASSIGN = true; | ||
if (!params[KEY]) { | ||
if (!conf.allowUnknown) return conf.error(`'${KEY}' not allowed`); | ||
if (!conf.allowUnknown) return conf.error(`Unknown parameter '${KEY}' not allowed`); | ||
if (conf.autoCamelKebabCase) { | ||
KEY = KEY.replace(re.camel, function (match, letter) { | ||
KEY = KEY.replace(re.kebab2camel, function (match, letter) { | ||
return letter.toUpperCase(); | ||
@@ -129,3 +129,3 @@ }); | ||
// @ts-ignore | ||
output[KEY] = +VAL == VAL ? +VAL : VAL; | ||
output[KEY] = +VAL + '' === VAL ? +VAL : VAL; | ||
} else { | ||
@@ -137,3 +137,3 @@ output[KEY] = true; | ||
if ('boolean' === params[KEY].type) { | ||
if ('boolean' === params[params[KEY].key].type) { | ||
if (ASSIGN) return conf.error(`'${KEY}' is boolean, so can't assign: '${arg}'`); | ||
@@ -144,4 +144,4 @@ output[params[KEY].key] = true; | ||
if ('count' === params[KEY].type) { | ||
if (ASSIGN) return conf.error(`'${KEY}' is count, so can't assign: '${arg}'`); | ||
if ('count' === params[params[KEY].key].type) { | ||
if (ASSIGN) return conf.error(`'${KEY}' counting, so can't assign: '${arg}'`); | ||
output[KEY]++; | ||
@@ -158,3 +158,3 @@ continue; | ||
switch (params[KEY].type) { | ||
switch (params[params[KEY].key].type) { | ||
case 'string': | ||
@@ -179,3 +179,3 @@ output[params[KEY].key] = VAL; | ||
num = +VAL | 0; | ||
if ('' + num !== VAL) num = NaN; | ||
if (num + '' !== VAL) num = NaN; | ||
break; | ||
@@ -185,10 +185,17 @@ | ||
case 'hex[]': | ||
num = parseInt(VAL, 16); | ||
if (re.isHex.test(VAL)) { | ||
num = parseInt(VAL, 16); | ||
} else { | ||
num = NaN; | ||
} | ||
break; | ||
default: | ||
return conf.panic(`'${KEY}' got invalid type: '${params[KEY].type}'`); | ||
return conf.panic(`'${KEY}' got invalid type: '${params[params[KEY].key].type}'`); | ||
} | ||
if (isNaN(num) || !isFinite(num)) { | ||
return conf.error(`'${KEY}' not a valid ${params[KEY].type}: '${VAL}'`); | ||
return conf.error( | ||
`'${KEY}' value is not a valid ${params[params[KEY].key].type}: '${VAL}'` | ||
); | ||
} | ||
@@ -226,3 +233,3 @@ | ||
`'${key.length > 1 ? '--' : '-'}${key}' is mandatory` + | ||
(params[key].alias.length | ||
(params[key]?.alias?.length | ||
? `. Or use an alias: ${params[key].alias | ||
@@ -244,5 +251,5 @@ .map(v => (v.length > 1 ? '--' : '-') + v) | ||
// todo: check for conflict | ||
// todo: check for conflict ? | ||
return output; | ||
} |
@@ -18,4 +18,6 @@ #!/usr/bin/env node | ||
export {argEngine}; | ||
export default function argMate(args: string[], params?: ArgMateParams, conf?: ArgMateConfig) { | ||
return argService(argEngine, args, params, conf); | ||
} |
@@ -19,3 +19,3 @@ #!/usr/bin/env node | ||
if (params) params_ = JSON.stringify(params); | ||
if (params) params_ = {...params}; | ||
@@ -43,4 +43,4 @@ if (conf) conf_ = {...conf}; | ||
{...conf_, ...conf}, | ||
params || JSON.parse(params_) | ||
{...params_, ...params} | ||
); | ||
} |
export const re = { | ||
kebab: /([a-z0-9]|(?=[A-Z]))([A-Z])/g, | ||
camel: /-+([^-])|-+$/g, | ||
arrayType: /(^array|\[\])$/, | ||
validTypes: /^((array|count)|(boolean|string|number|float|int|hex)(\[\])?)$/, | ||
isCamel: /[a-z0-9][A-Z]/, | ||
isKebab: /\w-\w+/, | ||
camel2kebab: /([a-z0-9]|(?=[A-Z]))([A-Z])/g, | ||
kebab2camel: /-+([^-])|-+$/g, | ||
isArrayType: /(^array|\[\])$/, | ||
validTypes: /^((array|count|json|split)|(boolean|string|number|float|int|hex)(\[\])?)$/, | ||
paramTokens: | ||
/^(?<STOP>--)$|^-(?<LONG>-+)?(?<NO>no-)?(?<KEY>[^=\s]+?)(?<KEYNUM>[\d]*)(?<ASSIGN>=(?<VAL>.*))?$/, | ||
listDeviders: /[,\s]+-?-?|^--?/, | ||
isHex: /^(0x)?[A-Fa-f0-9]+$/, | ||
isHexPrefix: /^(0x)[A-Fa-f0-9]+$/, | ||
truncate: /^(.{40}).*$/, | ||
boolStringTrue: /^(true|yes|on)$/i, | ||
boolstringfalse: /^(false|no|off)$/i, | ||
}; |
// @ts-ignore | ||
import {ArgMateParams, ArgMateConfig, ArgMateConfigMandatory} from './types.js'; | ||
import {ArgMateParams, ArgMateConfig, ArgMateConfigMandatory, ArgProcessObj} from './types.js'; | ||
@@ -7,32 +7,20 @@ // @ts-ignore | ||
const defaultConf: ArgMateConfigMandatory = { | ||
error: msg => { | ||
throw msg; | ||
}, | ||
panic: msg => { | ||
throw msg; | ||
}, | ||
allowUnknown: true, | ||
autoCamelKebabCase: true, | ||
allowNegatingFlags: true, | ||
allowKeyNumValues: true, | ||
allowAssign: true, | ||
}; | ||
const strictConf = { | ||
allowUnknown: false, | ||
autoCamelKebabCase: false, | ||
allowNegatingFlags: false, | ||
allowKeyNumValues: false, | ||
allowAssign: false, | ||
allowBoolString: false, | ||
}; | ||
export function precompileConfig(params: ArgMateParams, conf?: ArgMateConfig) { | ||
/** #__PURE__ */ export function precompileConfig(params: ArgMateParams, conf?: ArgMateConfig) { | ||
return objectToCode(compileConfig(params, conf)); | ||
} | ||
export function compileConfig(params: ArgMateParams, conf_: ArgMateConfig = {}) { | ||
export function compileConfig(params: ArgMateParams, conf_: ArgMateConfig = {}): ArgProcessObj { | ||
const mandatory: string[] = []; | ||
const validate: string[] = []; | ||
let complexDefault: any = {}; | ||
let output: any = { | ||
const conflict: string[] = []; | ||
const complexDefault: any = {}; | ||
const output: any = { | ||
_: [], | ||
@@ -42,3 +30,18 @@ }; | ||
const conf: ArgMateConfigMandatory = { | ||
...defaultConf, | ||
error: msg => { | ||
throw msg; | ||
}, | ||
panic: msg => { | ||
throw msg; | ||
}, | ||
autoCamelKebabCase: true, | ||
allowUnknown: true, | ||
allowNegatingFlags: true, | ||
allowKeyNumValues: true, | ||
allowAssign: true, | ||
allowBoolString: true, | ||
outputAlias: false, | ||
outputInflate: false, | ||
intro: '', | ||
outro: '', | ||
...(conf_.strict ? strictConf : {}), | ||
@@ -48,7 +51,10 @@ ...conf_, | ||
for (let key in params) { | ||
if (!params.hasOwnProperty(key)) continue; | ||
const {panic} = conf; | ||
const hasOwnProperty = Object.prototype.hasOwnProperty; | ||
for (const key in params) { | ||
if (!hasOwnProperty.call(params, key)) continue; | ||
let param = params[key]; | ||
// If only default value is provided, then transform to object with correct type | ||
if (param === null || typeof param !== 'object' || Array.isArray(param)) { | ||
@@ -62,5 +68,12 @@ param = { | ||
param.key = key; | ||
param.alias = param.alias || []; | ||
//param.conflict = param.conflict || []; | ||
if (param.conflict) { | ||
param.conflict = Array.isArray(param.conflict) | ||
? param.conflict | ||
: String(param.conflict).split(re.listDeviders); | ||
if (param.conflict.length) { | ||
conflict.push(key); | ||
} | ||
} | ||
if (undefined !== param.valid) { | ||
@@ -70,3 +83,3 @@ validate.push(key); | ||
if (!param.valid.length) | ||
return conf.panic(`Empty array found for valid values of '${key}'`); | ||
return panic(`Empty array found for valid values of '${key}'`); | ||
@@ -86,4 +99,4 @@ if (undefined === param.type) { | ||
} else if ('count' == param.type) { | ||
return conf.error( | ||
`Default parameters like '${param.default}' are not allowed on parameters like '${key}' with the type '${param.type}'` | ||
return panic( | ||
`Default parameter '${param.default}' is not allowed for '${key}' because of its type '${param.type}'` | ||
); | ||
@@ -99,7 +112,7 @@ } else { | ||
if (!param.type.match(re.validTypes)) { | ||
conf.error(`Invalid type '${param.type}' for parameter '${key}'`); | ||
if (!re.validTypes.test(param.type)) { | ||
panic(`Invalid type '${param.type}' for parameter '${key}'`); | ||
} | ||
if (param.type.match(re.arrayType)) { | ||
if (re.isArrayType.test(param.type)) { | ||
output[key] = []; | ||
@@ -112,15 +125,24 @@ } | ||
if (conf.autoCamelKebabCase) { | ||
let kebab = key.replace(re.kebab, '$1-$2').toLowerCase(); | ||
if (param.alias) { | ||
param.alias = Array.isArray(param.alias) | ||
? param.alias | ||
: String(param.alias).split(re.listDeviders).filter(Boolean); | ||
} | ||
if (conf.autoCamelKebabCase && re.isCamel.test(key)) { | ||
const kebab = key.replace(re.camel2kebab, '$1-$2').toLowerCase(); | ||
if (kebab !== key) { | ||
param.alias = [kebab].concat(param.alias || []); | ||
param.alias = param.alias ? [kebab, ...param.alias] : [kebab]; | ||
} | ||
} | ||
if (undefined !== param.alias && !Array.isArray(param.alias)) param.alias = [param.alias]; | ||
if (param.alias) { | ||
for (const alias of param.alias) { | ||
if (undefined === params[alias]) { | ||
params[alias] = {key}; | ||
} | ||
} | ||
} | ||
if (param.alias) | ||
param.alias.forEach(alias => { | ||
if (undefined === params[alias]) params[alias] = {type: params[key].type, key}; | ||
}); | ||
params[key] = param; | ||
} | ||
@@ -131,2 +153,3 @@ | ||
validate, | ||
conflict, | ||
mandatory, | ||
@@ -139,12 +162,8 @@ complexDefault, | ||
function findType(val) { | ||
if (null === val || undefined === val) return void 0; | ||
/** #__PURE__ */ function findType(val: any): string | undefined { | ||
if (val === null || val === undefined) return undefined; | ||
let type = typeof val; | ||
let isArray = Array.isArray(val); | ||
const type = typeof val; | ||
const isArray = Array.isArray(val); | ||
if (isArray && val.length > 0) { | ||
type = typeof val[0]; | ||
} | ||
switch (type) { | ||
@@ -159,3 +178,3 @@ case 'boolean': | ||
function objectToCode(obj, level = 1) { | ||
/** #__PURE__ */ function objectToCode(obj: any, level = 1): string { | ||
let str = '{\n'; | ||
@@ -165,3 +184,3 @@ | ||
str += `${' '.repeat(level)}"${key}": `; | ||
if (typeof value === 'function') { | ||
if (typeof value === 'function' || value instanceof RegExp) { | ||
str += value.toString(); | ||
@@ -168,0 +187,0 @@ } else if (typeof value === 'object' && !Array.isArray(value)) { |
@@ -34,2 +34,3 @@ export interface ArgMateParams { | ||
export interface ArgMateConfig { | ||
panic?: (msg: string) => void; | ||
error?: (msg: string) => void; | ||
@@ -42,4 +43,10 @@ strict?: boolean; | ||
allowAssign?: boolean; | ||
allowBoolString?: boolean; | ||
outputAlias?: boolean; | ||
outputInflate?: boolean; | ||
intro?: IntroOutroType; | ||
outro?: IntroOutroType; | ||
// 'dot-notation': false, | ||
// 'boolean-negation': false | ||
} | ||
@@ -71,2 +78,3 @@ | ||
validate: string[]; | ||
conflict: string[]; | ||
complexDefault: {[key: string]: string[] | number[]}; | ||
@@ -73,0 +81,0 @@ conf: ArgMateConfigMandatory; |
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
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
89444
22
1343
376
1
1