diff --git a/.vscode/settings.json b/.vscode/settings.json index 1e9b01cc..0c040673 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,5 +2,7 @@ "standard.enable": true, "standard.engine": "ts-standard", "standard.usePackageJson": true, - "standard.workingDirectories": ["client", "server"] + "standard.workingDirectories": ["client", "server"], + "standard.autoFixOnSave": true, + "typescript.tsdk": "node_modules/typescript/lib" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 82741957..417f6883 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 2.0.0 + +- **Feature**: Better options default to reduce configurations overhead for users so that they can use the extension fast without too much configurations and still following "best practices" by encouraging local installation per project. ([#263](https://github.com/standard/vscode-standard/pull/263)) + +Now the extension will be automatically be enabled in projects that has one of the engines (`standard`, `semistandard`, `standardx` or `ts-standard`) installed in `devDependencies` in `package.json`. + +**Note**: This feature is only working if you have only **one** open folder in your VSCode workspace. +**Note 2**: If you still want to enable the extension globally you can set the new option : `"standard.enableGlobally": true` (by default it is set to `false`). + +**BREAKING CHANGE**: This feature changed the default settings, before: `"standard.usePackageJson": false`, after: `"standard.usePackageJson": true` +**BREAKING CHANGE**: By default (if you don't set `"standard.enableGlobally": true`), the extension will not lint your files if you haven't got a `package.json` containing one of the engines installed in `devDependencies`. + ## 1.5.1 - **Fix**: Find babel config files with `@babel/eslint-parser` ([#207](https://github.com/standard/vscode-standardjs/pull/207)) diff --git a/README.md b/README.md index c60fc22c..4e4a6a20 100644 --- a/README.md +++ b/README.md @@ -15,34 +15,39 @@ ## How to use -1. **Install the 'JavaScript Standard Style' extension** +1. **Install the 'StandardJS - JavaScript Standard Style' extension** - If you don't know how to install extensions in VSCode, take a look at the [documentation](https://code.visualstudio.com/docs/editor/extension-gallery#_browse-and-install-extensions). + Launch VSCode Quick Open (⌘+P), paste the following command, and press enter. - You will need to reload VSCode before new extensions can be used. + ```text + ext install standard.vscode-standard + ``` + + For more information, take a look at the [documentation](https://code.visualstudio.com/docs/editor/extension-gallery#_browse-and-install-extensions). -2. **Install `standard`, `semistandard`, `standardx` or `ts-standard`** +2. **Install the engine `standard`, `semistandard`, `standardx` or `ts-standard`** This can be done globally or locally. We recommend that you install them locally (i.e. saved in your project's `devDependencies`), to ensure that other developers have it installed when working on the project. -3. **Disable the built-in VSCode validator** +3. **Enable the extension** - To do this, set `"javascript.validate.enable": false` in your VSCode `settings.json`. + That's it! The extension will automatically be enabled in projects that has one of the engines installed in `devDependencies` in `package.json`. -## Plugin options +## Extension options -We give you some options to customize vscode-standard in your VSCode [`settings.json`](https://code.visualstudio.com/docs/getstarted/settings). +We give you some options to customize `vscode-standard` in your VSCode [`settings.json`](https://code.visualstudio.com/docs/getstarted/settings). | Option | Description | Default | | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------- | | `standard.enable` | enable or disable JavaScript Standard Style | `true` | +| `standard.enableGlobally` | enable or disable JavaScript Standard Style globally | `false` | | `standard.run` | run linter `onSave` or `onType` | `onType` | | `standard.autoFixOnSave` | enable or disable auto fix on save. It is only available when VSCode's `files.autoSave` is either `off`, `onFocusChange` or `onWindowChange`. It will not work with `afterDelay`. | `false` | | `standard.nodePath` | use this setting if an installed `standard` package can't be detected. | `null` | | `standard.validate` | an array of language identifiers specify the files to be validated | `["javascript", "javascriptreact", "typescript", "typescriptreact]` | | `standard.workingDirectories` | an array for working directories to be used. | `[]` | | `standard.engine` | You can use `semistandard`, `standardx` or `ts-standard` instead of `standard`. **Just make sure you've installed the `semistandard`, the `standardx` or the `ts-standard` package, instead of `standard`.** | `standard` | -| `standard.usePackageJson` | if set to `true`, JavaScript Standard Style will use project's `package.json` settings, otherwise globally installed `standard` module is used | `false` | +| `standard.usePackageJson` | if set to `true`, JavaScript Standard Style will use project's `package.json` settings, otherwise globally installed `standard` module is used | `true` | | `standard.treatErrorsAsWarnings` | Any linting error reported by Standard will instead be displayed as a warning within VS Code. | `false` | ## Configuring Standard diff --git a/client/package-lock.json b/client/package-lock.json index c8c46a29..d8bd0264 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -5,6 +5,7 @@ "requires": true, "packages": { "": { + "name": "client", "version": "0.0.1", "license": "MIT", "dependencies": { @@ -22,29 +23,43 @@ } }, "../node_modules/snazzy": { - "version": "0.0.1", + "version": "9.0.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "inherits": "^2.0.4", "minimist": "^1.2.5", "readable-stream": "^3.6.0", - "standard": "*", "standard-json": "^1.1.0", "strip-ansi": "^6.0.0", "text-table": "^0.2.0" + }, + "bin": { + "snazzy": "bin/cmd.js" + }, + "devDependencies": { + "standard": "*" } }, "../node_modules/ts-standard": { - "version": "0.0.1", + "version": "10.0.0", + "license": "MIT", "dependencies": { - "@commitlint/cli": "^11.0.0", - "@commitlint/config-conventional": "^11.0.0", - "@types/eslint": "^7.2.5", - "@types/jest": "^26.0.15", - "@types/minimist": "^1.2.1", - "@types/node": "^14.14.10", "@typescript-eslint/eslint-plugin": "^4.8.2", - "coveralls": "^3.1.0", "eslint": "^7.14.0", "eslint-config-standard": "^16.0.2", "eslint-config-standard-jsx": "^10.0.0", @@ -55,15 +70,33 @@ "eslint-plugin-react": "^7.21.5", "eslint-plugin-standard": "4.1.0", "get-stdin": "^8.0.0", - "husky": "^4.3.0", - "jest": "^26.6.3", "minimist": "^1.2.5", "pkg-conf": "^3.1.0", + "standard-engine": "^14.0.1" + }, + "bin": { + "ts-standard": "bin/cmd.js" + }, + "devDependencies": { + "@commitlint/cli": "^11.0.0", + "@commitlint/config-conventional": "^11.0.0", + "@types/eslint": "^7.2.5", + "@types/jest": "^26.0.15", + "@types/minimist": "^1.2.1", + "@types/node": "^14.14.10", + "coveralls": "^3.1.0", + "husky": "^4.3.0", + "jest": "^26.6.3", "prettier": "^2.2.1", - "standard-engine": "^14.0.1", "ts-jest": "^26.4.4", "ts-node": "^9.0.0", "typescript": "^4.1.2" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "typescript": ">=3.8" } }, "node_modules/@types/vscode": { diff --git a/client/src/extension.ts b/client/src/extension.ts index 83e75717..72fd060e 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -1,4 +1,5 @@ import * as path from 'path' +import * as fs from 'fs' import { CodeActionContext, commands as Commands, @@ -12,6 +13,7 @@ import { TextEditor, window as Window, workspace as Workspace, + WorkspaceConfiguration, WorkspaceFolder as VWorkspaceFolder } from 'vscode' import { @@ -40,13 +42,20 @@ import * as NoStandardLibraryRequest from './utils/NoStandardLibraryRequest' import * as StatusNotification from './utils/StatusNotification' import * as ValidateItem from './utils/ValidateItem' -type LinterValues = 'standard' | 'semistandard' | 'standardx' | 'ts-standard' +const linterValues = [ + 'standard', + 'semistandard', + 'standardx', + 'ts-standard' +] as const + +type LinterValues = typeof linterValues[number] type LinterNameValues = | 'JavaScript Standard Style' | 'JavaScript Semi-Standard Style' | 'JavaScript Standard Style with custom tweaks' | 'TypeScript Standard Style' -var linterName: LinterNameValues +let linterName: LinterNameValues type RunValues = 'onType' | 'onSave' @@ -70,9 +79,7 @@ interface NoStandardState { workspaces?: { [key: string]: boolean } } -const exitCalled = new NotificationType<[number, string]>( - 'standard/exitCalled' -) +const exitCalled = new NotificationType<[number, string]>('standard/exitCalled') interface WorkspaceFolderItem extends QuickPickItem { folder: VWorkspaceFolder @@ -95,7 +102,7 @@ function pickFolder ( return Promise.resolve(folders[0]) } return Window.showQuickPick( - folders.map(folder => { + folders.map((folder) => { return { label: folder.name, description: folder.uri.fsPath, @@ -103,7 +110,7 @@ function pickFolder ( } }), { placeHolder: placeHolder } - ).then(selected => { + ).then((selected) => { if (selected == null) { return undefined } @@ -120,7 +127,7 @@ async function enable (): Promise { return undefined } const disabledFolders = folders.filter( - folder => + (folder) => !Workspace.getConfiguration('standard', folder.uri).get('enable', true) ) if (disabledFolders.length === 0) { @@ -156,7 +163,7 @@ async function disable (): Promise { ) return undefined } - const enabledFolders = folders.filter(folder => + const enabledFolders = folders.filter((folder) => Workspace.getConfiguration('standard', folder.uri).get('enable', true) ) if (enabledFolders.length === 0) { @@ -192,11 +199,10 @@ const defaultLanguages = [ 'typescript', 'typescriptreact' ] -function shouldBeValidated (textDocument: TextDocument): boolean { - const config = Workspace.getConfiguration('standard', textDocument.uri) - if (!config.get('enable', true)) { - return false - } +function shouldBeValidatedLanguage ( + config: WorkspaceConfiguration, + textDocument: TextDocument +): boolean { const validate = config.get>( 'validate', defaultLanguages @@ -214,6 +220,43 @@ function shouldBeValidated (textDocument: TextDocument): boolean { return false } +function shouldBeValidated (textDocument: TextDocument): boolean { + const config = Workspace.getConfiguration('standard', textDocument.uri) + const usePackageJson = config.get('usePackageJson', true) + const isEnabled = config.get('enable', true) + const isEnabledGlobally = config.get('enableGlobally', true) + if (!isEnabled) { + return false + } + if ( + !isEnabledGlobally && + usePackageJson && + Workspace.workspaceFolders?.length === 1 + ) { + const workspacePath = Workspace.workspaceFolders[0].uri.fsPath + const packageJsonPath = path.join(workspacePath, 'package.json') + if (fs.existsSync(packageJsonPath)) { + const packageJson = JSON.parse( + fs.readFileSync(packageJsonPath).toString() + ) + if (packageJson.devDependencies != null) { + const devDependencies = Object.keys(packageJson.devDependencies) + const hasStandardEngineInstalled = linterValues.some((engine) => { + return devDependencies.includes(engine) + }) + if (hasStandardEngineInstalled) { + return shouldBeValidatedLanguage(config, textDocument) + } + return false + } + } + } + if (isEnabledGlobally) { + return shouldBeValidatedLanguage(config, textDocument) + } + return false +} + export async function activate (context: ExtensionContext): Promise { let activated: boolean = false let openListener: Disposable | null = null @@ -244,9 +287,8 @@ export async function activate (context: ExtensionContext): Promise { await Commands.executeCommand('setContext', 'standardEnabled', activated) } openListener = Workspace.onDidOpenTextDocument(didOpenTextDocument) - configurationListener = Workspace.onDidChangeConfiguration( - configurationChanged - ) + configurationListener = + Workspace.onDidChangeConfiguration(configurationChanged) const notValidating = async (): Promise> => { return await Window.showInformationMessage( @@ -396,10 +438,10 @@ export function realActivate (context: ExtensionContext): void { ? configuration.get('validate', defaultLanguages) : defaultLanguages, workspaceFolders: - folders != null ? folders.map(folder => folder.name) : [] + folders != null ? folders.map((folder) => folder.name) : [] } }, - initializationFailedHandler: error => { + initializationFailedHandler: (error) => { client.error('Server initialization failed.', error) client.outputChannel.show(true) return false @@ -483,11 +525,16 @@ export function realActivate (context: ExtensionContext): void { } const result: Array = [] for (const item of params.items) { - if ((item?.section != null && item.section.length > 0) || item.scopeUri?.length === 0) { + if ( + (item?.section != null && item.section.length > 0) || + item.scopeUri?.length === 0 + ) { result.push(null) continue } - const resource = client.protocol2CodeConverter.asUri(item.scopeUri as string) + const resource = client.protocol2CodeConverter.asUri( + item.scopeUri as string + ) const config = Workspace.getConfiguration('standard', resource) const settings: TextDocumentSettings = { validate: false, @@ -541,9 +588,10 @@ export function realActivate (context: ExtensionContext): void { index: workspaceFolder.index } } - const workingDirectories = config.get< - Array - >('workingDirectories') + const workingDirectories = + config.get>( + 'workingDirectories' + ) if (Array.isArray(workingDirectories)) { let workingDirectory const workspaceFolderPath = @@ -557,7 +605,8 @@ export function realActivate (context: ExtensionContext): void { directory = entry } else if (DirectoryItem.is(entry)) { directory = entry.directory - changeProcessCWD = entry.changeProcessCWD != null ? changeProcessCWD : false + changeProcessCWD = + entry.changeProcessCWD != null ? changeProcessCWD : false } if (directory != null) { if ( @@ -605,7 +654,7 @@ export function realActivate (context: ExtensionContext): void { defaultErrorHandler = client.createDefaultErrorHandler() const running = `${linterName} server is running.` const stopped = `${linterName} server stopped.` - client.onDidChangeState(event => { + client.onDidChangeState((event) => { if (event.newState === ClientState.Running) { client.info(running) statusBarItem.tooltip = running @@ -620,14 +669,16 @@ export function realActivate (context: ExtensionContext): void { client .onReady() .then(() => { - client.onNotification(StatusNotification.type, params => { + client.onNotification(StatusNotification.type, (params) => { updateStatus(params.state) }) client.onNotification(exitCalled, (async (params: any) => { serverCalledProcessExit = true client.error( - `Server process exited with code ${params[0] as string}. This usually indicates a misconfigured ${linterName} setup.`, + `Server process exited with code ${ + params[0] as string + }. This usually indicates a misconfigured ${linterName} setup.`, params[1] ) await Window.showErrorMessage( @@ -635,7 +686,7 @@ export function realActivate (context: ExtensionContext): void { ) }) as unknown as () => void) - client.onRequest(NoStandardLibraryRequest.type, async params => { + client.onRequest(NoStandardLibraryRequest.type, async (params) => { const key = 'noStandardMessageShown' const state = context.globalState.get(key, {}) const uri = URI.parse(params.source.uri) @@ -657,7 +708,10 @@ export function realActivate (context: ExtensionContext): void { if (state.workspaces == null) { state.workspaces = Object.create(null) } - if (state.workspaces != null && !state.workspaces[workspaceFolder.uri.toString()]) { + if ( + state.workspaces != null && + !state.workspaces[workspaceFolder.uri.toString()] + ) { state.workspaces[workspaceFolder.uri.toString()] = true client.outputChannel.show(true) await context.globalState.update(key, state) @@ -682,7 +736,7 @@ export function realActivate (context: ExtensionContext): void { .catch(() => {}) if (dummyCommands != null) { - dummyCommands.forEach(command => command.dispose()) + dummyCommands.forEach((command) => command.dispose()) dummyCommands = null } context.subscriptions.push( @@ -717,6 +771,6 @@ export function realActivate (context: ExtensionContext): void { export function deactivate (): void { if (dummyCommands != null) { - dummyCommands.forEach(command => command.dispose()) + dummyCommands.forEach((command) => command.dispose()) } } diff --git a/package-lock.json b/package-lock.json index 6dc3bb62..66411f19 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,12 @@ { "name": "vscode-standard", - "version": "1.5.1", + "version": "2.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "1.5.1", + "name": "vscode-standard", + "version": "2.0.0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 64814348..2c769838 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "vscode-standard", "displayName": "StandardJS - JavaScript Standard Style", "description": "Visual Studio Code extension for JavaScript Standard Style with automatic fixing.", - "version": "1.5.1", + "version": "2.0.0", "author": "Standard", "license": "MIT", "repository": { @@ -44,6 +44,12 @@ "default": true, "description": "Controls whether JavaScript Standard Style is enabled for JavaScript files or not." }, + "standard.enableGlobally": { + "scope": "resource", + "type": "boolean", + "default": false, + "description": "Controls whether JavaScript Standard Style is enabled globally for JavaScript files or not." + }, "standard.nodePath": { "scope": "resource", "type": [ @@ -161,7 +167,7 @@ }, "standard.usePackageJson": { "type": "boolean", - "default": false, + "default": true, "description": "Activate JavaScript Standard Style based on project's package.json settings, use globally installed standard module if set to \"false\"" }, "standard.treatErrorsAsWarnings": { diff --git a/server/package-lock.json b/server/package-lock.json index 29e88652..70f86ff1 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -5,6 +5,7 @@ "requires": true, "packages": { "": { + "name": "server", "version": "0.0.1", "license": "MIT", "dependencies": {