Socket
Socket
Sign inDemoInstall

args

Package Overview
Dependencies
10
Maintainers
1
Versions
43
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.3.0 to 2.4.0

license.md

461

index.js

@@ -1,13 +0,12 @@

'use strict'
'use strict';
// Native
const path = require('path')
const spawn = require('child_process').spawn
const path = require('path');
const spawn = require('child_process').spawn;
// Packages
const parser = require('minimist')
const pkginfo = require('pkginfo')
const loudRejection = require('loud-rejection')
const camelcase = require('camelcase')
const chalk = require('chalk')
const parser = require('minimist');
const pkginfo = require('pkginfo');
const camelcase = require('camelcase');
const chalk = require('chalk');

@@ -19,4 +18,5 @@ class Args {

options: [],
commands: []
}
commands: [],
examples: []
};

@@ -29,33 +29,60 @@ // Configuration defaults

value: null,
name: null
name: null,
mainColor: 'yellow',
subColor: 'dim'
};
this.printMainColor = chalk;
this.printSubColor = chalk;
}
example(usage, description) {
if (typeof usage !== 'string' || typeof description !== 'string') {
throw new Error(
'Usage for adding an Example: args.example("usage", "description")'
);
}
this.details.examples.push({ usage, description });
// Make unhandled promise rejections fail loudly instead of the default silent fail
loudRejection()
return this;
}
examples(list) {
if (list.constructor !== Array) {
throw new Error('Item passed to .examples is not an array');
}
for (const item of list) {
const usage = item.usage || false;
const description = item.description || false;
this.example(usage, description);
}
return this;
}
options(list) {
if (list.constructor !== Array) {
throw new Error('Item passed to .options is not an array')
throw new Error('Item passed to .options is not an array');
}
for (const item of list) {
const preset = item.defaultValue || false
const init = item.init || false
const preset = item.defaultValue || false;
const init = item.init || false;
this.option(item.name, item.description, preset, init)
this.option(item.name, item.description, preset, init);
}
return this
return this;
}
option(name, description, defaultValue, init) {
let usage = []
let usage = [];
const assignShort = (name, options, short) => {
if (options.find(flagName => flagName.usage[0] === short)) {
short = name.charAt(0).toUpperCase()
short = name.charAt(0).toUpperCase();
}
return [short, name]
}
return [short, name];
};

@@ -66,9 +93,9 @@ // If name is an array, pick the values

case String:
usage = assignShort(name, this.details.options, name.charAt(0))
break
usage = assignShort(name, this.details.options, name.charAt(0));
break;
case Array:
usage = usage.concat(name)
break
usage = usage.concat(name);
break;
default:
throw new Error('Invalid name for option')
throw new Error('Invalid name for option');
}

@@ -78,3 +105,3 @@

if (usage.length > 0 && usage[0].length > 1) {
throw new Error('Short version of option is longer than 1 char')
throw new Error('Short version of option is longer than 1 char');
}

@@ -86,18 +113,18 @@

description
}
};
let defaultIsWrong
let defaultIsWrong;
switch (defaultValue) {
case false:
defaultIsWrong = true
break
defaultIsWrong = true;
break;
case null:
defaultIsWrong = true
break
defaultIsWrong = true;
break;
case undefined:
defaultIsWrong = true
break
defaultIsWrong = true;
break;
default:
defaultIsWrong = false
defaultIsWrong = false;
}

@@ -107,11 +134,13 @@

if (!defaultIsWrong) {
const initFunction = typeof init === 'function'
optionDetails.init = initFunction ? init : this.handleType(defaultValue)[1]
const initFunction = typeof init === 'function';
optionDetails.init = initFunction
? init
: this.handleType(defaultValue)[1];
}
// Register option to global scope
this.details.options.push(optionDetails)
this.details.options.push(optionDetails);
// Allow chaining of .option()
return this
return this;
}

@@ -121,7 +150,7 @@

if (Array.isArray(init)) {
aliases = init
init = undefined
aliases = init;
init = undefined;
}
if (aliases && Array.isArray(aliases)) {
usage = [].concat([usage], aliases)
usage = [].concat([usage], aliases);
}

@@ -134,13 +163,13 @@

init: typeof init === 'function' ? init : false
})
});
// Allow chaining of .command()
return this
return this;
}
handleType(value) {
let type = value
let type = value;
if (typeof value !== 'function') {
type = value.constructor
type = value.constructor;
}

@@ -152,10 +181,10 @@

case String:
return ['[value]']
return ['[value]'];
case Array:
return ['<list>']
return ['<list>'];
case Number:
case parseInt:
return ['<n>', parseInt]
return ['<n>', parseInt];
default:
return ['']
return [''];
}

@@ -165,10 +194,10 @@ }

