diff --git a/extensions/npm/package.json b/extensions/npm/package.json index 9013ac7..d4773d7 100644 --- a/extensions/npm/package.json +++ b/extensions/npm/package.json @@ -47,9 +47,17 @@ "url": "https://github.com/Idered/iridium" }, "activationEvents": [ - "onView:iridium.npm" + "onView:iridium.npm", + "onCommand:iridium.openClosestPackageJson" ], "contributes": { + "commands": [ + { + "command": "iridium.openClosestPackageJson", + "title": "Open Closest package.json to Current Editor", + "category": "Node Dependencies" + } + ], "viewsContainers": { "activitybar": [ { diff --git a/extensions/npm/src/commands/openClosestPackageJson.ts b/extensions/npm/src/commands/openClosestPackageJson.ts new file mode 100644 index 0000000..a888155 --- /dev/null +++ b/extensions/npm/src/commands/openClosestPackageJson.ts @@ -0,0 +1,57 @@ +import * as vscode from "vscode"; + +export const openClosestPackageJson = async () => { + const uri = vscode.window.activeTextEditor?.document.uri; + if (uri === undefined || uri.scheme === "untitled") { + return; + } + + const closestPackageJson = await findUpPackageJson(uri); + if (closestPackageJson === undefined) { + await vscode.window.showWarningMessage("No closest package.json found"); + return; + } + + const uriToOpen = vscode.Uri.joinPath(closestPackageJson, "package.json"); + await vscode.window.showTextDocument(uriToOpen); +}; + +/** + * @param uri Initial URI of textEditor, but not directory! + * @returns Uri with path of closest directory with package.json + */ +async function findUpPackageJson( + uri: vscode.Uri, + throws?: T +): Promise { + const currentWorkspacePath = vscode.workspace.getWorkspaceFolder(uri); + // TODO maybe allow? + if (!currentWorkspacePath) { + throw new Error( + "Opening closest package.json is not supported for files that are not part of opened workspace" + ); + } + const { fs } = vscode.workspace; + + let currentUri = vscode.Uri.joinPath(uri, ".."); + while (true) { + // eslint-disable-next-line no-await-in-loop + const fileList = await fs.readDirectory(currentUri); + const packageJsonFile = fileList.find( + ([name, type]) => name === "package.json" && type === vscode.FileType.File + ); + if (packageJsonFile) return currentUri; + if (currentUri.path === currentWorkspacePath.uri.path) { + // console.debug('find package.json: reached workspace boundary') + if (throws) { + throw new Error( + "There is no closest package.json from this file within current workspace" + ); + } + + return undefined!; + } + + currentUri = vscode.Uri.joinPath(currentUri, ".."); + } +} diff --git a/extensions/npm/src/extension.ts b/extensions/npm/src/extension.ts index a573f46..6ad48c2 100644 --- a/extensions/npm/src/extension.ts +++ b/extensions/npm/src/extension.ts @@ -8,6 +8,7 @@ import { ClientManager } from "./clients/ClientManager"; import { NpmClient } from "./clients/NpmClient"; import { YarnClient } from "./clients/YarnClient"; import { PnpmClient } from "./clients/PnpmClient"; +import { openClosestPackageJson } from "./commands/openClosestPackageJson"; export function activate(context: vscode.ExtensionContext) { const app = bootstrap({ @@ -49,6 +50,11 @@ export function activate(context: vscode.ExtensionContext) { webviewView.webview.postMessage({ type: "CONFIG_UPDATED" }); }); }); + + vscode.commands.registerCommand( + "iridium.openClosestPackageJson", + openClosestPackageJson + ); } export function deactivate() {}