index.js 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485
  1. var __create = Object.create;
  2. var __defProp = Object.defineProperty;
  3. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  4. var __getOwnPropNames = Object.getOwnPropertyNames;
  5. var __getProtoOf = Object.getPrototypeOf;
  6. var __hasOwnProp = Object.prototype.hasOwnProperty;
  7. var __commonJS = (cb, mod) => function __require() {
  8. return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
  9. };
  10. var __copyProps = (to, from, except, desc) => {
  11. if (from && typeof from === "object" || typeof from === "function") {
  12. for (let key of __getOwnPropNames(from))
  13. if (!__hasOwnProp.call(to, key) && key !== except)
  14. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  15. }
  16. return to;
  17. };
  18. var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  19. // If the importer is in node compatibility mode or this is not an ESM
  20. // file that has been converted to a CommonJS file using a Babel-
  21. // compatible transform (i.e. "__esModule" has not been set), then set
  22. // "default" to the CommonJS "module.exports" for node compatibility.
  23. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  24. mod
  25. ));
  26. // node_modules/.pnpm/clone@2.1.2/node_modules/clone/clone.js
  27. var require_clone = __commonJS({
  28. "node_modules/.pnpm/clone@2.1.2/node_modules/clone/clone.js"(exports, module) {
  29. "use strict";
  30. var clone2 = function() {
  31. "use strict";
  32. function _instanceof(obj, type) {
  33. return type != null && obj instanceof type;
  34. }
  35. var nativeMap;
  36. try {
  37. nativeMap = Map;
  38. } catch (_) {
  39. nativeMap = function() {
  40. };
  41. }
  42. var nativeSet;
  43. try {
  44. nativeSet = Set;
  45. } catch (_) {
  46. nativeSet = function() {
  47. };
  48. }
  49. var nativePromise;
  50. try {
  51. nativePromise = Promise;
  52. } catch (_) {
  53. nativePromise = function() {
  54. };
  55. }
  56. function clone3(parent, circular, depth, prototype, includeNonEnumerable) {
  57. if (typeof circular === "object") {
  58. depth = circular.depth;
  59. prototype = circular.prototype;
  60. includeNonEnumerable = circular.includeNonEnumerable;
  61. circular = circular.circular;
  62. }
  63. var allParents = [];
  64. var allChildren = [];
  65. var useBuffer = typeof Buffer != "undefined";
  66. if (typeof circular == "undefined")
  67. circular = true;
  68. if (typeof depth == "undefined")
  69. depth = Infinity;
  70. function _clone(parent2, depth2) {
  71. if (parent2 === null)
  72. return null;
  73. if (depth2 === 0)
  74. return parent2;
  75. var child;
  76. var proto;
  77. if (typeof parent2 != "object") {
  78. return parent2;
  79. }
  80. if (_instanceof(parent2, nativeMap)) {
  81. child = new nativeMap();
  82. } else if (_instanceof(parent2, nativeSet)) {
  83. child = new nativeSet();
  84. } else if (_instanceof(parent2, nativePromise)) {
  85. child = new nativePromise(function(resolve, reject) {
  86. parent2.then(function(value) {
  87. resolve(_clone(value, depth2 - 1));
  88. }, function(err) {
  89. reject(_clone(err, depth2 - 1));
  90. });
  91. });
  92. } else if (clone3.__isArray(parent2)) {
  93. child = [];
  94. } else if (clone3.__isRegExp(parent2)) {
  95. child = new RegExp(parent2.source, __getRegExpFlags(parent2));
  96. if (parent2.lastIndex) child.lastIndex = parent2.lastIndex;
  97. } else if (clone3.__isDate(parent2)) {
  98. child = new Date(parent2.getTime());
  99. } else if (useBuffer && Buffer.isBuffer(parent2)) {
  100. if (Buffer.allocUnsafe) {
  101. child = Buffer.allocUnsafe(parent2.length);
  102. } else {
  103. child = new Buffer(parent2.length);
  104. }
  105. parent2.copy(child);
  106. return child;
  107. } else if (_instanceof(parent2, Error)) {
  108. child = Object.create(parent2);
  109. } else {
  110. if (typeof prototype == "undefined") {
  111. proto = Object.getPrototypeOf(parent2);
  112. child = Object.create(proto);
  113. } else {
  114. child = Object.create(prototype);
  115. proto = prototype;
  116. }
  117. }
  118. if (circular) {
  119. var index = allParents.indexOf(parent2);
  120. if (index != -1) {
  121. return allChildren[index];
  122. }
  123. allParents.push(parent2);
  124. allChildren.push(child);
  125. }
  126. if (_instanceof(parent2, nativeMap)) {
  127. parent2.forEach(function(value, key) {
  128. var keyChild = _clone(key, depth2 - 1);
  129. var valueChild = _clone(value, depth2 - 1);
  130. child.set(keyChild, valueChild);
  131. });
  132. }
  133. if (_instanceof(parent2, nativeSet)) {
  134. parent2.forEach(function(value) {
  135. var entryChild = _clone(value, depth2 - 1);
  136. child.add(entryChild);
  137. });
  138. }
  139. for (var i in parent2) {
  140. var attrs;
  141. if (proto) {
  142. attrs = Object.getOwnPropertyDescriptor(proto, i);
  143. }
  144. if (attrs && attrs.set == null) {
  145. continue;
  146. }
  147. child[i] = _clone(parent2[i], depth2 - 1);
  148. }
  149. if (Object.getOwnPropertySymbols) {
  150. var symbols = Object.getOwnPropertySymbols(parent2);
  151. for (var i = 0; i < symbols.length; i++) {
  152. var symbol = symbols[i];
  153. var descriptor = Object.getOwnPropertyDescriptor(parent2, symbol);
  154. if (descriptor && !descriptor.enumerable && !includeNonEnumerable) {
  155. continue;
  156. }
  157. child[symbol] = _clone(parent2[symbol], depth2 - 1);
  158. if (!descriptor.enumerable) {
  159. Object.defineProperty(child, symbol, {
  160. enumerable: false
  161. });
  162. }
  163. }
  164. }
  165. if (includeNonEnumerable) {
  166. var allPropertyNames = Object.getOwnPropertyNames(parent2);
  167. for (var i = 0; i < allPropertyNames.length; i++) {
  168. var propertyName = allPropertyNames[i];
  169. var descriptor = Object.getOwnPropertyDescriptor(parent2, propertyName);
  170. if (descriptor && descriptor.enumerable) {
  171. continue;
  172. }
  173. child[propertyName] = _clone(parent2[propertyName], depth2 - 1);
  174. Object.defineProperty(child, propertyName, {
  175. enumerable: false
  176. });
  177. }
  178. }
  179. return child;
  180. }
  181. return _clone(parent, depth);
  182. }
  183. clone3.clonePrototype = function clonePrototype(parent) {
  184. if (parent === null)
  185. return null;
  186. var c = function() {
  187. };
  188. c.prototype = parent;
  189. return new c();
  190. };
  191. function __objToStr(o) {
  192. return Object.prototype.toString.call(o);
  193. }
  194. clone3.__objToStr = __objToStr;
  195. function __isDate(o) {
  196. return typeof o === "object" && __objToStr(o) === "[object Date]";
  197. }
  198. clone3.__isDate = __isDate;
  199. function __isArray(o) {
  200. return typeof o === "object" && __objToStr(o) === "[object Array]";
  201. }
  202. clone3.__isArray = __isArray;
  203. function __isRegExp(o) {
  204. return typeof o === "object" && __objToStr(o) === "[object RegExp]";
  205. }
  206. clone3.__isRegExp = __isRegExp;
  207. function __getRegExpFlags(re) {
  208. var flags = "";
  209. if (re.global) flags += "g";
  210. if (re.ignoreCase) flags += "i";
  211. if (re.multiline) flags += "m";
  212. return flags;
  213. }
  214. clone3.__getRegExpFlags = __getRegExpFlags;
  215. return clone3;
  216. }();
  217. if (typeof module === "object" && module.exports) {
  218. module.exports = clone2;
  219. }
  220. }
  221. });
  222. // node_modules/.pnpm/shell-quote@1.8.1/node_modules/shell-quote/quote.js
  223. var require_quote = __commonJS({
  224. "node_modules/.pnpm/shell-quote@1.8.1/node_modules/shell-quote/quote.js"(exports, module) {
  225. "use strict";
  226. module.exports = function quote(xs) {
  227. return xs.map(function(s) {
  228. if (s && typeof s === "object") {
  229. return s.op.replace(/(.)/g, "\\$1");
  230. }
  231. if (/["\s]/.test(s) && !/'/.test(s)) {
  232. return "'" + s.replace(/(['\\])/g, "\\$1") + "'";
  233. }
  234. if (/["'\s]/.test(s)) {
  235. return '"' + s.replace(/(["\\$`!])/g, "\\$1") + '"';
  236. }
  237. return String(s).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}])/g, "$1\\$2");
  238. }).join(" ");
  239. };
  240. }
  241. });
  242. // node_modules/.pnpm/shell-quote@1.8.1/node_modules/shell-quote/parse.js
  243. var require_parse = __commonJS({
  244. "node_modules/.pnpm/shell-quote@1.8.1/node_modules/shell-quote/parse.js"(exports, module) {
  245. "use strict";
  246. var CONTROL = "(?:" + [
  247. "\\|\\|",
  248. "\\&\\&",
  249. ";;",
  250. "\\|\\&",
  251. "\\<\\(",
  252. "\\<\\<\\<",
  253. ">>",
  254. ">\\&",
  255. "<\\&",
  256. "[&;()|<>]"
  257. ].join("|") + ")";
  258. var controlRE = new RegExp("^" + CONTROL + "$");
  259. var META = "|&;()<> \\t";
  260. var SINGLE_QUOTE = '"((\\\\"|[^"])*?)"';
  261. var DOUBLE_QUOTE = "'((\\\\'|[^'])*?)'";
  262. var hash = /^#$/;
  263. var SQ = "'";
  264. var DQ = '"';
  265. var DS = "$";
  266. var TOKEN = "";
  267. var mult = 4294967296;
  268. for (i = 0; i < 4; i++) {
  269. TOKEN += (mult * Math.random()).toString(16);
  270. }
  271. var i;
  272. var startsWithToken = new RegExp("^" + TOKEN);
  273. function matchAll(s, r) {
  274. var origIndex = r.lastIndex;
  275. var matches = [];
  276. var matchObj;
  277. while (matchObj = r.exec(s)) {
  278. matches.push(matchObj);
  279. if (r.lastIndex === matchObj.index) {
  280. r.lastIndex += 1;
  281. }
  282. }
  283. r.lastIndex = origIndex;
  284. return matches;
  285. }
  286. function getVar(env, pre, key) {
  287. var r = typeof env === "function" ? env(key) : env[key];
  288. if (typeof r === "undefined" && key != "") {
  289. r = "";
  290. } else if (typeof r === "undefined") {
  291. r = "$";
  292. }
  293. if (typeof r === "object") {
  294. return pre + TOKEN + JSON.stringify(r) + TOKEN;
  295. }
  296. return pre + r;
  297. }
  298. function parseInternal(string2, env, opts) {
  299. if (!opts) {
  300. opts = {};
  301. }
  302. var BS = opts.escape || "\\";
  303. var BAREWORD = "(\\" + BS + `['"` + META + `]|[^\\s'"` + META + "])+";
  304. var chunker = new RegExp([
  305. "(" + CONTROL + ")",
  306. // control chars
  307. "(" + BAREWORD + "|" + SINGLE_QUOTE + "|" + DOUBLE_QUOTE + ")+"
  308. ].join("|"), "g");
  309. var matches = matchAll(string2, chunker);
  310. if (matches.length === 0) {
  311. return [];
  312. }
  313. if (!env) {
  314. env = {};
  315. }
  316. var commented = false;
  317. return matches.map(function(match) {
  318. var s = match[0];
  319. if (!s || commented) {
  320. return void 0;
  321. }
  322. if (controlRE.test(s)) {
  323. return { op: s };
  324. }
  325. var quote = false;
  326. var esc = false;
  327. var out = "";
  328. var isGlob = false;
  329. var i2;
  330. function parseEnvVar() {
  331. i2 += 1;
  332. var varend;
  333. var varname;
  334. var char = s.charAt(i2);
  335. if (char === "{") {
  336. i2 += 1;
  337. if (s.charAt(i2) === "}") {
  338. throw new Error("Bad substitution: " + s.slice(i2 - 2, i2 + 1));
  339. }
  340. varend = s.indexOf("}", i2);
  341. if (varend < 0) {
  342. throw new Error("Bad substitution: " + s.slice(i2));
  343. }
  344. varname = s.slice(i2, varend);
  345. i2 = varend;
  346. } else if (/[*@#?$!_-]/.test(char)) {
  347. varname = char;
  348. i2 += 1;
  349. } else {
  350. var slicedFromI = s.slice(i2);
  351. varend = slicedFromI.match(/[^\w\d_]/);
  352. if (!varend) {
  353. varname = slicedFromI;
  354. i2 = s.length;
  355. } else {
  356. varname = slicedFromI.slice(0, varend.index);
  357. i2 += varend.index - 1;
  358. }
  359. }
  360. return getVar(env, "", varname);
  361. }
  362. for (i2 = 0; i2 < s.length; i2++) {
  363. var c = s.charAt(i2);
  364. isGlob = isGlob || !quote && (c === "*" || c === "?");
  365. if (esc) {
  366. out += c;
  367. esc = false;
  368. } else if (quote) {
  369. if (c === quote) {
  370. quote = false;
  371. } else if (quote == SQ) {
  372. out += c;
  373. } else {
  374. if (c === BS) {
  375. i2 += 1;
  376. c = s.charAt(i2);
  377. if (c === DQ || c === BS || c === DS) {
  378. out += c;
  379. } else {
  380. out += BS + c;
  381. }
  382. } else if (c === DS) {
  383. out += parseEnvVar();
  384. } else {
  385. out += c;
  386. }
  387. }
  388. } else if (c === DQ || c === SQ) {
  389. quote = c;
  390. } else if (controlRE.test(c)) {
  391. return { op: s };
  392. } else if (hash.test(c)) {
  393. commented = true;
  394. var commentObj = { comment: string2.slice(match.index + i2 + 1) };
  395. if (out.length) {
  396. return [out, commentObj];
  397. }
  398. return [commentObj];
  399. } else if (c === BS) {
  400. esc = true;
  401. } else if (c === DS) {
  402. out += parseEnvVar();
  403. } else {
  404. out += c;
  405. }
  406. }
  407. if (isGlob) {
  408. return { op: "glob", pattern: out };
  409. }
  410. return out;
  411. }).reduce(function(prev, arg) {
  412. return typeof arg === "undefined" ? prev : prev.concat(arg);
  413. }, []);
  414. }
  415. module.exports = function parse(s, env, opts) {
  416. var mapped = parseInternal(s, env, opts);
  417. if (typeof env !== "function") {
  418. return mapped;
  419. }
  420. return mapped.reduce(function(acc, s2) {
  421. if (typeof s2 === "object") {
  422. return acc.concat(s2);
  423. }
  424. var xs = s2.split(RegExp("(" + TOKEN + ".*?" + TOKEN + ")", "g"));
  425. if (xs.length === 1) {
  426. return acc.concat(xs[0]);
  427. }
  428. return acc.concat(xs.filter(Boolean).map(function(x) {
  429. if (startsWithToken.test(x)) {
  430. return JSON.parse(x.split(TOKEN)[1]);
  431. }
  432. return x;
  433. }));
  434. }, []);
  435. };
  436. }
  437. });
  438. // node_modules/.pnpm/shell-quote@1.8.1/node_modules/shell-quote/index.js
  439. var require_shell_quote = __commonJS({
  440. "node_modules/.pnpm/shell-quote@1.8.1/node_modules/shell-quote/index.js"(exports) {
  441. "use strict";
  442. exports.quote = require_quote();
  443. exports.parse = require_parse();
  444. }
  445. });
  446. // src/brocli-error.ts
  447. var BroCliError = class extends Error {
  448. constructor(message, event) {
  449. const errPrefix = "BroCli error: ";
  450. super(message === void 0 ? message : `${errPrefix}${message}`);
  451. this.event = event;
  452. }
  453. };
  454. // src/command-core.ts
  455. var import_clone = __toESM(require_clone(), 1);
  456. // src/event-handler.ts
  457. var getOptionTypeText = (option) => {
  458. let result = "";
  459. switch (option.type) {
  460. case "boolean":
  461. result = "";
  462. break;
  463. case "number": {
  464. if ((option.minVal ?? option.maxVal) !== void 0) {
  465. let text = "";
  466. if (option.isInt) text = text + `integer `;
  467. if (option.minVal !== void 0) text = text + `[${option.minVal};`;
  468. else text = text + `(\u221E;`;
  469. if (option.maxVal !== void 0) text = text + `${option.maxVal}]`;
  470. else text = text + `\u221E)`;
  471. result = text;
  472. break;
  473. }
  474. if (option.isInt) {
  475. result = "integer";
  476. break;
  477. }
  478. result = "number";
  479. break;
  480. }
  481. case "string": {
  482. if (option.enumVals) {
  483. result = "[ " + option.enumVals.join(" | ") + " ]";
  484. break;
  485. }
  486. result = "string";
  487. break;
  488. }
  489. case "positional": {
  490. result = `${option.isRequired ? "<" : "["}${option.enumVals ? option.enumVals.join("|") : option.name}${option.isRequired ? ">" : "]"}`;
  491. break;
  492. }
  493. }
  494. if (option.isRequired && option.type !== "positional") result = "!" + result.length ? " " : "" + result;
  495. return result;
  496. };
  497. var defaultEventHandler = async (event) => {
  498. switch (event.type) {
  499. case "command_help": {
  500. const command3 = event.command;
  501. const commandName = getCommandNameWithParents(command3);
  502. const cliName = event.name;
  503. const desc = command3.desc ?? command3.shortDesc;
  504. const subs = command3.subcommands?.filter((s) => !s.hidden);
  505. const subcommands = subs && subs.length ? subs : void 0;
  506. if (desc !== void 0) {
  507. console.log(`
  508. ${desc}`);
  509. }
  510. const opts = Object.values(command3.options ?? {}).filter(
  511. (opt) => !opt.config.isHidden
  512. );
  513. const positionals = opts.filter((opt) => opt.config.type === "positional");
  514. const options = opts.filter((opt) => opt.config.type !== "positional");
  515. console.log("\nUsage:");
  516. if (command3.handler) {
  517. console.log(
  518. ` ${cliName ? cliName + " " : ""}${commandName}${positionals.length ? " " + positionals.map(({ config: p }) => getOptionTypeText(p)).join(" ") : ""} [flags]`
  519. );
  520. } else console.log(` ${cliName ? cliName + " " : ""}${commandName} [command]`);
  521. if (command3.aliases) {
  522. console.log(`
  523. Aliases:`);
  524. console.log(` ${[command3.name, ...command3.aliases].join(", ")}`);
  525. }
  526. if (subcommands) {
  527. console.log("\nAvailable Commands:");
  528. const padding = 3;
  529. const maxLength = subcommands.reduce((p, e) => e.name.length > p ? e.name.length : p, 0);
  530. const paddedLength = maxLength + padding;
  531. const preDescPad = 2 + paddedLength;
  532. const data = subcommands.map(
  533. (s) => ` ${s.name.padEnd(paddedLength)}${(() => {
  534. const description = s.shortDesc ?? s.desc;
  535. if (!description?.length) return "";
  536. const split = description.split("\n");
  537. const first = split.shift();
  538. const final = [first, ...split.map((s2) => "".padEnd(preDescPad) + s2)].join("\n");
  539. return final;
  540. })()}`
  541. ).join("\n");
  542. console.log(data);
  543. }
  544. if (options.length) {
  545. const aliasLength = options.reduce((p, e) => {
  546. const currentLength = e.config.aliases.reduce((pa, a) => pa + a.length, 0) + (e.config.aliases.length - 1) * 2 + 1;
  547. return currentLength > p ? currentLength : p;
  548. }, 0);
  549. const paddedAliasLength = aliasLength > 0 ? aliasLength + 1 : 0;
  550. const nameLength = options.reduce((p, e) => {
  551. const typeLen = getOptionTypeText(e.config).length;
  552. const length = typeLen > 0 ? e.config.name.length + 1 + typeLen : e.config.name.length;
  553. return length > p ? length : p;
  554. }, 0) + 3;
  555. const preDescPad = paddedAliasLength + nameLength + 2;
  556. const data = options.map(
  557. ({ config: opt }) => ` ${`${opt.aliases.length ? opt.aliases.join(", ") + "," : ""}`.padEnd(paddedAliasLength)}${`${opt.name}${(() => {
  558. const typeText = getOptionTypeText(opt);
  559. return typeText.length ? " " + typeText : "";
  560. })()}`.padEnd(nameLength)}${(() => {
  561. if (!opt.description?.length) {
  562. return opt.default !== void 0 ? `default: ${JSON.stringify(opt.default)}` : "";
  563. }
  564. const split = opt.description.split("\n");
  565. const first = split.shift();
  566. const def = opt.default !== void 0 ? ` (default: ${JSON.stringify(opt.default)})` : "";
  567. const final = [first, ...split.map((s) => "".padEnd(preDescPad) + s)].join("\n") + def;
  568. return final;
  569. })()}`
  570. ).join("\n");
  571. console.log("\nFlags:");
  572. console.log(data);
  573. }
  574. console.log("\nGlobal flags:");
  575. console.log(` -h, --help help for ${commandName}`);
  576. console.log(` -v, --version version${cliName ? ` for ${cliName}` : ""}`);
  577. if (subcommands) {
  578. console.log(
  579. `
  580. Use "${cliName ? cliName + " " : ""}${commandName} [command] --help" for more information about a command.
  581. `
  582. );
  583. }
  584. return true;
  585. }
  586. case "global_help": {
  587. const cliName = event.name;
  588. const desc = event.description;
  589. const commands = event.commands.filter((c) => !c.hidden);
  590. if (desc !== void 0) {
  591. console.log(`${desc}
  592. `);
  593. }
  594. console.log("Usage:");
  595. console.log(` ${cliName ? cliName + " " : ""}[command]`);
  596. if (commands.length) {
  597. console.log("\nAvailable Commands:");
  598. const padding = 3;
  599. const maxLength = commands.reduce((p, e) => e.name.length > p ? e.name.length : p, 0);
  600. const paddedLength = maxLength + padding;
  601. const data = commands.map(
  602. (c) => ` ${c.name.padEnd(paddedLength)}${(() => {
  603. const desc2 = c.shortDesc ?? c.desc;
  604. if (!desc2?.length) return "";
  605. const split = desc2.split("\n");
  606. const first = split.shift();
  607. const final = [first, ...split.map((s) => "".padEnd(paddedLength + 2) + s)].join("\n");
  608. return final;
  609. })()}`
  610. ).join("\n");
  611. console.log(data);
  612. } else {
  613. console.log("\nNo available commands.");
  614. }
  615. console.log("\nFlags:");
  616. console.log(` -h, --help help${cliName ? ` for ${cliName}` : ""}`);
  617. console.log(` -v, --version version${cliName ? ` for ${cliName}` : ""}`);
  618. console.log("\n");
  619. return true;
  620. }
  621. case "version": {
  622. return true;
  623. }
  624. case "error": {
  625. let msg;
  626. switch (event.violation) {
  627. case "above_max": {
  628. const matchedName = event.offender.namePart;
  629. const data = event.offender.dataPart;
  630. const option = event.option;
  631. const max = option.maxVal;
  632. msg = `Invalid value: number type argument '${matchedName}' expects maximal value of ${max} as an input, got: ${data}`;
  633. break;
  634. }
  635. case "below_min": {
  636. const matchedName = event.offender.namePart;
  637. const data = event.offender.dataPart;
  638. const option = event.option;
  639. const min = option.minVal;
  640. msg = `Invalid value: number type argument '${matchedName}' expects minimal value of ${min} as an input, got: ${data}`;
  641. break;
  642. }
  643. case "expected_int": {
  644. const matchedName = event.offender.namePart;
  645. const data = event.offender.dataPart;
  646. msg = `Invalid value: number type argument '${matchedName}' expects an integer as an input, got: ${data}`;
  647. break;
  648. }
  649. case "invalid_boolean_syntax": {
  650. const matchedName = event.offender.namePart;
  651. const data = event.offender.dataPart;
  652. msg = `Invalid syntax: boolean type argument '${matchedName}' must have it's value passed in the following formats: ${matchedName}=<value> | ${matchedName} <value> | ${matchedName}.
  653. Allowed values: true, false, 0, 1`;
  654. break;
  655. }
  656. case "invalid_string_syntax": {
  657. const matchedName = event.offender.namePart;
  658. msg = `Invalid syntax: string type argument '${matchedName}' must have it's value passed in the following formats: ${matchedName}=<value> | ${matchedName} <value>`;
  659. break;
  660. }
  661. case "invalid_number_syntax": {
  662. const matchedName = event.offender.namePart;
  663. msg = `Invalid syntax: number type argument '${matchedName}' must have it's value passed in the following formats: ${matchedName}=<value> | ${matchedName} <value>`;
  664. break;
  665. }
  666. case "invalid_number_value": {
  667. const matchedName = event.offender.namePart;
  668. const data = event.offender.dataPart;
  669. msg = `Invalid value: number type argument '${matchedName}' expects a number as an input, got: ${data}`;
  670. break;
  671. }
  672. case "enum_violation": {
  673. const matchedName = event.offender.namePart;
  674. const data = event.offender.dataPart;
  675. const option = event.option;
  676. const values = option.enumVals;
  677. msg = option.type === "positional" ? `Invalid value: value for the positional argument '${option.name}' must be either one of the following: ${values.join(", ")}; Received: ${data}` : `Invalid value: value for the argument '${matchedName}' must be either one of the following: ${values.join(", ")}; Received: ${data}`;
  678. break;
  679. }
  680. case "unknown_command_error": {
  681. const msg2 = `Unknown command: '${event.offender}'.
  682. Type '--help' to get help on the cli.`;
  683. console.error(msg2);
  684. return true;
  685. }
  686. case "unknown_subcommand_error": {
  687. const cName = getCommandNameWithParents(event.command);
  688. const msg2 = `Unknown command: ${cName} ${event.offender}.
  689. Type '${cName} --help' to get the help on command.`;
  690. console.error(msg2);
  691. return true;
  692. }
  693. case "missing_args_error": {
  694. const { missing: missingOpts, command: command3 } = event;
  695. msg = `Command '${command3.name}' is missing following required options: ${missingOpts.map((opt) => {
  696. const name = opt.shift();
  697. const aliases = opt;
  698. if (aliases.length) return `${name} [${aliases.join(", ")}]`;
  699. return name;
  700. }).join(", ")}`;
  701. break;
  702. }
  703. case "unrecognized_args_error": {
  704. const { command: command3, unrecognized } = event;
  705. msg = `Unrecognized options for command '${command3.name}': ${unrecognized.join(", ")}`;
  706. break;
  707. }
  708. case "unknown_error": {
  709. const e = event.error;
  710. console.error(typeof e === "object" && e !== null && "message" in e ? e.message : e);
  711. return true;
  712. }
  713. }
  714. console.error(msg);
  715. return true;
  716. }
  717. }
  718. return false;
  719. };
  720. var eventHandlerWrapper = (customEventHandler) => async (event) => await customEventHandler(event) ? true : await defaultEventHandler(event);
  721. // src/util.ts
  722. var import_shell_quote = __toESM(require_shell_quote(), 1);
  723. function isInt(value) {
  724. return value === Math.floor(value);
  725. }
  726. var shellArgs = (str) => (0, import_shell_quote.parse)(str).map((e) => e.toString());
  727. var executeOrLog = async (target) => typeof target === "string" ? console.log(target) : target ? await target() : void 0;
  728. // src/command-core.ts
  729. var generatePrefix = (name) => name.startsWith("-") ? name : name.length > 1 ? `--${name}` : `-${name}`;
  730. var validateOptions = (config) => {
  731. const cloned = (0, import_clone.default)(config);
  732. const entries = [];
  733. const storedNames = [];
  734. const cfgEntries = Object.entries(cloned);
  735. for (const [key, value] of cfgEntries) {
  736. const cfg = value._.config;
  737. if (cfg.name === void 0) cfg.name = key;
  738. if (cfg.type === "positional") continue;
  739. if (cfg.name.includes("=")) {
  740. throw new BroCliError(
  741. `Can't define option '${generatePrefix(cfg.name)}' - option names and aliases cannot contain '='!`
  742. );
  743. }
  744. for (const alias of cfg.aliases) {
  745. if (alias.includes("=")) {
  746. throw new BroCliError(
  747. `Can't define option '${generatePrefix(cfg.name)}' - option names and aliases cannot contain '='!`
  748. );
  749. }
  750. }
  751. cfg.name = generatePrefix(cfg.name);
  752. cfg.aliases = cfg.aliases.map((a) => generatePrefix(a));
  753. }
  754. for (const [key, value] of cfgEntries) {
  755. const cfg = value._.config;
  756. if (cfg.type === "positional") {
  757. entries.push([key, { config: cfg, $output: void 0 }]);
  758. continue;
  759. }
  760. const reservedNames = ["--help", "-h", "--version", "-v"];
  761. const allNames = [cfg.name, ...cfg.aliases];
  762. for (const name of allNames) {
  763. const match = reservedNames.find((n) => n === name);
  764. if (match) throw new BroCliError(`Can't define option '${cfg.name}' - name '${match}' is reserved!`);
  765. }
  766. for (const storage of storedNames) {
  767. const nameOccupier = storage.find((e) => e === cfg.name);
  768. if (!nameOccupier) continue;
  769. throw new BroCliError(
  770. `Can't define option '${cfg.name}' - name is already in use by option '${storage[0]}'!`
  771. );
  772. }
  773. for (const alias of cfg.aliases) {
  774. for (const storage of storedNames) {
  775. const nameOccupier = storage.find((e) => e === alias);
  776. if (!nameOccupier) continue;
  777. throw new BroCliError(
  778. `Can't define option '${cfg.name}' - alias '${alias}' is already in use by option '${storage[0]}'!`
  779. );
  780. }
  781. }
  782. const currentNames = [cfg.name, ...cfg.aliases];
  783. storedNames.push(currentNames);
  784. currentNames.forEach((name, idx) => {
  785. if (currentNames.findIndex((e) => e === name) === idx) return;
  786. throw new BroCliError(
  787. `Can't define option '${cfg.name}' - duplicate alias '${name}'!`
  788. );
  789. });
  790. entries.push([key, { config: cfg, $output: void 0 }]);
  791. }
  792. return Object.fromEntries(entries);
  793. };
  794. var assignParent = (parent, subcommands) => subcommands.forEach((e) => {
  795. e.parent = parent;
  796. if (e.subcommands) assignParent(e, e.subcommands);
  797. });
  798. var command2 = (command3) => {
  799. const allNames = command3.aliases ? [command3.name, ...command3.aliases] : [command3.name];
  800. const cmd = (0, import_clone.default)(command3);
  801. if (command3.subcommands && command3.options && Object.values(command3.options).find((opt) => opt._.config.type === "positional")) {
  802. throw new BroCliError(
  803. `Can't define command '${cmd.name}' - command can't have subcommands and positional args at the same time!`
  804. );
  805. }
  806. if (!command3.handler && !command3.subcommands) {
  807. throw new BroCliError(
  808. `Can't define command '${cmd.name}' - command without subcommands must have a handler present!`
  809. );
  810. }
  811. const processedOptions = command3.options ? validateOptions(command3.options) : void 0;
  812. cmd.options = processedOptions;
  813. cmd.name = cmd.name ?? cmd.aliases?.shift();
  814. if (!cmd.name) throw new BroCliError(`Can't define command without name!`);
  815. cmd.aliases = cmd.aliases?.length ? cmd.aliases : void 0;
  816. if (cmd.name.startsWith("-")) {
  817. throw new BroCliError(`Can't define command '${cmd.name}' - command name can't start with '-'!`);
  818. }
  819. cmd.aliases?.forEach((a) => {
  820. if (a.startsWith("-")) {
  821. throw new BroCliError(`Can't define command '${cmd.name}' - command aliases can't start with '-'!`);
  822. }
  823. });
  824. allNames.forEach((n, i) => {
  825. if (n === "help") {
  826. throw new BroCliError(
  827. `Can't define command '${cmd.name}' - 'help' is a reserved name. If you want to redefine help message - do so in runCli's config.`
  828. );
  829. }
  830. const lCaseName = n?.toLowerCase();
  831. if (lCaseName === "0" || lCaseName === "1" || lCaseName === "true" || lCaseName === "false") {
  832. throw new BroCliError(
  833. `Can't define command '${cmd.name}' - '${n}' is a reserved for boolean values name!`
  834. );
  835. }
  836. const idx = allNames.findIndex((an) => an === n);
  837. if (idx !== i) throw new BroCliError(`Can't define command '${cmd.name}' - duplicate alias '${n}'!`);
  838. });
  839. if (cmd.subcommands) {
  840. assignParent(cmd, cmd.subcommands);
  841. }
  842. return cmd;
  843. };
  844. var getCommandInner = (commands, candidates, args, cliName, cliDescription) => {
  845. const { data: arg, originalIndex: index } = candidates.shift();
  846. const command3 = commands.find((c) => {
  847. const names = c.aliases ? [c.name, ...c.aliases] : [c.name];
  848. const res = names.find((name) => name === arg);
  849. return res;
  850. });
  851. if (!command3) {
  852. return {
  853. command: command3,
  854. args
  855. };
  856. }
  857. const newArgs = removeByIndex(args, index);
  858. if (!candidates.length || !command3.subcommands) {
  859. return {
  860. command: command3,
  861. args: newArgs
  862. };
  863. }
  864. const newCandidates = candidates.map((c) => ({ data: c.data, originalIndex: c.originalIndex - 1 }));
  865. const subcommand = getCommandInner(command3.subcommands, newCandidates, newArgs, cliName, cliDescription);
  866. if (!subcommand.command) {
  867. throw new BroCliError(void 0, {
  868. type: "error",
  869. violation: "unknown_subcommand_error",
  870. name: cliName,
  871. description: cliDescription,
  872. command: command3,
  873. offender: candidates[0].data
  874. });
  875. }
  876. return subcommand;
  877. };
  878. var getCommand = (commands, args, cliName, cliDescription) => {
  879. const candidates = [];
  880. for (let i = 0; i < args.length; ++i) {
  881. const arg = args[i];
  882. if (arg === "--help" || arg === "-h" || arg === "--version" || arg === "-v") {
  883. const lCaseNext = args[i + 1]?.toLowerCase();
  884. if (lCaseNext === "0" || lCaseNext === "1" || lCaseNext === "true" || lCaseNext === "false") ++i;
  885. continue;
  886. }
  887. if (arg?.startsWith("-")) {
  888. if (!arg.includes("=")) ++i;
  889. continue;
  890. }
  891. candidates.push({
  892. data: arg,
  893. originalIndex: i
  894. });
  895. }
  896. if (!candidates.length) {
  897. return {
  898. command: void 0,
  899. args
  900. };
  901. }
  902. const firstCandidate = candidates[0];
  903. if (firstCandidate.data === "help") {
  904. return {
  905. command: "help",
  906. args: removeByIndex(args, firstCandidate.originalIndex)
  907. };
  908. }
  909. const { command: command3, args: argsRes } = getCommandInner(commands, candidates, args, cliName, cliDescription);
  910. if (!command3) {
  911. throw new BroCliError(void 0, {
  912. type: "error",
  913. violation: "unknown_command_error",
  914. commands,
  915. name: cliName,
  916. description: cliDescription,
  917. offender: firstCandidate.data
  918. });
  919. }
  920. return {
  921. command: command3,
  922. args: argsRes
  923. };
  924. };
  925. var parseArg = (command3, options, positionals, arg, nextArg, cliName, cliDescription) => {
  926. let data = void 0;
  927. const argSplit = arg.split("=");
  928. const hasEq = arg.includes("=");
  929. const namePart = argSplit.shift();
  930. const dataPart = hasEq ? argSplit.join("=") : nextArg;
  931. let skipNext = !hasEq;
  932. if (namePart === "--help" || namePart === "-h") {
  933. return {
  934. isHelp: true
  935. };
  936. }
  937. if (namePart === "--version" || namePart === "-v") {
  938. return {
  939. isVersion: true
  940. };
  941. }
  942. if (!arg.startsWith("-")) {
  943. if (!positionals.length) return {};
  944. const pos = positionals.shift();
  945. if (pos[1].enumVals && !pos[1].enumVals.find((val) => val === arg)) {
  946. throw new BroCliError(void 0, {
  947. type: "error",
  948. name: cliName,
  949. description: cliDescription,
  950. violation: "enum_violation",
  951. command: command3,
  952. option: pos[1],
  953. offender: {
  954. dataPart: arg
  955. }
  956. });
  957. }
  958. data = arg;
  959. return {
  960. data,
  961. skipNext: false,
  962. name: pos[0],
  963. option: pos[1]
  964. };
  965. }
  966. const option = options.find(([optKey, opt]) => {
  967. const names = [opt.name, ...opt.aliases];
  968. if (opt.type === "boolean") {
  969. const match = names.find((name) => name === namePart);
  970. if (!match) return false;
  971. let lcaseData = dataPart?.toLowerCase();
  972. if (!hasEq && nextArg?.startsWith("-")) {
  973. data = true;
  974. skipNext = false;
  975. return true;
  976. }
  977. if (lcaseData === void 0 || lcaseData === "" || lcaseData === "true" || lcaseData === "1") {
  978. data = true;
  979. return true;
  980. }
  981. if (lcaseData === "false" || lcaseData === "0") {
  982. data = false;
  983. return true;
  984. }
  985. if (!hasEq) {
  986. data = true;
  987. skipNext = false;
  988. return true;
  989. }
  990. throw new BroCliError(void 0, {
  991. type: "error",
  992. name: cliName,
  993. description: cliDescription,
  994. violation: "invalid_boolean_syntax",
  995. option: opt,
  996. command: command3,
  997. offender: {
  998. namePart,
  999. dataPart
  1000. }
  1001. });
  1002. } else {
  1003. const match = names.find((name) => name === namePart);
  1004. if (!match) return false;
  1005. if (opt.type === "string") {
  1006. if (!hasEq && nextArg === void 0) {
  1007. throw new BroCliError(void 0, {
  1008. type: "error",
  1009. name: cliName,
  1010. description: cliDescription,
  1011. violation: "invalid_string_syntax",
  1012. option: opt,
  1013. command: command3,
  1014. offender: {
  1015. namePart,
  1016. dataPart
  1017. }
  1018. });
  1019. }
  1020. if (opt.enumVals && !opt.enumVals.find((val) => val === dataPart)) {
  1021. throw new BroCliError(void 0, {
  1022. type: "error",
  1023. name: cliName,
  1024. description: cliDescription,
  1025. violation: "enum_violation",
  1026. option: opt,
  1027. command: command3,
  1028. offender: {
  1029. namePart,
  1030. dataPart
  1031. }
  1032. });
  1033. }
  1034. data = dataPart;
  1035. return true;
  1036. }
  1037. if (!hasEq && nextArg === void 0) {
  1038. throw new BroCliError(void 0, {
  1039. type: "error",
  1040. name: cliName,
  1041. description: cliDescription,
  1042. violation: "invalid_number_syntax",
  1043. option: opt,
  1044. command: command3,
  1045. offender: {
  1046. namePart,
  1047. dataPart
  1048. }
  1049. });
  1050. }
  1051. const numData = Number(dataPart);
  1052. if (isNaN(numData)) {
  1053. throw new BroCliError(void 0, {
  1054. type: "error",
  1055. name: cliName,
  1056. description: cliDescription,
  1057. violation: "invalid_number_value",
  1058. option: opt,
  1059. command: command3,
  1060. offender: {
  1061. namePart,
  1062. dataPart
  1063. }
  1064. });
  1065. }
  1066. if (opt.isInt && !isInt(numData)) {
  1067. throw new BroCliError(void 0, {
  1068. type: "error",
  1069. name: cliName,
  1070. description: cliDescription,
  1071. violation: "expected_int",
  1072. option: opt,
  1073. command: command3,
  1074. offender: {
  1075. namePart,
  1076. dataPart
  1077. }
  1078. });
  1079. }
  1080. if (opt.minVal !== void 0 && numData < opt.minVal) {
  1081. throw new BroCliError(void 0, {
  1082. type: "error",
  1083. name: cliName,
  1084. description: cliDescription,
  1085. violation: "below_min",
  1086. option: opt,
  1087. command: command3,
  1088. offender: {
  1089. namePart,
  1090. dataPart
  1091. }
  1092. });
  1093. }
  1094. if (opt.maxVal !== void 0 && numData > opt.maxVal) {
  1095. throw new BroCliError(void 0, {
  1096. type: "error",
  1097. name: cliName,
  1098. description: cliDescription,
  1099. violation: "above_max",
  1100. option: opt,
  1101. command: command3,
  1102. offender: {
  1103. namePart,
  1104. dataPart
  1105. }
  1106. });
  1107. }
  1108. data = numData;
  1109. return true;
  1110. }
  1111. });
  1112. return {
  1113. data,
  1114. skipNext,
  1115. name: option?.[0],
  1116. option: option?.[1]
  1117. };
  1118. };
  1119. var parseOptions = (command3, args, cliName, cliDescription, omitKeysOfUndefinedOptions) => {
  1120. const options = command3.options;
  1121. const optEntries = Object.entries(options ?? {}).map(
  1122. (opt) => [opt[0], opt[1].config]
  1123. );
  1124. const nonPositionalEntries = optEntries.filter(([key, opt]) => opt.type !== "positional");
  1125. const positionalEntries = optEntries.filter(([key, opt]) => opt.type === "positional");
  1126. const result = {};
  1127. const missingRequiredArr = [];
  1128. const unrecognizedArgsArr = [];
  1129. for (let i = 0; i < args.length; ++i) {
  1130. const arg = args[i];
  1131. const nextArg = args[i + 1];
  1132. const {
  1133. data,
  1134. name,
  1135. option,
  1136. skipNext,
  1137. isHelp,
  1138. isVersion
  1139. } = parseArg(command3, nonPositionalEntries, positionalEntries, arg, nextArg, cliName, cliDescription);
  1140. if (!option) unrecognizedArgsArr.push(arg.split("=")[0]);
  1141. if (skipNext) ++i;
  1142. if (isHelp) return "help";
  1143. if (isVersion) return "version";
  1144. result[name] = data;
  1145. }
  1146. for (const [optKey, option] of optEntries) {
  1147. const data = result[optKey] ?? option.default;
  1148. if (!omitKeysOfUndefinedOptions) {
  1149. result[optKey] = data;
  1150. } else {
  1151. if (data !== void 0) result[optKey] = data;
  1152. }
  1153. if (option.isRequired && result[optKey] === void 0) missingRequiredArr.push([option.name, ...option.aliases]);
  1154. }
  1155. if (missingRequiredArr.length) {
  1156. throw new BroCliError(void 0, {
  1157. type: "error",
  1158. violation: "missing_args_error",
  1159. name: cliName,
  1160. description: cliDescription,
  1161. command: command3,
  1162. missing: missingRequiredArr
  1163. });
  1164. }
  1165. if (unrecognizedArgsArr.length) {
  1166. throw new BroCliError(void 0, {
  1167. type: "error",
  1168. violation: "unrecognized_args_error",
  1169. name: cliName,
  1170. description: cliDescription,
  1171. command: command3,
  1172. unrecognized: unrecognizedArgsArr
  1173. });
  1174. }
  1175. return Object.keys(result).length ? result : void 0;
  1176. };
  1177. var getCommandNameWithParents = (command3) => command3.parent ? `${getCommandNameWithParents(command3.parent)} ${command3.name}` : command3.name;
  1178. var validateCommands = (commands, parent) => {
  1179. const storedNames = {};
  1180. for (const cmd of commands) {
  1181. const storageVals = Object.values(storedNames);
  1182. for (const storage of storageVals) {
  1183. const nameOccupier = storage.find((e) => e === cmd.name);
  1184. if (!nameOccupier) continue;
  1185. throw new BroCliError(
  1186. `Can't define command '${getCommandNameWithParents(cmd)}': name is already in use by command '${parent ? `${getCommandNameWithParents(parent)} ` : ""}${storage[0]}'!`
  1187. );
  1188. }
  1189. if (cmd.aliases) {
  1190. for (const alias of cmd.aliases) {
  1191. for (const storage of storageVals) {
  1192. const nameOccupier = storage.find((e) => e === alias);
  1193. if (!nameOccupier) continue;
  1194. throw new BroCliError(
  1195. `Can't define command '${getCommandNameWithParents(cmd)}': alias '${alias}' is already in use by command '${parent ? `${getCommandNameWithParents(parent)} ` : ""}${storage[0]}'!`
  1196. );
  1197. }
  1198. }
  1199. }
  1200. storedNames[cmd.name] = cmd.aliases ? [cmd.name, ...cmd.aliases] : [cmd.name];
  1201. if (cmd.subcommands) cmd.subcommands = validateCommands(cmd.subcommands, cmd);
  1202. }
  1203. return commands;
  1204. };
  1205. var removeByIndex = (arr, idx) => [...arr.slice(0, idx), ...arr.slice(idx + 1, arr.length)];
  1206. var run = async (commands, config) => {
  1207. const eventHandler = config?.theme ? eventHandlerWrapper(config.theme) : defaultEventHandler;
  1208. const argSource = config?.argSource ?? process.argv;
  1209. const version = config?.version;
  1210. const help = config?.help;
  1211. const omitKeysOfUndefinedOptions = config?.omitKeysOfUndefinedOptions ?? false;
  1212. const cliName = config?.name;
  1213. const cliDescription = config?.description;
  1214. try {
  1215. const processedCmds = validateCommands(commands);
  1216. let args = argSource.slice(2, argSource.length);
  1217. if (!args.length) {
  1218. return help !== void 0 ? await executeOrLog(help) : await eventHandler({
  1219. type: "global_help",
  1220. description: cliDescription,
  1221. name: cliName,
  1222. commands: processedCmds
  1223. });
  1224. }
  1225. const helpIndex = args.findIndex((arg) => arg === "--help" || arg === "-h");
  1226. if (helpIndex !== -1 && (helpIndex > 0 ? args[helpIndex - 1]?.startsWith("-") && !args[helpIndex - 1].includes("=") ? false : true : true)) {
  1227. const command4 = getCommand(processedCmds, args, cliName, cliDescription).command;
  1228. if (typeof command4 === "object") {
  1229. return command4.help !== void 0 ? await executeOrLog(command4.help) : await eventHandler({
  1230. type: "command_help",
  1231. description: cliDescription,
  1232. name: cliName,
  1233. command: command4
  1234. });
  1235. } else {
  1236. return help !== void 0 ? await executeOrLog(help) : await eventHandler({
  1237. type: "global_help",
  1238. description: cliDescription,
  1239. name: cliName,
  1240. commands: processedCmds
  1241. });
  1242. }
  1243. }
  1244. const versionIndex = args.findIndex((arg) => arg === "--version" || arg === "-v");
  1245. if (versionIndex !== -1 && (versionIndex > 0 ? args[versionIndex - 1]?.startsWith("-") ? false : true : true)) {
  1246. return version !== void 0 ? await executeOrLog(version) : await eventHandler({
  1247. type: "version",
  1248. name: cliName,
  1249. description: cliDescription
  1250. });
  1251. }
  1252. const { command: command3, args: newArgs } = getCommand(processedCmds, args, cliName, cliDescription);
  1253. if (!command3) {
  1254. return help !== void 0 ? await executeOrLog(help) : await eventHandler({
  1255. type: "global_help",
  1256. description: cliDescription,
  1257. name: cliName,
  1258. commands: processedCmds
  1259. });
  1260. }
  1261. if (command3 === "help") {
  1262. let helpCommand;
  1263. let newestArgs = newArgs;
  1264. do {
  1265. const res = getCommand(processedCmds, newestArgs, cliName, cliDescription);
  1266. helpCommand = res.command;
  1267. newestArgs = res.args;
  1268. } while (helpCommand === "help");
  1269. return helpCommand ? helpCommand.help !== void 0 ? await executeOrLog(helpCommand.help) : await eventHandler({
  1270. type: "command_help",
  1271. description: cliDescription,
  1272. name: cliName,
  1273. command: helpCommand
  1274. }) : help !== void 0 ? await executeOrLog(help) : await eventHandler({
  1275. type: "global_help",
  1276. description: cliDescription,
  1277. name: cliName,
  1278. commands: processedCmds
  1279. });
  1280. }
  1281. const optionResult = parseOptions(command3, newArgs, cliName, cliDescription, omitKeysOfUndefinedOptions);
  1282. if (optionResult === "help") {
  1283. return command3.help !== void 0 ? await executeOrLog(command3.help) : await eventHandler({
  1284. type: "command_help",
  1285. description: cliDescription,
  1286. name: cliName,
  1287. command: command3
  1288. });
  1289. }
  1290. if (optionResult === "version") {
  1291. return version !== void 0 ? await executeOrLog(version) : await eventHandler({
  1292. type: "version",
  1293. name: cliName,
  1294. description: cliDescription
  1295. });
  1296. }
  1297. if (command3.handler) {
  1298. if (config?.hook) await config.hook("before", command3);
  1299. await command3.handler(command3.transform ? await command3.transform(optionResult) : optionResult);
  1300. if (config?.hook) await config.hook("after", command3);
  1301. return;
  1302. } else {
  1303. return command3.help !== void 0 ? await executeOrLog(command3.help) : await eventHandler({
  1304. type: "command_help",
  1305. description: cliDescription,
  1306. name: cliName,
  1307. command: command3
  1308. });
  1309. }
  1310. } catch (e) {
  1311. if (e instanceof BroCliError) {
  1312. if (e.event) await eventHandler(e.event);
  1313. else {
  1314. if (!config?.noExit) console.error(e.message);
  1315. else return e.message;
  1316. }
  1317. } else {
  1318. await eventHandler({
  1319. type: "error",
  1320. violation: "unknown_error",
  1321. name: cliName,
  1322. description: cliDescription,
  1323. error: e
  1324. });
  1325. }
  1326. if (!config?.noExit) process.exit(1);
  1327. return;
  1328. }
  1329. };
  1330. var handler = (options, handler2) => handler2;
  1331. var test = async (command3, args) => {
  1332. try {
  1333. const cliParsedArgs = shellArgs(args);
  1334. const options = parseOptions(command3, cliParsedArgs, void 0, void 0);
  1335. if (options === "help" || options === "version") {
  1336. return {
  1337. type: options
  1338. };
  1339. }
  1340. return {
  1341. options: command3.transform ? await command3.transform(options) : options,
  1342. type: "handler"
  1343. };
  1344. } catch (e) {
  1345. return {
  1346. type: "error",
  1347. error: e
  1348. };
  1349. }
  1350. };
  1351. var commandsInfo = (commands) => {
  1352. const validated = validateCommands(commands);
  1353. return Object.fromEntries(validated.map((c) => [c.name, {
  1354. name: c.name,
  1355. aliases: (0, import_clone.default)(c.aliases),
  1356. desc: c.desc,
  1357. shortDesc: c.shortDesc,
  1358. isHidden: c.hidden,
  1359. options: c.options ? Object.fromEntries(Object.entries(c.options).map(([key, opt]) => [key, (0, import_clone.default)(opt.config)])) : void 0,
  1360. metadata: (0, import_clone.default)(c.metadata),
  1361. subcommands: c.subcommands ? commandsInfo(c.subcommands) : void 0
  1362. }]));
  1363. };
  1364. // src/option-builder.ts
  1365. var OptionBuilderBase = class _OptionBuilderBase {
  1366. _;
  1367. config = () => this._.config;
  1368. constructor(config) {
  1369. this._ = {
  1370. config: config ?? {
  1371. aliases: [],
  1372. type: "string"
  1373. },
  1374. $output: void 0
  1375. };
  1376. }
  1377. string(name) {
  1378. const config = this.config();
  1379. return new _OptionBuilderBase({ ...config, type: "string", name });
  1380. }
  1381. number(name) {
  1382. const config = this.config();
  1383. return new _OptionBuilderBase({ ...config, type: "number", name });
  1384. }
  1385. boolean(name) {
  1386. const config = this.config();
  1387. return new _OptionBuilderBase({ ...config, type: "boolean", name });
  1388. }
  1389. positional(displayName) {
  1390. const config = this.config();
  1391. return new _OptionBuilderBase({ ...config, type: "positional", name: displayName });
  1392. }
  1393. alias(...aliases) {
  1394. const config = this.config();
  1395. return new _OptionBuilderBase({ ...config, aliases });
  1396. }
  1397. desc(description) {
  1398. const config = this.config();
  1399. return new _OptionBuilderBase({ ...config, description });
  1400. }
  1401. hidden() {
  1402. const config = this.config();
  1403. return new _OptionBuilderBase({ ...config, isHidden: true });
  1404. }
  1405. required() {
  1406. const config = this.config();
  1407. return new _OptionBuilderBase({ ...config, isRequired: true });
  1408. }
  1409. default(value) {
  1410. const config = this.config();
  1411. const enums = config.enumVals;
  1412. if (enums && !enums.find((v) => value === v)) {
  1413. throw new Error(
  1414. `Option enums [ ${enums.join(", ")} ] are incompatible with default value ${value}`
  1415. );
  1416. }
  1417. return new _OptionBuilderBase({ ...config, default: value });
  1418. }
  1419. enum(...values) {
  1420. const config = this.config();
  1421. const defaultVal = config.default;
  1422. if (defaultVal !== void 0 && !values.find((v) => defaultVal === v)) {
  1423. throw new Error(
  1424. `Option enums [ ${values.join(", ")} ] are incompatible with default value ${defaultVal}`
  1425. );
  1426. }
  1427. return new _OptionBuilderBase({ ...config, enumVals: values });
  1428. }
  1429. min(value) {
  1430. const config = this.config();
  1431. const maxVal = config.maxVal;
  1432. if (maxVal !== void 0 && maxVal < value) {
  1433. throw new BroCliError("Unable to define option's min value to be higher than max value!");
  1434. }
  1435. return new _OptionBuilderBase({ ...config, minVal: value });
  1436. }
  1437. max(value) {
  1438. const config = this.config();
  1439. const minVal = config.minVal;
  1440. if (minVal !== void 0 && minVal > value) {
  1441. throw new BroCliError("Unable to define option's max value to be lower than min value!");
  1442. }
  1443. return new _OptionBuilderBase({ ...config, maxVal: value });
  1444. }
  1445. int() {
  1446. const config = this.config();
  1447. return new _OptionBuilderBase({ ...config, isInt: true });
  1448. }
  1449. };
  1450. function string(name) {
  1451. return typeof name === "string" ? new OptionBuilderBase().string(name) : new OptionBuilderBase().string();
  1452. }
  1453. function number(name) {
  1454. return typeof name === "string" ? new OptionBuilderBase().number(name) : new OptionBuilderBase().number();
  1455. }
  1456. function boolean(name) {
  1457. return typeof name === "string" ? new OptionBuilderBase().boolean(name) : new OptionBuilderBase().boolean();
  1458. }
  1459. function positional(displayName) {
  1460. return typeof displayName === "string" ? new OptionBuilderBase().positional(displayName) : new OptionBuilderBase().positional();
  1461. }
  1462. export {
  1463. BroCliError,
  1464. boolean,
  1465. command2 as command,
  1466. commandsInfo,
  1467. getCommandNameWithParents,
  1468. handler,
  1469. number,
  1470. positional,
  1471. run,
  1472. string,
  1473. test
  1474. };
  1475. //# sourceMappingURL=index.js.map