readOption(option) {
let value = false
const contents = {}
let value = false;
const contents = {};
// If option has been used, get its value
for (const name of option.usage) {
const fromArgs = this.raw[name]
const fromArgs = this.raw[name];
if (typeof fromArgs !== 'undefined') {
value = fromArgs
value = fromArgs;
}

@@ -179,9 +208,12 @@ }

for (let name of option.usage) {
let propVal = value
let propVal = value;
if (typeof option.defaultValue !== 'undefined' && typeof propVal !== typeof option.defaultValue) {
propVal = option.defaultValue
if (
typeof option.defaultValue !== 'undefined' &&
typeof propVal !== typeof option.defaultValue
) {
propVal = option.defaultValue;
}
let condition = true
let condition = true;

@@ -191,3 +223,3 @@ if (option.init) {

if (option.init === toString) {
condition = propVal.constructor === Number
condition = propVal.constructor === Number;
}

@@ -197,3 +229,3 @@

// Pass it through the initializer
propVal = option.init(propVal)
propVal = option.init(propVal);
}

@@ -204,19 +236,19 @@ }

if (name.length > 1) {
name = camelcase(name)
name = camelcase(name);
}
// Add option to list
contents[name] = propVal
contents[name] = propVal;
}
return contents
return contents;
}
getOptions() {
const options = {}
const args = {}
const options = {};
const args = {};
// Copy over the arguments
Object.assign(args, this.raw)
delete args._
Object.assign(args, this.raw);
delete args._;

@@ -226,6 +258,6 @@ // Set option defaults

if (typeof option.defaultValue === 'undefined') {
continue
continue;
}
Object.assign(options, this.readOption(option))
Object.assign(options, this.readOption(option));
}

@@ -236,41 +268,62 @@

if (!{}.hasOwnProperty.call(args, option)) {
continue
continue;
}
const related = this.isDefined(option, 'options')
const related = this.isDefined(option, 'options');
if (related) {
const details = this.readOption(related)
Object.assign(options, details)
const details = this.readOption(related);
Object.assign(options, details);
}
}
return options
return options;
}
generateExamples() {
const examples = this.details.examples;
const parts = [];
for (const item in examples) {
if (!{}.hasOwnProperty.call(examples, item)) {
continue;
}
const usage = this.printSubColor('$ ' + examples[item].usage);
const description = this.printMainColor(
'- ' + examples[item].description
);
parts.push(` ${description}\n\n ${usage}\n\n`);
}
return parts;
}
generateDetails(kind) {
// Get all properties of kind from global scope
const items = this.details[kind]
const parts = []
const isCmd = kind === 'commands'
const items = this.details[kind];
const parts = [];
const isCmd = kind === 'commands';
// Sort items alphabetically
items.sort((a, b) => {
const first = isCmd ? a.usage : a.usage[1]
const second = isCmd ? b.usage : b.usage[1]
const first = isCmd ? a.usage : a.usage[1];
const second = isCmd ? b.usage : b.usage[1];
switch (true) {
case (first < second): return -1
case (first > second): return 1
default: return 0
case first < second:
return -1;
case first > second:
return 1;
default:
return 0;
}
})
});
for (const item in items) {
if (!{}.hasOwnProperty.call(items, item)) {
continue
continue;
}
let usage = items[item].usage
let initial = items[item].defaultValue
let usage = items[item].usage;
let initial = items[item].defaultValue;

@@ -280,12 +333,14 @@ // If usage is an array, show its contents

if (isCmd) {
usage = usage.join(', ')
usage = usage.join(', ');
} else {
const isVersion = usage.indexOf('v')
usage = `-${usage[0]}, --${usage[1]}`
const isVersion = usage.indexOf('v');
usage = `-${usage[0]}, --${usage[1]}`;
if (!initial) {
initial = items[item].init
initial = items[item].init;
}
usage += (initial && isVersion === -1) ? ' ' + this.handleType(initial)[0] : ''
usage += initial && isVersion === -1
? ' ' + this.handleType(initial)[0]
: '';
}

@@ -295,3 +350,3 @@ }

// Overwrite usage with readable syntax
items[item].usage = usage
items[item].usage = usage;
}

@@ -302,13 +357,13 @@

