Skip to content

Commit

Permalink
refactor(vscode): split Dart Frog project resolution into workspace a…
Browse files Browse the repository at this point in the history
…nd editor (#1018)
  • Loading branch information
alestiago authored Sep 13, 2023
1 parent 9bac0a9 commit c4e9ff4
Show file tree
Hide file tree
Showing 17 changed files with 533 additions and 353 deletions.
22 changes: 14 additions & 8 deletions extensions/vscode/src/commands/new-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
isDartFrogCLIInstalled,
nearestParentDartFrogProject,
normalizeRoutePath,
resolveDartFrogProjectPathFromWorkspace,
resolveDartFrogProjectPathFromActiveTextEditor,
resolveDartFrogProjectPathFromWorkspaceFolders,
suggestInstallingDartFrogCLI,
} from "../utils";

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

let selectedPath;
if (uri === undefined) {
selectedPath = resolveDartFrogProjectPathFromWorkspace();
selectedPath = resolveDartFrogProjectPathFromActiveTextEditor();

if (selectedPath === undefined) {
if (!selectedPath) {
selectedPath = resolveDartFrogProjectPathFromWorkspaceFolders();
}
if (!selectedPath) {
selectedPath = await promptForTargetDirectory();
}
if (selectedPath === undefined) {
if (!selectedPath) {
window.showErrorMessage("Please select a valid directory");
return;
}
Expand All @@ -58,7 +64,7 @@ export const newMiddleware = async (uri: Uri | undefined): Promise<void> => {
}

const dartFrogProjectPath = nearestParentDartFrogProject(selectedPath);
if (dartFrogProjectPath === undefined) {
if (!dartFrogProjectPath) {
window.showErrorMessage(
"No Dart Frog project found in the selected directory"
);
Expand Down
22 changes: 14 additions & 8 deletions extensions/vscode/src/commands/new-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
isDartFrogCLIInstalled,
nearestParentDartFrogProject,
normalizeRoutePath,
resolveDartFrogProjectPathFromWorkspace,
resolveDartFrogProjectPathFromActiveTextEditor,
resolveDartFrogProjectPathFromWorkspaceFolders,
suggestInstallingDartFrogCLI,
} from "../utils";

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

let selectedPath;
if (uri === undefined) {
selectedPath = resolveDartFrogProjectPathFromWorkspace();
selectedPath = resolveDartFrogProjectPathFromActiveTextEditor();

if (selectedPath === undefined) {
if (!selectedPath) {
selectedPath = resolveDartFrogProjectPathFromWorkspaceFolders();
}
if (!selectedPath) {
selectedPath = await promptForTargetDirectory();
}
if (selectedPath === undefined) {
if (!selectedPath) {
window.showErrorMessage("Please select a valid directory");
return;
}
Expand All @@ -58,7 +64,7 @@ export const newRoute = async (uri: Uri | undefined): Promise<void> => {
}

const dartFrogProjectPath = nearestParentDartFrogProject(selectedPath);
if (dartFrogProjectPath === undefined) {
if (!dartFrogProjectPath) {
window.showErrorMessage(
"No Dart Frog project found in the selected directory"
);
Expand Down
9 changes: 7 additions & 2 deletions extensions/vscode/src/commands/start-daemon.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {
isDartFrogCLIInstalled,
nearestParentDartFrogProject,
resolveDartFrogProjectPathFromWorkspace,
resolveDartFrogProjectPathFromActiveTextEditor,
resolveDartFrogProjectPathFromWorkspaceFolders,
suggestInstallingDartFrogCLI,
} from "../utils";
import { DartFrogDaemon } from "../daemon";
Expand Down Expand Up @@ -33,7 +34,11 @@ export const startDaemon = async (): Promise<void> => {
return;
}

const dartFrogProjectPath = resolveDartFrogProjectPathFromWorkspace();
let dartFrogProjectPath = resolveDartFrogProjectPathFromWorkspaceFolders();
if (!dartFrogProjectPath) {
dartFrogProjectPath = resolveDartFrogProjectPathFromActiveTextEditor();
}

const rootDartFrogProjectPath = dartFrogProjectPath
? nearestParentDartFrogProject(dartFrogProjectPath)
: undefined;
Expand Down
9 changes: 7 additions & 2 deletions extensions/vscode/src/commands/start-dev-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { Uri, commands, window } from "vscode";
import {
isDartFrogCLIInstalled,
nearestParentDartFrogProject,
resolveDartFrogProjectPathFromWorkspace,
resolveDartFrogProjectPathFromActiveTextEditor,
resolveDartFrogProjectPathFromWorkspaceFolders,
suggestInstallingDartFrogCLI,
} from "../utils";

Expand Down Expand Up @@ -56,7 +57,11 @@ export const startDevServer = async (): Promise<
return;
}

const workingPath = resolveDartFrogProjectPathFromWorkspace();
let workingPath = resolveDartFrogProjectPathFromWorkspaceFolders();
if (!workingPath) {
workingPath = resolveDartFrogProjectPathFromActiveTextEditor();
}

const workingDirectory = workingPath
? nearestParentDartFrogProject(workingPath)
: undefined;
Expand Down
22 changes: 10 additions & 12 deletions extensions/vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ import {
OpenApplicationStatusBarItem,
StartStopApplicationStatusBarItem,
} from "./status-bar";
import {
canResolveDartFrogProjectPath,
isCompatibleDartFrogCLIVersion,
isDartFrogCLIInstalled,
openChangelog,
readDartFrogCLIVersion,
readLatestDartFrogCLIVersion,
suggestInstallingDartFrogCLI,
} from "./utils";
import {
create,
debugDevServer,
Expand All @@ -19,15 +28,6 @@ import {
stopDevServer,
updateCLI,
} from "./commands";
import {
isCompatibleDartFrogCLIVersion,
isDartFrogCLIInstalled,
openChangelog,
readDartFrogCLIVersion,
readLatestDartFrogCLIVersion,
resolveDartFrogProjectPathFromWorkspace,
suggestInstallingDartFrogCLI,
} from "./utils";

/**
* This method is called when the extension is activated.
Expand Down Expand Up @@ -102,12 +102,10 @@ export function activate(
* @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.
*/
function updateAnyDartFrogProjectLoaded(): void {
const anyDartFrogProjectLoaded =
resolveDartFrogProjectPathFromWorkspace() !== undefined;
vscode.commands.executeCommand(
"setContext",
"dart-frog:anyDartFrogProjectLoaded",
anyDartFrogProjectLoaded
canResolveDartFrogProjectPath()
);
}

Expand Down
5 changes: 2 additions & 3 deletions extensions/vscode/src/status-bar/dart-frog-status-bar-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
window,
workspace,
} from "vscode";
import { resolveDartFrogProjectPathFromWorkspace } from "../utils";
import { canResolveDartFrogProjectPath } from "../utils";

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

private onChangeSetup(): void {
const isDartFrogProject = resolveDartFrogProjectPathFromWorkspace();
if (isDartFrogProject) {
if (canResolveDartFrogProjectPath()) {
this.update();
} else {
this.statusBarItem.hide();
Expand Down
113 changes: 80 additions & 33 deletions extensions/vscode/src/test/suite/commands/new-middleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,16 @@ suite("new-middleware command", () => {
utilsStub = {
nearestParentDartFrogProject: sinon.stub(),
normalizeRoutePath: sinon.stub(),
resolveDartFrogProjectPathFromWorkspace: sinon.stub(),
resolveDartFrogProjectPathFromActiveTextEditor: sinon.stub(),
resolveDartFrogProjectPathFromWorkspaceFolders: sinon.stub(),
isDartFrogCLIInstalled: sinon.stub(),
suggestInstallingDartFrogCLI: sinon.stub(),
};
utilsStub.isDartFrogCLIInstalled.returns(true);

utilsStub.nearestParentDartFrogProject
.withArgs(invalidUri.fsPath)
.returns(undefined);
.returns();
utilsStub.nearestParentDartFrogProject
.withArgs(validUri.fsPath)
.returns(validUri.fsPath);
Expand Down Expand Up @@ -74,9 +75,10 @@ suite("new-middleware command", () => {
});

suite("file open dialog", () => {
test("is shown when Uri is undefined and fails to resolve a path from workspace", async () => {
test("is shown when Uri is undefined and fails to resolve a path from workspace folder", async () => {
vscodeStub.window.showOpenDialog.resolves();
utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(undefined);
utilsStub.resolveDartFrogProjectPathFromActiveTextEditor.returns();
utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns();

await command.newMiddleware();

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

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

await command.newMiddleware();
sinon.assert.notCalled(vscodeStub.window.showOpenDialog);
});

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

test("is not shown when Uri is defined", async () => {
await command.newMiddleware(invalidUri);
await command.newMiddleware();

sinon.assert.notCalled(vscodeStub.window.showOpenDialog);
});

sinon.assert.notCalled(vscodeStub.window.showOpenDialog);
test("when Uri and active text editor are undefined but resolves a path from workspace folder", async () => {
utilsStub.resolveDartFrogProjectPathFromActiveTextEditor.returns();
utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns(
"/home/dart_frog/routes"
);
utilsStub.nearestParentDartFrogProject.returns("/home/dart_frog/");
utilsStub.normalizeRoutePath.returns("/");

await command.newMiddleware();

sinon.assert.called(
utilsStub.resolveDartFrogProjectPathFromActiveTextEditor
);
sinon.assert.notCalled(vscodeStub.window.showOpenDialog);
});
});
});

Expand Down Expand Up @@ -159,22 +179,49 @@ suite("new-middleware command", () => {
);

suite("prompts for route path", () => {
test("is shown when Uri is undefined and selected file is valid", async () => {
vscodeStub.window.showInputBox.returns("animals/frog");
utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(
"home/routes/animals/frog"
);
utilsStub.nearestParentDartFrogProject.returns(
"home/routes/animals/frog"
);
utilsStub.normalizeRoutePath.returns("/animals/frog");
suite("is shown", () => {
test("when Uri is undefined and resolved active text editor is valid", async () => {
vscodeStub.window.showInputBox.returns("animals/frog");
utilsStub.resolveDartFrogProjectPathFromActiveTextEditor.returns(
"home/routes/animals/frog"
);
utilsStub.nearestParentDartFrogProject.returns(
"home/routes/animals/frog"
);
utilsStub.normalizeRoutePath.returns("/animals/frog");

await command.newMiddleware();
await command.newMiddleware();

sinon.assert.calledWith(vscodeStub.window.showInputBox, {
prompt: "Middleware's route path",
value: "/animals/frog",
placeHolder: "_middleware",
sinon.assert.notCalled(
utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders
);
sinon.assert.calledWith(vscodeStub.window.showInputBox, {
prompt: "Middleware's route path",
value: "/animals/frog",
placeHolder: "_middleware",
});
});

test("when Uri and resolved active text editor are undefined but resolved workspace file is valid", async () => {
vscodeStub.window.showInputBox.returns("animals/frog");
utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns(
"home/routes/animals/frog"
);
utilsStub.nearestParentDartFrogProject.returns(
"home/routes/animals/frog"
);
utilsStub.normalizeRoutePath.returns("/animals/frog");

await command.newMiddleware();

sinon.assert.called(
utilsStub.resolveDartFrogProjectPathFromActiveTextEditor
);
sinon.assert.calledWith(vscodeStub.window.showInputBox, {
prompt: "Middleware's route path",
value: "/animals/frog",
placeHolder: "_middleware",
});
});
});

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

beforeEach(() => {
vscodeStub.window.showInputBox.returns("animals/frog");
utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(
utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns(
"home/routes/animals/frog"
);
utilsStub.nearestParentDartFrogProject.returns(
Expand All @@ -225,7 +272,7 @@ suite("new-middleware command", () => {
});

test("is shown when prompt is undefined", async () => {
vscodeStub.window.showInputBox.returns(undefined);
vscodeStub.window.showInputBox.returns();

await command.newMiddleware();

Expand Down Expand Up @@ -319,7 +366,7 @@ suite("new-middleware command", () => {
});

test("successfully with prompt route path", async () => {
utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(
utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns(
"home/routes/animals/frog"
);
utilsStub.nearestParentDartFrogProject.returns(
Expand Down
Loading

0 comments on commit c4e9ff4

Please sign in to comment.