UNPKG

2.03 kBJavaScriptView Raw
1'use strict';
2
3const _ = require('lodash');
4const chalk = require('chalk');
5const EOL = require('os').EOL;
6const levenshtein = require('fastest-levenshtein');
7
8/**
9 * @param {{ [key: string]: { alias?: string } }} allowedOptions
10 * @return {string[]}
11 */
12const buildAllowedOptions = (allowedOptions) => {
13 let options = Object.keys(allowedOptions);
14
15 options = options.reduce((opts, opt) => {
16 const alias = allowedOptions[opt].alias;
17
18 if (alias) {
19 opts.push(alias);
20 }
21
22 return opts;
23 }, options);
24 options.sort();
25
26 return options;
27};
28
29/**
30 * @param {string[]} all
31 * @param {string} invalid
32 * @return {null|string}
33 */
34const suggest = (all, invalid) => {
35 const maxThreshold = 10;
36
37 for (let threshold = 1; threshold <= maxThreshold; threshold++) {
38 const suggestion = all.find((option) => levenshtein.distance(option, invalid) <= threshold);
39
40 if (suggestion) {
41 return suggestion;
42 }
43 }
44
45 return null;
46};
47
48/**
49 * @param {string} opt
50 * @return {string}
51 */
52const cliOption = (opt) => {
53 if (opt.length === 1) {
54 return `"-${opt}"`;
55 }
56
57 return `"--${_.kebabCase(opt)}"`;
58};
59
60/**
61 * @param {string} invalid
62 * @param {string|null} suggestion
63 * @return {string}
64 */
65const buildMessageLine = (invalid, suggestion) => {
66 let line = `Invalid option ${chalk.red(cliOption(invalid))}.`;
67
68 if (suggestion) {
69 line += ` Did you mean ${chalk.cyan(cliOption(suggestion))}?`;
70 }
71
72 return line + EOL;
73};
74
75/**
76 * @param {{ [key: string]: any }} allowedOptions
77 * @param {{ [key: string]: any }} inputOptions
78 * @return {string}
79 */
80module.exports = function checkInvalidCLIOptions(allowedOptions, inputOptions) {
81 const allOptions = buildAllowedOptions(allowedOptions);
82
83 return Object.keys(inputOptions)
84 .filter((opt) => !allOptions.includes(opt))
85 .map(_.kebabCase)
86 .reduce((msg, invalid) => {
87 // NOTE: No suggestion for shortcut options because it's too difficult
88 const suggestion = invalid.length >= 2 ? suggest(allOptions, invalid) : null;
89
90 return msg + buildMessageLine(invalid, suggestion);
91 }, '');
92};