From f8a4c78b5b293d11da9075373c9de0bb5afdeffe Mon Sep 17 00:00:00 2001 From: Trevor Whitney Date: Mon, 20 Sep 2021 19:49:15 -0600 Subject: [PATCH] Add support for jsonnetfmt and jsonnet-lint (#3907) * update to lates Signed-off-by: Trevor Whitney * fix up docs Signed-off-by: Trevor Whitney * fix docs Signed-off-by: Trevor Whitney * get tests passing Signed-off-by: Trevor Whitney * update regex Signed-off-by: Trevor Whitney * use ale#Pad and AssertFixer Signed-off-by: Trevor Whitney --- ale_linters/jsonnet/jsonnet_lint.vim | 59 +++++++++++++++++++ ale_linters/jsonnet/jsonnetfmt.vim | 52 ++++++++++++++++ autoload/ale/fix/registry.vim | 5 ++ autoload/ale/fixers/jsonnetfmt.vim | 18 ++++++ doc/ale-jsonnet.txt | 43 ++++++++++++++ doc/ale-supported-languages-and-tools.txt | 3 + doc/ale.txt | 3 + supported-tools.md | 3 + .../test_jsonnetfmt_fixer_callback.vader | 38 ++++++++++++ test/jsonnet_files/testfile.jsonnet | 1 + test/linter/test_jsonnet_lint.vader | 19 ++++++ test/linter/test_jsonnetfmt.vader | 19 ++++++ 12 files changed, 263 insertions(+) create mode 100644 ale_linters/jsonnet/jsonnet_lint.vim create mode 100644 ale_linters/jsonnet/jsonnetfmt.vim create mode 100644 autoload/ale/fixers/jsonnetfmt.vim create mode 100644 doc/ale-jsonnet.txt create mode 100644 test/fixers/test_jsonnetfmt_fixer_callback.vader create mode 100644 test/jsonnet_files/testfile.jsonnet create mode 100644 test/linter/test_jsonnet_lint.vader create mode 100644 test/linter/test_jsonnetfmt.vader diff --git a/ale_linters/jsonnet/jsonnet_lint.vim b/ale_linters/jsonnet/jsonnet_lint.vim new file mode 100644 index 00000000..a5ebdc39 --- /dev/null +++ b/ale_linters/jsonnet/jsonnet_lint.vim @@ -0,0 +1,59 @@ +" Author: Trevor Whitney +" Description: jsonnet-lint for jsonnet files + +call ale#Set('jsonnet_jsonnet_lint_executable', 'jsonnet-lint') +call ale#Set('jsonnet_jsonnet_lint_options', '') + +function! ale_linters#jsonnet#jsonnet_lint#GetCommand(buffer) abort + let l:options = ale#Var(a:buffer, 'jsonnet_jsonnet_lint_options') + + return '%e' + \ . ale#Pad(l:options) + \ . ' %t' +endfunction + + +function! ale_linters#jsonnet#jsonnet_lint#Handle(buffer, lines) abort + " Matches patterns line the following: + " + " ERROR: foo.jsonnet:22:3-12 expected token OPERATOR but got (IDENTIFIER, "bar") + " ERROR: hoge.jsonnet:20:3 unexpected: "}" while parsing terminal + " ERROR: main.jsonnet:212:1-14 Expected , or ; but got (IDENTIFIER, "older_cluster") + let l:pattern = '^ERROR: [^:]*:\(\d\+\):\(\d\+\)\(-\d\+\)* \(.*\)' + let l:output = [] + + for l:line in a:lines + let l:match = matchlist(l:line, l:pattern) + + if len(l:match) == 0 + continue + endif + + let line_number = l:match[1] + 0 + let column = l:match[2] + 0 + " l:match[3] has optional -14, when linter is showing a range + let text = l:match[4] + + + " vcol is Needed to indicate that the column is a character. + call add(l:output, { + \ 'bufnr': a:buffer, + \ 'lnum': line_number, + \ 'vcol': 0, + \ 'col': column, + \ 'text': text, + \ 'type': 'E', + \ 'nr': -1, + \}) + endfor + + return l:output +endfunction + +call ale#linter#Define('jsonnet', { +\ 'name': 'jsonnet_lint', +\ 'output_stream': 'stderr', +\ 'executable': {b -> ale#Var(b, 'jsonnet_jsonnet_lint_executable')}, +\ 'command': function('ale_linters#jsonnet#jsonnet_lint#GetCommand'), +\ 'callback': 'ale_linters#jsonnet#jsonnet_lint#Handle', +\}) diff --git a/ale_linters/jsonnet/jsonnetfmt.vim b/ale_linters/jsonnet/jsonnetfmt.vim new file mode 100644 index 00000000..8904019e --- /dev/null +++ b/ale_linters/jsonnet/jsonnetfmt.vim @@ -0,0 +1,52 @@ +" Authors: Trevor Whitney and Takuya Kosugiyama +" Description: jsonnetfmt for jsonnet files + +call ale#Set('jsonnet_jsonnetfmt_executable', 'jsonnetfmt') +call ale#Set('jsonnet_jsonnetfmt_options', '') + +function! ale_linters#jsonnet#jsonnetfmt#GetCommand(buffer) abort + let l:options = ale#Var(a:buffer, 'jsonnet_jsonnetfmt_options') + + return '%e' + \ . ale#Pad(l:options) + \ . ' %t' +endfunction + + +function! ale_linters#jsonnet#jsonnetfmt#Handle(buffer, lines) abort + " Matches patterns line the following: + " + " STATIC ERROR: foo.jsonnet:22:3-12: expected token OPERATOR but got (IDENTIFIER, "bar") + " STATIC ERROR: hoge.jsonnet:20:3: unexpected: "}" while parsing terminal + let l:pattern = '^STATIC ERROR:[^:]*:\(\d\+\):\(\d\+\):*\(-\d\+\)* \(.*\)' + let l:output = [] + + for l:line in a:lines + let l:match = matchlist(l:line, l:pattern) + + if len(l:match) == 0 + continue + endif + + " vcol is Needed to indicate that the column is a character. + call add(l:output, { + \ 'bufnr': a:buffer, + \ 'lnum': l:match[1] + 0, + \ 'vcol': 0, + \ 'col': l:match[2] + 0, + \ 'text': l:match[4], + \ 'type': 'E', + \ 'nr': -1, + \}) + endfor + + return l:output +endfunction + +call ale#linter#Define('jsonnet', { +\ 'name': 'jsonnetfmt', +\ 'output_stream': 'stderr', +\ 'executable': {b -> ale#Var(b, 'jsonnet_jsonnetfmt_executable')}, +\ 'command': function('ale_linters#jsonnet#jsonnetfmt#GetCommand'), +\ 'callback': 'ale_linters#jsonnet#jsonnetfmt#Handle', +\}) diff --git a/autoload/ale/fix/registry.vim b/autoload/ale/fix/registry.vim index 975d02f6..0447bd3e 100644 --- a/autoload/ale/fix/registry.vim +++ b/autoload/ale/fix/registry.vim @@ -486,6 +486,11 @@ let s:default_registry = { \ 'suggested_filetypes': ['haskell'], \ 'description': 'A formatter for Haskell source code.', \ }, +\ 'jsonnetfmt': { +\ 'function': 'ale#fixers#jsonnetfmt#Fix', +\ 'suggested_filetypes': ['jsonnet'], +\ 'description': 'Fix jsonnet files with jsonnetfmt', +\ }, \ 'ptop': { \ 'function': 'ale#fixers#ptop#Fix', \ 'suggested_filetypes': ['pascal'], diff --git a/autoload/ale/fixers/jsonnetfmt.vim b/autoload/ale/fixers/jsonnetfmt.vim new file mode 100644 index 00000000..f1e41cd5 --- /dev/null +++ b/autoload/ale/fixers/jsonnetfmt.vim @@ -0,0 +1,18 @@ +" Authors: Trevor Whitney and Takuya Kosugiyama +" Description: Integration of jsonnetfmt with ALE. + +call ale#Set('jsonnet_jsonnetfmt_executable', 'jsonnetfmt') +call ale#Set('jsonnet_jsonnetfmt_options', '') + +function! ale#fixers#jsonnetfmt#Fix(buffer) abort + let l:executable = ale#Var(a:buffer, 'jsonnet_jsonnetfmt_executable') + let l:options = ale#Var(a:buffer, 'jsonnet_jsonnetfmt_options') + + return { + \ 'command': ale#Escape(l:executable) + \ . ' -i' + \ . ale#Pad(l:options) + \ . ' %t', + \ 'read_temporary_file': 1, + \} +endfunction diff --git a/doc/ale-jsonnet.txt b/doc/ale-jsonnet.txt new file mode 100644 index 00000000..f99d415f --- /dev/null +++ b/doc/ale-jsonnet.txt @@ -0,0 +1,43 @@ +=============================================================================== +ALE Jsonnet Integration *ale-jsonnet-options* + + +=============================================================================== +jsonnetfmt *ale-jsonnet-jsonnetfmt* + +g:ale_jsonnet_jsonnetfmt_executable *g:ale_jsonnet_jsonnetfmt_executable* + *b:ale_jsonnet_jsonnetfmt_executable* + Type: |String| + Default: `'jsonnetfmt'` + + This option can be changed to change the path for `jsonnetfmt`. + + +g:ale_jsonnet_jsonnetfmt_options *g:ale_jsonnet_jsonnetfmt_options* + *b:ale_jsonnet_jsonnetfmt_options* + Type: |String| + Default: `''` + + This option can be changed to pass extra options to `jsonnetfmt`. + + +=============================================================================== +jsonnet-lint *ale-jsonnet-jsonnet-lint* + +g:ale_jsonnet_jsonnet_lint_executable *g:ale_jsonnet_jsonnet_lint_executable* + *b:ale_jsonnet_jsonnet_lint_executable* + Type: |String| + Default: `'jsonnet-lint'` + + This option can be changed to change the path for `jsonnet-lint`. + + +g:ale_jsonnet_jsonnet_lint_options *g:ale_jsonnet_jsonnet_lint_options* + *b:ale_jsonnet_jsonnet_lint_options* + Type: |String| + Default: `''` + + This option can be changed to pass extra options to `jsonnet-lint`. + + + vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: diff --git a/doc/ale-supported-languages-and-tools.txt b/doc/ale-supported-languages-and-tools.txt index 32e38b89..fec6937e 100644 --- a/doc/ale-supported-languages-and-tools.txt +++ b/doc/ale-supported-languages-and-tools.txt @@ -271,6 +271,9 @@ Notes: * `eslint` * JSONC * `eslint` +* Jsonnet + * `jsonnet-lint` + * `jsonnetfmt` * Julia * `languageserver` * Kotlin diff --git a/doc/ale.txt b/doc/ale.txt index 9a21e9f0..c9921b8b 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -2833,6 +2833,9 @@ documented in additional help files. spectral..............................|ale-json-spectral| jsonc...................................|ale-jsonc-options| eslint................................|ale-jsonc-eslint| + jsonnet.................................|ale-jsonnet-options| + jsonnetfmt............................|ale-jsonnet-jsonnetfmt| + jsonnet-lint..........................|ale-jsonnet-jsonnet-lint| json5...................................|ale-json5-options| eslint................................|ale-json5-eslint| julia...................................|ale-julia-options| diff --git a/supported-tools.md b/supported-tools.md index 4e04b53a..774029e0 100644 --- a/supported-tools.md +++ b/supported-tools.md @@ -280,6 +280,9 @@ formatting. * [eslint](http://eslint.org/) * JSONC * [eslint](http://eslint.org/) +* Jsonnet + * [jsonnet-lint](https://jsonnet.org/learning/tools.html) + * [jsonnetfmt](https://jsonnet.org/learning/tools.html) * Julia * [languageserver](https://github.com/JuliaEditorSupport/LanguageServer.jl) * Kotlin diff --git a/test/fixers/test_jsonnetfmt_fixer_callback.vader b/test/fixers/test_jsonnetfmt_fixer_callback.vader new file mode 100644 index 00000000..204d6583 --- /dev/null +++ b/test/fixers/test_jsonnetfmt_fixer_callback.vader @@ -0,0 +1,38 @@ +Before: + Save g:ale_jsonnet_jsonnetfmt_executable + Save g:ale_jsonnet_jsonnetfmt_options + + " Use an invalid global executable, so we don't match it. + let g:ale_jsonnet_jsonnetfmt_executable = 'xxxinvalid' + let g:ale_jsonnet_jsonnetfmt_options = '' + + call ale#test#SetDirectory('/testplugin/test/fixers') + call ale#assert#SetUpFixerTest('jsonnet', 'jsonnetfmt') + +After: + call ale#test#RestoreDirectory() + call ale#assert#TearDownFixerTest() + +Execute(The jsonnetfmt callback should return the correct default values): + call ale#test#SetFilename('../jsonnet_files/testfile.jsonnet') + + AssertFixer { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape(g:ale_jsonnet_jsonnetfmt_executable) + \ . ' -i' + \ . ' %t', + \} + +Execute(The jsonnetfmt callback should include custom options): + let g:ale_jsonnet_jsonnetfmt_options = '--pad-arrays' + + call ale#test#SetFilename('../jsonnet_files/testfile.jsonnet') + + AssertFixer { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape(g:ale_jsonnet_jsonnetfmt_executable) + \ . ' -i' + \ . ' ' . g:ale_jsonnet_jsonnetfmt_options + \ . ' %t', + \} + diff --git a/test/jsonnet_files/testfile.jsonnet b/test/jsonnet_files/testfile.jsonnet new file mode 100644 index 00000000..fc8fb78a --- /dev/null +++ b/test/jsonnet_files/testfile.jsonnet @@ -0,0 +1 @@ +{ foo: bar } diff --git a/test/linter/test_jsonnet_lint.vader b/test/linter/test_jsonnet_lint.vader new file mode 100644 index 00000000..529ae008 --- /dev/null +++ b/test/linter/test_jsonnet_lint.vader @@ -0,0 +1,19 @@ +Before: + call ale#assert#SetUpLinterTest('jsonnet', 'jsonnet_lint') + call ale#test#SetFilename('../jsonnet_files/testfile.jsonnet') + +After: + Restore + + call ale#assert#TearDownLinterTest() + +Execute(The default jsonnet-lint command should be correct): + AssertLinter 'jsonnet-lint', + \ ale#Escape('jsonnet-lint') . ' %t' + +Execute(jsonnet-lint command and options should be customizable): + let g:ale_jsonnet_jsonnet_lint_executable = 'jsonnet' + let g:ale_jsonnet_jsonnet_lint_options = 'fmt' + + AssertLinter 'jsonnet', + \ ale#Escape('jsonnet') . ' fmt %t' diff --git a/test/linter/test_jsonnetfmt.vader b/test/linter/test_jsonnetfmt.vader new file mode 100644 index 00000000..d070cd9f --- /dev/null +++ b/test/linter/test_jsonnetfmt.vader @@ -0,0 +1,19 @@ +Before: + call ale#assert#SetUpLinterTest('jsonnet', 'jsonnetfmt') + call ale#test#SetFilename('../jsonnet_files/testfile.jsonnet') + +After: + Restore + + call ale#assert#TearDownLinterTest() + +Execute(The default jsonnetfmt command should be correct): + AssertLinter 'jsonnetfmt', + \ ale#Escape('jsonnetfmt') . ' %t' + +Execute(jsonnetfmt command and options should be customizable): + let g:ale_jsonnet_jsonnetfmt_executable = 'jsonnet' + let g:ale_jsonnet_jsonnetfmt_options = 'fmt' + + AssertLinter 'jsonnet', + \ ale#Escape('jsonnet') . ' fmt %t'