@@ -38,7 +38,7 @@ import { convertSchemaToOptions, parseSchema } from './json-schema';
38
38
39
39
40
40
export interface CommandMap {
41
- [ key : string ] : string ;
41
+ [ key : string ] : Path ;
42
42
}
43
43
44
44
interface CommandMetadata {
@@ -84,9 +84,12 @@ function levenshtein(a: string, b: string): number {
84
84
* @param logger The logger to use.
85
85
* @param context Execution context.
86
86
*/
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 > {
90
93
91
94
// if not args supplied, just run the help command.
92
95
if ( ! args || args . length === 0 ) {
@@ -101,24 +104,31 @@ export async function runCommand(args: string[],
101
104
? CommandScope . inProject
102
105
: CommandScope . outsideProject ;
103
106
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.' ) ;
107
111
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
+ }
109
122
}
110
- const cliDir = dirname ( normalize ( commandMapPath ) ) ;
111
- const commandsText = readFileSync ( commandMapPath ) . toString ( 'utf-8' ) ;
112
- const commandMap = JSON . parse ( commandsText ) as CommandMap ;
113
123
114
- let commandMetadata = commandName ? findCommand ( cliDir , commandMap , commandName ) : null ;
124
+ let commandMetadata = commandName ? findCommand ( commandMap , commandName ) : null ;
115
125
116
126
if ( ! commandMetadata && ( rawOptions . v || rawOptions . version ) ) {
117
127
commandName = 'version' ;
118
- commandMetadata = findCommand ( cliDir , commandMap , commandName ) ;
128
+ commandMetadata = findCommand ( commandMap , commandName ) ;
119
129
} else if ( ! commandMetadata && rawOptions . help ) {
120
130
commandName = 'help' ;
121
- commandMetadata = findCommand ( cliDir , commandMap , commandName ) ;
131
+ commandMetadata = findCommand ( commandMap , commandName ) ;
122
132
}
123
133
124
134
if ( ! commandMetadata ) {
@@ -132,7 +142,7 @@ export async function runCommand(args: string[],
132
142
return 1 ;
133
143
} else {
134
144
const commandsDistance = { } as { [ name : string ] : number } ;
135
- const allCommands = listAllCommandNames ( cliDir , commandMap ) . sort ( ( a , b ) => {
145
+ const allCommands = Object . keys ( commandMap ) . sort ( ( a , b ) => {
136
146
if ( ! ( a in commandsDistance ) ) {
137
147
commandsDistance [ a ] = levenshtein ( a , commandName ) ;
138
148
}
@@ -153,7 +163,7 @@ export async function runCommand(args: string[],
153
163
}
154
164
}
155
165
156
- const command = await createCommand ( cliDir , commandMetadata , context , logger ) ;
166
+ const command = await createCommand ( commandMetadata , context , logger ) ;
157
167
const metadataOptions = await convertSchemaToOptions ( commandMetadata . text ) ;
158
168
if ( command === null ) {
159
169
logger . error ( tags . stripIndent `Command (${ commandName } ) failed to instantiate.` ) ;
@@ -173,7 +183,7 @@ export async function runCommand(args: string[],
173
183
options = parseOptions ( args , command . options ) ;
174
184
175
185
if ( commandName === 'help' ) {
176
- options . commandInfo = getAllCommandInfo ( cliDir , commandMap ) ;
186
+ options . commandInfo = getAllCommandInfo ( commandMap ) ;
177
187
}
178
188
179
189
if ( options . help ) {
@@ -350,7 +360,7 @@ export function parseOptions(args: string[], optionsAndArguments: Option[]) {
350
360
}
351
361
352
362
// Find a command.
353
- function findCommand ( rootDir : Path , map : CommandMap , name : string ) : CommandLocation | null {
363
+ function findCommand ( map : CommandMap , name : string ) : CommandLocation | null {
354
364
// let Cmd: CommandConstructor = map[name];
355
365
let commandName = name ;
356
366
@@ -359,8 +369,7 @@ function findCommand(rootDir: Path, map: CommandMap, name: string): CommandLocat
359
369
commandName = Object . keys ( map )
360
370
. filter ( key => {
361
371
// 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' ) ;
364
373
const metadata = JSON . parse ( metadataText ) ;
365
374
const aliases = metadata [ '$aliases' ] ;
366
375
if ( ! aliases ) {
@@ -372,12 +381,11 @@ function findCommand(rootDir: Path, map: CommandMap, name: string): CommandLocat
372
381
} ) [ 0 ] ;
373
382
}
374
383
375
- const relativeMetadataPath = map [ commandName ] ;
384
+ const metadataPath = map [ commandName ] ;
376
385
377
- if ( ! relativeMetadataPath ) {
386
+ if ( ! metadataPath ) {
378
387
return null ;
379
388
}
380
- const metadataPath = join ( rootDir , relativeMetadataPath ) ;
381
389
const metadataText = readFileSync ( metadataPath ) . toString ( 'utf-8' ) ;
382
390
383
391
const metadata = parseJson ( metadataText ) as any ;
@@ -390,8 +398,7 @@ function findCommand(rootDir: Path, map: CommandMap, name: string): CommandLocat
390
398
}
391
399
392
400
// Create an instance of a command.
393
- async function createCommand ( rootDir : Path ,
394
- metadata : CommandLocation ,
401
+ async function createCommand ( metadata : CommandLocation ,
395
402
context : CommandContext ,
396
403
logger : logging . Logger ) : Promise < Command | null > {
397
404
const schema = parseSchema ( metadata . text ) ;
@@ -424,26 +431,18 @@ function mapCommandScope(scope: 'in' | 'out' | undefined): CommandScope {
424
431
return commandScope ;
425
432
}
426
433
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
-
435
434
interface CommandInfo {
436
435
name : string ;
437
436
description : string ;
438
437
aliases : string [ ] ;
439
438
hidden : boolean ;
440
439
}
441
- function getAllCommandInfo ( rootDir : Path , map : CommandMap ) : CommandInfo [ ] {
440
+ function getAllCommandInfo ( map : CommandMap ) : CommandInfo [ ] {
442
441
return Object . keys ( map )
443
442
. map ( name => {
444
443
return {
445
444
name : name ,
446
- metadata : findCommand ( rootDir , map , name ) ,
445
+ metadata : findCommand ( map , name ) ,
447
446
} ;
448
447
} )
449
448
. map ( info => {
0 commit comments