Skip to content

Commit b3a98dc

Browse files
authored
builtins/selene: get diagnostics from json (#222)
Co-authored-by: mosheavni <[email protected]>
1 parent 4654a4f commit b3a98dc

File tree

2 files changed

+86
-33
lines changed

2 files changed

+86
-33
lines changed

lua/null-ls/builtins/diagnostics/selene.lua

+41-8
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,50 @@ return h.make_builtin({
1414
filetypes = { "lua", "luau" },
1515
generator_opts = {
1616
command = "selene",
17-
args = { "--display-style", "quiet", "-" },
17+
args = { "--display-style", "json2", "-" },
1818
to_stdin = true,
19-
format = "line",
19+
format = "raw",
2020
check_exit_code = function(code)
21-
return code <= 1
21+
return code <= 3
22+
end,
23+
on_output = function(params, done)
24+
local output = vim.split(params.output, "\n")
25+
local all_diagnostics = {}
26+
for _, v in ipairs(output) do
27+
local _, decoded = pcall(vim.json.decode, v)
28+
if decoded == vim.NIL or decoded == "" then
29+
decoded = nil
30+
end
31+
if decoded and decoded.primary_label and decoded.primary_label.span then
32+
decoded.line = decoded.primary_label.span.start_line
33+
decoded.column = decoded.primary_label.span.start_column
34+
decoded.endLine = decoded.primary_label.span.end_line
35+
decoded.endColumn = decoded.primary_label.span.end_column
36+
decoded.message = decoded.message .. "\n" .. table.concat(decoded.notes, ", ")
37+
decoded.primary_label = nil
38+
end
39+
if decoded.type == "Diagnostic" then
40+
table.insert(all_diagnostics, decoded)
41+
end
42+
end
43+
local parser = h.diagnostics.from_json({
44+
severities = {
45+
Warning = h.diagnostics.severities["warning"],
46+
Error = h.diagnostics.severities["error"],
47+
},
48+
attributes = {
49+
code = "code",
50+
severity = "severity",
51+
},
52+
offsets = {
53+
col = 1,
54+
end_col = 1,
55+
row = 1,
56+
end_row = 1,
57+
},
58+
})
59+
return done(parser({ output = all_diagnostics }))
2260
end,
23-
on_output = h.diagnostics.from_pattern(
24-
[[(%d+):(%d+): (%w+)%[([%w_]+)%]: ([`]*([%w_]+)[`]*.*)]],
25-
{ "row", "col", "severity", "code", "message", "_quote" },
26-
{ adapters = { h.diagnostics.adapters.end_col.from_quote } }
27-
),
2861
cwd = h.cache.by_bufnr(function(params)
2962
-- https://kampfkarren.github.io/selene/usage/configuration.html
3063
return u.root_pattern("selene.toml")(params.bufname)

test/spec/builtins/diagnostics_spec.lua

+45-25
Original file line numberDiff line numberDiff line change
@@ -419,35 +419,55 @@ describe("diagnostics", function()
419419
describe("selene", function()
420420
local linter = diagnostics.selene
421421
local parser = linter._opts.on_output
422-
local file = {
423-
"vim.cmd [[",
424-
[[CACHE_PATH = vim.fn.stdpath "cache"]],
425-
}
422+
local selene_diagnostics = {}
423+
local function done(_diagnostics)
424+
table.insert(selene_diagnostics, _diagnostics)
425+
end
426+
it("should create a diagnostic with an Error severity", function()
427+
local output = [[
428+
{"type":"Diagnostic","severity":"Error","code":"undefined_variable","message":"`vim` is not defined","primary_label":{"filename":"init.lua","span":{"start":0,"start_line":0,"start_column":0,"end":3,"end_line":0,"end_column":3},"message":""},"notes":[],"secondary_labels":[]}
429+
]]
426430

427-
it("should create a diagnostic (quote is between backquotes)", function()
428-
local output = [[init.lua:1:1: error[undefined_variable]: `vim` is not defined]]
429-
local diagnostic = parser(output, { content = file })
431+
parser({ output = output }, done)
430432
assert.same({
431-
row = "1",
432-
col = "1",
433-
end_col = 4,
434-
severity = 1,
435-
code = "undefined_variable",
436-
message = "`vim` is not defined",
437-
}, diagnostic)
433+
{
434+
code = "undefined_variable",
435+
col = 1,
436+
end_col = 4,
437+
end_row = 1,
438+
row = 1,
439+
message = "`vim` is not defined\n",
440+
severity = 1,
441+
},
442+
}, selene_diagnostics[1])
438443
end)
439-
it("should create a diagnostic (quote is not between backquotes)", function()
440-
local output =
441-
[[lua/default-config.lua:2:1: warning[unused_variable]: CACHE_PATH is defined, but never used]]
442-
local diagnostic = parser(output, { content = file })
444+
445+
it("should create a diagnostic", function()
446+
local output = [[
447+
{"type":"Diagnostic","severity":"Warning","code":"unused_variable","message":"CACHE_PATH is assigned a value, but never used","primary_label":{"filename":"lua/default-config.lua","span":{"start":1,"start_line":1,"start_column":0,"end":1,"end_line":1,"end_column":10},"message":""},"notes":[],"secondary_labels":[]}
448+
]]
449+
450+
parser({ output = output }, done)
443451
assert.same({
444-
row = "2",
445-
col = "1",
446-
end_col = 11,
447-
severity = 2,
448-
code = "unused_variable",
449-
message = "CACHE_PATH is defined, but never used",
450-
}, diagnostic)
452+
{
453+
code = "unused_variable",
454+
row = 2,
455+
end_row = 2,
456+
col = 1,
457+
end_col = 11,
458+
message = "CACHE_PATH is assigned a value, but never used\n",
459+
severity = 2,
460+
},
461+
}, selene_diagnostics[2])
462+
end)
463+
464+
it("should not create a diagnostic for summary", function()
465+
local output = [[
466+
{"type":"Summary","errors":1,"warnings":1,"parse_errors":0}
467+
]]
468+
469+
parser({ output = output }, done)
470+
assert.same({}, selene_diagnostics[3])
451471
end)
452472
end)
453473

0 commit comments

Comments
 (0)