const longest = items.slice().sort((a, b) => {
return b.usage.length - a.usage.length
})[0].usage.length
return b.usage.length - a.usage.length;
})[0].usage.length;
for (const item of items) {
let usage = item.usage
let description = item.description
const defaultValue = item.defaultValue
const difference = longest - usage.length
let usage = item.usage;
let description = item.description;
const defaultValue = item.defaultValue;
const difference = longest - usage.length;
// Compensate the difference to longest property with spaces
usage += ' '.repeat(difference)
usage += ' '.repeat(difference);

@@ -318,11 +373,16 @@ // Add some space around it as well

if (typeof defaultValue === 'boolean') {
description += ` (${defaultValue ? 'enabled' : 'disabled'} by default)`
description += ` (${defaultValue ? 'enabled' : 'disabled'} by default)`;
} else {
description += ` (defaults to ${JSON.stringify(defaultValue)})`
description += ` (defaults to ${JSON.stringify(defaultValue)})`;
}
}
parts.push(' ' + chalk.yellow(usage) + ' ' + chalk.dim(description))
parts.push(
' ' +
this.printMainColor(usage) +
' ' +
this.printSubColor(description)
);
}
return parts
return parts;
}

@@ -333,3 +393,3 @@

if (details.usage === 'help' && !this.config.help) {
details.init = false
details.init = false;
}

@@ -339,17 +399,19 @@

if (details.init) {
const sub = [].concat(this.sub)
sub.shift()
const sub = [].concat(this.sub);
sub.shift();
return details.init.bind(this)(details.usage, sub, options)
return details.init.bind(this)(details.usage, sub, options);
}
// Generate full name of binary
const full = this.binary + '-' + (Array.isArray(details.usage) ? details.usage[0] : details.usage)
const full = this.binary +
'-' +
(Array.isArray(details.usage) ? details.usage[0] : details.usage);
const args = process.argv
let i = 0
const args = process.argv;
let i = 0;
while (i < 3) {
args.shift()
i++
args.shift();
i++;
}

@@ -360,19 +422,19 @@

stdio: 'inherit'
})
});
// Throw an error if something fails within that binary
this.child.on('error', err => {
throw err
})
throw err;
});
this.child.on('exit', (code, signal) => {
process.on('exit', () => {
this.child = null
this.child = null;
if (signal) {
process.kill(process.pid, signal)
process.kill(process.pid, signal);
} else {
process.exit(code)
process.exit(code);
}
})
})
});
});

@@ -382,25 +444,27 @@ // proxy SIGINT to child process

if (this.child) {
this.child.kill('SIGINT')
this.child.kill('SIGTERM') // if that didn't work, we're probably in an infinite loop, so make it die
this.child.kill('SIGINT');
this.child.kill('SIGTERM'); // if that didn't work, we're probably in an infinite loop, so make it die
}
})
});
}
checkVersion() {
const parent = module.parent
const parent = module.parent;
// Load parent module
pkginfo(parent)
pkginfo(parent);
// And get its version propery
const version = parent.exports.version
const version = parent.exports.version;
if (version) {
// If it exists, register it as a default option
this.option('version', 'Output the version number')
this.option('version', 'Output the version number');
// And immediately output it if used in command line
if (this.raw.v || this.raw.version) {
console.log(version)
process.exit()
console.log(version);
// eslint-disable-next-line unicorn/no-process-exit
process.exit();
}

@@ -412,15 +476,15 @@ }

// Get all items of kind
const children = this.details[list]
const children = this.details[list];
// Check if a child matches the requested name
for (const child of children) {
const usage = child.usage
const type = usage.constructor
const usage = child.usage;
const type = usage.constructor;
if (type === Array && usage.indexOf(name) > -1) {
return child
return child;
}
if (type === String && usage === name) {
return child
return child;
}

@@ -430,3 +494,3 @@ }

// If nothing matches, item is not defined
return false
return false;
}

@@ -436,36 +500,60 @@

// Override default option values
Object.assign(this.config, options)
Object.assign(this.config, options);
if (Array.isArray(this.config.mainColor)) {
for (const item in this.config.mainColor) {
if (!{}.hasOwnProperty.call(this.config.mainColor, item)) {
continue;
}
// chain all colors to our print method
this.printMainColor = this.printMainColor[this.config.mainColor[item]];
}
} else {
this.printMainColor = this.printMainColor[this.config.mainColor];
}
if (Array.isArray(this.config.subColor)) {
for (const item in this.config.subColor) {
if (!{}.hasOwnProperty.call(this.config.subColor, item)) {
continue;
}
// chain all colors to our print method
this.printSubColor = this.printSubColor[this.config.subColor[item]];
}
} else {
this.printSubColor = this.printSubColor[this.config.subColor];
}
if (this.config.help) {
// Register default options and commands
this.option('help', 'Output usage information')
this.command('help', 'Display help', this.showHelp)
this.option('help', 'Output usage information');
this.command('help', 'Display help', this.showHelp);
}
// Parse arguments using minimist
this.raw = parser(argv.slice(1), this.config.minimist)
this.binary = path.basename(this.raw._[0])
this.raw = parser(argv.slice(1), this.config.minimist);
this.binary = path.basename(this.raw._[0]);
// If default version is allowed, check for it
if (this.config.version) {
this.checkVersion()
this.checkVersion();
}
const subCommand = this.raw._[1]
const helpTriggered = this.raw.h || this.raw.help
const subCommand = this.raw._[1];
const helpTriggered = this.raw.h || this.raw.help;
const args = {}
const defined = this.isDefined(subCommand, 'commands')
const optionList = this.getOptions()
const args = {};
const defined = this.isDefined(subCommand, 'commands');
const optionList = this.getOptions();
Object.assign(args, this.raw)
args._.shift()
Object.assign(args, this.raw);
args._.shift();
// Export sub arguments of command
this.sub = args._
this.sub = args._;
// If sub command is defined, run it
if (defined) {
this.runCommand(defined, optionList)
return {}
this.runCommand(defined, optionList);
return {};
}

