diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..cb6912d --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,46 @@ +module.exports = { + "env": { + "browser": true, + "es6": true, + "node": true + }, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint" + ], + "rules": { + "@typescript-eslint/class-name-casing": "error", + "@typescript-eslint/member-delimiter-style": [ + "error", + { + "multiline": { + "delimiter": "semi", + "requireLast": true + }, + "singleline": { + "delimiter": "semi", + "requireLast": false + } + } + ], + "@typescript-eslint/semi": [ + "error", + "always" + ], + "@typescript-eslint/class-name-casing": [ + "off", + "always" + ], + "curly": "error", + "eqeqeq": [ + "error", + "always" + ], + "no-redeclare": "error", + "no-unused-expressions": "error", + "prefer-const": "error" + } +}; diff --git a/CHANGELOG.md b/CHANGELOG.md index f05f6ec..a7e960b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,14 @@ -## 2.0 - 07th of Augest, 2021 +## 2.1.0 - 21st of February, 2022 + +* Add Explorer context menu submenus for additional Yarn commands. +`Install Packages`, `Test`, `Build`, `Start`, `Run Script`, `Add & Save Package`, `Add & Save Dev Package`, `Remove Package`, `Publish`, `Outdated` + +## 2.0.0 - 07th of August, 2021 * Add WSL support * Add Multi-Workspace support -## 1.7 - 08th of December, 2019 +## 1.7.0 - 08th of December, 2019 * Fix for [Issue 11](https://github.com/gamunu/vscode-yarn/issues/11) * Add touchbar assets and update package.json. diff --git a/LICENSE b/LICENSE.md similarity index 96% rename from LICENSE rename to LICENSE.md index 728f502..7401b70 100644 --- a/LICENSE +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016-2018 Gamunu Balagalla +Copyright (c) 2016-2022 Gamunu Balagalla Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index c0c4189..2ffea3c 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ git clone git@github.com:gamunu/vscode-yarn.git gamunu.vscode-yarn ### Explorer context menu -`yarn install` also available in the `package.json` file's explorer context menu. +Few `yarn` commands also available in the `package.json` file's explorer context menu. ![Context menu](images/context.png) diff --git a/images/context.png b/images/context.png index 973f032..a5aa6a6 100644 Binary files a/images/context.png and b/images/context.png differ diff --git a/package.json b/package.json index b25a22f..2698103 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "vscode-yarn", "displayName": "yarn", "description": "Yarn commands for VSCode", - "version": "2.0.0", + "version": "2.1.0", "publisher": "gamunu", "icon": "yarn_icon.png", "engines": { @@ -57,43 +57,43 @@ }, { "command": "yarn-script.terminate", - "title": "Terminate Running Yarn Script", + "title": "Terminate Running Script", "category": "Yarn" }, { "command": "yarn-script.installPackages", - "title": "Install Yarn Packages", + "title": "Install Packages", "category": "Yarn", "icon": "./assets/install.png" }, { "command": "yarn-script.addPackage", - "title": "Add and Save Dependency", + "title": "Add & Save Dependency", "category": "Yarn" }, { "command": "yarn-script.addPackageDev", - "title": "Add and Save dev. Dependency", + "title": "Add & Save dev. Dependency", "category": "Yarn" }, { "command": "yarn-script.runScript", - "title": "Run Yarn Script", + "title": "Run Script", "category": "Yarn" }, { "command": "yarn-script.runScriptLast", - "title": "Run Last Yarn Script", + "title": "Run Last Script", "category": "Yarn" }, { "command": "yarn-script.init", - "title": "Initialize Yarn Package", + "title": "Initialize Package", "category": "Yarn" }, { "command": "yarn-script.outdated", - "title": "Run outdated", + "title": "Outdated", "category": "Yarn" }, { @@ -103,7 +103,7 @@ }, { "command": "yarn-script.build", - "title": "Run Build", + "title": "Build", "category": "Yarn", "icon": "./assets/build.png" }, @@ -114,7 +114,7 @@ }, { "command": "yarn-script.raw", - "title": "Raw Yarn Command", + "title": "Raw Command", "category": "Yarn" } ], @@ -122,8 +122,60 @@ "explorer/context": [ { "when": "resourceFilename == 'package.json'", + "group": "navigation@1", + "submenu": "vscode.yarn" + } + ], + "vscode.yarn": [ + { "command": "yarn-script.installPackages", - "group": "navigation@+1" + "group": "navigation@1", + "submenu": "vscode.yarn" + }, + { + "command": "yarn-script.test", + "group": "navigation@2", + "submenu": "vscode.yarn" + }, + { + "command": "yarn-script.build", + "group": "navigation@3", + "submenu": "vscode.yarn" + }, + { + "command": "yarn-script.start", + "group": "navigation@4", + "submenu": "vscode.yarn" + }, + { + "command": "yarn-script.runScript", + "group": "navigation@5", + "submenu": "vscode.yarn" + }, + { + "command": "yarn-script.addPackage", + "group": "navigation@6", + "submenu": "vscode.yarn" + }, + { + "command": "yarn-script.addPackageDev", + "group": "navigation@7", + "submenu": "vscode.yarn" + }, + { + "command": "yarn-script.removePackage", + "group": "navigation@8", + "submenu": "vscode.yarn" + }, + { + "command": "yarn-script.publish", + "group": "navigation@9", + "submenu": "vscode.yarn" + }, + { + "command": "yarn-script.outdated", + "group": "navigation@10", + "submenu": "vscode.yarn" } ], "touchBar": [ @@ -149,6 +201,12 @@ } ] }, + "submenus": [ + { + "id": "vscode.yarn", + "label": "Yarn" + } + ], "keybindings": [ { "command": "yarn-script.runScript", @@ -216,16 +274,17 @@ "webpack": "webpack --mode development", "webpack-dev": "webpack --mode development --watch", "test-compile": "tsc -p ./", - "eslint": "eslint src/ .ts,.tsx" + "eslint": "eslint -c .eslintrc.js --ext .ts src/*.ts" }, "devDependencies": { - "@types/vscode": "^1.58.1", - "@types/node": "^12.12.0", "@types/mocha": "^2.2.42", - "@typescript-eslint/eslint-plugin": "^4.16.0", - "typescript": "^4.3.5", - "ts-loader": "^7.0.5", + "@types/node": "^12.12.0", + "@types/vscode": "^1.58.1", + "@typescript-eslint/eslint-plugin": "^5.12.0", + "@typescript-eslint/parser": "^5.12.0", "eslint": "^7.0.5", + "ts-loader": "^7.0.5", + "typescript": "^4.5.5", "webpack": "^4.39.1", "webpack-cli": "^3.3.0" }, diff --git a/src/add.ts b/src/add.ts index e9d60df..b90ef0b 100644 --- a/src/add.ts +++ b/src/add.ts @@ -1,32 +1,28 @@ -import { window as Window } from 'vscode'; -import { packageExists, pickPackageJson } from './utils'; +import { window as Window, Uri } from 'vscode'; +import { getPackageJson } from './utils'; import * as Messages from './messages'; import { runCommand } from './run-command'; -export async function yarnAddPackages() { - let packageJson = await pickPackageJson() - if (!packageExists(packageJson)) { - Messages.noPackageError(); - return; - } +export async function yarnAddPackages(arg: Uri) { + const packageJson: string = await getPackageJson(arg); + + if (packageJson === null) { return; } runCommand(['add'], packageJson); } -export function yarnAddPackage() { - return _addPackage(false); +export function yarnAddPackage(arg: Uri) { + return _addPackage(false, arg); } -export function yarnAddPackageDev() { - return _addPackage(true); +export function yarnAddPackageDev(arg: Uri) { + return _addPackage(true, arg); } -const _addPackage = async function (dev: boolean) { - let packageJson = await pickPackageJson() - if (!packageExists(packageJson)) { - Messages.noPackageError(); - return; - } +const _addPackage = async function (dev: boolean, arg: Uri) { + const packageJson: string = await getPackageJson(arg); + + if (packageJson === null) { return; } Window.showInputBox({ prompt: 'Package to add', diff --git a/src/init.ts b/src/init.ts index df49977..6e47ca9 100644 --- a/src/init.ts +++ b/src/init.ts @@ -5,9 +5,9 @@ import * as Messages from './messages'; import { packageExists, pickPackageJson } from './utils'; export default async function () { - let packageJson = await pickPackageJson() + const packageJson = await pickPackageJson(); - if (packageJson == null) { + if (packageJson === null) { Messages.noProjectOpenError(); return; } diff --git a/src/install.ts b/src/install.ts index a004e04..37ee398 100644 --- a/src/install.ts +++ b/src/install.ts @@ -1,20 +1,11 @@ -import { packageExists, CommandArgument, pickPackageJson } from './utils'; -import * as Messages from './messages'; +import { getPackageJson } from './utils'; +import { Uri } from 'vscode'; import { runCommand } from './run-command'; -export async function yarnInstallPackages(arg: CommandArgument) { - let packageJson = null +export async function yarnInstallPackages(arg: Uri) { + const packageJson: string = await getPackageJson(arg); - // context menu wins always - if (arg !== undefined) { - packageJson = arg.fsPath; - } else { // fall back to pick - packageJson = await pickPackageJson() - } + if (packageJson === null) { return; } - if (!packageExists(packageJson)) { - Messages.noPackageError(); - return; - } runCommand(['install'], packageJson); } diff --git a/src/outdated.ts b/src/outdated.ts index 842c540..ded238b 100644 --- a/src/outdated.ts +++ b/src/outdated.ts @@ -1,13 +1,11 @@ -import { packageExists, pickPackageJson } from './utils'; -import * as Messages from './messages'; +import { getPackageJson } from './utils'; +import { Uri } from 'vscode'; import { runCommand } from './run-command'; -export async function yarnOutdated() { - let packageJson = await pickPackageJson() - if (!packageExists(packageJson)) { - Messages.noPackageError(); - return; - } +export async function yarnOutdated(arg: Uri) { + const packageJson: string = await getPackageJson(arg); + + if (packageJson === null) { return; } runCommand(['outdated'], packageJson); } diff --git a/src/publish.ts b/src/publish.ts index 61c2ed4..7808f42 100644 --- a/src/publish.ts +++ b/src/publish.ts @@ -1,18 +1,13 @@ -import { window as Window } from 'vscode'; -import { packageExists, pickPackageJson } from './utils'; +import { window as Window, Uri } from 'vscode'; +import { getPackageJson } from './utils'; import * as Messages from './messages'; import { runCommand } from './run-command'; -export function yarnPublish() { - _do('publish'); -} +export async function yarnPublish(arg: Uri) { + const cmd: string = 'publish'; + const packageJson: string = await getPackageJson(arg); -const _do = async function (cmd: string) { - let packageJson = await pickPackageJson() - if (!packageExists(packageJson)) { - Messages.noPackageError(); - return; - } + if (packageJson === null) { return; } Window.showInputBox({ prompt: 'Optional tag (enter to skip tag)', diff --git a/src/raw.ts b/src/raw.ts index 4d5e04a..8ea1d9b 100644 --- a/src/raw.ts +++ b/src/raw.ts @@ -4,7 +4,7 @@ import * as Messages from './messages'; import { runCommand } from './run-command'; export async function yarnRawCommand() { - let packageJson = await pickPackageJson() + const packageJson = await pickPackageJson(); if (!packageExists(packageJson)) { Messages.noPackageError(); return; diff --git a/src/remove.ts b/src/remove.ts index 0987002..f36d8c7 100644 --- a/src/remove.ts +++ b/src/remove.ts @@ -1,18 +1,12 @@ -import { window as Window } from 'vscode'; -import { packageExists, pickPackageJson } from './utils'; +import { window as Window, Uri } from 'vscode'; +import { getPackageJson } from './utils'; import * as Messages from './messages'; import { runCommand } from './run-command'; -export function yarnRemovePackage() { - return _removePackage(); -} +export async function yarnRemovePackage(arg: Uri) { + const packageJson: string = await getPackageJson(arg); -const _removePackage = async function () { - let packageJson = await pickPackageJson() - if (!packageExists(packageJson)) { - Messages.noPackageError(); - return; - } + if (packageJson === null) { return; } Window.showInputBox({ prompt: 'Package to remove', @@ -31,4 +25,4 @@ const _removePackage = async function () { runCommand(args, packageJson); }); -}; +} diff --git a/src/run-command.ts b/src/run-command.ts index 94d1869..50ac04a 100644 --- a/src/run-command.ts +++ b/src/run-command.ts @@ -27,7 +27,7 @@ export function terminate(pid: number) { } export function runCommand(args: string[], packageJson: string) { - let cwd = packageJson.replace(/package.json$/i, ""); + const cwd = packageJson.replace(/package.json$/i, ""); const options = { cwd: cwd, diff --git a/src/run.ts b/src/run.ts index a307ee8..f2959f8 100644 --- a/src/run.ts +++ b/src/run.ts @@ -1,20 +1,18 @@ import * as Fs from 'fs'; -import { window as Window, QuickPickItem } from 'vscode'; +import { window as Window, Uri, QuickPickItem } from 'vscode'; import * as Messages from './messages'; import { runCommand } from './run-command'; -import { pickPackageJson, packageExists } from './utils'; +import { packageExists, getPackageJson } from './utils'; let lastScript: { - packageJson: string, - script: string + packageJson: string; + script: string; }; -export async function yarnRunScript() { - let packageJson = await pickPackageJson() - if (!packageExists(packageJson)) { - Messages.noPackageError(); - return; - } +export async function yarnRunScript(arg: Uri) { + const packageJson: string = await getPackageJson(arg); + + if (packageJson === null) { return; } const scripts = readScripts(packageJson); if (!scripts) { @@ -34,12 +32,10 @@ export async function yarnRunScript() { }); } -export async function yarnTest() { - let packageJson = await pickPackageJson() - if (!packageExists(packageJson)) { - Messages.noPackageError(); - return; - } +export async function yarnTest(arg: Uri) { + const packageJson: string = await getPackageJson(arg); + + if (packageJson === null) { return; } const scripts = readScripts(packageJson); if (!scripts) { @@ -58,12 +54,10 @@ export async function yarnTest() { runCommand(['run', 'test'], packageJson); } -export async function yarnStart() { - let packageJson = await pickPackageJson() - if (!packageExists(packageJson)) { - Messages.noPackageError(); - return; - } +export async function yarnStart(arg: Uri) { + const packageJson: string = await getPackageJson(arg); + + if (packageJson === null) { return; } const scripts = readScripts(packageJson); if (!scripts) { @@ -82,12 +76,10 @@ export async function yarnStart() { runCommand(['run', 'start'], packageJson); } -export async function yarnBuild() { - let packageJson = await pickPackageJson() - if (!packageExists(packageJson)) { - Messages.noPackageError(); - return; - } +export async function yarnBuild(arg: Uri) { + const packageJson: string = await getPackageJson(arg); + + if (packageJson === null) { return; } const scripts = readScripts(packageJson); if (!scripts) { @@ -108,9 +100,9 @@ export async function yarnBuild() { export async function yarnRunLastScript() { if (lastScript) { - let rootPath = lastScript.packageJson + const rootPath = lastScript.packageJson; - if (rootPath != null && !packageExists(rootPath)) { + if (rootPath !== null && !packageExists(rootPath)) { Messages.noPackageError(); return; } diff --git a/src/utils.ts b/src/utils.ts index 2b43fce..d39bdbf 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,12 +1,7 @@ import * as Fs from 'fs'; import * as Path from 'path'; import * as Messages from './messages'; -import { workspace as Workspace, window as Window, QuickPickItem } from 'vscode'; - -// Explorer context menu command argument -export interface CommandArgument { - fsPath: string; -} +import { workspace as Workspace, window as Window, QuickPickItem, Uri } from 'vscode'; interface PackageJsonRoot { fsPath: string; @@ -20,17 +15,17 @@ export async function pickPackageJson(): Promise> { return editor.document.fileName; } - let workspaceFolders = Workspace.workspaceFolders + const workspaceFolders = Workspace.workspaceFolders; if (workspaceFolders !== undefined) { // find if we have more than one workspace / multi root - let nodeWorkspaces: PackageJsonRoot[] = [] + const nodeWorkspaces: PackageJsonRoot[] = []; workspaceFolders.forEach(workspace => { // get package json path for workspace folder - let conf = Workspace.getConfiguration('yarn', workspace)['packageJson']; + const conf = Workspace.getConfiguration('yarn', workspace)['packageJson']; // look for root directory for package json - let packageJson = Path.join(workspace.uri.fsPath, conf); + const packageJson = Path.join(workspace.uri.fsPath, conf); if (Fs.existsSync(packageJson)) { nodeWorkspaces.push({ name: workspace.name, fsPath: packageJson }); @@ -42,19 +37,25 @@ export async function pickPackageJson(): Promise> { const items: QuickPickItem[] = nodeWorkspaces.map((workspace) => { return { label: workspace.name, description: workspace.fsPath }; }); - let item = await Window.showQuickPick(items, { ignoreFocusOut: true, canPickMany: false }) + const item = await Window.showQuickPick(items, { ignoreFocusOut: true, canPickMany: false }); if (undefined === item) { Messages.noValueError(); return undefined; } return nodeWorkspaces.filter(w => w.name === item.label)[0].fsPath; - } else if (nodeWorkspaces.length == 1) { - return nodeWorkspaces[0].fsPath + } else if (nodeWorkspaces.length === 1) { + return nodeWorkspaces[0].fsPath; } } - return undefined + return undefined; } +/** + * Check the file exisit in the path + * + * @param packageJson string location for the file + * @returns boolean + */ export function packageExists(packageJson: string) { try { const stat = Fs.statSync(packageJson); @@ -65,14 +66,54 @@ export function packageExists(packageJson: string) { } } +/** + * Get the package.json location from context menu or prompt + * to pick the project location. + * + * @param arg path to the file where command orignated + * @returns + */ +export async function getPackageJson(arg: Uri) { + let packageJson: string = null; + + // context menu wins always + if (arg !== undefined && arg.fsPath.length >= 0) { + packageJson = arg.fsPath; + } else { // fall back to pick + packageJson = await pickPackageJson(); + } + + if (!packageExists(packageJson)) { + Messages.noPackageError(); + } + + return packageJson; +} + +/** + * Get the configured value for the selection between output + * window and terminal window. + * + * @returns WorkspaceConfiguration boolean + */ export function useTerminal() { return Workspace.getConfiguration('yarn')['runInTerminal']; } +/** + * Get the configured yarn binary location. If not defualt to 'yarn' + * + * @returns WorkspaceConfiguration path to the yarn binary + */ export function getYarnBin() { return Workspace.getConfiguration('yarn')['bin'] || 'yarn'; } +/** + * Get the configuration value for the output window autohide feature + * + * @returns WorkspaceConfiguration boolen value + */ export function dontHideOutputOnSuccess() { return Workspace.getConfiguration('yarn')['dontHideOutputOnSuccess']; }