Skip to content

Commit 9e8171b

Browse files
committed
Cli: suggest close option when typo is made
1 parent bc3d4c1 commit 9e8171b

File tree

2 files changed

+80
-3
lines changed

2 files changed

+80
-3
lines changed

src/Cli.php

+35-3
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@
33
namespace ShipMonk\ComposerDependencyAnalyser;
44

55
use ShipMonk\ComposerDependencyAnalyser\Exception\InvalidCliException;
6+
use function array_keys;
67
use function array_slice;
78
use function is_dir;
89
use function is_file;
10+
use function levenshtein;
11+
use function strlen;
912
use function strpos;
1013
use function substr;
14+
use function trim;
1115

1216
class Cli
1317
{
@@ -54,23 +58,26 @@ public function __construct(string $cwd, array $argv)
5458
$startsWithDashDash = strpos($arg, '--') === 0;
5559

5660
if ($startsWithDash && !$startsWithDashDash) {
57-
throw new InvalidCliException("Unknown option $arg, see --help");
61+
$suggestedOption = $this->suggestOption($arg);
62+
throw new InvalidCliException("Unknown option $arg, $suggestedOption");
5863
}
5964

6065
if (!$startsWithDashDash) {
6166
if (is_file($cwd . '/' . $arg) || is_dir($cwd . '/' . $arg)) {
6267
throw new InvalidCliException("Cannot pass paths ($arg) to analyse as arguments, use --config instead.");
6368
}
6469

65-
throw new InvalidCliException("Unknown argument $arg, see --help");
70+
$suggestedOption = $this->suggestOption($arg);
71+
throw new InvalidCliException("Unknown argument $arg, $suggestedOption");
6672
}
6773

6874
/** @var string $noDashesArg this is never false as we know it starts with -- */
6975
$noDashesArg = substr($arg, 2);
7076
$optionName = $this->getKnownOptionName($noDashesArg);
7177

7278
if ($optionName === null) {
73-
throw new InvalidCliException("Unknown option $arg, see --help");
79+
$suggestedOption = $this->suggestOption($noDashesArg);
80+
throw new InvalidCliException("Unknown option $arg, $suggestedOption");
7481
}
7582

7683
if ($this->isOptionWithRequiredValue($optionName)) {
@@ -186,4 +193,29 @@ public function getProvidedOptions(): CliOptions
186193
return $options;
187194
}
188195

196+
/**
197+
* Params inspired by tracy/tracy
198+
*/
199+
private function suggestOption(string $input): string
200+
{
201+
$value = trim($input, '-');
202+
$options = array_keys(self::OPTIONS);
203+
204+
$bestGuess = null;
205+
$minDistance = (strlen($value) / 4 + 1) * 10 + .1;
206+
207+
foreach ($options as $option) {
208+
$distance = levenshtein($option, $value, 9, 11, 9);
209+
210+
if ($distance > 0 && $distance < $minDistance) {
211+
$minDistance = $distance;
212+
$bestGuess = $option;
213+
}
214+
}
215+
216+
return $bestGuess === null
217+
? 'see --help'
218+
: "did you mean --$bestGuess?";
219+
}
220+
189221
}

tests/CliTest.php

+45
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,51 @@ public function validationDataProvider(): iterable
114114
'Missing argument value in --composer-json=, see --help',
115115
['bin/script.php', '--composer-json='],
116116
];
117+
118+
yield 'suggestion #1' => [
119+
'Unknown option --hep, did you mean --help?',
120+
['bin/script.php', '--hep'],
121+
];
122+
123+
yield 'suggestion #2' => [
124+
'Unknown option --ignore-shadow-dependencies, did you mean --ignore-shadow-deps?',
125+
['bin/script.php', '--ignore-shadow-dependencies'],
126+
];
127+
128+
yield 'suggestion #3' => [
129+
'Unknown option --composer-lock, did you mean --composer-json?',
130+
['bin/script.php', '--composer-lock'],
131+
];
132+
133+
yield 'suggestion #4' => [
134+
'Unknown option --ignore-prod-in-dev-deps, did you mean --ignore-prod-only-in-dev-deps?',
135+
['bin/script.php', '--ignore-prod-in-dev-deps'],
136+
];
137+
138+
yield 'suggestion #5' => [
139+
'Unknown option --ignore-dev-prod-deps, did you mean --ignore-dev-in-prod-deps?',
140+
['bin/script.php', '--ignore-dev-prod-deps'],
141+
];
142+
143+
yield 'no suggestion #1' => [
144+
'Unknown option --vvv, see --help',
145+
['bin/script.php', '--vvv'],
146+
];
147+
148+
yield 'no suggestion #2' => [
149+
'Unknown option --v, see --help',
150+
['bin/script.php', '--v'],
151+
];
152+
153+
yield 'no suggestion #3' => [
154+
'Unknown option --nonsense, see --help',
155+
['bin/script.php', '--nonsense'],
156+
];
157+
158+
yield 'no suggestion #4' => [
159+
'Unknown option --four, see --help',
160+
['bin/script.php', '--four'],
161+
];
117162
}
118163

119164
}

0 commit comments

Comments
 (0)