Skip to content

Commit 6fa2b3b

Browse files
author
Carnavale
authored
feat(eslint): add vim.lsp.config support #3731
1 parent b335f1c commit 6fa2b3b

File tree

1 file changed

+182
-0
lines changed

1 file changed

+182
-0
lines changed

lsp/eslint.lua

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
--- @brief
2+
---
3+
--- https://github.com/hrsh7th/vscode-langservers-extracted
4+
---
5+
--- `vscode-eslint-language-server` is a linting engine for JavaScript / Typescript.
6+
--- It can be installed via `npm`:
7+
---
8+
--- ```sh
9+
--- npm i -g vscode-langservers-extracted
10+
--- ```
11+
---
12+
--- `vscode-eslint-language-server` provides an `EslintFixAll` command that can be used to format a document on save:
13+
--- ```lua
14+
--- vim.lsp.config('eslint', {
15+
--- --- ...
16+
--- on_attach = function(client, bufnr)
17+
--- vim.api.nvim_create_autocmd("BufWritePre", {
18+
--- buffer = bufnr,
19+
--- command = "EslintFixAll",
20+
--- })
21+
--- end,
22+
--- })
23+
--- ```
24+
---
25+
--- See [vscode-eslint](https://github.com/microsoft/vscode-eslint/blob/55871979d7af184bf09af491b6ea35ebd56822cf/server/src/eslintServer.ts#L216-L229) for configuration options.
26+
---
27+
--- Messages handled in lspconfig: `eslint/openDoc`, `eslint/confirmESLintExecution`, `eslint/probeFailed`, `eslint/noLibrary`
28+
---
29+
--- Additional messages you can handle: `eslint/noConfig`
30+
31+
local util = require 'lspconfig.util'
32+
local lsp = vim.lsp
33+
34+
return {
35+
cmd = { 'vscode-eslint-language-server', '--stdio' },
36+
filetypes = {
37+
'javascript',
38+
'javascriptreact',
39+
'javascript.jsx',
40+
'typescript',
41+
'typescriptreact',
42+
'typescript.tsx',
43+
'vue',
44+
'svelte',
45+
'astro',
46+
},
47+
on_init = function(client)
48+
vim.api.nvim_create_user_command('LspEslintFixAll', function()
49+
local bufnr = vim.api.nvim_get_current_buf()
50+
51+
client:exec_cmd({
52+
title = 'Fix all Eslint errors for current buffer',
53+
command = 'eslint.applyAllFixes',
54+
arguments = {
55+
{
56+
uri = vim.uri_from_bufnr(bufnr),
57+
version = lsp.util.buf_versions[bufnr],
58+
},
59+
},
60+
}, { bufnr = bufnr })
61+
end, {})
62+
end,
63+
-- https://eslint.org/docs/user-guide/configuring/configuration-files#configuration-file-formats
64+
root_dir = function(bufnr, on_dir)
65+
local root_file_patterns = {
66+
'.eslintrc',
67+
'.eslintrc.js',
68+
'.eslintrc.cjs',
69+
'.eslintrc.yaml',
70+
'.eslintrc.yml',
71+
'.eslintrc.json',
72+
'eslint.config.js',
73+
'eslint.config.mjs',
74+
'eslint.config.cjs',
75+
'eslint.config.ts',
76+
'eslint.config.mts',
77+
'eslint.config.cts',
78+
}
79+
80+
local fname = vim.api.nvim_buf_get_name(bufnr)
81+
root_file_patterns = util.insert_package_json(root_file_patterns, 'eslintConfig', fname)
82+
local root_dir = vim.fs.dirname(vim.fs.find(root_file_patterns, { path = fname, upward = true })[1])
83+
on_dir(root_dir)
84+
end,
85+
-- Refer to https://github.com/Microsoft/vscode-eslint#settings-options for documentation.
86+
settings = {
87+
validate = 'on',
88+
packageManager = nil,
89+
useESLintClass = false,
90+
experimental = {
91+
useFlatConfig = false,
92+
},
93+
codeActionOnSave = {
94+
enable = false,
95+
mode = 'all',
96+
},
97+
format = true,
98+
quiet = false,
99+
onIgnoredFiles = 'off',
100+
rulesCustomizations = {},
101+
run = 'onType',
102+
problems = {
103+
shortenToSingleLine = false,
104+
},
105+
-- nodePath configures the directory in which the eslint server should start its node_modules resolution.
106+
-- This path is relative to the workspace folder (root dir) of the server instance.
107+
nodePath = '',
108+
-- use the workspace folder location or the file location (if no workspace folder is open) as the working directory
109+
workingDirectory = { mode = 'location' },
110+
codeAction = {
111+
disableRuleComment = {
112+
enable = true,
113+
location = 'separateLine',
114+
},
115+
showDocumentation = {
116+
enable = true,
117+
},
118+
},
119+
},
120+
before_init = function(_, config)
121+
-- The "workspaceFolder" is a VSCode concept. It limits how far the
122+
-- server will traverse the file system when locating the ESLint config
123+
-- file (e.g., .eslintrc).
124+
local root_dir = config.root_dir
125+
126+
if root_dir then
127+
config.settings = config.settings or {}
128+
config.settings.workspaceFolder = {
129+
uri = root_dir,
130+
name = vim.fn.fnamemodify(root_dir, ':t'),
131+
}
132+
133+
-- Support flat config
134+
local flat_config_files = {
135+
'eslint.config.js',
136+
'eslint.config.mjs',
137+
'eslint.config.cjs',
138+
'eslint.config.ts',
139+
'eslint.config.mts',
140+
'eslint.config.cts',
141+
}
142+
143+
for _, file in ipairs(flat_config_files) do
144+
if vim.fn.filereadable(root_dir .. '/' .. file) == 1 then
145+
config.settings.experimental = config.settings.experimental or {}
146+
config.settings.experimental.useFlatConfig = true
147+
break
148+
end
149+
end
150+
151+
-- Support Yarn2 (PnP) projects
152+
local pnp_cjs = root_dir .. '/.pnp.cjs'
153+
local pnp_js = root_dir .. '/.pnp.js'
154+
if vim.uv.fs_stat(pnp_cjs) or vim.uv.fs_stat(pnp_js) then
155+
local cmd = config.cmd
156+
config.cmd = vim.list_extend({ 'yarn', 'exec' }, cmd)
157+
end
158+
end
159+
end,
160+
handlers = {
161+
['eslint/openDoc'] = function(_, result)
162+
if result then
163+
vim.ui.open(result.url)
164+
end
165+
return {}
166+
end,
167+
['eslint/confirmESLintExecution'] = function(_, result)
168+
if not result then
169+
return
170+
end
171+
return 4 -- approved
172+
end,
173+
['eslint/probeFailed'] = function()
174+
vim.notify('[lspconfig] ESLint probe failed.', vim.log.levels.WARN)
175+
return {}
176+
end,
177+
['eslint/noLibrary'] = function()
178+
vim.notify('[lspconfig] Unable to find ESLint library.', vim.log.levels.WARN)
179+
return {}
180+
end,
181+
},
182+
}

0 commit comments

Comments
 (0)