Skip to content

Commit f041cd3

Browse files
committed
feat: support user triggered BAD_ARGS
Also includes small refactors to return rejected promises instead of throwing, and to simplify a few areas of code around aliases.
1 parent 9ffd47b commit f041cd3

File tree

7 files changed

+104
-30
lines changed

7 files changed

+104
-30
lines changed

lib/args.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function args(argv, config) {
2121

2222
let aliasShortcuts = abbrev(aliases);
2323

24-
// fixes up any issue
24+
// fixes up any issues
2525
settings.options.forEach(t => delete settings.alias[t]);
2626
debug('config', config);
2727

@@ -43,6 +43,11 @@ function args(argv, config) {
4343

4444
defaultsDeep(settings.alias, abbrev(all));
4545

46+
// set abbreviated aliases to have the value of the alias
47+
Object.keys(aliasShortcuts).forEach(a => {
48+
settings.alias[a] = settings.alias[aliasShortcuts[a]];
49+
});
50+
4651
// total hack to capture the yargs help output
4752
let res = yargslib.reset().options(settings.yargs);
4853
var help = '';
@@ -76,11 +81,6 @@ function args(argv, config) {
7681

7782
args.$_ = settings.commands[override || args._[0]] || // override or real
7883
settings.commands[settings.alias[args._[0]]] || // alias
79-
settings.commands[ // alias of an alias command
80-
settings.alias[args._[0]] &&
81-
aliasShortcuts[args._[0]] &&
82-
settings.alias[settings.alias[args._[0]]]
83-
] ||
8484
settings.commands._; // default
8585

8686
// if there's no command config, then try to let the command match the
@@ -97,7 +97,7 @@ function args(argv, config) {
9797
}
9898

9999
return {
100-
help: help,
100+
help,
101101
args,
102102
};
103103
}

lib/help.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function getHelpItem(args, config) {
2525
return reject(new Error(`"${args.help}" help can't be found`));
2626
}
2727

28-
var error = new Error('no help configured');
28+
var error = new Error('No help configured');
2929
error.code = 'NO_HELP_CONFIGURED';
3030
reject(error);
3131
});

lib/index.js

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,20 @@ module.exports = (config, root) => {
1111
[path.join(root, 'node_modules')] :
1212
module.parent.parent.paths).slice(0); // copy
1313
let settings = getSettings(config);
14+
let help = '';
1415

