@@ -18,13 +18,13 @@ interface IScript {
18
18
command : string ;
19
19
}
20
20
21
- type ScriptPickItem = vscode . QuickPickItem & { script : IScript } ;
21
+ type ScriptPickItem = vscode . QuickPickItem & { script ? : IScript } ;
22
22
23
23
/**
24
24
* Opens a quickpick and them subsequently debugs a configured npm script.
25
25
* @param inFolder - Optionally scopes lookups to the given workspace folder
26
26
*/
27
- export async function debugNpmScript ( inFolder ?: string ) {
27
+ export async function debugNpmScript ( inFolder ?: vscode . WorkspaceFolder | string ) {
28
28
const scripts = await findScripts ( inFolder ? [ inFolder ] : undefined ) ;
29
29
if ( ! scripts ) {
30
30
return ; // cancelled
@@ -50,14 +50,28 @@ export async function debugNpmScript(inFolder?: string) {
50
50
const multiDir = scripts . some ( s => s . directory !== scripts [ 0 ] . directory ) ;
51
51
const quickPick = vscode . window . createQuickPick < ScriptPickItem > ( ) ;
52
52
53
- quickPick . items = scripts . map ( script => ( {
54
- script,
55
- label : multiDir ? `${ path . basename ( script . directory ) } : ${ script . name } ` : script . name ,
56
- description : script . command ,
57
- } ) ) ;
53
+ let lastDir : string | undefined ;
54
+ const items : ScriptPickItem [ ] = [ ] ;
55
+ for ( const script of scripts ) {
56
+ if ( script . directory !== lastDir && multiDir ) {
57
+ items . push ( {
58
+ label : path . basename ( script . directory ) ,
59
+ kind : vscode . QuickPickItemKind . Separator ,
60
+ } ) ;
61
+ lastDir = script . directory ;
62
+ }
63
+
64
+ items . push ( {
65
+ script,
66
+ label : script . name ,
67
+ description : script . command ,
68
+ } ) ;
69
+ }
70
+ quickPick . items = items ;
58
71
59
72
quickPick . onDidAccept ( async ( ) => {
60
- runScript ( quickPick . selectedItems [ 0 ] . script ) ;
73
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
74
+ runScript ( quickPick . selectedItems [ 0 ] . script ! ) ;
61
75
quickPick . dispose ( ) ;
62
76
} ) ;
63
77
@@ -76,10 +90,10 @@ const updateEditCandidate = (existing: IEditCandidate, updated: IEditCandidate)
76
90
* Finds configured npm scripts in the workspace.
77
91
*/
78
92
export async function findScripts (
79
- inFolders : string [ ] | undefined ,
93
+ inFolders : ( vscode . WorkspaceFolder | string ) [ ] | undefined ,
80
94
silent = false ,
81
95
) : Promise < IScript [ ] | undefined > {
82
- const folders = inFolders ?? vscode . workspace . workspaceFolders ?. map ( f => f . uri . fsPath ) ?? [ ] ;
96
+ const folders = inFolders ?? vscode . workspace . workspaceFolders ?? [ ] ;
83
97
84
98
// 1. If there are no open folders, show an error and abort.
85
99
if ( ! folders || folders . length === 0 ) {
@@ -95,32 +109,39 @@ export async function findScripts(
95
109
}
96
110
97
111
// Otherwise, go through all package.json's in the folder and pull all the npm scripts we find.
98
- const candidates = folders . map ( directory => path . join ( directory , 'package.json' ) ) ;
112
+ const candidates = (
113
+ await Promise . all (
114
+ folders . map ( f =>
115
+ vscode . workspace . findFiles (
116
+ new vscode . RelativePattern ( f , '**/package.json' ) ,
117
+ // matches https://github.com/microsoft/vscode/blob/18f743d534ef3f528c5e81e82e695b87c60d2ebf/extensions/npm/src/tasks.ts#L189
118
+ '**/{node_modules,.vscode-test}/**' ,
119
+ ) ,
120
+ ) ,
121
+ )
122
+ ) . flat ( ) ;
123
+
99
124
const scripts : IScript [ ] = [ ] ;
100
125
101
126
// editCandidate is the file we'll edit if we don't find any npm scripts.
102
127
// We 'narrow' this as we parse to files that look more like a package.json we want
103
- let editCandidate : IEditCandidate = { path : candidates [ 0 ] , score : 0 } ;
104
- for ( const packageJson of candidates ) {
105
- if ( ! fs . existsSync ( packageJson ) ) {
106
- continue ;
107
- }
108
-
128
+ let editCandidate : IEditCandidate = { path : candidates [ 0 ] . fsPath , score : 0 } ;
129
+ for ( const { fsPath } of new Set ( candidates ) ) {
109
130
// update this now, because we know it exists
110
131
editCandidate = updateEditCandidate ( editCandidate , {
111
- path : packageJson ,
132
+ path : fsPath ,
112
133
score : 1 ,
113
134
} ) ;
114
135
115
136
let parsed : { scripts ?: { [ key : string ] : string } } ;
116
137
try {
117
- parsed = JSON . parse ( await readfile ( packageJson ) ) ;
138
+ parsed = JSON . parse ( await readfile ( fsPath ) ) ;
118
139
} catch ( e ) {
119
140
if ( ! silent ) {
120
141
promptToOpen (
121
142
'showWarningMessage' ,
122
- localize ( 'debug.npm.parseError' , 'Could not read {0}: {1}' , packageJson , e . message ) ,
123
- packageJson ,
143
+ localize ( 'debug.npm.parseError' , 'Could not read {0}: {1}' , fsPath , e . message ) ,
144
+ fsPath ,
124
145
) ;
125
146
}
126
147
// set the candidate to 'undefined', since we already displayed an error
@@ -138,7 +159,7 @@ export async function findScripts(
138
159
139
160
for ( const key of Object . keys ( parsed . scripts ) ) {
140
161
scripts . push ( {
141
- directory : path . dirname ( packageJson ) ,
162
+ directory : path . dirname ( fsPath ) ,
142
163
name : key ,
143
164
command : parsed . scripts [ key ] ,
144
165
} ) ;
0 commit comments