@@ -165,7 +165,7 @@ class Command extends EventEmitter {
165
165
cmd . _hidden = ! ! ( opts . noHelp || opts . hidden ) ; // noHelp is deprecated old name for hidden
166
166
cmd . _executableFile = opts . executableFile || null ; // Custom name for executable file, set missing to null to match constructor
167
167
if ( args ) cmd . arguments ( args ) ;
168
- this . commands . push ( cmd ) ;
168
+ this . _registerCommand ( cmd ) ;
169
169
cmd . parent = this ;
170
170
cmd . copyInheritedSettings ( this ) ;
171
171
@@ -282,7 +282,7 @@ class Command extends EventEmitter {
282
282
if ( opts . isDefault ) this . _defaultCommandName = cmd . _name ;
283
283
if ( opts . noHelp || opts . hidden ) cmd . _hidden = true ; // modifying passed command due to existing implementation
284
284
285
- this . commands . push ( cmd ) ;
285
+ this . _registerCommand ( cmd ) ;
286
286
cmd . parent = this ;
287
287
cmd . _checkForBrokenPassThrough ( ) ;
288
288
@@ -535,10 +535,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
535
535
throw err ;
536
536
}
537
537
}
538
+
538
539
/**
539
540
* Check for option flag conflicts.
540
- * Register option if no conflicts found.
541
- * Throw otherwise.
541
+ * Register option if no conflicts found, or throw on conflict.
542
542
*
543
543
* @param {Option } option
544
544
* @api private
@@ -552,9 +552,33 @@ Expecting one of '${allowedValues.join("', '")}'`);
552
552
throw new Error ( `Cannot add option '${ option . flags } '${ this . _name && ` to command '${ this . _name } '` } due to conflicting flag '${ matchingFlag } '
553
553
- already used by option '${ matchingOption . flags } '` ) ;
554
554
}
555
+
555
556
this . options . push ( option ) ;
556
557
}
557
558
559
+ /**
560
+ * Check for command name and alias conflicts with existing commands.
561
+ * Register command if no conflicts found, or throw on conflict.
562
+ *
563
+ * @param {Command } command
564
+ * @api private
565
+ */
566
+
567
+ _registerCommand ( command ) {
568
+ const knownBy = ( cmd ) => {
569
+ return [ cmd . name ( ) ] . concat ( cmd . aliases ( ) ) ;
570
+ } ;
571
+
572
+ const alreadyUsed = knownBy ( command ) . find ( ( name ) => this . _findCommand ( name ) ) ;
573
+ if ( alreadyUsed ) {
574
+ const existingCmd = knownBy ( this . _findCommand ( alreadyUsed ) ) . join ( '|' ) ;
575
+ const newCmd = knownBy ( command ) . join ( '|' ) ;
576
+ throw new Error ( `cannot add command '${ newCmd } ' as already have command '${ existingCmd } '` ) ;
577
+ }
578
+
579
+ this . commands . push ( command ) ;
580
+ }
581
+
558
582
/**
559
583
* Add an option.
560
584
*
@@ -1900,6 +1924,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
1900
1924
}
1901
1925
1902
1926
if ( alias === command . _name ) throw new Error ( 'Command alias can\'t be the same as its name' ) ;
1927
+ const matchingCommand = this . parent ?. _findCommand ( alias ) ;
1928
+ if ( matchingCommand ) {
1929
+ // c.f. _registerCommand
1930
+ const existingCmd = [ matchingCommand . name ( ) ] . concat ( matchingCommand . aliases ( ) ) . join ( '|' ) ;
1931
+ throw new Error ( `cannot add alias '${ alias } ' to command '${ this . name ( ) } ' as already have command '${ existingCmd } '` ) ;
1932
+ }
1903
1933
1904
1934
command . _aliases . push ( alias ) ;
1905
1935
return this ;
0 commit comments