'use strict'; const path = require('path'); const buildMinimistOptions = require('minimist-options'); const yargs = require('yargs-parser'); const camelcaseKeys = require('camelcase-keys'); const decamelizeKeys = require('decamelize-keys'); const trimNewlines = require('trim-newlines'); const redent = require('redent'); const readPkgUp = require('read-pkg-up'); const loudRejection = require('loud-rejection'); const normalizePackageData = require('normalize-package-data'); // Prevent caching of this module so module.parent is always accurate delete require.cache[__filename]; const parentDir = path.dirname(module.parent.filename); module.exports = (helpMessage, options) => { loudRejection(); if (typeof helpMessage === 'object' && !Array.isArray(helpMessage)) { options = helpMessage; helpMessage = ''; } options = Object.assign({ pkg: readPkgUp.sync({ cwd: parentDir, normalize: false }).pkg || {}, argv: process.argv.slice(2), inferType: false, input: 'string', help: helpMessage, autoHelp: true, autoVersion: true, booleanDefault: false }, options); const minimistFlags = options.flags && typeof options.booleanDefault !== 'undefined' ? Object.keys(options.flags).reduce( (flags, flag) => { if (flags[flag].type === 'boolean' && !Object.prototype.hasOwnProperty.call(flags[flag], 'default')) { flags[flag].default = options.booleanDefault; } return flags; }, options.flags ) : options.flags; let minimistoptions = Object.assign({ arguments: options.input }, minimistFlags); minimistoptions = decamelizeKeys(minimistoptions, '-', {exclude: ['stopEarly', '--']}); if (options.inferType) { delete minimistoptions.arguments; } minimistoptions = buildMinimistOptions(minimistoptions); if (minimistoptions['--']) { minimistoptions.configuration = Object.assign({}, minimistoptions.configuration, {'populate--': true}); } const {pkg} = options; const argv = yargs(options.argv, minimistoptions); let help = redent(trimNewlines((options.help || '').replace(/\t+\n*$/, '')), 2); normalizePackageData(pkg); process.title = pkg.bin ? Object.keys(pkg.bin)[0] : pkg.name; let {description} = options; if (!description && description !== false) { ({description} = pkg); } help = (description ? `\n ${description}\n` : '') + (help ? `\n${help}\n` : '\n'); const showHelp = code => { console.log(help); process.exit(typeof code === 'number' ? code : 2); }; const showVersion = () => { console.log(typeof options.version === 'string' ? options.version : pkg.version); process.exit(); }; if (argv.version && options.autoVersion) { showVersion(); } if (argv.help && options.autoHelp) { showHelp(0); } const input = argv._; delete argv._; const flags = camelcaseKeys(argv, {exclude: ['--', /^\w$/]}); return { input, flags, pkg, help, showHelp, showVersion }; };