Skip to content

Commit c4e9ff4

Browse files
authored
refactor(vscode): split Dart Frog project resolution into workspace and editor (#1018)
1 parent 9bac0a9 commit c4e9ff4

17 files changed

+533
-353
lines changed

extensions/vscode/src/commands/new-middleware.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import {
1111
isDartFrogCLIInstalled,
1212
nearestParentDartFrogProject,
1313
normalizeRoutePath,
14-
resolveDartFrogProjectPathFromWorkspace,
14+
resolveDartFrogProjectPathFromActiveTextEditor,
15+
resolveDartFrogProjectPathFromWorkspaceFolders,
1516
suggestInstallingDartFrogCLI,
1617
} from "../utils";
1718

@@ -20,9 +21,11 @@ import {
2021
*
2122
* This command is available from the command palette and the context menu.
2223
*
23-
* When launching the command from the command palette, the Uri is undefined
24-
* and the user is prompted to select a valid directory or file to create the
25-
* route in.
24+
* When launching the command from the command palette, the Uri is undefined.
25+
* Therefore, the command attempts to resolve a path from the user's active text
26+
* editor first and then from the user's workspace folders. If no path can be
27+
* resolved from either of those sources, the user is prompted to select a valid
28+
* directory or file to create the route in.
2629
*
2730
* When launching the command from the context menu, the Uri corresponds to the
2831
* selected file or directory. Only those directories or dart files under a
@@ -44,12 +47,15 @@ export const newMiddleware = async (uri: Uri | undefined): Promise<void> => {
4447

4548
let selectedPath;
4649
if (uri === undefined) {
47-
selectedPath = resolveDartFrogProjectPathFromWorkspace();
50+
selectedPath = resolveDartFrogProjectPathFromActiveTextEditor();
4851

49-
if (selectedPath === undefined) {
52+
if (!selectedPath) {
53+
selectedPath = resolveDartFrogProjectPathFromWorkspaceFolders();
54+
}
55+
if (!selectedPath) {
5056
selectedPath = await promptForTargetDirectory();
5157
}
52-
if (selectedPath === undefined) {
58+
if (!selectedPath) {
5359
window.showErrorMessage("Please select a valid directory");
5460
return;
5561
}
@@ -58,7 +64,7 @@ export const newMiddleware = async (uri: Uri | undefined): Promise<void> => {
5864
}
5965

6066
const dartFrogProjectPath = nearestParentDartFrogProject(selectedPath);
61-
if (dartFrogProjectPath === undefined) {
67+
if (!dartFrogProjectPath) {
6268
window.showErrorMessage(
6369
"No Dart Frog project found in the selected directory"
6470
);

extensions/vscode/src/commands/new-route.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import {
1111
isDartFrogCLIInstalled,
1212
nearestParentDartFrogProject,
1313
normalizeRoutePath,
14-
resolveDartFrogProjectPathFromWorkspace,
14+
resolveDartFrogProjectPathFromActiveTextEditor,
15+
resolveDartFrogProjectPathFromWorkspaceFolders,
1516
suggestInstallingDartFrogCLI,
1617
} from "../utils";
1718

@@ -20,9 +21,11 @@ import {
2021
*
2122
* This command is available from the command palette and the context menu.
2223
*
23-
* When launching the command from the command palette, the Uri is undefined
24-
* and the user is prompted to select a valid directory or file to create the
25-
* route in.
24+
* When launching the command from the command palette, the Uri is undefined.
25+
* Therefore, the command attempts to resolve a path from the user's active text
26+
* editor first and then from the user's workspace folders. If no path can be
27+
* resolved from either of those sources, the user is prompted to select a valid
28+
* directory or file to create the route in.
2629
*
2730
* When launching the command from the context menu, the Uri corresponds to the
2831
* selected file or directory. Only those directories or dart files under a
@@ -44,12 +47,15 @@ export const newRoute = async (uri: Uri | undefined): Promise<void> => {
4447

4548
let selectedPath;
4649
if (uri === undefined) {
47-
selectedPath = resolveDartFrogProjectPathFromWorkspace();
50+
selectedPath = resolveDartFrogProjectPathFromActiveTextEditor();
4851

49-
if (selectedPath === undefined) {
52+
if (!selectedPath) {
53+
selectedPath = resolveDartFrogProjectPathFromWorkspaceFolders();
54+
}
55+
if (!selectedPath) {
5056
selectedPath = await promptForTargetDirectory();
5157
}
52-
if (selectedPath === undefined) {
58+
if (!selectedPath) {
5359
window.showErrorMessage("Please select a valid directory");
5460
return;
5561
}
@@ -58,7 +64,7 @@ export const newRoute = async (uri: Uri | undefined): Promise<void> => {
5864
}
5965

6066
const dartFrogProjectPath = nearestParentDartFrogProject(selectedPath);
61-
if (dartFrogProjectPath === undefined) {
67+
if (!dartFrogProjectPath) {
6268
window.showErrorMessage(
6369
"No Dart Frog project found in the selected directory"
6470
);

extensions/vscode/src/commands/start-daemon.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import {
22
isDartFrogCLIInstalled,
33
nearestParentDartFrogProject,
4-
resolveDartFrogProjectPathFromWorkspace,
4+
resolveDartFrogProjectPathFromActiveTextEditor,
5+
resolveDartFrogProjectPathFromWorkspaceFolders,
56
suggestInstallingDartFrogCLI,
67
} from "../utils";
78
import { DartFrogDaemon } from "../daemon";
@@ -33,7 +34,11 @@ export const startDaemon = async (): Promise<void> => {
3334
return;
3435
}
3536

36-
const dartFrogProjectPath = resolveDartFrogProjectPathFromWorkspace();
37+
let dartFrogProjectPath = resolveDartFrogProjectPathFromWorkspaceFolders();
38+
if (!dartFrogProjectPath) {
39+
dartFrogProjectPath = resolveDartFrogProjectPathFromActiveTextEditor();
40+
}
41+
3742
const rootDartFrogProjectPath = dartFrogProjectPath
3843
? nearestParentDartFrogProject(dartFrogProjectPath)
3944
: undefined;

extensions/vscode/src/commands/start-dev-server.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import { Uri, commands, window } from "vscode";
99
import {
1010
isDartFrogCLIInstalled,
1111
nearestParentDartFrogProject,
12-
resolveDartFrogProjectPathFromWorkspace,
12+
resolveDartFrogProjectPathFromActiveTextEditor,
13+
resolveDartFrogProjectPathFromWorkspaceFolders,
1314
suggestInstallingDartFrogCLI,
1415
} from "../utils";
1516

@@ -56,7 +57,11 @@ export const startDevServer = async (): Promise<
5657
return;
5758
}
5859

59-
const workingPath = resolveDartFrogProjectPathFromWorkspace();
60+
let workingPath = resolveDartFrogProjectPathFromWorkspaceFolders();
61+
if (!workingPath) {
62+
workingPath = resolveDartFrogProjectPathFromActiveTextEditor();
63+
}
64+
6065
const workingDirectory = workingPath
6166
? nearestParentDartFrogProject(workingPath)
6267
: undefined;

extensions/vscode/src/extension.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ import {
77
OpenApplicationStatusBarItem,
88
StartStopApplicationStatusBarItem,
99
} from "./status-bar";
10+
import {
11+
canResolveDartFrogProjectPath,
12+
isCompatibleDartFrogCLIVersion,
13+
isDartFrogCLIInstalled,
14+
openChangelog,
15+
readDartFrogCLIVersion,
16+
readLatestDartFrogCLIVersion,
17+
suggestInstallingDartFrogCLI,
18+
} from "./utils";
1019
import {
1120
create,
1221
debugDevServer,
@@ -19,15 +28,6 @@ import {
1928
stopDevServer,
2029
updateCLI,
2130
} from "./commands";
22-
import {
23-
isCompatibleDartFrogCLIVersion,
24-
isDartFrogCLIInstalled,
25-
openChangelog,
26-
readDartFrogCLIVersion,
27-
readLatestDartFrogCLIVersion,
28-
resolveDartFrogProjectPathFromWorkspace,
29-
suggestInstallingDartFrogCLI,
30-
} from "./utils";
3131

3232
/**
3333
* This method is called when the extension is activated.
@@ -102,12 +102,10 @@ export function activate(
102102
* @see {@link https://code.visualstudio.com/api/references/when-clause-contexts#add-a-custom-when-clause-context} for further details about custom when clause context.
103103
*/
104104
function updateAnyDartFrogProjectLoaded(): void {
105-
const anyDartFrogProjectLoaded =
106-
resolveDartFrogProjectPathFromWorkspace() !== undefined;
107105
vscode.commands.executeCommand(
108106
"setContext",
109107
"dart-frog:anyDartFrogProjectLoaded",
110-
anyDartFrogProjectLoaded
108+
canResolveDartFrogProjectPath()
111109
);
112110
}
113111

extensions/vscode/src/status-bar/dart-frog-status-bar-item.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
window,
66
workspace,
77
} from "vscode";
8-
import { resolveDartFrogProjectPathFromWorkspace } from "../utils";
8+
import { canResolveDartFrogProjectPath } from "../utils";
99

1010
/**
1111
* Wraps a status bar item so that is only visible when the current workspace
@@ -35,8 +35,7 @@ export abstract class DartFrogStatusBarItem implements Disposable {
3535
public abstract update(): any;
3636

3737
private onChangeSetup(): void {
38-
const isDartFrogProject = resolveDartFrogProjectPathFromWorkspace();
39-
if (isDartFrogProject) {
38+
if (canResolveDartFrogProjectPath()) {
4039
this.update();
4140
} else {
4241
this.statusBarItem.hide();

extensions/vscode/src/test/suite/commands/new-middleware.test.ts

Lines changed: 80 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,16 @@ suite("new-middleware command", () => {
2828
utilsStub = {
2929
nearestParentDartFrogProject: sinon.stub(),
3030
normalizeRoutePath: sinon.stub(),
31-
resolveDartFrogProjectPathFromWorkspace: sinon.stub(),
31+
resolveDartFrogProjectPathFromActiveTextEditor: sinon.stub(),
32+
resolveDartFrogProjectPathFromWorkspaceFolders: sinon.stub(),
3233
isDartFrogCLIInstalled: sinon.stub(),
3334
suggestInstallingDartFrogCLI: sinon.stub(),
3435
};
3536
utilsStub.isDartFrogCLIInstalled.returns(true);
3637

3738
utilsStub.nearestParentDartFrogProject
3839
.withArgs(invalidUri.fsPath)
39-
.returns(undefined);
40+
.returns();
4041
utilsStub.nearestParentDartFrogProject
4142
.withArgs(validUri.fsPath)
4243
.returns(validUri.fsPath);
@@ -74,9 +75,10 @@ suite("new-middleware command", () => {
7475
});
7576

7677
suite("file open dialog", () => {
77-
test("is shown when Uri is undefined and fails to resolve a path from workspace", async () => {
78+
test("is shown when Uri is undefined and fails to resolve a path from workspace folder", async () => {
7879
vscodeStub.window.showOpenDialog.resolves();
79-
utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(undefined);
80+
utilsStub.resolveDartFrogProjectPathFromActiveTextEditor.returns();
81+
utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns();
8082

8183
await command.newMiddleware();
8284

@@ -88,22 +90,40 @@ suite("new-middleware command", () => {
8890
});
8991
});
9092

91-
test("is not shown when Uri is undefined but resolves a path from workspace", async () => {
92-
utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(
93-
"/home/dart_frog/routes"
94-
);
95-
utilsStub.nearestParentDartFrogProject.returns("/home/dart_frog/");
96-
utilsStub.normalizeRoutePath.returns("/");
93+
suite("is not shown", () => {
94+
test("when Uri is defined", async () => {
95+
await command.newMiddleware(invalidUri);
9796

98-
await command.newMiddleware();
97+
sinon.assert.notCalled(vscodeStub.window.showOpenDialog);
98+
});
9999

100-
sinon.assert.notCalled(vscodeStub.window.showOpenDialog);
101-
});
100+
test("when Uri is undefined but resolves a path from active text editor", async () => {
101+
utilsStub.resolveDartFrogProjectPathFromActiveTextEditor.returns(
102+
"/home/dart_frog/routes/index.dart"
103+
);
104+
utilsStub.nearestParentDartFrogProject.returns("/home/dart_frog/");
105+
utilsStub.normalizeRoutePath.returns("/");
102106

103-
test("is not shown when Uri is defined", async () => {
104-
await command.newMiddleware(invalidUri);
107+
await command.newMiddleware();
108+
109+
sinon.assert.notCalled(vscodeStub.window.showOpenDialog);
110+
});
105111

106-
sinon.assert.notCalled(vscodeStub.window.showOpenDialog);
112+
test("when Uri and active text editor are undefined but resolves a path from workspace folder", async () => {
113+
utilsStub.resolveDartFrogProjectPathFromActiveTextEditor.returns();
114+
utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns(
115+
"/home/dart_frog/routes"
116+
);
117+
utilsStub.nearestParentDartFrogProject.returns("/home/dart_frog/");
118+
utilsStub.normalizeRoutePath.returns("/");
119+
120+
await command.newMiddleware();
121+
122+
sinon.assert.called(
123+
utilsStub.resolveDartFrogProjectPathFromActiveTextEditor
124+
);
125+
sinon.assert.notCalled(vscodeStub.window.showOpenDialog);
126+
});
107127
});
108128
});
109129

@@ -159,22 +179,49 @@ suite("new-middleware command", () => {
159179
);
160180

161181
suite("prompts for route path", () => {
162-
test("is shown when Uri is undefined and selected file is valid", async () => {
163-
vscodeStub.window.showInputBox.returns("animals/frog");
164-
utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(
165-
"home/routes/animals/frog"
166-
);
167-
utilsStub.nearestParentDartFrogProject.returns(
168-
"home/routes/animals/frog"
169-
);
170-
utilsStub.normalizeRoutePath.returns("/animals/frog");
182+
suite("is shown", () => {
183+
test("when Uri is undefined and resolved active text editor is valid", async () => {
184+
vscodeStub.window.showInputBox.returns("animals/frog");
185+
utilsStub.resolveDartFrogProjectPathFromActiveTextEditor.returns(
186+
"home/routes/animals/frog"
187+
);
188+
utilsStub.nearestParentDartFrogProject.returns(
189+
"home/routes/animals/frog"
190+
);
191+
utilsStub.normalizeRoutePath.returns("/animals/frog");
171192

172-
await command.newMiddleware();
193+
await command.newMiddleware();
173194

174-
sinon.assert.calledWith(vscodeStub.window.showInputBox, {
175-
prompt: "Middleware's route path",
176-
value: "/animals/frog",
177-
placeHolder: "_middleware",
195+
sinon.assert.notCalled(
196+
utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders
197+
);
198+
sinon.assert.calledWith(vscodeStub.window.showInputBox, {
199+
prompt: "Middleware's route path",
200+
value: "/animals/frog",
201+
placeHolder: "_middleware",
202+
});
203+
});
204+
205+
test("when Uri and resolved active text editor are undefined but resolved workspace file is valid", async () => {
206+
vscodeStub.window.showInputBox.returns("animals/frog");
207+
utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns(
208+
"home/routes/animals/frog"
209+
);
210+
utilsStub.nearestParentDartFrogProject.returns(
211+
"home/routes/animals/frog"
212+
);
213+
utilsStub.normalizeRoutePath.returns("/animals/frog");
214+
215+
await command.newMiddleware();
216+
217+
sinon.assert.called(
218+
utilsStub.resolveDartFrogProjectPathFromActiveTextEditor
219+
);
220+
sinon.assert.calledWith(vscodeStub.window.showInputBox, {
221+
prompt: "Middleware's route path",
222+
value: "/animals/frog",
223+
placeHolder: "_middleware",
224+
});
178225
});
179226
});
180227

@@ -199,7 +246,7 @@ suite("new-middleware command", () => {
199246

200247
beforeEach(() => {
201248
vscodeStub.window.showInputBox.returns("animals/frog");
202-
utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(
249+
utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns(
203250
"home/routes/animals/frog"
204251
);
205252
utilsStub.nearestParentDartFrogProject.returns(
@@ -225,7 +272,7 @@ suite("new-middleware command", () => {
225272
});
226273

227274
test("is shown when prompt is undefined", async () => {
228-
vscodeStub.window.showInputBox.returns(undefined);
275+
vscodeStub.window.showInputBox.returns();
229276

230277
await command.newMiddleware();
231278

@@ -319,7 +366,7 @@ suite("new-middleware command", () => {
319366
});
320367

321368
test("successfully with prompt route path", async () => {
322-
utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(
369+
utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns(
323370
"home/routes/animals/frog"
324371
);
325372
utilsStub.nearestParentDartFrogProject.returns(

0 commit comments

Comments
 (0)