diff options
author | Kevin Locke <kevin@kevinlocke.name> | 2020-07-08 13:42:01 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-08 14:42:01 +0100 |
commit | 106c27644b4ff7543d600ae54ab9c53bec909828 (patch) | |
tree | 9051aa409edf4ef7361b3af992ef98c49a2b8be1 | |
parent | fd399c527f1812825bfd63c63255c648aa7ceef4 (diff) | |
download | ale-106c27644b4ff7543d600ae54ab9c53bec909828.zip |
eslint: Use cwd from executable location to fix nested projects (#3222)
* Split FindNearestExecutable from FindExecutable
The path searching in ale#node#FindExecutable() will be useful for
eslint. Refactor it into a separate function so it can be used without
regard for the state of the _use_global and _executable variables.
Signed-off-by: Kevin Locke <kevin@kevinlocke.name>
* eslint: Set project root from local executable
Using the nearest directory with node_modules does not work correctly
for nested projects where the eslint dependencies are in the outer
project. For example:
https://github.com/dense-analysis/ale/issues/3143#issuecomment-652452362
Adopt the behavior of SublimeLinter, which runs from project_root
determined by the presence of the eslint executable in node_modules/.bin
(or eslint in dependencies/devDependencies of package.json, which we can
add later as necessary). See [NodeLinter#find_local_executable].
[NodeLinter#find_local_executable]: https://github.com/SublimeLinter/SublimeLinter/blob/056e6f6/lint/base_linter/node_linter.py#L109
Signed-off-by: Kevin Locke <kevin@kevinlocke.name>
-rw-r--r-- | autoload/ale/handlers/eslint.vim | 26 | ||||
-rw-r--r-- | autoload/ale/node.vim | 14 | ||||
-rw-r--r-- | test/eslint-test-files/react-app/subdir-with-package-json/node_modules/.gitkeep | 0 | ||||
-rw-r--r-- | test/test_eslint_executable_detection.vader | 19 |
4 files changed, 50 insertions, 9 deletions
diff --git a/autoload/ale/handlers/eslint.vim b/autoload/ale/handlers/eslint.vim index c7c47d78..e37d6902 100644 --- a/autoload/ale/handlers/eslint.vim +++ b/autoload/ale/handlers/eslint.vim @@ -1,6 +1,11 @@ " Author: w0rp <devw0rp@gmail.com> " Description: Functions for working with eslint, for checking or fixing files. +let s:executables = [ +\ 'node_modules/.bin/eslint_d', +\ 'node_modules/eslint/bin/eslint.js', +\ 'node_modules/.bin/eslint', +\] let s:sep = has('win32') ? '\' : '/' call ale#Set('javascript_eslint_options', '') @@ -30,11 +35,7 @@ function! ale#handlers#eslint#FindConfig(buffer) abort endfunction function! ale#handlers#eslint#GetExecutable(buffer) abort - return ale#node#FindExecutable(a:buffer, 'javascript_eslint', [ - \ 'node_modules/.bin/eslint_d', - \ 'node_modules/eslint/bin/eslint.js', - \ 'node_modules/.bin/eslint', - \]) + return ale#node#FindExecutable(a:buffer, 'javascript_eslint', s:executables) endfunction " Given a buffer, return a command prefix string which changes directory @@ -44,10 +45,19 @@ function! ale#handlers#eslint#GetCdString(buffer) abort " By default, the project root is simply the CWD of the running process. " https://github.com/eslint/rfcs/blob/master/designs/2018-simplified-package-loading/README.md " https://github.com/dense-analysis/ale/issues/2787 - " Identify project root from presence of node_modules dir. + " + " If eslint is installed in a directory which contains the buffer, assume + " it is the ESLint project root. Otherwise, use nearest node_modules. " Note: If node_modules not present yet, can't load local deps anyway. - let l:modules_dir = ale#path#FindNearestDirectory(a:buffer, 'node_modules') - let l:project_dir = !empty(l:modules_dir) ? fnamemodify(l:modules_dir, ':h:h') : '' + let l:executable = ale#node#FindNearestExecutable(a:buffer, s:executables) + + if !empty(l:executable) + let l:nmi = strridx(l:executable, 'node_modules') + let l:project_dir = l:executable[0:l:nmi - 2] + else + let l:modules_dir = ale#path#FindNearestDirectory(a:buffer, 'node_modules') + let l:project_dir = !empty(l:modules_dir) ? fnamemodify(l:modules_dir, ':h:h') : '' + endif return !empty(l:project_dir) ? ale#path#CdString(l:project_dir) : '' endfunction diff --git a/autoload/ale/node.vim b/autoload/ale/node.vim index 69060122..9b9b335a 100644 --- a/autoload/ale/node.vim +++ b/autoload/ale/node.vim @@ -12,6 +12,18 @@ function! ale#node#FindExecutable(buffer, base_var_name, path_list) abort return ale#Var(a:buffer, a:base_var_name . '_executable') endif + let l:nearest = ale#node#FindNearestExecutable(a:buffer, a:path_list) + + if !empty(l:nearest) + return l:nearest + endif + + return ale#Var(a:buffer, a:base_var_name . '_executable') +endfunction + +" Given a buffer number, a base variable name, and a list of paths to search +" for in ancestor directories, detect the executable path for a Node program. +function! ale#node#FindNearestExecutable(buffer, path_list) abort for l:path in a:path_list let l:executable = ale#path#FindNearestFile(a:buffer, l:path) @@ -20,7 +32,7 @@ function! ale#node#FindExecutable(buffer, base_var_name, path_list) abort endif endfor - return ale#Var(a:buffer, a:base_var_name . '_executable') + return '' endfunction " Create a executable string which executes a Node.js script command with a diff --git a/test/eslint-test-files/react-app/subdir-with-package-json/node_modules/.gitkeep b/test/eslint-test-files/react-app/subdir-with-package-json/node_modules/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/eslint-test-files/react-app/subdir-with-package-json/node_modules/.gitkeep diff --git a/test/test_eslint_executable_detection.vader b/test/test_eslint_executable_detection.vader index c2071131..3fed63da 100644 --- a/test/test_eslint_executable_detection.vader +++ b/test/test_eslint_executable_detection.vader @@ -70,6 +70,25 @@ Execute(eslint.js executables should be run with node on Windows): \ ale#handlers#eslint#GetCommand(bufnr('')) endif +Execute(eslint.js should be run from containing project with eslint): + call ale#test#SetFilename('eslint-test-files/react-app/subdir-with-package-json/testfile.js') + + " We have to execute the file with node. + if has('win32') + AssertEqual + \ ale#path#CdString(ale#path#Simplify(g:dir . '/eslint-test-files/react-app')) + \ . ale#Escape('node.exe') . ' ' + \ . ale#Escape(ale#path#Simplify(g:dir . '/eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) + \ . ' -f json --stdin --stdin-filename %s', + \ ale#handlers#eslint#GetCommand(bufnr('')) + else + AssertEqual + \ ale#path#CdString(ale#path#Simplify(g:dir . '/eslint-test-files/react-app')) + \ . ale#Escape(ale#path#Simplify(g:dir . '/eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) + \ . ' -f json --stdin --stdin-filename %s', + \ ale#handlers#eslint#GetCommand(bufnr('')) + endif + Execute(eslint.js executables can be run outside project dir): " Set filename above eslint-test-files (which contains node_modules) call ale#test#SetFilename('testfile.js') |