1516
return Promise.all([
1617
parseArgs(process.argv, config),
1718
read(),
1819
findRoot(paths).then(res => root = res),
1920
]).then(res => {
2021
let args = res[0].args;
21-
let help = res[0].help;
22+
help = res[0].help;
2223
let body = res[1];
2324
if (!args.$_ && !settings.commands._ && !body) {
24-
return loadCommand(root, { $_: ':::./help' }, body, settings).catch(e => {
25-
if (e.code === 'NO_HELP_CONFIGURED') {
26-
e.message = help.trim();
27-
}
28-
throw e;
29-
}).then(res => {
30-
var e = new Error(res);
31-
throw e;
32-
});
25+
var e = new Error('BAD_ARGS');
26+
e.code = 'BAD_ARGS';
27+
return Promise.reject(e);
3328
}
3429

3530
return loadCommand(root, args, body, settings);
@@ -42,13 +37,39 @@ module.exports = (config, root) => {
4237

4338
return res;
4439
}).catch(e => {
45-
/* istanbul ignore if */
46-
if (!settings.return) {
47-
debug(e.stack);
48-
console.error(e.message);
49-
return process.exit(1);
40+
var promise = Promise.reject(e);
41+
42+
if (e.code === 'BAD_ARGS') {
43+
// show either the configured help or the automatically generated help
44+
promise = loadCommand(root, {
45+
$_: ':::./help', help: true,
46+
}, null, settings).then(res => {
47+
var error = new Error(res); // based on loaded help
48+
error.code = 'BAD_ARGS';
49+
return Promise.reject(error);
50+
}).catch(error => {
51+
if (error.code === 'NO_HELP_CONFIGURED') {
52+
error.code = 'BAD_ARGS';
53+
error.message = help.trim();
54+
}
55+
56+
if (error.code === 'BAD_ARGS' && e.message !== 'BAD_ARGS') {
57+
error.message = `${e.message}\n\n${error.message}`;
58+
}
59+
60+
return Promise.reject(error);
61+
});
5062
}
51-
throw e;
63+
64+
return promise.catch(e => {
65+
/* istanbul ignore if */
66+
if (!settings.return) {
67+
debug(e.stack);
68+
console.error(e.message);
69+
return process.exit(1);
70+
}
71+
return Promise.reject(e);
72+
});
5273
});
5374
};
5475

@@ -75,7 +96,7 @@ function loadCommand(root, args, body, settings) {
7596
resolve(require(filename));
7697
}).catch(e => {
7798
e.message = `Fatal: command failed to load "${filename}"`;
78-
throw e;
99+
return Promise.reject(e);
79100
}).then(res => res(args, settings, body)).then(res => {
80101
/* istanbul ignore if */
81102
if (!settings.return && internal) {

test/fixtures/basic-clite/err.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = function () {
2+
var e = new Error('This did not work');
3+
e.code = 'BAD_ARGS';
4+
return Promise.reject(e);
5+
};

test/integration/clite.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ test('throws when no command', function (t) {
2525
return clite({}, fixtures + '/basic-clite').then(function (res) {
2626
t.fail('did not want: ' + res);
2727
}).catch(function (e) {
28-
t.equal(e.code, 'NO_HELP_CONFIGURED', 'throws when no command');
28+
t.equal(e.code, 'BAD_ARGS', 'throws when no command');
2929
});
3030
});
3131

test/integration/help.test.js

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ var opts = {
1616
test('errors on help', function (t) {
1717
process.argv = sampleArgs.concat('--help');
1818
return clite({}, fixtures + '/basic-clite').catch(function (e) {
19-
t.match(e.message, /no help configured/, 'warns on no help');
19+
t.match(e.message, /no help configured/i, 'warns on no help');
2020
});
2121
});
2222

@@ -52,9 +52,42 @@ test('finds specific help', function (t) {
5252
});
5353
});
5454

55-
test('erros on unknown help', function (t) {
55+
test('errors on unknown help', function (t) {
5656
process.argv = sampleArgs.concat('--help', 'bar');
5757
return clite(opts, fixtures + '/basic-clite').catch(function (e) {
58-
t.match(e.message, /"bar" help/, 'warns on missing help');
58+
t.match(e.message, /"bar" help/i, 'warns on missing help');
5959
});
60-
});
60+
});
61+
62+
test('throws with help with no command', function (t) {
63+
process.argv = sampleArgs.slice(0);
64+
return clite(opts, fixtures + '/basic-clite').then(function (res) {
65+
t.fail('did not want: ' + res);
66+
}).catch(function (e) {
67+
t.equal(e.code, 'BAD_ARGS', 'bad arguments');
68+
t.match(e.message, /This is the help/i, 'configured help shown');
69+
});
70+
});
71+
72+
test('throws with generated help with no command', function (t) {
73+
process.argv = sampleArgs.slice(0);
74+
return clite({}, fixtures + '/basic-clite').then(function (res) {
75+
t.fail('did not want: ' + res);
76+
}).catch(function (e) {
77+
t.equal(e.code, 'BAD_ARGS', 'bad arguments');
78+
t.match(e.message, /Options:\s+--version/im, 'generated help shown');
79+
});
80+
});
81+
82+
test('user can trigger usage error', function (t) {
83+
process.argv = sampleArgs.slice(0);
84+
return clite({
85+
commands: { _: './err' },
86+
help: opts.help
87+
}, fixtures + '/basic-clite').then(function (res) {
88+
t.fail('did not want: ' + res);
89+
}).catch(function (e) {
90+
t.equal(e.code, 'BAD_ARGS', 'bad arguments');
91+
t.match(e.message, /This did not work/i, 'user error shown');
92+
});
93+
});

test/unit/args.test.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,19 @@ test('options', function (t) {
141141
// t.equal(res.$_, '.', 'command defaulted');
142142
t.equal(res.grep, 'sed', 'option captured');
143143
t.end();
144+
});
145+
146+
test('aliases options get abbreviated', function (t) {
147+
var res = args(sampleArgs.concat('-f', 'foo'), { options: ['grep'], alias: { filter: 'grep' } });
148+
t.equal(res.grep, 'foo', 'option captured');
149+
t.end();
150+
});
151+
152+
test('aliases commands get abbreviated', function (t) {
153+
var res = args(sampleArgs.concat('f'), {
154+
commands: { grep: '.' },
155+
alias: { filter: 'grep' }
156+
});
157+
t.equal(res.$_, '.', 'command captured');
158+
t.end();
144159
});

0 commit comments

Comments
 (0)