Skip to content

Commit 60133d3

Browse files
authored
Merge pull request #1417 from microsoft/search-npm-scripts
fix: discover npm scripts in nested workspace folders
2 parents 9102e35 + 6f8681a commit 60133d3

File tree

3 files changed

+45
-23
lines changed

3 files changed

+45
-23
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ This changelog records changes to stable releases since 1.50.2. "TBA" changes he
88
- feat: add automatic support for nested sourcemaps ([#1390](https://github.com/microsoft/vscode-js-debug/issues/1390))
99
- fix: breakpoints failing to set on paths with multibyte URL characters ([#1364](https://github.com/microsoft/vscode-js-debug/issues/1364))
1010
- fix: properly handle UNC paths ([#1148](https://github.com/microsoft/vscode-js-debug/issues/1148))
11+
- fix: discover npm scripts in nested workspace folders ([#1321](https://github.com/microsoft/vscode-js-debug/issues/1321))
1112

1213
## v1.72 (September 2022)
1314

src/ui/configuration/nodeDebugConfigurationProvider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export class NodeDynamicDebugConfigurationProvider extends BaseConfigurationProv
9090
return [openTerminal];
9191
}
9292

93-
const scripts = await findScripts([folder.uri.fsPath], true);
93+
const scripts = await findScripts([folder], true);
9494
if (!scripts) {
9595
return [openTerminal];
9696
}

src/ui/debugNpmScript.ts

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ interface IScript {
1818
command: string;
1919
}
2020

21-
type ScriptPickItem = vscode.QuickPickItem & { script: IScript };
21+
type ScriptPickItem = vscode.QuickPickItem & { script?: IScript };
2222

2323
/**
2424
* Opens a quickpick and them subsequently debugs a configured npm script.
2525
* @param inFolder - Optionally scopes lookups to the given workspace folder
2626
*/
27-
export async function debugNpmScript(inFolder?: string) {
27+
export async function debugNpmScript(inFolder?: vscode.WorkspaceFolder | string) {
2828
const scripts = await findScripts(inFolder ? [inFolder] : undefined);
2929
if (!scripts) {
3030
return; // cancelled
@@ -50,14 +50,28 @@ export async function debugNpmScript(inFolder?: string) {
5050
const multiDir = scripts.some(s => s.directory !== scripts[0].directory);
5151
const quickPick = vscode.window.createQuickPick<ScriptPickItem>();
5252

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;
5871

5972
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!);
6175
quickPick.dispose();
6276
});
6377

@@ -76,10 +90,10 @@ const updateEditCandidate = (existing: IEditCandidate, updated: IEditCandidate)
7690
* Finds configured npm scripts in the workspace.
7791
*/
7892
export async function findScripts(
79-
inFolders: string[] | undefined,
93+
inFolders: (vscode.WorkspaceFolder | string)[] | undefined,
8094
silent = false,
8195
): Promise<IScript[] | undefined> {
82-
const folders = inFolders ?? vscode.workspace.workspaceFolders?.map(f => f.uri.fsPath) ?? [];
96+
const folders = inFolders ?? vscode.workspace.workspaceFolders ?? [];
8397

8498
// 1. If there are no open folders, show an error and abort.
8599
if (!folders || folders.length === 0) {
@@ -95,32 +109,39 @@ export async function findScripts(
95109
}
96110

97111
// 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+
99124
const scripts: IScript[] = [];
100125

101126
// editCandidate is the file we'll edit if we don't find any npm scripts.
102127
// 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)) {
109130
// update this now, because we know it exists
110131
editCandidate = updateEditCandidate(editCandidate, {
111-
path: packageJson,
132+
path: fsPath,
112133
score: 1,
113134
});
114135

115136
let parsed: { scripts?: { [key: string]: string } };
116137
try {
117-
parsed = JSON.parse(await readfile(packageJson));
138+
parsed = JSON.parse(await readfile(fsPath));
118139
} catch (e) {
119140
if (!silent) {
120141
promptToOpen(
121142
'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,
124145
);
125146
}
126147
// set the candidate to 'undefined', since we already displayed an error
@@ -138,7 +159,7 @@ export async function findScripts(
138159

139160
for (const key of Object.keys(parsed.scripts)) {
140161
scripts.push({
141-
directory: path.dirname(packageJson),
162+
directory: path.dirname(fsPath),
142163
name: key,
143164
command: parsed.scripts[key],
144165
});

0 commit comments

Comments
 (0)