yargs.js 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.isYargsInstance = exports.rebase = exports.Yargs = void 0;
  4. const command_1 = require("./command");
  5. const common_types_1 = require("./common-types");
  6. const yerror_1 = require("./yerror");
  7. const usage_1 = require("./usage");
  8. const argsert_1 = require("./argsert");
  9. const fs = require("fs");
  10. const completion_1 = require("./completion");
  11. const path = require("path");
  12. const validation_1 = require("./validation");
  13. const obj_filter_1 = require("./obj-filter");
  14. const apply_extends_1 = require("./apply-extends");
  15. const middleware_1 = require("./middleware");
  16. const processArgv = require("./process-argv");
  17. const is_promise_1 = require("./is-promise");
  18. const Parser = require("yargs-parser");
  19. const y18nFactory = require("y18n");
  20. const setBlocking = require("set-blocking");
  21. const findUp = require("find-up");
  22. const requireMainFilename = require("require-main-filename");
  23. function Yargs(processArgs = [], cwd = process.cwd(), parentRequire = require) {
  24. const self = {};
  25. let command;
  26. let completion = null;
  27. let groups = {};
  28. const globalMiddleware = [];
  29. let output = '';
  30. const preservedGroups = {};
  31. let usage;
  32. let validation;
  33. let handlerFinishCommand = null;
  34. const y18n = y18nFactory({
  35. directory: path.resolve(__dirname, '../../locales'),
  36. updateFiles: false
  37. });
  38. self.middleware = middleware_1.globalMiddlewareFactory(globalMiddleware, self);
  39. self.scriptName = function (scriptName) {
  40. self.customScriptName = true;
  41. self.$0 = scriptName;
  42. return self;
  43. };
  44. // ignore the node bin, specify this in your
  45. // bin file with #!/usr/bin/env node
  46. let default$0;
  47. if (/\b(node|iojs|electron)(\.exe)?$/.test(process.argv[0])) {
  48. default$0 = process.argv.slice(1, 2);
  49. }
  50. else {
  51. default$0 = process.argv.slice(0, 1);
  52. }
  53. self.$0 = default$0
  54. .map(x => {
  55. const b = rebase(cwd, x);
  56. return x.match(/^(\/|([a-zA-Z]:)?\\)/) && b.length < x.length ? b : x;
  57. })
  58. .join(' ').trim();
  59. if (process.env._ !== undefined && processArgv.getProcessArgvBin() === process.env._) {
  60. self.$0 = process.env._.replace(`${path.dirname(process.execPath)}/`, '');
  61. }
  62. // use context object to keep track of resets, subcommand execution, etc
  63. // submodules should modify and check the state of context as necessary
  64. const context = { resets: -1, commands: [], fullCommands: [], files: [] };
  65. self.getContext = () => context;
  66. // puts yargs back into an initial state. any keys
  67. // that have been set to "global" will not be reset
  68. // by this action.
  69. let options;
  70. self.resetOptions = self.reset = function resetOptions(aliases = {}) {
  71. context.resets++;
  72. options = options || {};
  73. // put yargs back into an initial state, this
  74. // logic is used to build a nested command
  75. // hierarchy.
  76. const tmpOptions = {};
  77. tmpOptions.local = options.local ? options.local : [];
  78. tmpOptions.configObjects = options.configObjects ? options.configObjects : [];
  79. // if a key has been explicitly set as local,
  80. // we should reset it before passing options to command.
  81. const localLookup = {};
  82. tmpOptions.local.forEach((l) => {
  83. localLookup[l] = true;
  84. (aliases[l] || []).forEach((a) => {
  85. localLookup[a] = true;
  86. });
  87. });
  88. // add all groups not set to local to preserved groups
  89. Object.assign(preservedGroups, Object.keys(groups).reduce((acc, groupName) => {
  90. const keys = groups[groupName].filter(key => !(key in localLookup));
  91. if (keys.length > 0) {
  92. acc[groupName] = keys;
  93. }
  94. return acc;
  95. }, {}));
  96. // groups can now be reset
  97. groups = {};
  98. const arrayOptions = [
  99. 'array', 'boolean', 'string', 'skipValidation',
  100. 'count', 'normalize', 'number',
  101. 'hiddenOptions'
  102. ];
  103. const objectOptions = [
  104. 'narg', 'key', 'alias', 'default', 'defaultDescription',
  105. 'config', 'choices', 'demandedOptions', 'demandedCommands', 'coerce',
  106. 'deprecatedOptions'
  107. ];
  108. arrayOptions.forEach(k => {
  109. tmpOptions[k] = (options[k] || []).filter(k => !localLookup[k]);
  110. });
  111. objectOptions.forEach((k) => {
  112. tmpOptions[k] = obj_filter_1.objFilter(options[k], k => !localLookup[k]);
  113. });
  114. tmpOptions.envPrefix = options.envPrefix;
  115. options = tmpOptions;
  116. // if this is the first time being executed, create
  117. // instances of all our helpers -- otherwise just reset.
  118. usage = usage ? usage.reset(localLookup) : usage_1.usage(self, y18n);
  119. validation = validation ? validation.reset(localLookup) : validation_1.validation(self, usage, y18n);
  120. command = command ? command.reset() : command_1.command(self, usage, validation, globalMiddleware);
  121. if (!completion)
  122. completion = completion_1.completion(self, usage, command);
  123. completionCommand = null;
  124. output = '';
  125. exitError = null;
  126. hasOutput = false;
  127. self.parsed = false;
  128. return self;
  129. };
  130. self.resetOptions();
  131. // temporary hack: allow "freezing" of reset-able state for parse(msg, cb)
  132. const frozens = [];
  133. function freeze() {
  134. frozens.push({
  135. options,
  136. configObjects: options.configObjects.slice(0),
  137. exitProcess,
  138. groups,
  139. strict,
  140. strictCommands,
  141. completionCommand,
  142. output,
  143. exitError,
  144. hasOutput,
  145. parsed: self.parsed,
  146. parseFn,
  147. parseContext,
  148. handlerFinishCommand
  149. });
  150. usage.freeze();
  151. validation.freeze();
  152. command.freeze();
  153. }
  154. function unfreeze() {
  155. const frozen = frozens.pop();
  156. common_types_1.assertNotStrictEqual(frozen, undefined);
  157. let configObjects;
  158. ({
  159. options,
  160. configObjects,
  161. exitProcess,
  162. groups,
  163. output,
  164. exitError,
  165. hasOutput,
  166. parsed: self.parsed,
  167. strict,
  168. strictCommands,
  169. completionCommand,
  170. parseFn,
  171. parseContext,
  172. handlerFinishCommand
  173. } = frozen);
  174. options.configObjects = configObjects;
  175. usage.unfreeze();
  176. validation.unfreeze();
  177. command.unfreeze();
  178. }
  179. self.boolean = function (keys) {
  180. argsert_1.argsert('<array|string>', [keys], arguments.length);
  181. populateParserHintArray('boolean', keys);
  182. return self;
  183. };
  184. self.array = function (keys) {
  185. argsert_1.argsert('<array|string>', [keys], arguments.length);
  186. populateParserHintArray('array', keys);
  187. return self;
  188. };
  189. self.number = function (keys) {
  190. argsert_1.argsert('<array|string>', [keys], arguments.length);
  191. populateParserHintArray('number', keys);
  192. return self;
  193. };
  194. self.normalize = function (keys) {
  195. argsert_1.argsert('<array|string>', [keys], arguments.length);
  196. populateParserHintArray('normalize', keys);
  197. return self;
  198. };
  199. self.count = function (keys) {
  200. argsert_1.argsert('<array|string>', [keys], arguments.length);
  201. populateParserHintArray('count', keys);
  202. return self;
  203. };
  204. self.string = function (keys) {
  205. argsert_1.argsert('<array|string>', [keys], arguments.length);
  206. populateParserHintArray('string', keys);
  207. return self;
  208. };
  209. self.requiresArg = function (keys) {
  210. // the 2nd paramter [number] in the argsert the assertion is mandatory
  211. // as populateParserHintSingleValueDictionary recursively calls requiresArg
  212. // with Nan as a 2nd parameter, although we ignore it
  213. argsert_1.argsert('<array|string|object> [number]', [keys], arguments.length);
  214. // If someone configures nargs at the same time as requiresArg,
  215. // nargs should take precedent,
  216. // see: https://github.com/yargs/yargs/pull/1572
  217. // TODO: make this work with aliases, using a check similar to
  218. // checkAllAliases() in yargs-parser.
  219. if (typeof keys === 'string' && options.narg[keys]) {
  220. return self;
  221. }
  222. else {
  223. populateParserHintSingleValueDictionary(self.requiresArg, 'narg', keys, NaN);
  224. }
  225. return self;
  226. };
  227. self.skipValidation = function (keys) {
  228. argsert_1.argsert('<array|string>', [keys], arguments.length);
  229. populateParserHintArray('skipValidation', keys);
  230. return self;
  231. };
  232. function populateParserHintArray(type, keys) {
  233. keys = [].concat(keys);
  234. keys.forEach((key) => {
  235. key = sanitizeKey(key);
  236. options[type].push(key);
  237. });
  238. }
  239. self.nargs = function (key, value) {
  240. argsert_1.argsert('<string|object|array> [number]', [key, value], arguments.length);
  241. populateParserHintSingleValueDictionary(self.nargs, 'narg', key, value);
  242. return self;
  243. };
  244. self.choices = function (key, value) {
  245. argsert_1.argsert('<object|string|array> [string|array]', [key, value], arguments.length);
  246. populateParserHintArrayDictionary(self.choices, 'choices', key, value);
  247. return self;
  248. };
  249. self.alias = function (key, value) {
  250. argsert_1.argsert('<object|string|array> [string|array]', [key, value], arguments.length);
  251. populateParserHintArrayDictionary(self.alias, 'alias', key, value);
  252. return self;
  253. };
  254. // TODO: actually deprecate self.defaults.
  255. self.default = self.defaults = function (key, value, defaultDescription) {
  256. argsert_1.argsert('<object|string|array> [*] [string]', [key, value, defaultDescription], arguments.length);
  257. if (defaultDescription) {
  258. common_types_1.assertSingleKey(key);
  259. options.defaultDescription[key] = defaultDescription;
  260. }
  261. if (typeof value === 'function') {
  262. common_types_1.assertSingleKey(key);
  263. if (!options.defaultDescription[key])
  264. options.defaultDescription[key] = usage.functionDescription(value);
  265. value = value.call();
  266. }
  267. populateParserHintSingleValueDictionary(self.default, 'default', key, value);
  268. return self;
  269. };
  270. self.describe = function (key, desc) {
  271. argsert_1.argsert('<object|string|array> [string]', [key, desc], arguments.length);
  272. setKey(key, true);
  273. usage.describe(key, desc);
  274. return self;
  275. };
  276. function setKey(key, set) {
  277. populateParserHintSingleValueDictionary(setKey, 'key', key, set);
  278. return self;
  279. }
  280. function demandOption(keys, msg) {
  281. argsert_1.argsert('<object|string|array> [string]', [keys, msg], arguments.length);
  282. populateParserHintSingleValueDictionary(self.demandOption, 'demandedOptions', keys, msg);
  283. return self;
  284. }
  285. self.demandOption = demandOption;
  286. self.coerce = function (keys, value) {
  287. argsert_1.argsert('<object|string|array> [function]', [keys, value], arguments.length);
  288. populateParserHintSingleValueDictionary(self.coerce, 'coerce', keys, value);
  289. return self;
  290. };
  291. function populateParserHintSingleValueDictionary(builder, type, key, value) {
  292. populateParserHintDictionary(builder, type, key, value, (type, key, value) => {
  293. options[type][key] = value;
  294. });
  295. }
  296. function populateParserHintArrayDictionary(builder, type, key, value) {
  297. populateParserHintDictionary(builder, type, key, value, (type, key, value) => {
  298. options[type][key] = (options[type][key] || []).concat(value);
  299. });
  300. }
  301. function populateParserHintDictionary(builder, type, key, value, singleKeyHandler) {
  302. if (Array.isArray(key)) {
  303. // an array of keys with one value ['x', 'y', 'z'], function parse () {}
  304. key.forEach((k) => {
  305. builder(k, value);
  306. });
  307. }
  308. else if (((key) => typeof key === 'object')(key)) {
  309. // an object of key value pairs: {'x': parse () {}, 'y': parse() {}}
  310. for (const k of common_types_1.objectKeys(key)) {
  311. builder(k, key[k]);
  312. }
  313. }
  314. else {
  315. singleKeyHandler(type, sanitizeKey(key), value);
  316. }
  317. }
  318. function sanitizeKey(key) {
  319. if (key === '__proto__')
  320. return '___proto___';
  321. return key;
  322. }
  323. function deleteFromParserHintObject(optionKey) {
  324. // delete from all parsing hints:
  325. // boolean, array, key, alias, etc.
  326. common_types_1.objectKeys(options).forEach((hintKey) => {
  327. // configObjects is not a parsing hint array
  328. if (((key) => key === 'configObjects')(hintKey))
  329. return;
  330. const hint = options[hintKey];
  331. if (Array.isArray(hint)) {
  332. if (~hint.indexOf(optionKey))
  333. hint.splice(hint.indexOf(optionKey), 1);
  334. }
  335. else if (typeof hint === 'object') {
  336. delete hint[optionKey];
  337. }
  338. });
  339. // now delete the description from usage.js.
  340. delete usage.getDescriptions()[optionKey];
  341. }
  342. self.config = function config(key = 'config', msg, parseFn) {
  343. argsert_1.argsert('[object|string] [string|function] [function]', [key, msg, parseFn], arguments.length);
  344. // allow a config object to be provided directly.
  345. if ((typeof key === 'object') && !Array.isArray(key)) {
  346. key = apply_extends_1.applyExtends(key, cwd, self.getParserConfiguration()['deep-merge-config']);
  347. options.configObjects = (options.configObjects || []).concat(key);
  348. return self;
  349. }
  350. // allow for a custom parsing function.
  351. if (typeof msg === 'function') {
  352. parseFn = msg;
  353. msg = undefined;
  354. }
  355. self.describe(key, msg || usage.deferY18nLookup('Path to JSON config file'));
  356. (Array.isArray(key) ? key : [key]).forEach((k) => {
  357. options.config[k] = parseFn || true;
  358. });
  359. return self;
  360. };
  361. self.example = function (cmd, description) {
  362. argsert_1.argsert('<string|array> [string]', [cmd, description], arguments.length);
  363. if (Array.isArray(cmd)) {
  364. cmd.forEach((exampleParams) => self.example(...exampleParams));
  365. }
  366. else {
  367. usage.example(cmd, description);
  368. }
  369. return self;
  370. };
  371. self.command = function (cmd, description, builder, handler, middlewares, deprecated) {
  372. argsert_1.argsert('<string|array|object> [string|boolean] [function|object] [function] [array] [boolean|string]', [cmd, description, builder, handler, middlewares, deprecated], arguments.length);
  373. command.addHandler(cmd, description, builder, handler, middlewares, deprecated);
  374. return self;
  375. };
  376. self.commandDir = function (dir, opts) {
  377. argsert_1.argsert('<string> [object]', [dir, opts], arguments.length);
  378. const req = parentRequire || require;
  379. command.addDirectory(dir, self.getContext(), req, require('get-caller-file')(), opts);
  380. return self;
  381. };
  382. // TODO: deprecate self.demand in favor of
  383. // .demandCommand() .demandOption().
  384. self.demand = self.required = self.require = function demand(keys, max, msg) {
  385. // you can optionally provide a 'max' key,
  386. // which will raise an exception if too many '_'
  387. // options are provided.
  388. if (Array.isArray(max)) {
  389. max.forEach((key) => {
  390. common_types_1.assertNotStrictEqual(msg, true);
  391. demandOption(key, msg);
  392. });
  393. max = Infinity;
  394. }
  395. else if (typeof max !== 'number') {
  396. msg = max;
  397. max = Infinity;
  398. }
  399. if (typeof keys === 'number') {
  400. common_types_1.assertNotStrictEqual(msg, true);
  401. self.demandCommand(keys, max, msg, msg);
  402. }
  403. else if (Array.isArray(keys)) {
  404. keys.forEach((key) => {
  405. common_types_1.assertNotStrictEqual(msg, true);
  406. demandOption(key, msg);
  407. });
  408. }
  409. else {
  410. if (typeof msg === 'string') {
  411. demandOption(keys, msg);
  412. }
  413. else if (msg === true || typeof msg === 'undefined') {
  414. demandOption(keys);
  415. }
  416. }
  417. return self;
  418. };
  419. self.demandCommand = function demandCommand(min = 1, max, minMsg, maxMsg) {
  420. argsert_1.argsert('[number] [number|string] [string|null|undefined] [string|null|undefined]', [min, max, minMsg, maxMsg], arguments.length);
  421. if (typeof max !== 'number') {
  422. minMsg = max;
  423. max = Infinity;
  424. }
  425. self.global('_', false);
  426. options.demandedCommands._ = {
  427. min,
  428. max,
  429. minMsg,
  430. maxMsg
  431. };
  432. return self;
  433. };
  434. self.getDemandedOptions = () => {
  435. argsert_1.argsert([], 0);
  436. return options.demandedOptions;
  437. };
  438. self.getDemandedCommands = () => {
  439. argsert_1.argsert([], 0);
  440. return options.demandedCommands;
  441. };
  442. self.deprecateOption = function deprecateOption(option, message) {
  443. argsert_1.argsert('<string> [string|boolean]', [option, message], arguments.length);
  444. options.deprecatedOptions[option] = message;
  445. return self;
  446. };
  447. self.getDeprecatedOptions = () => {
  448. argsert_1.argsert([], 0);
  449. return options.deprecatedOptions;
  450. };
  451. self.implies = function (key, value) {
  452. argsert_1.argsert('<string|object> [number|string|array]', [key, value], arguments.length);
  453. validation.implies(key, value);
  454. return self;
  455. };
  456. self.conflicts = function (key1, key2) {
  457. argsert_1.argsert('<string|object> [string|array]', [key1, key2], arguments.length);
  458. validation.conflicts(key1, key2);
  459. return self;
  460. };
  461. self.usage = function (msg, description, builder, handler) {
  462. argsert_1.argsert('<string|null|undefined> [string|boolean] [function|object] [function]', [msg, description, builder, handler], arguments.length);
  463. if (description !== undefined) {
  464. common_types_1.assertNotStrictEqual(msg, null);
  465. // .usage() can be used as an alias for defining
  466. // a default command.
  467. if ((msg || '').match(/^\$0( |$)/)) {
  468. return self.command(msg, description, builder, handler);
  469. }
  470. else {
  471. throw new yerror_1.YError('.usage() description must start with $0 if being used as alias for .command()');
  472. }
  473. }
  474. else {
  475. usage.usage(msg);
  476. return self;
  477. }
  478. };
  479. self.epilogue = self.epilog = function (msg) {
  480. argsert_1.argsert('<string>', [msg], arguments.length);
  481. usage.epilog(msg);
  482. return self;
  483. };
  484. self.fail = function (f) {
  485. argsert_1.argsert('<function>', [f], arguments.length);
  486. usage.failFn(f);
  487. return self;
  488. };
  489. self.onFinishCommand = function (f) {
  490. argsert_1.argsert('<function>', [f], arguments.length);
  491. handlerFinishCommand = f;
  492. return self;
  493. };
  494. self.getHandlerFinishCommand = () => handlerFinishCommand;
  495. self.check = function (f, _global) {
  496. argsert_1.argsert('<function> [boolean]', [f, _global], arguments.length);
  497. validation.check(f, _global !== false);
  498. return self;
  499. };
  500. self.global = function global(globals, global) {
  501. argsert_1.argsert('<string|array> [boolean]', [globals, global], arguments.length);
  502. globals = [].concat(globals);
  503. if (global !== false) {
  504. options.local = options.local.filter(l => globals.indexOf(l) === -1);
  505. }
  506. else {
  507. globals.forEach((g) => {
  508. if (options.local.indexOf(g) === -1)
  509. options.local.push(g);
  510. });
  511. }
  512. return self;
  513. };
  514. self.pkgConf = function pkgConf(key, rootPath) {
  515. argsert_1.argsert('<string> [string]', [key, rootPath], arguments.length);
  516. let conf = null;
  517. // prefer cwd to require-main-filename in this method
  518. // since we're looking for e.g. "nyc" config in nyc consumer
  519. // rather than "yargs" config in nyc (where nyc is the main filename)
  520. const obj = pkgUp(rootPath || cwd);
  521. // If an object exists in the key, add it to options.configObjects
  522. if (obj[key] && typeof obj[key] === 'object') {
  523. conf = apply_extends_1.applyExtends(obj[key], rootPath || cwd, self.getParserConfiguration()['deep-merge-config']);
  524. options.configObjects = (options.configObjects || []).concat(conf);
  525. }
  526. return self;
  527. };
  528. const pkgs = {};
  529. function pkgUp(rootPath) {
  530. const npath = rootPath || '*';
  531. if (pkgs[npath])
  532. return pkgs[npath];
  533. let obj = {};
  534. try {
  535. let startDir = rootPath || requireMainFilename(parentRequire);
  536. // When called in an environment that lacks require.main.filename, such as a jest test runner,
  537. // startDir is already process.cwd(), and should not be shortened.
  538. // Whether or not it is _actually_ a directory (e.g., extensionless bin) is irrelevant, find-up handles it.
  539. if (!rootPath && path.extname(startDir)) {
  540. startDir = path.dirname(startDir);
  541. }
  542. const pkgJsonPath = findUp.sync('package.json', {
  543. cwd: startDir
  544. });
  545. common_types_1.assertNotStrictEqual(pkgJsonPath, undefined);
  546. obj = JSON.parse(fs.readFileSync(pkgJsonPath).toString());
  547. }
  548. catch (noop) { }
  549. pkgs[npath] = obj || {};
  550. return pkgs[npath];
  551. }
  552. let parseFn = null;
  553. let parseContext = null;
  554. self.parse = function parse(args, shortCircuit, _parseFn) {
  555. argsert_1.argsert('[string|array] [function|boolean|object] [function]', [args, shortCircuit, _parseFn], arguments.length);
  556. freeze();
  557. if (typeof args === 'undefined') {
  558. const argv = self._parseArgs(processArgs);
  559. const tmpParsed = self.parsed;
  560. unfreeze();
  561. // TODO: remove this compatibility hack when we release yargs@15.x:
  562. self.parsed = tmpParsed;
  563. return argv;
  564. }
  565. // a context object can optionally be provided, this allows
  566. // additional information to be passed to a command handler.
  567. if (typeof shortCircuit === 'object') {
  568. parseContext = shortCircuit;
  569. shortCircuit = _parseFn;
  570. }
  571. // by providing a function as a second argument to
  572. // parse you can capture output that would otherwise
  573. // default to printing to stdout/stderr.
  574. if (typeof shortCircuit === 'function') {
  575. parseFn = shortCircuit;
  576. shortCircuit = false;
  577. }
  578. // completion short-circuits the parsing process,
  579. // skipping validation, etc.
  580. if (!shortCircuit)
  581. processArgs = args;
  582. if (parseFn)
  583. exitProcess = false;
  584. const parsed = self._parseArgs(args, !!shortCircuit);
  585. completion.setParsed(self.parsed);
  586. if (parseFn)
  587. parseFn(exitError, parsed, output);
  588. unfreeze();
  589. return parsed;
  590. };
  591. self._getParseContext = () => parseContext || {};
  592. self._hasParseCallback = () => !!parseFn;
  593. self.option = self.options = function option(key, opt) {
  594. argsert_1.argsert('<string|object> [object]', [key, opt], arguments.length);
  595. if (typeof key === 'object') {
  596. Object.keys(key).forEach((k) => {
  597. self.options(k, key[k]);
  598. });
  599. }
  600. else {
  601. if (typeof opt !== 'object') {
  602. opt = {};
  603. }
  604. options.key[key] = true; // track manually set keys.
  605. if (opt.alias)
  606. self.alias(key, opt.alias);
  607. const deprecate = opt.deprecate || opt.deprecated;
  608. if (deprecate) {
  609. self.deprecateOption(key, deprecate);
  610. }
  611. const demand = opt.demand || opt.required || opt.require;
  612. // A required option can be specified via "demand: true".
  613. if (demand) {
  614. self.demand(key, demand);
  615. }
  616. if (opt.demandOption) {
  617. self.demandOption(key, typeof opt.demandOption === 'string' ? opt.demandOption : undefined);
  618. }
  619. if (opt.conflicts) {
  620. self.conflicts(key, opt.conflicts);
  621. }
  622. if ('default' in opt) {
  623. self.default(key, opt.default);
  624. }
  625. if (opt.implies !== undefined) {
  626. self.implies(key, opt.implies);
  627. }
  628. if (opt.nargs !== undefined) {
  629. self.nargs(key, opt.nargs);
  630. }
  631. if (opt.config) {
  632. self.config(key, opt.configParser);
  633. }
  634. if (opt.normalize) {
  635. self.normalize(key);
  636. }
  637. if (opt.choices) {
  638. self.choices(key, opt.choices);
  639. }
  640. if (opt.coerce) {
  641. self.coerce(key, opt.coerce);
  642. }
  643. if (opt.group) {
  644. self.group(key, opt.group);
  645. }
  646. if (opt.boolean || opt.type === 'boolean') {
  647. self.boolean(key);
  648. if (opt.alias)
  649. self.boolean(opt.alias);
  650. }
  651. if (opt.array || opt.type === 'array') {
  652. self.array(key);
  653. if (opt.alias)
  654. self.array(opt.alias);
  655. }
  656. if (opt.number || opt.type === 'number') {
  657. self.number(key);
  658. if (opt.alias)
  659. self.number(opt.alias);
  660. }
  661. if (opt.string || opt.type === 'string') {
  662. self.string(key);
  663. if (opt.alias)
  664. self.string(opt.alias);
  665. }
  666. if (opt.count || opt.type === 'count') {
  667. self.count(key);
  668. }
  669. if (typeof opt.global === 'boolean') {
  670. self.global(key, opt.global);
  671. }
  672. if (opt.defaultDescription) {
  673. options.defaultDescription[key] = opt.defaultDescription;
  674. }
  675. if (opt.skipValidation) {
  676. self.skipValidation(key);
  677. }
  678. const desc = opt.describe || opt.description || opt.desc;
  679. self.describe(key, desc);
  680. if (opt.hidden) {
  681. self.hide(key);
  682. }
  683. if (opt.requiresArg) {
  684. self.requiresArg(key);
  685. }
  686. }
  687. return self;
  688. };
  689. self.getOptions = () => options;
  690. self.positional = function (key, opts) {
  691. argsert_1.argsert('<string> <object>', [key, opts], arguments.length);
  692. if (context.resets === 0) {
  693. throw new yerror_1.YError(".positional() can only be called in a command's builder function");
  694. }
  695. // .positional() only supports a subset of the configuration
  696. // options available to .option().
  697. const supportedOpts = ['default', 'defaultDescription', 'implies', 'normalize',
  698. 'choices', 'conflicts', 'coerce', 'type', 'describe',
  699. 'desc', 'description', 'alias'];
  700. opts = obj_filter_1.objFilter(opts, (k, v) => {
  701. let accept = supportedOpts.indexOf(k) !== -1;
  702. // type can be one of string|number|boolean.
  703. if (k === 'type' && ['string', 'number', 'boolean'].indexOf(v) === -1)
  704. accept = false;
  705. return accept;
  706. });
  707. // copy over any settings that can be inferred from the command string.
  708. const fullCommand = context.fullCommands[context.fullCommands.length - 1];
  709. const parseOptions = fullCommand ? command.cmdToParseOptions(fullCommand) : {
  710. array: [],
  711. alias: {},
  712. default: {},
  713. demand: {}
  714. };
  715. common_types_1.objectKeys(parseOptions).forEach((pk) => {
  716. const parseOption = parseOptions[pk];
  717. if (Array.isArray(parseOption)) {
  718. if (parseOption.indexOf(key) !== -1)
  719. opts[pk] = true;
  720. }
  721. else {
  722. if (parseOption[key] && !(pk in opts))
  723. opts[pk] = parseOption[key];
  724. }
  725. });
  726. self.group(key, usage.getPositionalGroupName());
  727. return self.option(key, opts);
  728. };
  729. self.group = function group(opts, groupName) {
  730. argsert_1.argsert('<string|array> <string>', [opts, groupName], arguments.length);
  731. const existing = preservedGroups[groupName] || groups[groupName];
  732. if (preservedGroups[groupName]) {
  733. // we now only need to track this group name in groups.
  734. delete preservedGroups[groupName];
  735. }
  736. const seen = {};
  737. groups[groupName] = (existing || []).concat(opts).filter((key) => {
  738. if (seen[key])
  739. return false;
  740. return (seen[key] = true);
  741. });
  742. return self;
  743. };
  744. // combine explicit and preserved groups. explicit groups should be first
  745. self.getGroups = () => Object.assign({}, groups, preservedGroups);
  746. // as long as options.envPrefix is not undefined,
  747. // parser will apply env vars matching prefix to argv
  748. self.env = function (prefix) {
  749. argsert_1.argsert('[string|boolean]', [prefix], arguments.length);
  750. if (prefix === false)
  751. delete options.envPrefix;
  752. else
  753. options.envPrefix = prefix || '';
  754. return self;
  755. };
  756. self.wrap = function (cols) {
  757. argsert_1.argsert('<number|null|undefined>', [cols], arguments.length);
  758. usage.wrap(cols);
  759. return self;
  760. };
  761. let strict = false;
  762. self.strict = function (enabled) {
  763. argsert_1.argsert('[boolean]', [enabled], arguments.length);
  764. strict = enabled !== false;
  765. return self;
  766. };
  767. self.getStrict = () => strict;
  768. let strictCommands = false;
  769. self.strictCommands = function (enabled) {
  770. argsert_1.argsert('[boolean]', [enabled], arguments.length);
  771. strictCommands = enabled !== false;
  772. return self;
  773. };
  774. self.getStrictCommands = () => strictCommands;
  775. let parserConfig = {};
  776. self.parserConfiguration = function parserConfiguration(config) {
  777. argsert_1.argsert('<object>', [config], arguments.length);
  778. parserConfig = config;
  779. return self;
  780. };
  781. self.getParserConfiguration = () => parserConfig;
  782. self.showHelp = function (level) {
  783. argsert_1.argsert('[string|function]', [level], arguments.length);
  784. if (!self.parsed)
  785. self._parseArgs(processArgs); // run parser, if it has not already been executed.
  786. if (command.hasDefaultCommand()) {
  787. context.resets++; // override the restriction on top-level positoinals.
  788. command.runDefaultBuilderOn(self);
  789. }
  790. usage.showHelp(level);
  791. return self;
  792. };
  793. let versionOpt = null;
  794. self.version = function version(opt, msg, ver) {
  795. const defaultVersionOpt = 'version';
  796. argsert_1.argsert('[boolean|string] [string] [string]', [opt, msg, ver], arguments.length);
  797. // nuke the key previously configured
  798. // to return version #.
  799. if (versionOpt) {
  800. deleteFromParserHintObject(versionOpt);
  801. usage.version(undefined);
  802. versionOpt = null;
  803. }
  804. if (arguments.length === 0) {
  805. ver = guessVersion();
  806. opt = defaultVersionOpt;
  807. }
  808. else if (arguments.length === 1) {
  809. if (opt === false) { // disable default 'version' key.
  810. return self;
  811. }
  812. ver = opt;
  813. opt = defaultVersionOpt;
  814. }
  815. else if (arguments.length === 2) {
  816. ver = msg;
  817. msg = undefined;
  818. }
  819. versionOpt = typeof opt === 'string' ? opt : defaultVersionOpt;
  820. msg = msg || usage.deferY18nLookup('Show version number');
  821. usage.version(ver || undefined);
  822. self.boolean(versionOpt);
  823. self.describe(versionOpt, msg);
  824. return self;
  825. };
  826. function guessVersion() {
  827. const obj = pkgUp();
  828. return obj.version || 'unknown';
  829. }
  830. let helpOpt = null;
  831. self.addHelpOpt = self.help = function addHelpOpt(opt, msg) {
  832. const defaultHelpOpt = 'help';
  833. argsert_1.argsert('[string|boolean] [string]', [opt, msg], arguments.length);
  834. // nuke the key previously configured
  835. // to return help.
  836. if (helpOpt) {
  837. deleteFromParserHintObject(helpOpt);
  838. helpOpt = null;
  839. }
  840. if (arguments.length === 1) {
  841. if (opt === false)
  842. return self;
  843. }
  844. // use arguments, fallback to defaults for opt and msg
  845. helpOpt = typeof opt === 'string' ? opt : defaultHelpOpt;
  846. self.boolean(helpOpt);
  847. self.describe(helpOpt, msg || usage.deferY18nLookup('Show help'));
  848. return self;
  849. };
  850. const defaultShowHiddenOpt = 'show-hidden';
  851. options.showHiddenOpt = defaultShowHiddenOpt;
  852. self.addShowHiddenOpt = self.showHidden = function addShowHiddenOpt(opt, msg) {
  853. argsert_1.argsert('[string|boolean] [string]', [opt, msg], arguments.length);
  854. if (arguments.length === 1) {
  855. if (opt === false)
  856. return self;
  857. }
  858. const showHiddenOpt = typeof opt === 'string' ? opt : defaultShowHiddenOpt;
  859. self.boolean(showHiddenOpt);
  860. self.describe(showHiddenOpt, msg || usage.deferY18nLookup('Show hidden options'));
  861. options.showHiddenOpt = showHiddenOpt;
  862. return self;
  863. };
  864. self.hide = function hide(key) {
  865. argsert_1.argsert('<string>', [key], arguments.length);
  866. options.hiddenOptions.push(key);
  867. return self;
  868. };
  869. self.showHelpOnFail = function showHelpOnFail(enabled, message) {
  870. argsert_1.argsert('[boolean|string] [string]', [enabled, message], arguments.length);
  871. usage.showHelpOnFail(enabled, message);
  872. return self;
  873. };
  874. var exitProcess = true;
  875. self.exitProcess = function (enabled = true) {
  876. argsert_1.argsert('[boolean]', [enabled], arguments.length);
  877. exitProcess = enabled;
  878. return self;
  879. };
  880. self.getExitProcess = () => exitProcess;
  881. var completionCommand = null;
  882. self.completion = function (cmd, desc, fn) {
  883. argsert_1.argsert('[string] [string|boolean|function] [function]', [cmd, desc, fn], arguments.length);
  884. // a function to execute when generating
  885. // completions can be provided as the second
  886. // or third argument to completion.
  887. if (typeof desc === 'function') {
  888. fn = desc;
  889. desc = undefined;
  890. }
  891. // register the completion command.
  892. completionCommand = cmd || completionCommand || 'completion';
  893. if (!desc && desc !== false) {
  894. desc = 'generate completion script';
  895. }
  896. self.command(completionCommand, desc);
  897. // a function can be provided
  898. if (fn)
  899. completion.registerFunction(fn);
  900. return self;
  901. };
  902. self.showCompletionScript = function ($0, cmd) {
  903. argsert_1.argsert('[string] [string]', [$0, cmd], arguments.length);
  904. $0 = $0 || self.$0;
  905. _logger.log(completion.generateCompletionScript($0, cmd || completionCommand || 'completion'));
  906. return self;
  907. };
  908. self.getCompletion = function (args, done) {
  909. argsert_1.argsert('<array> <function>', [args, done], arguments.length);
  910. completion.getCompletion(args, done);
  911. };
  912. self.locale = function (locale) {
  913. argsert_1.argsert('[string]', [locale], arguments.length);
  914. if (!locale) {
  915. guessLocale();
  916. return y18n.getLocale();
  917. }
  918. detectLocale = false;
  919. y18n.setLocale(locale);
  920. return self;
  921. };
  922. self.updateStrings = self.updateLocale = function (obj) {
  923. argsert_1.argsert('<object>', [obj], arguments.length);
  924. detectLocale = false;
  925. y18n.updateLocale(obj);
  926. return self;
  927. };
  928. let detectLocale = true;
  929. self.detectLocale = function (detect) {
  930. argsert_1.argsert('<boolean>', [detect], arguments.length);
  931. detectLocale = detect;
  932. return self;
  933. };
  934. self.getDetectLocale = () => detectLocale;
  935. var hasOutput = false;
  936. var exitError = null;
  937. // maybe exit, always capture
  938. // context about why we wanted to exit.
  939. self.exit = (code, err) => {
  940. hasOutput = true;
  941. exitError = err;
  942. if (exitProcess)
  943. process.exit(code);
  944. };
  945. // we use a custom logger that buffers output,
  946. // so that we can print to non-CLIs, e.g., chat-bots.
  947. const _logger = {
  948. log(...args) {
  949. if (!self._hasParseCallback())
  950. console.log(...args);
  951. hasOutput = true;
  952. if (output.length)
  953. output += '\n';
  954. output += args.join(' ');
  955. },
  956. error(...args) {
  957. if (!self._hasParseCallback())
  958. console.error(...args);
  959. hasOutput = true;
  960. if (output.length)
  961. output += '\n';
  962. output += args.join(' ');
  963. }
  964. };
  965. self._getLoggerInstance = () => _logger;
  966. // has yargs output an error our help
  967. // message in the current execution context.
  968. self._hasOutput = () => hasOutput;
  969. self._setHasOutput = () => {
  970. hasOutput = true;
  971. };
  972. let recommendCommands;
  973. self.recommendCommands = function (recommend = true) {
  974. argsert_1.argsert('[boolean]', [recommend], arguments.length);
  975. recommendCommands = recommend;
  976. return self;
  977. };
  978. self.getUsageInstance = () => usage;
  979. self.getValidationInstance = () => validation;
  980. self.getCommandInstance = () => command;
  981. self.terminalWidth = () => {
  982. argsert_1.argsert([], 0);
  983. return typeof process.stdout.columns !== 'undefined' ? process.stdout.columns : null;
  984. };
  985. Object.defineProperty(self, 'argv', {
  986. get: () => self._parseArgs(processArgs),
  987. enumerable: true
  988. });
  989. self._parseArgs = function parseArgs(args, shortCircuit, _calledFromCommand, commandIndex) {
  990. let skipValidation = !!_calledFromCommand;
  991. args = args || processArgs;
  992. options.__ = y18n.__;
  993. options.configuration = self.getParserConfiguration();
  994. const populateDoubleDash = !!options.configuration['populate--'];
  995. const config = Object.assign({}, options.configuration, {
  996. 'populate--': true
  997. });
  998. const parsed = Parser.detailed(args, Object.assign({}, options, {
  999. configuration: config
  1000. }));
  1001. let argv = parsed.argv;
  1002. if (parseContext)
  1003. argv = Object.assign({}, argv, parseContext);
  1004. const aliases = parsed.aliases;
  1005. argv.$0 = self.$0;
  1006. self.parsed = parsed;
  1007. try {
  1008. guessLocale(); // guess locale lazily, so that it can be turned off in chain.
  1009. // while building up the argv object, there
  1010. // are two passes through the parser. If completion
  1011. // is being performed short-circuit on the first pass.
  1012. if (shortCircuit) {
  1013. return (populateDoubleDash || _calledFromCommand) ? argv : self._copyDoubleDash(argv);
  1014. }
  1015. // if there's a handler associated with a
  1016. // command defer processing to it.
  1017. if (helpOpt) {
  1018. // consider any multi-char helpOpt alias as a valid help command
  1019. // unless all helpOpt aliases are single-char
  1020. // note that parsed.aliases is a normalized bidirectional map :)
  1021. const helpCmds = [helpOpt]
  1022. .concat(aliases[helpOpt] || [])
  1023. .filter(k => k.length > 1);
  1024. // check if help should trigger and strip it from _.
  1025. if (~helpCmds.indexOf(argv._[argv._.length - 1])) {
  1026. argv._.pop();
  1027. argv[helpOpt] = true;
  1028. }
  1029. }
  1030. const handlerKeys = command.getCommands();
  1031. const requestCompletions = completion.completionKey in argv;
  1032. const skipRecommendation = argv[helpOpt] || requestCompletions;
  1033. const skipDefaultCommand = skipRecommendation && (handlerKeys.length > 1 || handlerKeys[0] !== '$0');
  1034. if (argv._.length) {
  1035. if (handlerKeys.length) {
  1036. let firstUnknownCommand;
  1037. for (let i = (commandIndex || 0), cmd; argv._[i] !== undefined; i++) {
  1038. cmd = String(argv._[i]);
  1039. if (~handlerKeys.indexOf(cmd) && cmd !== completionCommand) {
  1040. // commands are executed using a recursive algorithm that executes
  1041. // the deepest command first; we keep track of the position in the
  1042. // argv._ array that is currently being executed.
  1043. const innerArgv = command.runCommand(cmd, self, parsed, i + 1);
  1044. return populateDoubleDash ? innerArgv : self._copyDoubleDash(innerArgv);
  1045. }
  1046. else if (!firstUnknownCommand && cmd !== completionCommand) {
  1047. firstUnknownCommand = cmd;
  1048. break;
  1049. }
  1050. }
  1051. // run the default command, if defined
  1052. if (command.hasDefaultCommand() && !skipDefaultCommand) {
  1053. const innerArgv = command.runCommand(null, self, parsed);
  1054. return populateDoubleDash ? innerArgv : self._copyDoubleDash(innerArgv);
  1055. }
  1056. // recommend a command if recommendCommands() has
  1057. // been enabled, and no commands were found to execute
  1058. if (recommendCommands && firstUnknownCommand && !skipRecommendation) {
  1059. validation.recommendCommands(firstUnknownCommand, handlerKeys);
  1060. }
  1061. }
  1062. // generate a completion script for adding to ~/.bashrc.
  1063. if (completionCommand && ~argv._.indexOf(completionCommand) && !requestCompletions) {
  1064. if (exitProcess)
  1065. setBlocking(true);
  1066. self.showCompletionScript();
  1067. self.exit(0);
  1068. }
  1069. }
  1070. else if (command.hasDefaultCommand() && !skipDefaultCommand) {
  1071. const innerArgv = command.runCommand(null, self, parsed);
  1072. return populateDoubleDash ? innerArgv : self._copyDoubleDash(innerArgv);
  1073. }
  1074. // we must run completions first, a user might
  1075. // want to complete the --help or --version option.
  1076. if (requestCompletions) {
  1077. if (exitProcess)
  1078. setBlocking(true);
  1079. // we allow for asynchronous completions,
  1080. // e.g., loading in a list of commands from an API.
  1081. args = [].concat(args);
  1082. const completionArgs = args.slice(args.indexOf(`--${completion.completionKey}`) + 1);
  1083. completion.getCompletion(completionArgs, (completions) => {
  1084. ;
  1085. (completions || []).forEach((completion) => {
  1086. _logger.log(completion);
  1087. });
  1088. self.exit(0);
  1089. });
  1090. return (populateDoubleDash || _calledFromCommand) ? argv : self._copyDoubleDash(argv);
  1091. }
  1092. // Handle 'help' and 'version' options
  1093. // if we haven't already output help!
  1094. if (!hasOutput) {
  1095. Object.keys(argv).forEach((key) => {
  1096. if (key === helpOpt && argv[key]) {
  1097. if (exitProcess)
  1098. setBlocking(true);
  1099. skipValidation = true;
  1100. self.showHelp('log');
  1101. self.exit(0);
  1102. }
  1103. else if (key === versionOpt && argv[key]) {
  1104. if (exitProcess)
  1105. setBlocking(true);
  1106. skipValidation = true;
  1107. usage.showVersion();
  1108. self.exit(0);
  1109. }
  1110. });
  1111. }
  1112. // Check if any of the options to skip validation were provided
  1113. if (!skipValidation && options.skipValidation.length > 0) {
  1114. skipValidation = Object.keys(argv).some(key => options.skipValidation.indexOf(key) >= 0 && argv[key] === true);
  1115. }
  1116. // If the help or version options where used and exitProcess is false,
  1117. // or if explicitly skipped, we won't run validations.
  1118. if (!skipValidation) {
  1119. if (parsed.error)
  1120. throw new yerror_1.YError(parsed.error.message);
  1121. // if we're executed via bash completion, don't
  1122. // bother with validation.
  1123. if (!requestCompletions) {
  1124. self._runValidation(argv, aliases, {}, parsed.error);
  1125. }
  1126. }
  1127. }
  1128. catch (err) {
  1129. if (err instanceof yerror_1.YError)
  1130. usage.fail(err.message, err);
  1131. else
  1132. throw err;
  1133. }
  1134. return (populateDoubleDash || _calledFromCommand) ? argv : self._copyDoubleDash(argv);
  1135. };
  1136. // to simplify the parsing of positionals in commands,
  1137. // we temporarily populate '--' rather than _, with arguments
  1138. // after the '--' directive. After the parse, we copy these back.
  1139. self._copyDoubleDash = function (argv) {
  1140. if (is_promise_1.isPromise(argv) || !argv._ || !argv['--'])
  1141. return argv;
  1142. argv._.push.apply(argv._, argv['--']);
  1143. // TODO(bcoe): refactor command parsing such that this delete is not
  1144. // necessary: https://github.com/yargs/yargs/issues/1482
  1145. try {
  1146. delete argv['--'];
  1147. }
  1148. catch (_err) { }
  1149. return argv;
  1150. };
  1151. self._runValidation = function runValidation(argv, aliases, positionalMap, parseErrors, isDefaultCommand = false) {
  1152. if (parseErrors)
  1153. throw new yerror_1.YError(parseErrors.message);
  1154. validation.nonOptionCount(argv);
  1155. validation.requiredArguments(argv);
  1156. let failedStrictCommands = false;
  1157. if (strictCommands) {
  1158. failedStrictCommands = validation.unknownCommands(argv);
  1159. }
  1160. if (strict && !failedStrictCommands) {
  1161. validation.unknownArguments(argv, aliases, positionalMap, isDefaultCommand);
  1162. }
  1163. validation.customChecks(argv, aliases);
  1164. validation.limitedChoices(argv);
  1165. validation.implications(argv);
  1166. validation.conflicting(argv);
  1167. };
  1168. function guessLocale() {
  1169. if (!detectLocale)
  1170. return;
  1171. const locale = process.env.LC_ALL || process.env.LC_MESSAGES || process.env.LANG || process.env.LANGUAGE || 'en_US';
  1172. self.locale(locale.replace(/[.:].*/, ''));
  1173. }
  1174. // an app should almost always have --version and --help,
  1175. // if you *really* want to disable this use .help(false)/.version(false).
  1176. self.help();
  1177. self.version();
  1178. return self;
  1179. }
  1180. exports.Yargs = Yargs;
  1181. // rebase an absolute path to a relative one with respect to a base directory
  1182. // exported for tests
  1183. function rebase(base, dir) {
  1184. return path.relative(base, dir);
  1185. }
  1186. exports.rebase = rebase;
  1187. function isYargsInstance(y) {
  1188. return !!y && (typeof y._parseArgs === 'function');
  1189. }
  1190. exports.isYargsInstance = isYargsInstance;