diff --git a/ale_linters/javascript/flow.vim b/ale_linters/javascript/flow.vim old mode 100644 new mode 100755 index 6d51628b..8dc930cd --- a/ale_linters/javascript/flow.vim +++ b/ale_linters/javascript/flow.vim @@ -1,6 +1,9 @@ " Author: Zach Perrault -- @zperrault " Description: FlowType checking for JavaScript files +" Flow extra errors +" Author: Florian Beeres + call ale#Set('javascript_flow_executable', 'flow') call ale#Set('javascript_flow_use_global', 0) @@ -53,6 +56,44 @@ function! s:GetJSONLines(lines) abort return a:lines[l:start_index :] endfunction +function! s:ExtraErrorMsg(current, new) abort + let l:newMsg = '' + + if a:current is# '' + " extra messages appear to already have a : + let l:newMsg = a:new + else + let l:newMsg = a:current . ' ' . a:new + endif + + return l:newMsg +endfunction + + +function! s:GetDetails(error) abort + let l:detail = '' + + for l:extra_error in a:error.extra + + if has_key(l:extra_error, 'message') + for l:extra_message in l:extra_error.message + let l:detail = s:ExtraErrorMsg(l:detail, l:extra_message.descr) + endfor + endif + + if has_key(l:extra_error, 'children') + for l:child in l:extra_error.children + for l:child_message in l:child.message + let l:detail = l:detail . ' ' . l:child_message.descr + endfor + endfor + endif + + endfor + + return l:detail +endfunction + function! ale_linters#javascript#flow#Handle(buffer, lines) abort let l:str = join(s:GetJSONLines(a:lines), '') @@ -91,12 +132,19 @@ function! ale_linters#javascript#flow#Handle(buffer, lines) abort let l:text = l:text . ' See also: ' . l:error.operation.descr endif - call add(l:output, { + let l:errorToAdd = { \ 'lnum': l:line, \ 'col': l:col, \ 'text': l:text, - \ 'type': l:error.level is# 'error' ? 'E' : 'W', - \}) + \ 'type': has_key(l:error, 'level') && l:error.level is# 'error' ? 'E' : 'W', + \} + + if has_key(l:error, 'extra') + let l:errorToAdd.detail = s:GetDetails(l:error) + endif + + call add(l:output, l:errorToAdd) + endfor return l:output diff --git a/test/handler/test_flow_handler.vader b/test/handler/test_flow_handler.vader index 47efc30d..3a575a01 100644 --- a/test/handler/test_flow_handler.vader +++ b/test/handler/test_flow_handler.vader @@ -243,7 +243,7 @@ Execute(The flow handler should fetch the correct location for the currently ope \ 'lnum': 6, \ 'col': 3, \ 'type': 'E', - \ 'text': 'property `bar`: Property not found in props of React element `Foo` See also: React element `Foo`' + \ 'text': 'property `bar`: Property not found in props of React element `Foo` See also: React element `Foo`', \ } \] @@ -347,7 +347,159 @@ Execute(The flow handler should handle relative paths): \ 'lnum': 6, \ 'col': 3, \ 'type': 'E', - \ 'text': 'property `bar`: Property not found in props of React element `Foo` See also: React element `Foo`' + \ 'text': 'property `bar`: Property not found in props of React element `Foo` See also: React element `Foo`', + \ } + \] + + AssertEqual g:expected, g:actual + +Execute(The flow handler should handle extra errors): + silent! noautocmd file /Users/rav/Projects/vim-ale-flow/index.js + + let g:flow_output = { + \ "flowVersion": "0.54.0", + \ "errors": [{ + \ "extra": [{ + \ "message": [{ + \ "context": v:null, + \ "descr": "Property \`setVector\` is incompatible:", + \ "type": "Blame ", + \ "path": "", + \ "line": 0, + \ "endline": 0, + \ "start": 1, + \ "end": 0 + \ }], + \ "children": [{ + \ "message": [{ + \ "context": "setVector = \{2\}", + \ "descr": "number ", + \ "type": "Blame ", + \ "loc": { + \ "source": expand('%:p'), + \ "type": "SourceFile ", + \ "start": { + \ "line": 90, + \ "column": 30, + \ "offset": 2296 + \ }, + \ "end": { + \ "line": 90, + \ "column": 30, + \ "offset": 2297 + \ } + \ }, + \ "path": expand('%:p'), + \ "line": 90, + \ "endline": 90, + \ "start": 30, + \ "end": 30 + \ }, { + \ "context": v:null, + \ "descr": "This type is incompatible with ", + \ "type": "Comment ", + \ "path": "", + \ "line": 0, + \ "endline": 0, + \ "start": 1, + \ "end": 0 + \ }, { + \ "context": "setVector: VectorType => void,", + \ "descr": "function type ", + \ "type": "Blame ", + \ "loc": { + \ "source": expand('%:p'), + \ "type": "SourceFile", + \ "start": { + \ "line": 9, + \ "column": 14, + \ "offset": 252 + \ }, + \ "end": { + \ "line": 9, + \ "column": 31, + \ "offset": 270 + \ } + \ }, + \ "path": expand('%:p'), + \ "line": 9, + \ "endline": 9, + \ "start": 14, + \ "end": 31 + \ }] + \ }] + \ }], + \ "kind": "infer", + \ "level": "error", + \ "suppressions": [], + \ "message": [{ + \ "context": " < New ", + \ "descr": "props of React element `New`", + \ "type": "Blame", + \ "loc": { + \ "source": "vim-ale-flow/foo.js", + \ "type": "SourceFile", + \ "start": { + \ "line": 89, + \ "column": 17, + \ "offset": 2262 + \ }, + \ "end": { + \ "line": 94, + \ "column": 18, + \ "offset": 2488 + \ } + \ }, + \ "path": "", + \ "line": 89, + \ "endline": 94, + \ "start": 17, + \ "end": 18 + \ }, { + \ "context": v:null, + \ "descr": "This type is incompatible with", + \ "type": "Comment", + \ "path": "", + \ "line": 0, + \ "endline": 0, + \ "start": 1, + \ "end": 0 + \ }, { + \ "context": "class New extends React.Component < NewProps,NewState > {", + \ "descr": "object type", + \ "type": "Blame", + \ "loc": { + \ "source": expand('%:p'), + \ "type": "SourceFile", + \ "start": { + \ "line": 20, + \ "column": 35, + \ "offset": 489 + \ }, + \ "end": { + \ "line": 20, + \ "column": 42, + \ "offset": 497 + \ } + \ }, + \ "path": expand('%:p'), + \ "line": 20, + \ "endline": 20, + \ "start": 35, + \ "end": 42 + \ }] + \ }], + \ "passed": v:false + \} + + let g:actual = ale_linters#javascript#flow#Handle(bufnr(''), [json_encode(g:flow_output)]) + let g:expected = [ + \ { + \ 'lnum': 20, + \ 'col': 35, + \ 'type': 'E', + \ 'text': 'props of React element `New`: This type is incompatible with object type', + \ 'detail': 'Property `setVector` is incompatible: number This type is incompatible with function type ', \ } \]