@@ -476,77 +564,82 @@

if (this.config.help && helpTriggered) {
this.showHelp()
this.showHelp();
}
// Hand back list of options
return optionList
return optionList;
}
showHelp() {
const name = this.config.name || this.binary.replace('-', ' ')
const firstBig = word => word.charAt(0).toUpperCase() + word.substr(1)
const name = this.config.name || this.binary.replace('-', ' ');
const firstBig = word => word.charAt(0).toUpperCase() + word.substr(1);
const parts = []
const parts = [];
const groups = {
commands: true,
options: true
}
options: true,
examples: true
};
for (const group in groups) {
if (this.details[group].length > 0) {
continue
continue;
}
groups[group] = false
groups[group] = false;
}
const optionHandle = groups.options ? ' [options]' : ''
const cmdHandle = groups.commands ? ' [command]' : ''
const value = typeof this.config.value === 'string' ? ' ' + this.config.value : ''
const optionHandle = groups.options ? '[options] ' : '';
const cmdHandle = groups.commands ? '[command]' : '';
const value = typeof this.config.value === 'string'
? ' ' + this.config.value
: '';
parts.push([
'',
'Usage: ' + chalk.yellow(name) + chalk.dim(optionHandle + cmdHandle + value),
`Usage: ${this.printMainColor(name)} ${this.printSubColor(optionHandle + cmdHandle + value)}`,
''
])
]);
for (const group in groups) {
if (!groups[group]) {
continue
continue;
}
parts.push([
'',
firstBig(group) + ':',
'',
''
])
parts.push(['', firstBig(group) + ':', '', '']);
parts.push(this.generateDetails(group))
parts.push(['', ''])
if (group === 'examples') {
parts.push(this.generateExamples());
} else {
parts.push(this.generateDetails(group));
}
parts.push(['', '']);
}
let output = ''
let output = '';
// And finally, merge and output them
for (const part of parts) {
output += part.join('\n ')
output += part.join('\n ');
}
if (!groups.commands && !groups.options) {
output = 'No sub commands or options available'
output = 'No sub commands or options available';
}
const usageFilter = this.config.usageFilter
const usageFilter = this.config.usageFilter;
// If filter is available, pass usage information through
if (typeof usageFilter === 'function') {
output = usageFilter(output) || output
output = usageFilter(output) || output;
}
console.log(output)
process.exit()
console.log(output);
// eslint-disable-next-line unicorn/no-process-exit
process.exit();
}
}
module.exports = exports.default = new Args()
module.exports = (exports.default = new Args());
{
"name": "args",
"version": "2.3.0",
"version": "2.4.0",
"description": "Minimal toolkit for building CLIs",

@@ -9,7 +9,9 @@ "files": [

"scripts": {
"test": "xo && ava"
"precommit": "lint-staged",
"test": "npm run lint && ava",
"lint": "xo"
},
"repository": "leo/args",
"engines": {
"node": ">= 4.0.0"
"node": ">= 6.6.0"
},

@@ -26,12 +28,11 @@ "keywords": [

"xo": {
"esnext": true,
"space": true,
"semicolon": false,
"rules": {
"unicorn/no-process-exit": 0,
"max-lines": 0,
"ava/no-ignored-test-files": 0,
"import/no-unresolved": 0
}
"extends": "prettier"
},
"lint-staged": {
"*.js": [
"npm run lint",
"prettier --single-quote --write",
"git add"
]
},
"author": "leo",

@@ -44,4 +45,8 @@ "license": "MIT",

"devDependencies": {
"ava": "0.18.0",
"ava": "0.18.2",
"eslint-config-prettier": "1.5.0",
"execa": "0.6.0",
"husky": "0.13.3",
"lint-staged": "3.4.0",
"prettier": "0.22.0",
"xo": "0.17.0"

@@ -52,3 +57,2 @@ },

"chalk": "1.1.3",
"loud-rejection": "1.3.0",
"minimist": "1.2.0",

@@ -55,0 +59,0 @@ "pkginfo": "0.4.0"

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc