From 5a47d878fbb837af4c89ab545f473f8526bd4d64 Mon Sep 17 00:00:00 2001 From: tatsuya Date: Sun, 13 Dec 2020 17:06:23 +0900 Subject: [PATCH 1/3] add spectral linter for yaml ci --- ale_linters/yaml/spectral.vim | 42 +++++++++++++++ doc/ale-supported-languages-and-tools.txt | 1 + doc/ale-yaml.txt | 32 ++++++++++++ doc/ale.txt | 1 + supported-tools.md | 1 + .../spectral_paths/node_modules/.bin/spectral | 0 .../spectral_paths/openapi.yaml | 0 .../test_spectral_command_callback.vader | 31 +++++++++++ test/handler/test_spectral_handler.vader | 52 +++++++++++++++++++ 9 files changed, 160 insertions(+) create mode 100644 ale_linters/yaml/spectral.vim create mode 100644 test/command_callback/spectral_paths/node_modules/.bin/spectral create mode 100644 test/command_callback/spectral_paths/openapi.yaml create mode 100644 test/command_callback/test_spectral_command_callback.vader create mode 100644 test/handler/test_spectral_handler.vader diff --git a/ale_linters/yaml/spectral.vim b/ale_linters/yaml/spectral.vim new file mode 100644 index 00000000..c1644f3e --- /dev/null +++ b/ale_linters/yaml/spectral.vim @@ -0,0 +1,42 @@ +" Author: t2h5 +" Description: Integration of Stoplight Spectral CLI with ALE. + +call ale#Set('yaml_spectral_executable', 'spectral') +call ale#Set('yaml_spectral_use_global', get(g:, 'ale_use_global_executables', 0)) + +function! ale_linters#yaml#spectral#Handle(buffer, lines) abort + " Matches patterns like the following: + " openapi.yml:1:1 error oas3-schema "Object should have required property `info`." + " openapi.yml:1:1 warning oas3-api-servers "OpenAPI `servers` must be present and non-empty array." + let l:pattern = '\v^.*:(\d+):(\d+) (error|warning) (.*)$' + let l:output = [] + + for l:match in ale#util#GetMatches(a:lines, l:pattern) + let l:obj = { + \ 'lnum': l:match[1] + 0, + \ 'col': l:match[2] + 0, + \ 'type': l:match[3] is# 'error' ? 'E' : 'W', + \ 'text': l:match[4], + \} + + let l:code_match = matchlist(l:obj.text, '\v^(.+) "(.+)"$') + + if !empty(l:code_match) + let l:obj.code = l:code_match[1] + let l:obj.text = l:code_match[2] + endif + + call add(l:output, l:obj) + endfor + + return l:output +endfunction + +call ale#linter#Define('yaml', { +\ 'name': 'spectral', +\ 'executable': {b -> ale#node#FindExecutable(b, 'yaml_spectral', [ +\ 'node_modules/.bin/spectral', +\ ])}, +\ 'command': '%e lint --ignore-unknown-format -q -f text %t', +\ 'callback': 'ale_linters#yaml#spectral#Handle' +\}) diff --git a/doc/ale-supported-languages-and-tools.txt b/doc/ale-supported-languages-and-tools.txt index 6744e30e..0b864b48 100644 --- a/doc/ale-supported-languages-and-tools.txt +++ b/doc/ale-supported-languages-and-tools.txt @@ -537,6 +537,7 @@ Notes: * `xmllint` * YAML * `prettier` + * `spectral` * `swaglint` * `yamlfix` * `yamllint` diff --git a/doc/ale-yaml.txt b/doc/ale-yaml.txt index 61bfc139..04871403 100644 --- a/doc/ale-yaml.txt +++ b/doc/ale-yaml.txt @@ -15,6 +15,38 @@ Install prettier either globally or locally: > npm install prettier -g # global npm install prettier # local < +=============================================================================== +spectral *ale-yaml-spectral* + +Website: https://github.com/stoplightio/spectral + +Installation +------------------------------------------------------------------------------- + +Install spectral either globally or locally: > + + npm install @stoplight/spectral -g # global + npm install @stoplight/spectral # local +< + +Options +------------------------------------------------------------------------------- + +g:ale_yaml_spectral_executable *g:ale_yaml_spectral_executable* + *b:ale_yaml_spectral_executable* + Type: |String| + Default: `'spectral'` + + This variable can be set to change the path to spectral. + +g:ale_yaml_spectral_use_global *g:ale_yaml_spectral_use_global* + *b:ale_yaml_spectral_use_global* + Type: |String| + Default: `get(g:, 'ale_use_global_executables', 0)` + + See |ale-integrations-local-executables| + + =============================================================================== swaglint *ale-yaml-swaglint* diff --git a/doc/ale.txt b/doc/ale.txt index 97fb0786..f8fea05b 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -3028,6 +3028,7 @@ documented in additional help files. xmllint...............................|ale-xml-xmllint| yaml....................................|ale-yaml-options| prettier..............................|ale-yaml-prettier| + spectral..............................|ale-yaml-spectral| swaglint..............................|ale-yaml-swaglint| yamlfix...............................|ale-yaml-yamlfix| yamllint..............................|ale-yaml-yamllint| diff --git a/supported-tools.md b/supported-tools.md index cd8a8fdc..cf0370a9 100644 --- a/supported-tools.md +++ b/supported-tools.md @@ -546,6 +546,7 @@ formatting. * [xmllint](http://xmlsoft.org/xmllint.html) * YAML * [prettier](https://github.com/prettier/prettier) + * [spectral](https://github.com/stoplightio/spectral) * [swaglint](https://github.com/byCedric/swaglint) * [yamlfix](https://lyz-code.github.io/yamlfix) * [yamllint](https://yamllint.readthedocs.io/) diff --git a/test/command_callback/spectral_paths/node_modules/.bin/spectral b/test/command_callback/spectral_paths/node_modules/.bin/spectral new file mode 100644 index 00000000..e69de29b diff --git a/test/command_callback/spectral_paths/openapi.yaml b/test/command_callback/spectral_paths/openapi.yaml new file mode 100644 index 00000000..e69de29b diff --git a/test/command_callback/test_spectral_command_callback.vader b/test/command_callback/test_spectral_command_callback.vader new file mode 100644 index 00000000..ed3795b9 --- /dev/null +++ b/test/command_callback/test_spectral_command_callback.vader @@ -0,0 +1,31 @@ +Before: + call ale#assert#SetUpLinterTest('yaml', 'spectral') + +After: + call ale#assert#TearDownLinterTest() + +Execute(The yaml spectral command callback should return the correct default string): + AssertLinter 'spectral', ale#Escape('spectral') . ' lint --ignore-unknown-format -q -f text %t' + +Execute(The yaml spectral command callback should be configurable): + let g:ale_yaml_spectral_executable = '~/.local/bin/spectral' + + AssertLinter '~/.local/bin/spectral', + \ ale#Escape('~/.local/bin/spectral') + \ . ' lint --ignore-unknown-format -q -f text %t' + +Execute(The yaml spectral command callback should allow a global installation to be used): + let g:ale_yaml_spectral_executable = '/usr/local/bin/spectral' + let g:ale_yaml_spectral_use_global = 1 + + AssertLinter '/usr/local/bin/spectral', + \ ale#Escape('/usr/local/bin/spectral') + \ . ' lint --ignore-unknown-format -q -f text %t' + +Execute(The yaml spectral command callback should allow a local installation to be used): + call ale#test#SetFilename('spectral_paths/openapi.yaml') + + AssertLinter + \ ale#path#Simplify(g:dir . '/spectral_paths/node_modules/.bin/spectral'), + \ ale#Escape(ale#path#Simplify(g:dir . '/spectral_paths/node_modules/.bin/spectral')) + \ . ' lint --ignore-unknown-format -q -f text %t' diff --git a/test/handler/test_spectral_handler.vader b/test/handler/test_spectral_handler.vader new file mode 100644 index 00000000..b315168f --- /dev/null +++ b/test/handler/test_spectral_handler.vader @@ -0,0 +1,52 @@ +Before: + runtime ale_linters/yaml/spectral.vim + +After: + call ale#linter#Reset() + +Execute(spectral handler should parse lines correctly): + AssertEqual + \ [ + \ { + \ 'lnum': 1, + \ 'col': 1, + \ 'code': 'oas3-api-servers', + \ 'text': 'OpenAPI `servers` must be present and non-empty array.', + \ 'type': 'W' + \ }, + \ { + \ 'lnum': 1, + \ 'col': 1, + \ 'code': 'oas3-schema', + \ 'text': 'Object should have required property `paths`.', + \ 'type': 'E' + \ }, + \ { + \ 'lnum': 1, + \ 'col': 1, + \ 'code': 'openapi-tags', + \ 'text': 'OpenAPI object should have non-empty `tags` array.', + \ 'type': 'W' + \ }, + \ { + \ 'lnum': 3, + \ 'col': 6, + \ 'code': 'info-contact', + \ 'text': 'Info object should contain `contact` object.', + \ 'type': 'W' + \ }, + \ { + \ 'lnum': 3, + \ 'col': 6, + \ 'code': 'oas3-schema', + \ 'text': '`info` property should have required property `version`.', + \ 'type': 'E' + \ }, + \ ], + \ ale_linters#yaml#spectral#Handle(bufnr(''), [ + \ 'openapi.yml:1:1 warning oas3-api-servers "OpenAPI `servers` must be present and non-empty array."', + \ 'openapi.yml:1:1 error oas3-schema "Object should have required property `paths`."', + \ 'openapi.yml:1:1 warning openapi-tags "OpenAPI object should have non-empty `tags` array."', + \ 'openapi.yml:3:6 warning info-contact "Info object should contain `contact` object."', + \ 'openapi.yml:3:6 error oas3-schema "`info` property should have required property `version`."', + \ ]) From 997dd7f8fe45030e65b418c5f46e20d808b1c5eb Mon Sep 17 00:00:00 2001 From: tatsuya Date: Wed, 6 Jan 2021 13:22:08 +0900 Subject: [PATCH 2/3] add spectral handler --- ale_linters/yaml/spectral.vim | 30 +---------------------- autoload/ale/handlers/spectral.vim | 31 ++++++++++++++++++++++++ test/handler/test_spectral_handler.vader | 2 +- 3 files changed, 33 insertions(+), 30 deletions(-) create mode 100644 autoload/ale/handlers/spectral.vim diff --git a/ale_linters/yaml/spectral.vim b/ale_linters/yaml/spectral.vim index c1644f3e..bd4623a5 100644 --- a/ale_linters/yaml/spectral.vim +++ b/ale_linters/yaml/spectral.vim @@ -4,39 +4,11 @@ call ale#Set('yaml_spectral_executable', 'spectral') call ale#Set('yaml_spectral_use_global', get(g:, 'ale_use_global_executables', 0)) -function! ale_linters#yaml#spectral#Handle(buffer, lines) abort - " Matches patterns like the following: - " openapi.yml:1:1 error oas3-schema "Object should have required property `info`." - " openapi.yml:1:1 warning oas3-api-servers "OpenAPI `servers` must be present and non-empty array." - let l:pattern = '\v^.*:(\d+):(\d+) (error|warning) (.*)$' - let l:output = [] - - for l:match in ale#util#GetMatches(a:lines, l:pattern) - let l:obj = { - \ 'lnum': l:match[1] + 0, - \ 'col': l:match[2] + 0, - \ 'type': l:match[3] is# 'error' ? 'E' : 'W', - \ 'text': l:match[4], - \} - - let l:code_match = matchlist(l:obj.text, '\v^(.+) "(.+)"$') - - if !empty(l:code_match) - let l:obj.code = l:code_match[1] - let l:obj.text = l:code_match[2] - endif - - call add(l:output, l:obj) - endfor - - return l:output -endfunction - call ale#linter#Define('yaml', { \ 'name': 'spectral', \ 'executable': {b -> ale#node#FindExecutable(b, 'yaml_spectral', [ \ 'node_modules/.bin/spectral', \ ])}, \ 'command': '%e lint --ignore-unknown-format -q -f text %t', -\ 'callback': 'ale_linters#yaml#spectral#Handle' +\ 'callback': 'ale#handlers#spectral#HandleSpectralOutput' \}) diff --git a/autoload/ale/handlers/spectral.vim b/autoload/ale/handlers/spectral.vim new file mode 100644 index 00000000..1eb4a5de --- /dev/null +++ b/autoload/ale/handlers/spectral.vim @@ -0,0 +1,31 @@ +" Author: t2h5 +" Description: Integration of Stoplight Spectral CLI with ALE. + +function! ale#handlers#spectral#HandleSpectralOutput(buffer, lines) abort + " Matches patterns like the following: + " openapi.yml:1:1 error oas3-schema "Object should have required property `info`." + " openapi.yml:1:1 warning oas3-api-servers "OpenAPI `servers` must be present and non-empty array." + let l:pattern = '\v^.*:(\d+):(\d+) (error|warning) (.*)$' + let l:output = [] + + for l:match in ale#util#GetMatches(a:lines, l:pattern) + let l:obj = { + \ 'lnum': l:match[1] + 0, + \ 'col': l:match[2] + 0, + \ 'type': l:match[3] is# 'error' ? 'E' : 'W', + \ 'text': l:match[4], + \} + + let l:code_match = matchlist(l:obj.text, '\v^(.+) "(.+)"$') + + if !empty(l:code_match) + let l:obj.code = l:code_match[1] + let l:obj.text = l:code_match[2] + endif + + call add(l:output, l:obj) + endfor + + return l:output +endfunction + diff --git a/test/handler/test_spectral_handler.vader b/test/handler/test_spectral_handler.vader index b315168f..89a3ff1b 100644 --- a/test/handler/test_spectral_handler.vader +++ b/test/handler/test_spectral_handler.vader @@ -43,7 +43,7 @@ Execute(spectral handler should parse lines correctly): \ 'type': 'E' \ }, \ ], - \ ale_linters#yaml#spectral#Handle(bufnr(''), [ + \ ale#handlers#spectral#HandleSpectralOutput(bufnr(''), [ \ 'openapi.yml:1:1 warning oas3-api-servers "OpenAPI `servers` must be present and non-empty array."', \ 'openapi.yml:1:1 error oas3-schema "Object should have required property `paths`."', \ 'openapi.yml:1:1 warning openapi-tags "OpenAPI object should have non-empty `tags` array."', From 66b3e768db55b0c03fa34310a5c79bbd24209694 Mon Sep 17 00:00:00 2001 From: tatsuya Date: Wed, 6 Jan 2021 13:25:52 +0900 Subject: [PATCH 3/3] add spectral support for json --- ale_linters/json/spectral.vim | 14 ++++++++++ doc/ale-json.txt | 32 +++++++++++++++++++++++ doc/ale-supported-languages-and-tools.txt | 1 + doc/ale.txt | 1 + supported-tools.md | 1 + 5 files changed, 49 insertions(+) create mode 100644 ale_linters/json/spectral.vim diff --git a/ale_linters/json/spectral.vim b/ale_linters/json/spectral.vim new file mode 100644 index 00000000..c7d56234 --- /dev/null +++ b/ale_linters/json/spectral.vim @@ -0,0 +1,14 @@ +" Author: t2h5 +" Description: Integration of Stoplight Spectral CLI with ALE. + +call ale#Set('json_spectral_executable', 'spectral') +call ale#Set('json_spectral_use_global', get(g:, 'ale_use_global_executables', 0)) + +call ale#linter#Define('json', { +\ 'name': 'spectral', +\ 'executable': {b -> ale#node#FindExecutable(b, 'json_spectral', [ +\ 'node_modules/.bin/spectral', +\ ])}, +\ 'command': '%e lint --ignore-unknown-format -q -f text %t', +\ 'callback': 'ale#handlers#spectral#HandleSpectralOutput' +\}) diff --git a/doc/ale-json.txt b/doc/ale-json.txt index 96499a04..dc91e14c 100644 --- a/doc/ale-json.txt +++ b/doc/ale-json.txt @@ -101,5 +101,37 @@ prettier *ale-json-prettier* See |ale-javascript-prettier| for information about the available options. +=============================================================================== +spectral *ale-json-spectral* + +Website: https://github.com/stoplightio/spectral + +Installation +------------------------------------------------------------------------------- + +Install spectral either globally or locally: > + + npm install @stoplight/spectral -g # global + npm install @stoplight/spectral # local +< + +Options +------------------------------------------------------------------------------- + +g:ale_json_spectral_executable *g:ale_json_spectral_executable* + *b:ale_json_spectral_executable* + Type: |String| + Default: `'spectral'` + + This variable can be set to change the path to spectral. + +g:ale_json_spectral_use_global *g:ale_json_spectral_use_global* + *b:ale_json_spectral_use_global* + Type: |String| + Default: `get(g:, 'ale_use_global_executables', 0)` + + See |ale-integrations-local-executables| + + =============================================================================== 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 0b864b48..ce73136f 100644 --- a/doc/ale-supported-languages-and-tools.txt +++ b/doc/ale-supported-languages-and-tools.txt @@ -248,6 +248,7 @@ Notes: * `jq` * `jsonlint` * `prettier` + * `spectral` * Julia * `languageserver` * Kotlin diff --git a/doc/ale.txt b/doc/ale.txt index f8fea05b..5cbc10c4 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -2785,6 +2785,7 @@ documented in additional help files. jsonlint..............................|ale-json-jsonlint| jq....................................|ale-json-jq| prettier..............................|ale-json-prettier| + spectral..............................|ale-json-spectral| julia...................................|ale-julia-options| languageserver........................|ale-julia-languageserver| kotlin..................................|ale-kotlin-options| diff --git a/supported-tools.md b/supported-tools.md index cf0370a9..0e1e6b29 100644 --- a/supported-tools.md +++ b/supported-tools.md @@ -257,6 +257,7 @@ formatting. * [jq](https://stedolan.github.io/jq/) * [jsonlint](http://zaa.ch/jsonlint/) * [prettier](https://github.com/prettier/prettier) + * [spectral](https://github.com/stoplightio/spectral) * Julia * [languageserver](https://github.com/JuliaEditorSupport/LanguageServer.jl) * Kotlin