@@ -38,7 +38,7 @@ import { convertSchemaToOptions, parseSchema } from './json-schema';
3838
3939
4040export interface CommandMap {
41- [ key : string ] : string ;
41+ [ key : string ] : Path ;
4242}
4343
4444interface CommandMetadata {
@@ -84,9 +84,12 @@ function levenshtein(a: string, b: string): number {
8484 * @param logger The logger to use.
8585 * @param context Execution context.
8686 */
87- export async function runCommand ( args : string [ ] ,
88- logger : logging . Logger ,
89- context : CommandContext ) : Promise < number | void > {
87+ export async function runCommand (
88+ args : string [ ] ,
89+ logger : logging . Logger ,
90+ context : CommandContext ,
91+ commandMap ?: CommandMap ,
92+ ) : Promise < number | void > {
9093
9194 // if not args supplied, just run the help command.
9295 if ( ! args || args . length === 0 ) {
@@ -101,24 +104,31 @@ export async function runCommand(args: string[],
101104 ? CommandScope . inProject
102105 : CommandScope . outsideProject ;
103106
104- const commandMapPath = findUp ( 'commands.json' , __dirname ) ;
105- if ( commandMapPath === null ) {
106- logger . fatal ( 'Unable to find command map.' ) ;
107+ if ( commandMap === undefined ) {
108+ const commandMapPath = findUp ( 'commands.json' , __dirname ) ;
109+ if ( commandMapPath === null ) {
110+ logger . fatal ( 'Unable to find command map.' ) ;
107111
108- return 1 ;
112+ return 1 ;
113+ }
114+ const cliDir = dirname ( normalize ( commandMapPath ) ) ;
115+ const commandsText = readFileSync ( commandMapPath ) . toString ( 'utf-8' ) ;
116+ const commandJson = JSON . parse ( commandsText ) as { [ name : string ] : string } ;
117+
118+ commandMap = { } ;
119+ for ( const commandName of Object . keys ( commandJson ) ) {
120+ commandMap [ commandName ] = join ( cliDir , commandJson [ commandName ] ) ;
121+ }
109122 }
110- const cliDir = dirname ( normalize ( commandMapPath ) ) ;
111- const commandsText = readFileSync ( commandMapPath ) . toString ( 'utf-8' ) ;
112- const commandMap = JSON . parse ( commandsText ) as CommandMap ;
113123
114- let commandMetadata = commandName ? findCommand ( cliDir , commandMap , commandName ) : null ;
124+ let commandMetadata = commandName ? findCommand ( commandMap , commandName ) : null ;
115125
116126 if ( ! commandMetadata && ( rawOptions . v || rawOptions . version ) ) {
117127 commandName = 'version' ;
118- commandMetadata = findCommand ( cliDir , commandMap , commandName ) ;
128+ commandMetadata = findCommand ( commandMap , commandName ) ;
119129 } else if ( ! commandMetadata && rawOptions . help ) {
120130 commandName = 'help' ;
121- commandMetadata = findCommand ( cliDir , commandMap , commandName ) ;
131+ commandMetadata = findCommand ( commandMap , commandName ) ;
122132 }
123133
124134 if ( ! commandMetadata ) {
@@ -132,7 +142,7 @@ export async function runCommand(args: string[],
132142 return 1 ;
133143 } else {
134144 const commandsDistance = { } as { [ name : string ] : number } ;
135- const allCommands = listAllCommandNames ( cliDir , commandMap ) . sort ( ( a , b ) => {
145+ const allCommands = Object . keys ( commandMap ) . sort ( ( a , b ) => {
136146 if ( ! ( a in commandsDistance ) ) {
137147 commandsDistance [ a ] = levenshtein ( a , commandName ) ;
138148 }
@@ -153,7 +163,7 @@ export async function runCommand(args: string[],
153163 }
154164 }
155165
156- const command = await createCommand ( cliDir , commandMetadata , context , logger ) ;
166+ const command = await createCommand ( commandMetadata , context , logger ) ;
157167 const metadataOptions = await convertSchemaToOptions ( commandMetadata . text ) ;
158168 if ( command === null ) {
159169 logger . error ( tags . stripIndent `Command (${ commandName } ) failed to instantiate.` ) ;
@@ -173,7 +183,7 @@ export async function runCommand(args: string[],
173183 options = parseOptions ( args , command . options ) ;
174184
175185 if ( commandName === 'help' ) {
176- options . commandInfo = getAllCommandInfo ( cliDir , commandMap ) ;
186+ options . commandInfo = getAllCommandInfo ( commandMap ) ;
177187 }
178188
179189 if ( options . help ) {
@@ -350,7 +360,7 @@ export function parseOptions(args: string[], optionsAndArguments: Option[]) {
350360}
351361
352362// Find a command.
353- function findCommand ( rootDir : Path , map : CommandMap , name : string ) : CommandLocation | null {
363+ function findCommand ( map : CommandMap , name : string ) : CommandLocation | null {
354364 // let Cmd: CommandConstructor = map[name];
355365 let commandName = name ;
356366
@@ -359,8 +369,7 @@ function findCommand(rootDir: Path, map: CommandMap, name: string): CommandLocat
359369 commandName = Object . keys ( map )
360370 . filter ( key => {
361371 // get aliases for the key
362- const metadataPath = map [ key ] ;
363- const metadataText = readFileSync ( join ( rootDir , metadataPath ) ) . toString ( 'utf-8' ) ;
372+ const metadataText = readFileSync ( map [ key ] ) . toString ( 'utf-8' ) ;
364373 const metadata = JSON . parse ( metadataText ) ;
365374 const aliases = metadata [ '$aliases' ] ;
366375 if ( ! aliases ) {
@@ -372,12 +381,11 @@ function findCommand(rootDir: Path, map: CommandMap, name: string): CommandLocat
372381 } ) [ 0 ] ;
373382 }
374383
375- const relativeMetadataPath = map [ commandName ] ;
384+ const metadataPath = map [ commandName ] ;
376385
377- if ( ! relativeMetadataPath ) {
386+ if ( ! metadataPath ) {
378387 return null ;
379388 }
380- const metadataPath = join ( rootDir , relativeMetadataPath ) ;
381389 const metadataText = readFileSync ( metadataPath ) . toString ( 'utf-8' ) ;
382390
383391 const metadata = parseJson ( metadataText ) as any ;
@@ -390,8 +398,7 @@ function findCommand(rootDir: Path, map: CommandMap, name: string): CommandLocat
390398}
391399
392400// Create an instance of a command.
393- async function createCommand ( rootDir : Path ,
394- metadata : CommandLocation ,
401+ async function createCommand ( metadata : CommandLocation ,
395402 context : CommandContext ,
396403 logger : logging . Logger ) : Promise < Command | null > {
397404 const schema = parseSchema ( metadata . text ) ;
@@ -424,26 +431,18 @@ function mapCommandScope(scope: 'in' | 'out' | undefined): CommandScope {
424431 return commandScope ;
425432}
426433
427- // TODO: filter out commands that should not be listed based upon the command's metadata
428- function listAllCommandNames ( rootDir : Path , map : CommandMap ) : string [ ] {
429- return getAllCommandInfo ( rootDir , map )
430- . reduce ( ( acc , cmd ) => {
431- return [ ...acc , cmd . name , ...cmd . aliases ] ;
432- } , [ ] as string [ ] ) ;
433- }
434-
435434interface CommandInfo {
436435 name : string ;
437436 description : string ;
438437 aliases : string [ ] ;
439438 hidden : boolean ;
440439}
441- function getAllCommandInfo ( rootDir : Path , map : CommandMap ) : CommandInfo [ ] {
440+ function getAllCommandInfo ( map : CommandMap ) : CommandInfo [ ] {
442441 return Object . keys ( map )
443442 . map ( name => {
444443 return {
445444 name : name ,
446- metadata : findCommand ( rootDir , map , name ) ,
445+ metadata : findCommand ( map , name ) ,
447446 } ;
448447 } )
449448 . map ( info => {
0 commit comments