Anyone have a successful lint setup for js/ts?

I cant seem to get linting working correctly for me, oddly enough. I’ve tried following the directions in the wiki, ive installed the formatter and everything, but it doesnt seem to work.

i currently have this in my kakrc, but i dont see any gutter signs in projects with a .eslintrc file present. When i run the :lint command, i get an empty lint-buffer even though i know there are errors.

hook global WinSetOption filetype=javascript %{
  set buffer lintcmd 'node_modules/.bin/eslint --config=.eslintrc --format=node_modules/eslint-formatter-kakoune'
  lint-enable
  lint
}

I’ve looked into the issues but it doesnt seem like anything offered there works. would love some help here. thanks.

This is my javascript linting configuration. It works without any problem.

hook global WinSetOption filetype=javascript %{
	set buffer lintcmd './node_modules/.bin/eslint --format=node_modules/eslint-formatter-kakoune -c .eslintrc.js'
	lint-enable
}

The only differences I find with yours is than you are using node_modules and I’m using ./node_modules but I don’t think that is relevant.
Try to run the command alone on a terminal with some file as a test. You might get some ideas on what is failing.

1 Like

I hope eslint-formatter-kakoune still works with the latest version of eslint (there’s no reason it shouldn’t anymore, but who knows). If this piece is indeed the guilty one on this issue, don’t hesitate to ping me on https://github.com/Delapouite/eslint-formatter-kakoune to update it.

Why --config .eslintrc.js is specified?

Does it look for .eslintrc.js in the current directory only or also the ancestors?

I added the path to the config file because it seemed necessary from this issue:

but with or without it, i get the same exact outcome. running the following from the command line outputs errors
❯ node_modules/.bin/eslint -f ~/node_modules/eslint-formatter-kakoune/index.js assets/js/**/*.js

i have basically the same thing without the js glob pattern in my kakrc:

6│hook global WinSetOption filetype=javascript %{ 
57│  set window lintcmd 'eslint -f ~/node_modules/eslint-formatter-kakoune/index.js --config=.eslintrc.js' 
58│  lint-enable 
59│}

but when i open a file with kakoune, i get no errors, i run :lint and a lint-output buffer is created without any errors. in the status line, it reads 0 errors, 0 warnings…

and yes i even removed the path to the config file, same thing happens.

Bump?

I guess most kakoune users are not web developers :sweat_smile:

Have you looked in the *debug* buffer for any error messages or warnings from Kakoune that might have occurred when it tries to run eslint?

theres nothing in the debug buffer unfortunately.

How do you trigger the lint command on save?

I am doing web dev stuff, but my lint takes legit 3 minutes to run, so don’t want it on save. :slight_smile:

@jssee did you try with the ./node_modules instead of node_modules?

You can also use npm bin if you don’t want to tweak your path.

set-option window lintcmd "%sh(npm bin)/eslint --format eslint-formatter-kakoune"

If it helps, this is the current setup I use with Kakoune and TypeScript.

I define hidden commands for formatting with eslint, prettier, or tslint. Depending on the project’s requirements, a different formatter might be required. I use npx and the actual file to make sure that the tool picks up the correct project config for formatting.

define-command -hidden eslint-format %{
    set-option window autoreload 'yes'
    execute-keys ': w<ret>'
    nop %sh{
        npx eslint --fix "$kak_buffile"
    }
    hook -once window BufReload .* %{
        unset-option window autoreload
    }
}

define-command -hidden prettier-format %{
    execute-keys '%|npx prettier --stdin-filepath $kak_buffile<ret><space>;'
}

define-command -hidden tslint-format %{
    set-option window autoreload 'yes'
    execute-keys ': w<ret>'
    nop %sh{
        npx tslint --fix "$kak_buffile"
    }
    hook -once window BufReload .* %{
        unset-option window autoreload
    }
}

The nice thing about the prettier formatter is, that it doesn’t need any file changes on disk. It simply updates the buffer with the formatted content.
eslint and tslint save the file to disk, format it there, and then Kakoune auto-reloads that change.

If you have jq available, you can use eslint formatting without writing anything to disk.
Replace the eslint-format command from above with this one:

define-command -hidden eslint-format %{
    execute-keys '%|echo "$kak_selection" | npx eslint --format json --fix-dry-run --stdin --stdin-filename "$kak_buffile" | jq -j ".[].output"<ret>'
}

Then I do the following to let me trigger linting and formatting.
For eslint, I use the lintcmd from the wiki (Lint) which works fine for me.
I have a development user mode, where keys for linting, formatting, etc. go.

# Setting eslint as linter and default formatter
hook global WinSetOption filetype=(javascript|typescript) %{
    # Eslint
    set window lintcmd 'run() { cat "$1" | npx eslint -f $path_to/node_modules/eslint-formatter-kakoune/index.js --stdin --stdin-filename $kak_buffile;} && run '
    map window development l -docstring 'lint' ': lint<ret>'
    lint-enable

    # Formatting
    # Defaults to `eslint --fix`
    # Overwrite this alias in a `.kakrc.local` to use one of the other formatters
    # that are defined commands above.
    alias window tsformat eslint-format
    map window development f -docstring 'format' ': tsformat<ret>'
}

I try to source .kakrc.local as described in the wiki (IDE), which allows me to set the formatter on a per-project basis.

So:

  • Linting with eslint works just fine and as expected.
  • Linting with tslint doesn’t work, as I don’t know a formatter. However, I try to avoid tslint where possible anyways.
  • Formatting “works” with all options, but I really only like the prettier option and eslint with jq. But that is an extra dependency on jq for eslint.

Could anyone help me and tell me how I could keep the cursor position with the prettier approach? Now it ends up at the very end due to the key combinations.

You could add hooks to auto-lint and/or auto-format on specific occasions if you want, e.g. when leaving insert mode or writing a buffer.
With prettier, since it only changes the buffer, you can do a BufWritePre hook, which works quite nicely. With the other formatters it is required to use BufWritePost.

You can do something like the following in your .kakrc.local:

hook global WinSetOption filetype=(javascript|typescript) %{
    # Use *one* of the following to replace eslint as a formatter:
    alias window tsformat prettier-format
    alias window tsformat tslint-format

    # To auto-format on write with prettier:
    # (Or eslint if you go with the jq option that doesn't write to disk)
    hook buffer BufWritePre .* tsformat
}

Hope this helps anyone looking to do TS development with Kakoune.

I could make it more generic and add it to the Wiki, if there is interest.

hook buffer BufWritePost .* tsformat

I don’t think this is going to work well

Because of the : w? Whoops, that would need to get moved for that.

I removed it from the post for now

no, BufWritePost will call tsformat after buffer save

That would be intended in these cases, as the fixer runs on the actual file on disk, thus the buffer needs to be written to disk first. However, since in the eslint case for example the command starts with : w, I thought you meant I would end up in endless recursion.
So it seems I misunderstood you, can you please elaborate?

I think I understood. It will format file on disk, not the buffer?

Yes. I haven’t found a way to do it with eslint on the buffer directly while also using the local project configuration for it.
It would work if I found an eslint-formatter that prints the formatted file to stdout. In that case it could work the same way that prettier works, with a simple pipe from Kakoune.

you can pipe buffer to temporary file, format it, and replace buffer with contents of that file. But this is quite a dirty way

Yes, but it wouldn’t be nice. The temporary file would need to be located next to the original file in order to keep the project settings and relative imports working.
It could work, though.

I could check format.kak for how to do that. I am not sure it is better than working on the actual file, though.

First, I want to try to create a formatter that outputs the fixed file.