diff --git a/extensions/vscode/src/commands/new-middleware.ts b/extensions/vscode/src/commands/new-middleware.ts index fde2aec3e..b54eab6e6 100644 --- a/extensions/vscode/src/commands/new-middleware.ts +++ b/extensions/vscode/src/commands/new-middleware.ts @@ -11,7 +11,8 @@ import { isDartFrogCLIInstalled, nearestParentDartFrogProject, normalizeRoutePath, - resolveDartFrogProjectPathFromWorkspace, + resolveDartFrogProjectPathFromActiveTextEditor, + resolveDartFrogProjectPathFromWorkspaceFolders, suggestInstallingDartFrogCLI, } from "../utils"; @@ -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 @@ -44,12 +47,15 @@ export const newMiddleware = async (uri: Uri | undefined): Promise => { 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; } @@ -58,7 +64,7 @@ export const newMiddleware = async (uri: Uri | undefined): Promise => { } const dartFrogProjectPath = nearestParentDartFrogProject(selectedPath); - if (dartFrogProjectPath === undefined) { + if (!dartFrogProjectPath) { window.showErrorMessage( "No Dart Frog project found in the selected directory" ); diff --git a/extensions/vscode/src/commands/new-route.ts b/extensions/vscode/src/commands/new-route.ts index 54dee47a1..7c5492274 100644 --- a/extensions/vscode/src/commands/new-route.ts +++ b/extensions/vscode/src/commands/new-route.ts @@ -11,7 +11,8 @@ import { isDartFrogCLIInstalled, nearestParentDartFrogProject, normalizeRoutePath, - resolveDartFrogProjectPathFromWorkspace, + resolveDartFrogProjectPathFromActiveTextEditor, + resolveDartFrogProjectPathFromWorkspaceFolders, suggestInstallingDartFrogCLI, } from "../utils"; @@ -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 @@ -44,12 +47,15 @@ export const newRoute = async (uri: Uri | undefined): Promise => { 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; } @@ -58,7 +64,7 @@ export const newRoute = async (uri: Uri | undefined): Promise => { } const dartFrogProjectPath = nearestParentDartFrogProject(selectedPath); - if (dartFrogProjectPath === undefined) { + if (!dartFrogProjectPath) { window.showErrorMessage( "No Dart Frog project found in the selected directory" ); diff --git a/extensions/vscode/src/commands/start-daemon.ts b/extensions/vscode/src/commands/start-daemon.ts index d8d129e54..21091d0b8 100644 --- a/extensions/vscode/src/commands/start-daemon.ts +++ b/extensions/vscode/src/commands/start-daemon.ts @@ -1,7 +1,8 @@ import { isDartFrogCLIInstalled, nearestParentDartFrogProject, - resolveDartFrogProjectPathFromWorkspace, + resolveDartFrogProjectPathFromActiveTextEditor, + resolveDartFrogProjectPathFromWorkspaceFolders, suggestInstallingDartFrogCLI, } from "../utils"; import { DartFrogDaemon } from "../daemon"; @@ -33,7 +34,11 @@ export const startDaemon = async (): Promise => { return; } - const dartFrogProjectPath = resolveDartFrogProjectPathFromWorkspace(); + let dartFrogProjectPath = resolveDartFrogProjectPathFromWorkspaceFolders(); + if (!dartFrogProjectPath) { + dartFrogProjectPath = resolveDartFrogProjectPathFromActiveTextEditor(); + } + const rootDartFrogProjectPath = dartFrogProjectPath ? nearestParentDartFrogProject(dartFrogProjectPath) : undefined; diff --git a/extensions/vscode/src/commands/start-dev-server.ts b/extensions/vscode/src/commands/start-dev-server.ts index 817676f32..1d9a856a4 100644 --- a/extensions/vscode/src/commands/start-dev-server.ts +++ b/extensions/vscode/src/commands/start-dev-server.ts @@ -9,7 +9,8 @@ import { Uri, commands, window } from "vscode"; import { isDartFrogCLIInstalled, nearestParentDartFrogProject, - resolveDartFrogProjectPathFromWorkspace, + resolveDartFrogProjectPathFromActiveTextEditor, + resolveDartFrogProjectPathFromWorkspaceFolders, suggestInstallingDartFrogCLI, } from "../utils"; @@ -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; diff --git a/extensions/vscode/src/extension.ts b/extensions/vscode/src/extension.ts index 4fd96be75..fbafb8588 100644 --- a/extensions/vscode/src/extension.ts +++ b/extensions/vscode/src/extension.ts @@ -7,6 +7,15 @@ import { OpenApplicationStatusBarItem, StartStopApplicationStatusBarItem, } from "./status-bar"; +import { + canResolveDartFrogProjectPath, + isCompatibleDartFrogCLIVersion, + isDartFrogCLIInstalled, + openChangelog, + readDartFrogCLIVersion, + readLatestDartFrogCLIVersion, + suggestInstallingDartFrogCLI, +} from "./utils"; import { create, debugDevServer, @@ -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. @@ -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() ); } diff --git a/extensions/vscode/src/status-bar/dart-frog-status-bar-item.ts b/extensions/vscode/src/status-bar/dart-frog-status-bar-item.ts index 8919cd907..a57cd00b5 100644 --- a/extensions/vscode/src/status-bar/dart-frog-status-bar-item.ts +++ b/extensions/vscode/src/status-bar/dart-frog-status-bar-item.ts @@ -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 @@ -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(); diff --git a/extensions/vscode/src/test/suite/commands/new-middleware.test.ts b/extensions/vscode/src/test/suite/commands/new-middleware.test.ts index 7f47370f4..74a6ead30 100644 --- a/extensions/vscode/src/test/suite/commands/new-middleware.test.ts +++ b/extensions/vscode/src/test/suite/commands/new-middleware.test.ts @@ -28,7 +28,8 @@ 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(), }; @@ -36,7 +37,7 @@ suite("new-middleware command", () => { utilsStub.nearestParentDartFrogProject .withArgs(invalidUri.fsPath) - .returns(undefined); + .returns(); utilsStub.nearestParentDartFrogProject .withArgs(validUri.fsPath) .returns(validUri.fsPath); @@ -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(); @@ -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); + }); }); }); @@ -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", + }); }); }); @@ -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( @@ -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(); @@ -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( diff --git a/extensions/vscode/src/test/suite/commands/new-route.test.ts b/extensions/vscode/src/test/suite/commands/new-route.test.ts index c5f697f94..95ef2494b 100644 --- a/extensions/vscode/src/test/suite/commands/new-route.test.ts +++ b/extensions/vscode/src/test/suite/commands/new-route.test.ts @@ -30,7 +30,8 @@ suite("new-route command", () => { utilsStub = { nearestParentDartFrogProject: sinon.stub(), normalizeRoutePath: sinon.stub(), - resolveDartFrogProjectPathFromWorkspace: sinon.stub(), + resolveDartFrogProjectPathFromActiveTextEditor: sinon.stub(), + resolveDartFrogProjectPathFromWorkspaceFolders: sinon.stub(), isDartFrogCLIInstalled: sinon.stub(), suggestInstallingDartFrogCLI: sinon.stub(), }; @@ -152,7 +153,9 @@ suite("new-route command", () => { test("is shown when Uri is undefined and fails to resolve a path from workspace", async () => { vscodeStub.window.showInputBox.returns(validRouteName); vscodeStub.window.showOpenDialog.resolves(); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(undefined); + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns( + undefined + ); await command.newRoute(); @@ -164,23 +167,40 @@ suite("new-route command", () => { }); }); - test("is not shown when Uri is undefined but resolves a path from workspace", async () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns( - validUri.fsPath - ); - utilsStub.normalizeRoutePath.returns("/"); + suite("is not shwon", () => { + test("when Uri is defined", async () => { + vscodeStub.window.showInputBox.returns(validRouteName); - await command.newRoute(); + await command.newRoute(invalidUri); - sinon.assert.notCalled(vscodeStub.window.showOpenDialog); - }); + sinon.assert.notCalled(vscodeStub.window.showOpenDialog); + }); - test("is not shown when Uri is defined", async () => { - vscodeStub.window.showInputBox.returns(validRouteName); + test("when Uri is undefined but resolves a path from active text editor", async () => { + utilsStub.resolveDartFrogProjectPathFromActiveTextEditor.returns( + validUri.fsPath + ); + utilsStub.normalizeRoutePath.returns("/"); - await command.newRoute(invalidUri); + await command.newRoute(); + + 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( + validUri.fsPath + ); + utilsStub.normalizeRoutePath.returns("/"); + + await command.newRoute(); - sinon.assert.notCalled(vscodeStub.window.showOpenDialog); + sinon.assert.called( + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders + ); + sinon.assert.notCalled(vscodeStub.window.showOpenDialog); + }); }); }); diff --git a/extensions/vscode/src/test/suite/commands/start-daemon.test.ts b/extensions/vscode/src/test/suite/commands/start-daemon.test.ts index aa33c7af7..1e46fc79f 100644 --- a/extensions/vscode/src/test/suite/commands/start-daemon.test.ts +++ b/extensions/vscode/src/test/suite/commands/start-daemon.test.ts @@ -21,7 +21,8 @@ suite("start-daemon command", () => { utilsStub = { isDartFrogCLIInstalled: sinon.stub(), suggestInstallingDartFrogCLI: sinon.stub(), - resolveDartFrogProjectPathFromWorkspace: sinon.stub(), + resolveDartFrogProjectPathFromActiveTextEditor: sinon.stub(), + resolveDartFrogProjectPathFromWorkspaceFolders: sinon.stub(), nearestParentDartFrogProject: sinon.stub(), }; utilsStub.isDartFrogCLIInstalled.returns(true); @@ -81,58 +82,89 @@ suite("start-daemon command", () => { ); }); - test("shows error when failed to find Dart Frog project path", async () => { - utilsStub.isDartFrogCLIInstalled.returns(true); - dartFrogDaemon.DartFrogDaemon.instance.isReady = false; - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(undefined); + suite("shows error", () => { + test("when failed to find Dart Frog project path from workspace folders and active text editor", async () => { + utilsStub.isDartFrogCLIInstalled.returns(true); + dartFrogDaemon.DartFrogDaemon.instance.isReady = false; + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns(); + utilsStub.resolveDartFrogProjectPathFromActiveTextEditor.returns(); - await command.startDaemon(); + await command.startDaemon(); - sinon.assert.calledOnceWithExactly( - vscodeStub.window.showErrorMessage, - "Failed to find a Dart Frog project within the current workspace." - ); - }); + sinon.assert.calledOnceWithExactly( + vscodeStub.window.showErrorMessage, + "Failed to find a Dart Frog project within the current workspace." + ); + }); - test("shows error when failed to find Dart Frog root project path", async () => { - utilsStub.isDartFrogCLIInstalled.returns(true); - dartFrogDaemon.DartFrogDaemon.instance.isReady = false; - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns("path"); - utilsStub.nearestParentDartFrogProject.returns(undefined); + test("when failed to find Dart Frog root project path", async () => { + utilsStub.isDartFrogCLIInstalled.returns(true); + dartFrogDaemon.DartFrogDaemon.instance.isReady = false; + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns("path"); + utilsStub.nearestParentDartFrogProject.returns(); - await command.startDaemon(); + await command.startDaemon(); - sinon.assert.calledOnceWithExactly( - vscodeStub.window.showErrorMessage, - "Failed to find a Dart Frog project within the current workspace." - ); + sinon.assert.calledOnceWithExactly( + vscodeStub.window.showErrorMessage, + "Failed to find a Dart Frog project within the current workspace." + ); + }); }); - test("starts daemon when found a Dart Frog project path", async () => { - utilsStub.isDartFrogCLIInstalled.returns(true); - dartFrogDaemon.DartFrogDaemon.instance.isReady = false; - dartFrogDaemon.DartFrogDaemon.instance.invoke = sinon.stub(); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns("path"); - utilsStub.nearestParentDartFrogProject.returns("path"); + suite("starts daemon", () => { + test("starts daemon when found a Dart Frog project path from workspace folder", async () => { + utilsStub.isDartFrogCLIInstalled.returns(true); + dartFrogDaemon.DartFrogDaemon.instance.isReady = false; + dartFrogDaemon.DartFrogDaemon.instance.invoke = sinon.stub(); + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns("path"); + utilsStub.nearestParentDartFrogProject.returns("path"); - await command.startDaemon(); + await command.startDaemon(); - const progressFunction = vscodeStub.window.withProgress.getCall(0).args[1]; - const progress = sinon.stub(); - progress.report = sinon.stub(); - await progressFunction(progress); + const progressFunction = + vscodeStub.window.withProgress.getCall(0).args[1]; + const progress = sinon.stub(); + progress.report = sinon.stub(); + await progressFunction(progress); - sinon.assert.calledOnceWithExactly( - dartFrogDaemon.DartFrogDaemon.instance.invoke, - "path" - ); + sinon.assert.calledOnceWithExactly( + dartFrogDaemon.DartFrogDaemon.instance.invoke, + "path" + ); + }); + + test("starts daemon when found a Dart Frog project path from active text editor", async () => { + utilsStub.isDartFrogCLIInstalled.returns(true); + dartFrogDaemon.DartFrogDaemon.instance.isReady = false; + dartFrogDaemon.DartFrogDaemon.instance.invoke = sinon.stub(); + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns(); + utilsStub.resolveDartFrogProjectPathFromActiveTextEditor.returns("path"); + utilsStub.nearestParentDartFrogProject.returns("path"); + + await command.startDaemon(); + + const progressFunction = + vscodeStub.window.withProgress.getCall(0).args[1]; + const progress = sinon.stub(); + progress.report = sinon.stub(); + await progressFunction(progress); + + sinon.assert.called( + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders + ); + sinon.assert.calledOnceWithExactly( + dartFrogDaemon.DartFrogDaemon.instance.invoke, + "path" + ); + }); }); test("updates progress when starting daemon", async () => { utilsStub.isDartFrogCLIInstalled.returns(true); dartFrogDaemon.DartFrogDaemon.instance.isReady = false; dartFrogDaemon.DartFrogDaemon.instance.invoke = sinon.stub(); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns("path"); + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns("path"); utilsStub.nearestParentDartFrogProject.returns("path"); await command.startDaemon(); @@ -162,11 +194,12 @@ suite("start-daemon command", () => { sinon.assert.notCalled(dartFrogDaemon.DartFrogDaemon.instance.invoke); }); - test("when failed to find Dart Frog project path", async () => { + test("when failed to find Dart Frog project path from workspace folders and active text editor", async () => { utilsStub.isDartFrogCLIInstalled.returns(true); dartFrogDaemon.DartFrogDaemon.instance.isReady = false; dartFrogDaemon.DartFrogDaemon.instance.invoke = sinon.stub(); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(undefined); + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns(); + utilsStub.resolveDartFrogProjectPathFromActiveTextEditor.returns(); await command.startDaemon(); @@ -177,7 +210,7 @@ suite("start-daemon command", () => { utilsStub.isDartFrogCLIInstalled.returns(true); dartFrogDaemon.DartFrogDaemon.instance.isReady = false; dartFrogDaemon.DartFrogDaemon.instance.invoke = sinon.stub(); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns("path"); + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns("path"); utilsStub.nearestParentDartFrogProject.returns(undefined); await command.startDaemon(); diff --git a/extensions/vscode/src/test/suite/commands/start-dev-server.test.ts b/extensions/vscode/src/test/suite/commands/start-dev-server.test.ts index e96e1430d..835959915 100644 --- a/extensions/vscode/src/test/suite/commands/start-dev-server.test.ts +++ b/extensions/vscode/src/test/suite/commands/start-dev-server.test.ts @@ -32,11 +32,13 @@ suite("start-dev-server command", () => { utilsStub = { isDartFrogCLIInstalled: sinon.stub(), suggestInstallingDartFrogCLI: sinon.stub(), - resolveDartFrogProjectPathFromWorkspace: sinon.stub(), + resolveDartFrogProjectPathFromActiveTextEditor: sinon.stub(), + resolveDartFrogProjectPathFromWorkspaceFolders: sinon.stub(), nearestParentDartFrogProject: sinon.stub(), }; utilsStub.isDartFrogCLIInstalled.returns(true); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(); + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns(); + utilsStub.resolveDartFrogProjectPathFromActiveTextEditor.returns(); utilsStub.nearestParentDartFrogProject.returns(); const dartFrogDaemon = { @@ -166,42 +168,85 @@ suite("start-dev-server command", () => { const errorMessage = "Failed to find a Dart Frog project within the current workspace."; - test("is shown when failed to find Dart Frog project path", async () => { - await command.startDevServer(); + suite("is shown", () => { + test("when failed to find Dart Frog project path", async () => { + await command.startDevServer(); - sinon.assert.calledOnceWithExactly( - vscodeStub.window.showErrorMessage, - errorMessage - ); - }); + sinon.assert.calledOnceWithExactly( + vscodeStub.window.showErrorMessage, + errorMessage + ); + }); - test("is shown when failed to find Dart Frog root project path", async () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns("path"); + test("when failed to find Dart Frog project from workspace folder", async () => { + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns( + "path" + ); + utilsStub.nearestParentDartFrogProject.returns(undefined); - await command.startDevServer(); + await command.startDevServer(); - sinon.assert.calledOnceWithExactly( - vscodeStub.window.showErrorMessage, - errorMessage - ); + sinon.assert.calledOnceWithExactly( + vscodeStub.window.showErrorMessage, + errorMessage + ); + }); + + test("when failed to find Dart Frog project from active text editor", async () => { + utilsStub.resolveDartFrogProjectPathFromActiveTextEditor.returns( + "path" + ); + utilsStub.nearestParentDartFrogProject.returns(undefined); + + await command.startDevServer(); + + sinon.assert.called( + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders + ); + sinon.assert.calledOnceWithExactly( + vscodeStub.window.showErrorMessage, + errorMessage + ); + }); }); - test("is not shown when found a Dart Frog project path", async () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns("path"); - utilsStub.nearestParentDartFrogProject.returns("path"); + suite("is not shown", () => { + test("when found a Dart Frog project path from workspace folder", async () => { + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns( + "path" + ); + utilsStub.nearestParentDartFrogProject.returns("path"); - await command.startDevServer(); + await command.startDevServer(); - sinon.assert.neverCalledWith( - vscodeStub.window.showErrorMessage, - errorMessage - ); + sinon.assert.neverCalledWith( + vscodeStub.window.showErrorMessage, + errorMessage + ); + }); + + test("when found a Dart Frog project path from active text editor and no workspace folders", async () => { + utilsStub.resolveDartFrogProjectPathFromActiveTextEditor.returns( + "path" + ); + utilsStub.nearestParentDartFrogProject.returns("path"); + + await command.startDevServer(); + + sinon.assert.called( + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders + ); + sinon.assert.neverCalledWith( + vscodeStub.window.showErrorMessage, + errorMessage + ); + }); }); }); suite("port number prompt is shown", () => { beforeEach(() => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns("path"); + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns("path"); utilsStub.nearestParentDartFrogProject.returns("path"); }); @@ -353,7 +398,7 @@ suite("start-dev-server command", () => { const portNumber = "8079"; beforeEach(() => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns("path"); + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns("path"); utilsStub.nearestParentDartFrogProject.returns("path"); vscodeStub.window.showInputBox @@ -537,7 +582,7 @@ suite("start-dev-server command", () => { ); beforeEach(() => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns( + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns( startRequest.params.workingDirectory ); utilsStub.nearestParentDartFrogProject.returns( @@ -602,7 +647,7 @@ suite("start-dev-server command", () => { }); test("when Dart Frog project root path failed to be retrieved", async () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns( + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns( startRequest.params.workingDirectory ); @@ -612,7 +657,7 @@ suite("start-dev-server command", () => { }); test("when port number is dismissed", async () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns( + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns( startRequest.params.workingDirectory ); vscodeStub.window.showInputBox @@ -631,7 +676,7 @@ suite("start-dev-server command", () => { }); test("when Dart VM service port number is dismissed", async () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns( + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns( startRequest.params.workingDirectory ); vscodeStub.window.showInputBox @@ -675,7 +720,7 @@ suite("start-dev-server command", () => { let progress: any; beforeEach(() => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns( + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns( startRequest.params.workingDirectory ); utilsStub.nearestParentDartFrogProject.returns( @@ -829,7 +874,7 @@ suite("start-dev-server command", () => { let progress: any; beforeEach(() => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns( + utilsStub.resolveDartFrogProjectPathFromWorkspaceFolders.returns( startRequest.params.workingDirectory ); utilsStub.nearestParentDartFrogProject.returns( diff --git a/extensions/vscode/src/test/suite/commands/stop-dev-server.test.ts b/extensions/vscode/src/test/suite/commands/stop-dev-server.test.ts index 9d0eb8c99..ded98f16b 100644 --- a/extensions/vscode/src/test/suite/commands/stop-dev-server.test.ts +++ b/extensions/vscode/src/test/suite/commands/stop-dev-server.test.ts @@ -31,7 +31,7 @@ suite("stop-dev-server command", () => { utilsStub = { isDartFrogCLIInstalled: sinon.stub(), suggestInstallingDartFrogCLI: sinon.stub(), - resolveDartFrogProjectPathFromWorkspace: sinon.stub(), + resolveDartFrogProjectPathFromWorkspaceFolders: sinon.stub(), nearestParentDartFrogProject: sinon.stub(), quickPickApplication: sinon.stub(), }; diff --git a/extensions/vscode/src/test/suite/extension.test.ts b/extensions/vscode/src/test/suite/extension.test.ts index 463a4c37d..98b13088d 100644 --- a/extensions/vscode/src/test/suite/extension.test.ts +++ b/extensions/vscode/src/test/suite/extension.test.ts @@ -37,15 +37,13 @@ suite("activate", () => { readDartFrogCLIVersion: sinon.stub(), isCompatibleDartFrogCLIVersion: sinon.stub(), isDartFrogCLIInstalled: sinon.stub(), - resolveDartFrogProjectPathFromWorkspace: sinon.stub(), + canResolveDartFrogProjectPath: sinon.stub(), suggestInstallingDartFrogCLI: sinon.stub(), }; utilsStub.readDartFrogCLIVersion.returns("0.0.0"); utilsStub.isCompatibleDartFrogCLIVersion.returns(true); utilsStub.isDartFrogCLIInstalled.returns(true); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns( - "path/to/project" - ); + utilsStub.canResolveDartFrogProjectPath.returns(true); const childProcessStub = { execSync: sinon.stub(), @@ -185,9 +183,7 @@ suite("activate", () => { suite("sets anyDartFrogProjectLoaded", () => { suite("to true", () => { test("when can resolve Dart Frog project", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns( - "path/to/project" - ); + utilsStub.canResolveDartFrogProjectPath.returns(true); const context = { subscriptions: [] }; extension.activate(context); @@ -201,14 +197,12 @@ suite("activate", () => { }); test("when active text editor changes to a Dart Frog project", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(undefined); + utilsStub.canResolveDartFrogProjectPath.returns(false); const context = { subscriptions: [] }; extension.activate(context); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns( - "path/to/project" - ); + utilsStub.canResolveDartFrogProjectPath.returns(true); vscodeStub.window.onDidChangeActiveTextEditor.getCall(0).args[0](); sinon.assert.calledWith( @@ -220,14 +214,12 @@ suite("activate", () => { }); test("when workspace folder changes to a Dart Frog project", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(undefined); + utilsStub.canResolveDartFrogProjectPath.returns(false); const context = { subscriptions: [] }; extension.activate(context); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns( - "path/to/project" - ); + utilsStub.canResolveDartFrogProjectPath.returns(true); vscodeStub.workspace.onDidChangeWorkspaceFolders.getCall(0).args[0](); sinon.assert.calledWith( @@ -241,7 +233,7 @@ suite("activate", () => { suite("to false", () => { test("when can not resolve Dart Frog project", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(undefined); + utilsStub.canResolveDartFrogProjectPath.returns(false); const context = { subscriptions: [] }; extension.activate(context); @@ -255,14 +247,12 @@ suite("activate", () => { }); test("when active text editor changes and is not a Dart Frog project", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns( - "path/to/project" - ); + utilsStub.canResolveDartFrogProjectPath.returns(true); const context = { subscriptions: [] }; extension.activate(context); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(undefined); + utilsStub.canResolveDartFrogProjectPath.returns(false); vscodeStub.window.onDidChangeActiveTextEditor.getCall(0).args[0](); sinon.assert.calledWith( @@ -274,14 +264,12 @@ suite("activate", () => { }); test("when workspace folder changes and is not a Dart Frog project", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns( - "path/to/project" - ); + utilsStub.canResolveDartFrogProjectPath.returns(true); const context = { subscriptions: [] }; extension.activate(context); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(undefined); + utilsStub.canResolveDartFrogProjectPath.returns(false); vscodeStub.workspace.onDidChangeWorkspaceFolders.getCall(0).args[0](); sinon.assert.calledWith( diff --git a/extensions/vscode/src/test/suite/status-bar/open-application-status-bar-item.test.ts b/extensions/vscode/src/test/suite/status-bar/open-application-status-bar-item.test.ts index 30deec1fd..18400d542 100644 --- a/extensions/vscode/src/test/suite/status-bar/open-application-status-bar-item.test.ts +++ b/extensions/vscode/src/test/suite/status-bar/open-application-status-bar-item.test.ts @@ -57,9 +57,9 @@ suite("OpenApplicationStatusBarItem", () => { statusBarItem.dispose = sinon.stub(); utilsStub = { - resolveDartFrogProjectPathFromWorkspace: sinon.stub(), + canResolveDartFrogProjectPath: sinon.stub(), }; - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(true); + utilsStub.canResolveDartFrogProjectPath.returns(true); const dartFrogDaemon = { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -121,12 +121,12 @@ suite("OpenApplicationStatusBarItem", () => { suite("upon workspace folder change to a Dart Frog project", () => { test("with one registered application", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(false); + utilsStub.canResolveDartFrogProjectPath.returns(false); daemon.applicationRegistry.all.returns([application1]); const openApplicationStatusBarItem = new OpenApplicationStatusBarItem(); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(true); + utilsStub.canResolveDartFrogProjectPath.returns(true); vscodeStub.workspace.onDidChangeWorkspaceFolders.callArg(0); sinon.assert.calledOnce( @@ -135,12 +135,12 @@ suite("OpenApplicationStatusBarItem", () => { }); test("with multiple registered applications", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(false); + utilsStub.canResolveDartFrogProjectPath.returns(false); daemon.applicationRegistry.all.returns([application1, application2]); const openApplicationStatusBarItem = new OpenApplicationStatusBarItem(); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(true); + utilsStub.canResolveDartFrogProjectPath.returns(true); vscodeStub.workspace.onDidChangeWorkspaceFolders.callArg(0); sinon.assert.calledOnce( @@ -151,12 +151,12 @@ suite("OpenApplicationStatusBarItem", () => { suite("upon active file change to a Dart Frog project", () => { test("with one registered application", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(false); + utilsStub.canResolveDartFrogProjectPath.returns(false); daemon.applicationRegistry.all.returns([application1]); const openApplicationStatusBarItem = new OpenApplicationStatusBarItem(); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(true); + utilsStub.canResolveDartFrogProjectPath.returns(true); vscodeStub.window.onDidChangeActiveTextEditor.callArg(0); sinon.assert.calledOnce( @@ -165,12 +165,12 @@ suite("OpenApplicationStatusBarItem", () => { }); test("with multiple registered applications", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(false); + utilsStub.canResolveDartFrogProjectPath.returns(false); daemon.applicationRegistry.all.returns([application1, application2]); const openApplicationStatusBarItem = new OpenApplicationStatusBarItem(); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(true); + utilsStub.canResolveDartFrogProjectPath.returns(true); vscodeStub.window.onDidChangeActiveTextEditor.callArg(0); sinon.assert.calledOnce( @@ -241,7 +241,7 @@ suite("OpenApplicationStatusBarItem", () => { suite("when not in a Dart Frog project", () => { test("upon start", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(false); + utilsStub.canResolveDartFrogProjectPath.returns(false); daemon.applicationRegistry.all.returns([application1]); const openApplicationStatusBarItem = new OpenApplicationStatusBarItem(); @@ -252,12 +252,12 @@ suite("OpenApplicationStatusBarItem", () => { }); test("upon workspace folder change", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(true); + utilsStub.canResolveDartFrogProjectPath.returns(true); daemon.applicationRegistry.all.returns([application1]); const openApplicationStatusBarItem = new OpenApplicationStatusBarItem(); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(false); + utilsStub.canResolveDartFrogProjectPath.returns(false); vscodeStub.workspace.onDidChangeWorkspaceFolders.callArg(0); sinon.assert.calledOnce( @@ -266,12 +266,12 @@ suite("OpenApplicationStatusBarItem", () => { }); test("upon active file change", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(true); + utilsStub.canResolveDartFrogProjectPath.returns(true); daemon.applicationRegistry.all.returns([application1]); const openApplicationStatusBarItem = new OpenApplicationStatusBarItem(); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(false); + utilsStub.canResolveDartFrogProjectPath.returns(false); vscodeStub.window.onDidChangeActiveTextEditor.callArg(0); sinon.assert.calledOnce( diff --git a/extensions/vscode/src/test/suite/status-bar/start-stop-application-status-bar-item.test.ts b/extensions/vscode/src/test/suite/status-bar/start-stop-application-status-bar-item.test.ts index 1ce1aacba..a5f600bb9 100644 --- a/extensions/vscode/src/test/suite/status-bar/start-stop-application-status-bar-item.test.ts +++ b/extensions/vscode/src/test/suite/status-bar/start-stop-application-status-bar-item.test.ts @@ -56,9 +56,9 @@ suite("StartStopApplicationStatusBarItem", () => { statusBarItem.dispose = sinon.stub(); utilsStub = { - resolveDartFrogProjectPathFromWorkspace: sinon.stub(), + canResolveDartFrogProjectPath: sinon.stub(), }; - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(true); + utilsStub.canResolveDartFrogProjectPath.returns(true); const dartFrogDaemon = { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -97,7 +97,7 @@ suite("StartStopApplicationStatusBarItem", () => { suite("is shown", () => { test("upon start when in a Dart Frog project", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(true); + utilsStub.canResolveDartFrogProjectPath.returns(true); daemon.applicationRegistry.all.returns([]); const startStopApplicationStatusBarItem = @@ -109,13 +109,13 @@ suite("StartStopApplicationStatusBarItem", () => { }); test("upon workspace folder change to a Dart Frog project", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(false); + utilsStub.canResolveDartFrogProjectPath.returns(false); daemon.applicationRegistry.all.returns([]); const startStopApplicationStatusBarItem = new StartStopApplicationStatusBarItem(); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(true); + utilsStub.canResolveDartFrogProjectPath.returns(true); vscodeStub.workspace.onDidChangeWorkspaceFolders.callArg(0); sinon.assert.calledOnce( @@ -124,13 +124,13 @@ suite("StartStopApplicationStatusBarItem", () => { }); test("upon active file change to a Dart Frog project", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(false); + utilsStub.canResolveDartFrogProjectPath.returns(false); daemon.applicationRegistry.all.returns([]); const startStopApplicationStatusBarItem = new StartStopApplicationStatusBarItem(); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(true); + utilsStub.canResolveDartFrogProjectPath.returns(true); vscodeStub.window.onDidChangeActiveTextEditor.callArg(0); sinon.assert.calledOnce( @@ -226,7 +226,7 @@ suite("StartStopApplicationStatusBarItem", () => { suite("is hidden", () => { suite("when not in a Dart Frog project", () => { test("upon start", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(false); + utilsStub.canResolveDartFrogProjectPath.returns(false); daemon.applicationRegistry.all.returns([]); const startStopApplicationStatusBarItem = @@ -238,13 +238,13 @@ suite("StartStopApplicationStatusBarItem", () => { }); test("upon workspace folder change", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(true); + utilsStub.canResolveDartFrogProjectPath.returns(true); daemon.applicationRegistry.all.returns([]); const startStopApplicationStatusBarItem = new StartStopApplicationStatusBarItem(); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(false); + utilsStub.canResolveDartFrogProjectPath.returns(false); vscodeStub.workspace.onDidChangeWorkspaceFolders.callArg(0); sinon.assert.calledOnce( @@ -253,13 +253,13 @@ suite("StartStopApplicationStatusBarItem", () => { }); test("upon active file change", () => { - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(true); + utilsStub.canResolveDartFrogProjectPath.returns(true); daemon.applicationRegistry.all.returns([]); const startStopApplicationStatusBarItem = new StartStopApplicationStatusBarItem(); - utilsStub.resolveDartFrogProjectPathFromWorkspace.returns(false); + utilsStub.canResolveDartFrogProjectPath.returns(false); vscodeStub.window.onDidChangeActiveTextEditor.callArg(0); sinon.assert.calledOnce( diff --git a/extensions/vscode/src/test/suite/utils/dart-frog-structure.test.ts b/extensions/vscode/src/test/suite/utils/dart-frog-project.test.ts similarity index 80% rename from extensions/vscode/src/test/suite/utils/dart-frog-structure.test.ts rename to extensions/vscode/src/test/suite/utils/dart-frog-project.test.ts index 7833f97b5..2eb443426 100644 --- a/extensions/vscode/src/test/suite/utils/dart-frog-structure.test.ts +++ b/extensions/vscode/src/test/suite/utils/dart-frog-project.test.ts @@ -15,7 +15,7 @@ suite("normalizeRoutePath", () => { readFileSync: sinon.stub(), }; - normalizeRoutePath = proxyquire("../../../utils/dart-frog-structure", { + normalizeRoutePath = proxyquire("../../../utils/dart-frog-project", { fs: fsStub, }).normalizeRoutePath; }); @@ -109,7 +109,7 @@ suite("nearestParentDartFrogProject", () => { }; nearestParentDartFrogProject = proxyquire( - "../../../utils/dart-frog-structure", + "../../../utils/dart-frog-project", { fs: fsStub, } @@ -215,7 +215,7 @@ suite("nearestChildDartFrogProjects", () => { }; nearestChildDartFrogProjects = proxyquire( - "../../../utils/dart-frog-structure", + "../../../utils/dart-frog-project", { fs: fsStub, } @@ -396,7 +396,7 @@ suite("isDartFrogProject", () => { readFileSync: sinon.stub(), }; - isDartFrogProject = proxyquire("../../../utils/dart-frog-structure", { + isDartFrogProject = proxyquire("../../../utils/dart-frog-project", { fs: fsStub, }).isDartFrogProject; }); @@ -474,175 +474,175 @@ suite("isDartFrogProject", () => { }); }); -suite("resolveDartFrogProjectPathFromWorkspace", () => { +suite("resolveDartFrogProjectPathFromWorkspaceFolders", () => { + let resolveDartFrogProjectPathFromWorkspaceFolders: any; let vscodeStub: any; - let resolveDartFrogProjectPathFromWorkspace: any; + let nearestParentDartFrogProject: any; + + const projectUri = { + uri: { + fsPath: `home/project/`, + }, + }; beforeEach(() => { vscodeStub = { workspace: { workspaceFolders: sinon.stub(), }, - window: { - activeTextEditor: sinon.stub(), - }, }; - resolveDartFrogProjectPathFromWorkspace = proxyquire( - "../../../utils/dart-frog-structure", + resolveDartFrogProjectPathFromWorkspaceFolders = proxyquire( + "../../../utils/dart-frog-project", { vscode: vscodeStub, } - ).resolveDartFrogProjectPathFromWorkspace; + ).resolveDartFrogProjectPathFromWorkspaceFolders; + + nearestParentDartFrogProject = sinon.stub(); }); afterEach(() => { sinon.restore(); }); - test("returns the file path of the active route Dart file", () => { - vscodeStub.window.activeTextEditor = { - document: { - uri: { - fsPath: `home/user/routes/index.dart`, - }, - }, - }; + test("returns the path of the active worskpace folder when it is a Dart Frog project", () => { + vscodeStub.workspace.workspaceFolders = [projectUri]; + nearestParentDartFrogProject + .withArgs(projectUri.uri.fsPath) + .returns(projectUri.uri.fsPath); - const result = resolveDartFrogProjectPathFromWorkspace( - sinon.stub().returns("home/user/") + const dartFrogProjectPath = resolveDartFrogProjectPathFromWorkspaceFolders( + nearestParentDartFrogProject ); - sinon.assert.match(result, "home/user/routes/index.dart"); + assert.deepEqual(dartFrogProjectPath, projectUri.uri.fsPath); }); - suite("returns the directory path of the active workspace folder", () => { - test("when there is no active text editor", () => { - vscodeStub.window.activeTextEditor = undefined; - vscodeStub.workspace.workspaceFolders = [ - { - uri: { - fsPath: `home/user/routes/animals`, - }, - }, - ]; + suite("returns undefined", () => { + test("when there is no active workspace folder", () => { + vscodeStub.workspace.workspaceFolders = []; - const result = resolveDartFrogProjectPathFromWorkspace( - sinon.stub().returns("home/user/") - ); + const dartFrogProjectPath = + resolveDartFrogProjectPathFromWorkspaceFolders( + nearestParentDartFrogProject + ); - sinon.assert.match(result, "home/user/routes/animals"); + assert.deepEqual(dartFrogProjectPath, undefined); }); - test("when the active text editor is not a route", () => { - vscodeStub.window.activeTextEditor = { - document: { - uri: { - fsPath: `home/user/pubspec.yaml`, - }, - }, - }; - vscodeStub.workspace.workspaceFolders = [ - { - uri: { - fsPath: `home/user/`, - }, - }, - ]; + test("when there is no active Dart Frog workspace folder", () => { + vscodeStub.workspace.workspaceFolders = [projectUri]; + nearestParentDartFrogProject + .withArgs(projectUri.uri.fsPath) + .returns(undefined); - const result = resolveDartFrogProjectPathFromWorkspace( - sinon.stub().returns("home/user/") - ); + const dartFrogProjectPath = + resolveDartFrogProjectPathFromWorkspaceFolders( + nearestParentDartFrogProject + ); - sinon.assert.match(result, "home/user/"); + assert.deepEqual(dartFrogProjectPath, undefined); }); + }); +}); - test("when the active text editor is not a Dart route", () => { - vscodeStub.window.activeTextEditor = { - document: { - uri: { - fsPath: `home/user/routes/hello.yaml`, - }, - }, - }; - vscodeStub.workspace.workspaceFolders = [ - { - uri: { - fsPath: `home/user/`, - }, - }, - ]; +suite("resolveDartFrogProjectPathFromActiveTextEditor", () => { + let resolveDartFrogProjectPathFromActiveTextEditor: any; + let vscodeStub: any; + let nearestParentDartFrogProject: any; - const result = resolveDartFrogProjectPathFromWorkspace( - sinon.stub().returns("home/user/") - ); + beforeEach(() => { + vscodeStub = { + window: { + activeTextEditor: sinon.stub(), + }, + }; - sinon.assert.match(result, "home/user/"); - }); + resolveDartFrogProjectPathFromActiveTextEditor = proxyquire( + "../../../utils/dart-frog-project", + { + vscode: vscodeStub, + } + ).resolveDartFrogProjectPathFromActiveTextEditor; - test("when the active text editor is not a Dart Frog project", () => { - vscodeStub.window.activeTextEditor = { - document: { - uri: { - fsPath: `/home/bin/routes/animals/frog.dart`, - }, - }, - }; - vscodeStub.workspace.workspaceFolders = [ - { - uri: { - fsPath: `home/user/`, - }, - }, - ]; + nearestParentDartFrogProject = sinon.stub(); + }); - const nearestParentDartFrogProject = sinon.stub(); - nearestParentDartFrogProject - .withArgs("/home/bin/routes/animals") - .returns(undefined); - nearestParentDartFrogProject.withArgs("home/user/").returns("home/user/"); + afterEach(() => { + sinon.restore(); + }); - const result = resolveDartFrogProjectPathFromWorkspace( - nearestParentDartFrogProject - ); + test("returns the path of the active text editor when it is a Dart Frog Dart route file", () => { + const projectUri = { + uri: { + fsPath: `home/project/routes/index.dart`, + }, + }; + vscodeStub.window.activeTextEditor = { + document: projectUri, + }; + nearestParentDartFrogProject + .withArgs(projectUri.uri.fsPath) + .returns(`home/project`); - sinon.assert.match(result, "home/user/"); - }); + const dartFrogProjectPath = resolveDartFrogProjectPathFromActiveTextEditor( + nearestParentDartFrogProject + ); + + assert.deepEqual(dartFrogProjectPath, projectUri.uri.fsPath); }); suite("returns undefined", () => { - test("when there is no active workspace folder nor text editor", () => { + test("when there is no active text editor", () => { vscodeStub.window.activeTextEditor = undefined; - vscodeStub.workspace.workspaceFolders = undefined; - const result = resolveDartFrogProjectPathFromWorkspace( - sinon.stub().returns(undefined) - ); + const dartFrogProjectPath = + resolveDartFrogProjectPathFromActiveTextEditor( + nearestParentDartFrogProject + ); - sinon.assert.match(result, undefined); + assert.deepEqual(dartFrogProjectPath, undefined); }); - test("when there is not an active workspace folder nor text editor that are Dart Frog projects", () => { - vscodeStub.window.activeTextEditor = { - document: { - uri: { - fsPath: `home/user/routes/animals/frog.dart`, - }, + test("when there is an active text editor that is not a Dart file", () => { + const projectUri = { + uri: { + fsPath: `home/project/routes/index.py`, }, }; - vscodeStub.workspace.workspaceFolders = [ - { - uri: { - fsPath: `home/user/`, - }, + vscodeStub.window.activeTextEditor = { + document: projectUri, + }; + nearestParentDartFrogProject + .withArgs(projectUri.uri.fsPath) + .returns(projectUri.uri.fsPath); + + const dartFrogProjectPath = + resolveDartFrogProjectPathFromActiveTextEditor( + nearestParentDartFrogProject + ); + + assert.deepEqual(dartFrogProjectPath, undefined); + }); + + test("when there is an active text editor that is not a Dart Frog route file", () => { + const projectUri = { + uri: { + fsPath: `home/project/not-routes/index.dart`, }, - ]; + }; + vscodeStub.window.activeTextEditor.document = projectUri; + nearestParentDartFrogProject + .withArgs(projectUri.uri.fsPath) + .returns(projectUri.uri.fsPath); - const result = resolveDartFrogProjectPathFromWorkspace( - sinon.stub().returns(undefined) - ); + const dartFrogProjectPath = + resolveDartFrogProjectPathFromActiveTextEditor( + nearestParentDartFrogProject + ); - sinon.assert.match(result, undefined); + assert.deepEqual(dartFrogProjectPath, undefined); }); }); }); diff --git a/extensions/vscode/src/utils/dart-frog-structure.ts b/extensions/vscode/src/utils/dart-frog-project.ts similarity index 79% rename from extensions/vscode/src/utils/dart-frog-structure.ts rename to extensions/vscode/src/utils/dart-frog-project.ts index 6d7fc1c54..21eea7969 100644 --- a/extensions/vscode/src/utils/dart-frog-structure.ts +++ b/extensions/vscode/src/utils/dart-frog-project.ts @@ -1,6 +1,6 @@ /** * @file Provides utilities for inspecting and dealing with a Dart Frog - * project's structure. + * project's. */ const fs = require("fs"); @@ -101,8 +101,8 @@ export function nearestChildDartFrogProjects( if (isDartFrogProject(filePath)) { return [filePath]; } - - const dartFrogProjects = new Set(); + + const dartFrogProjects = new Set(); let currentSubdirectories = fs .readdirSync(filePath) @@ -163,6 +163,19 @@ export function isDartFrogProject(filePath: string): boolean { return false; } +/** + * Determines if the user's workspace contains a Dart Frog project. + * + * @returns {boolean} Whether or not the user's workspace contains a Dart Frog + * project. + */ +export function canResolveDartFrogProjectPath(): boolean { + return ( + resolveDartFrogProjectPathFromWorkspaceFolders() !== undefined || + resolveDartFrogProjectPathFromActiveTextEditor() !== undefined + ); +} + /** * Resolves a path of a file or directory within a Dart Frog project from the * user's workspace. @@ -171,20 +184,44 @@ export function isDartFrogProject(filePath: string): boolean { * it lacks a defined path. * * @param {function} _nearestParentDartFrogProject A function, used for testing, - * that finds the root of a Dart Frog project from a file path. Defaults to - * {@link nearestParentDartFrogProject}. + * that finds the root of a Dart Frog project from a file path by traversing up + * the directory tree. Defaults to {@link nearestParentDartFrogProject}. + * @returns {string | undefined} A path, derived from the user's workspace + * folders, that is located within a Dart Frog project; or `undefined` if no + * such path could be resolved. + */ +export function resolveDartFrogProjectPathFromWorkspaceFolders( + _nearestParentDartFrogProject: ( + filePath: string + ) => string | undefined = nearestParentDartFrogProject +): string | undefined { + if (workspace.workspaceFolders && workspace.workspaceFolders.length > 0) { + const currentWorkspaceFolder = path.normalize( + workspace.workspaceFolders[0].uri.fsPath + ); + if (_nearestParentDartFrogProject(currentWorkspaceFolder)) { + return currentWorkspaceFolder; + } + } + + return undefined; +} + +/** + * Resolves a path of a file or directory within a Dart Frog project from the + * user's active text editor. * - * @returns {string | undefined} A path, derived from the user's workspace, that - * is located within a Dart Frog project; or `undefined` if no such path could - * be resolved. The resolution is done in the following order: + * Usually used for when the command is launched from the command palette since + * it lacks a defined path. * - * 1. If the user has a Dart file open in the editor that is under a `routes` - * directory and within a Dart Frog project, then the path of that file is - * returned. - * 2. If the user has a workspace folder open that is within a Dart Frog - * project, then the path of that workspace folder is returned. + * @param _nearestParentDartFrogProject A function, used for testing, that + * finds the root of a Dart Frog project from a file path by traversing up the + * directory tree. Defaults to {@link nearestParentDartFrogProject}. + * @returns {string | undefined} A path, derived from the user's active text + * editor, that is located within a Dart Frog project; or `undefined` if no such + * path could be resolved. */ -export function resolveDartFrogProjectPathFromWorkspace( +export function resolveDartFrogProjectPathFromActiveTextEditor( _nearestParentDartFrogProject: ( filePath: string ) => string | undefined = nearestParentDartFrogProject @@ -208,14 +245,5 @@ export function resolveDartFrogProjectPathFromWorkspace( } } - if (workspace.workspaceFolders && workspace.workspaceFolders.length > 0) { - const currentWorkspaceFolder = path.normalize( - workspace.workspaceFolders[0].uri.fsPath - ); - if (_nearestParentDartFrogProject(currentWorkspaceFolder)) { - return currentWorkspaceFolder; - } - } - return undefined; } diff --git a/extensions/vscode/src/utils/index.ts b/extensions/vscode/src/utils/index.ts index 091c9bfea..950a42e41 100644 --- a/extensions/vscode/src/utils/index.ts +++ b/extensions/vscode/src/utils/index.ts @@ -1,5 +1,5 @@ export * from "./cli-version"; -export * from "./dart-frog-structure"; +export * from "./dart-frog-project"; export * from "./suggest-installing-dart-frog-cli"; export * from "./identifier-generator"; export * from "./dart-frog-application";