@@ -24,6 +24,23 @@ class Parser
2424
2525 protected $ trailingArray ;
2626
27+ /**
28+ * List of unknown arguments and best argument suggestion.
29+ *
30+ * The key corresponds to the unknown argument and the value to the
31+ * argument suggestion, if any.
32+ *
33+ * @var array
34+ */
35+ protected $ unknowPrefixedArguments = [];
36+
37+ /**
38+ * Minimum similarity percentage to detect similar arguments.
39+ *
40+ * @var float
41+ */
42+ protected $ minimumSimilarityPercentage = 0.6 ;
43+
2744 public function __construct ()
2845 {
2946 $ this ->summary = new Summary ();
@@ -61,6 +78,10 @@ public function parse(array $argv = null)
6178
6279 $ unParsedArguments = $ this ->prefixedArguments ($ cliArguments );
6380
81+ // Searches for unknown prefixed arguments and finds a suggestion
82+ // within the list of valid arguments.
83+ $ this ->unknowPrefixedArguments ($ unParsedArguments );
84+
6485 $ this ->nonPrefixedArguments ($ unParsedArguments );
6586
6687 // After parsing find out which arguments were required but not
@@ -306,4 +327,98 @@ protected function getCommandAndArguments(array $argv = null)
306327
307328 return compact ('arguments ' , 'command ' );
308329 }
330+
331+ /**
332+ * Processes unknown prefixed arguments and sets suggestions if no matching
333+ * prefix is found.
334+ *
335+ * @param array $unParsedArguments The array of unparsed arguments to
336+ * process.
337+ */
338+ protected function unknowPrefixedArguments (array $ unParsedArguments )
339+ {
340+ foreach ($ unParsedArguments as $ arg ) {
341+ $ unknowArgumentName = $ this ->getUnknowArgumentName ($ arg );
342+ if (!$ this ->findPrefixedArgument ($ unknowArgumentName )) {
343+ if (is_null ($ unknowArgumentName )) {
344+ continue ;
345+ }
346+ $ suggestion = $ this ->findSuggestionsForUnknowPrefixedArguments (
347+ $ unknowArgumentName ,
348+ $ this ->filter ->withPrefix ()
349+ );
350+ $ this ->setSuggestion ($ unknowArgumentName , $ suggestion );
351+ }
352+ }
353+ }
354+
355+ /**
356+ * Sets the suggestion for an unknown argument name.
357+ *
358+ * @param string $unknowArgName The name of the unknown argument.
359+ * @param string $suggestion The suggestion for the unknown argument.
360+ */
361+ protected function setSuggestion (string $ unknowArgName , string $ suggestion )
362+ {
363+ $ this ->unknowPrefixedArguments [$ unknowArgName ] = $ suggestion ;
364+ }
365+
366+ /**
367+ * Extracts the unknown argument name from a given argument string.
368+ *
369+ * @param string $arg The argument string to process.
370+ * @return string|null The extracted unknown argument name or null if not
371+ * found.
372+ */
373+ protected function getUnknowArgumentName (string $ arg )
374+ {
375+ if (preg_match ('/^[-]{1,2}([^-]+?)(?:=|$)/ ' , $ arg , $ matches )) {
376+ return $ matches [1 ];
377+ }
378+ return null ;
379+ }
380+
381+ /**
382+ * Finds the most similar known argument for an unknown prefixed argument.
383+ *
384+ * @param string $argName The name of the unknown argument to find
385+ * suggestions for.
386+ * @param array $argList The list of known arguments to compare against.
387+ * @return string The most similar known argument name.
388+ */
389+ protected function findSuggestionsForUnknowPrefixedArguments (
390+ string $ argName ,
391+ array $ argList
392+ ) {
393+ $ mostSimilar = '' ;
394+ $ greatestSimilarity = $ this ->minimumSimilarityPercentage * 100 ;
395+ foreach ($ argList as $ arg ) {
396+ similar_text ($ argName , $ arg ->name (), $ percent );
397+ if ($ percent > $ greatestSimilarity ) {
398+ $ greatestSimilarity = $ percent ;
399+ $ mostSimilar = $ arg ->name ();
400+ }
401+ }
402+ return $ mostSimilar ;
403+ }
404+
405+ /**
406+ * Returns the list of unknown prefixed arguments and their suggestions.
407+ *
408+ * @return array The list of unknown prefixed arguments and their suggestions.
409+ */
410+ public function getUnknowPrefixedArgumentsAndSuggestions ()
411+ {
412+ return $ this ->unknowPrefixedArguments ;
413+ }
414+
415+ /**
416+ * Sets the minimum similarity percentage for finding suggestions.
417+ *
418+ * @param float $percentage The minimum similarity percentage to set.
419+ */
420+ public function setMinimumSimilarityPercentage (float $ percentage )
421+ {
422+ $ this ->minimumSimilarityPercentage = $ percentage ;
423+ }
309424}
0 commit comments