Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect eslint project root when using nested node_modules #4790

Closed
kimberli opened this issue May 31, 2024 · 2 comments
Closed

Incorrect eslint project root when using nested node_modules #4790

kimberli opened this issue May 31, 2024 · 2 comments
Labels

Comments

@kimberli
Copy link

kimberli commented May 31, 2024

Information

VIM version
NVIM v0.9.5
Build type: Release

Operating System: Mac OS X 14.3.1 (23D60)

What went wrong

When using eslint in a project that uses pnpm to manage dependencies, the eslint devDependency can be installed into a folder like project/node_modules/.pnpm/[email protected]/node_modules/eslint/bin/eslint.js.

Reproducing the bug

  1. Make sure pnpm is installed: https://pnpm.io/installation
  2. Clone this repo: https://github.com/kimberli/new-project
  3. Run pnpm install
  4. Open the index.ts file in vim
  5. Expect lint errors to appear for Parsing error (You may need configure typescript-eslint-parser): ',' expected.. Instead you get a Cannot read file '/users/kim/new-project/node_modules/.pnpm/[email protected]/tsconfig.json'.

:ALEInfo

 Current Filetype: typescript
Available Linters: ['biome', 'cspell', 'deno', 'eslint', 'standard', 'tslint', 'tsserver', 'typecheck', 'xo']
  Enabled Linters: ['eslint']
  Ignored Linters: []
 Suggested Fixers:
  'biome' - Fix JavaScript and TypeScript using biome.
  'deno' - Fix TypeScript using deno fmt.
  'dprint' - Pluggable and configurable code formatting platform
  'eslint' - Apply eslint --fix to a file.
  'prettier' - Apply prettier to a file.
  'remove_trailing_lines' - Remove all blank lines at the end of a file.
  'trim_whitespace' - Remove all trailing whitespace characters at the end of every line.
  'tslint' - Fix typescript files with tslint --fix.
  'xo' - Fix JavaScript/TypeScript files using xo --fix.

 Linter Variables:
" Press Space to read :help for a setting
let g:ale_typescript_eslint_executable = 'eslint_d'
let g:ale_typescript_eslint_use_global = 1

 Global Variables:
" Press Space to read :help for a setting
let g:ale_cache_executable_check_failures = v:null
let g:ale_change_sign_column_color = v:null
let g:ale_command_wrapper = ''
let g:ale_completion_delay = v:null
let g:ale_completion_enabled = 0
let g:ale_completion_max_suggestions = v:null
let g:ale_disable_lsp = 'auto'
let g:ale_echo_cursor = 1
let g:ale_echo_msg_error_str = 'Error'
let g:ale_echo_msg_format = '%code: %%s'
let g:ale_echo_msg_info_str = 'Info'
let g:ale_echo_msg_warning_str = 'Warning'
let g:ale_enabled = 1
let g:ale_fix_on_save = 1
let g:ale_fixers = {'cpp': ['clang-format'], 'typescript': ['eslint'], 'typescriptreact': ['eslint'], 'javascript': ['eslint'], 'typescript.tsx': ['eslint']}
let g:ale_history_enabled = 1
let g:ale_info_default_mode = 'preview'
let g:ale_history_log_output = 1
let g:ale_keep_list_window_open = 0
let g:ale_lint_delay = 200
let g:ale_lint_on_enter = 1
let g:ale_lint_on_filetype_changed = 1
let g:ale_lint_on_insert_leave = 1
let g:ale_lint_on_save = 1
let g:ale_lint_on_text_changed = 'normal'
let g:ale_linter_aliases = {}
let g:ale_linters = {'cpp': ['cpplint'], 'typescript': ['eslint'], 'typescriptreact': ['eslint'], 'javascript': ['eslint'], 'typescript.tsx': ['eslint'], 'python': ['pylint']}
let g:ale_linters_explicit = 0
let g:ale_linters_ignore = {}
let g:ale_list_vertical = 0
let g:ale_list_window_size = 5
let g:ale_loclist_msg_format = '%code: %%s'
let g:ale_max_buffer_history_size = 20
let g:ale_max_signs = v:null
let g:ale_maximum_file_size = v:null
let g:ale_open_list = 1
let g:ale_pattern_options = v:null
let g:ale_pattern_options_enabled = v:null
let g:ale_root = {}
let g:ale_set_balloons = 0
let g:ale_set_highlights = 1
let g:ale_set_loclist = 1
let g:ale_set_quickfix = 0
let g:ale_set_signs = 1
let g:ale_sign_column_always = v:null
let g:ale_sign_error = '>'
let g:ale_sign_info = v:null
let g:ale_sign_offset = v:null
let g:ale_sign_style_error = v:null
let g:ale_sign_style_warning = v:null
let g:ale_sign_warning = '-'
let g:ale_sign_highlight_linenrs = v:null
let g:ale_type_map = {}
let g:ale_use_neovim_diagnostics_api = 1
let g:ale_use_global_executables = v:null
let g:ale_virtualtext_cursor = 'all'
let g:ale_warn_about_trailing_blank_lines = 1
let g:ale_warn_about_trailing_whitespace = 1

  Command History:

(executable check - success) eslint_d
(finished - exit code 1) ['/bin/zsh', '-c', 'cd ''/Users/kim/new-project/node_modules/.pnpm/[email protected]'' && ''eslint_d'' -f json --stdin --stdin-filename ''/Users/kim/new-project/index.ts'' < ''/var/  folders/b2/z7lztvt5667b9sfxryv2cg_m0000gn/T/nvim.kim/rMvcQ1/1/index.ts''']

<<<OUTPUT STARTS>>>
[{"filePath":"/Users/kim/new-project/index.ts","messages":[{"ruleId":null,"fatal":true,"severity":2,"message":"Parsing error: Cannot read file '/users/kim/new-project/node_modules/.pnpm/[email protected]/    tsconfig.json'.","nodeType":null}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":1,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"test test\n","usedDeprecatedRules":  []}]
<<<OUTPUT ENDS>>>

Potential fix

In https://github.com/dense-analysis/ale/blob/master/autoload/ale/handlers/eslint.vim:

" Given a buffer, return an appropriate working directory for ESLint.
function! ale#handlers#eslint#GetCwd(buffer) abort
    " ESLint 6 loads plugins/configs/parsers from the project root
    " 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
    "
    " 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:executable = ale#path#FindNearestExecutable(a:buffer, s:executables)

    " Function to truncate path at the first 'node_modules'
    function! TruncateNodeModules(path)
        let l:truncated_path = a:path
        let l:index = stridx(l:truncated_path, 'node_modules')
        if l:index > -1
            let l:truncated_path = l:truncated_path[0:l:index - 1]
        endif
        return l:truncated_path
    endfunction

    if !empty(l:executable)
        let l:modules_root = TruncateNodeModules(l:executable)

        let l:sdks_index = strridx(l:executable, ale#path#Simplify('.yarn/sdks'))
        let l:sdks_root = l:sdks_index > -1 ? l:executable[0:l:sdks_index - 2] : ''
    else
        let l:modules_dir = ale#path#FindNearestDirectory(a:buffer, 'node_modules')
        let l:modules_root = !empty(l:modules_dir) ? TruncateNodeModules(l:modules_dir) : ''

        let l:sdks_dir = ale#path#FindNearestDirectory(a:buffer, ale#path#Simplify('.yarn/sdks'))
        let l:sdks_root = !empty(l:sdks_dir) ? fnamemodify(l:sdks_dir, ':h:h:h') : ''
    endif

    return strlen(l:modules_root) > strlen(l:sdks_root) ? l:modules_root : l:sdks_root
endfunction
@kimberli kimberli added the bug label May 31, 2024
@kimberli
Copy link
Author

kimberli commented May 31, 2024

Actually more correct fix is probably #4781 (tested and it seems to do the trick)

@w0rp
Copy link
Member

w0rp commented May 31, 2024

I've merged #4781 now, which should fix this.

@w0rp w0rp closed this as completed May 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants