Add JSON formatter

This commit is contained in:
Vitalii Elenhaupt 2018-05-11 21:09:15 +03:00 committed by V. Elenhaupt
parent 9708b94587
commit 4546b90b54
3 changed files with 212 additions and 0 deletions

View file

@ -0,0 +1,78 @@
require "../../spec_helper"
module Ameba
def get_result(sources = [Source.new ""])
file = IO::Memory.new
formatter = Formatter::JSONFormatter.new file
formatter.started sources
sources.each { |source| formatter.source_finished source }
formatter.finished sources
JSON.parse file.to_s
end
describe Formatter::JSONFormatter do
context "metadata" do
it "shows ameba version" do
get_result["metadata"]["ameba_version"].should eq Ameba::VERSION
end
it "shows crystal version" do
get_result["metadata"]["crystal_version"].should eq Crystal::VERSION
end
end
context "sources" do
it "shows path to the source" do
result = get_result [Source.new "", "source.cr"]
result["sources"].first["path"].should eq "source.cr"
end
it "shows rule name" do
s = Source.new ""
s.error DummyRule.new, 1, 2, "message1"
result = get_result [s]
result["sources"].first["errors"].first["rule_name"].should eq DummyRule.name
end
it "shows a message" do
s = Source.new ""
s.error DummyRule.new, 1, 2, "message"
result = get_result [s]
result["sources"].first["errors"].first["message"].should eq "message"
end
it "shows error location" do
s = Source.new ""
s.error DummyRule.new, 1, 2, "message"
result = get_result [s]
location = result["sources"].first["errors"].first["location"]
location["line"].should eq 1
location["column"].should eq 2
end
end
context "summary" do
it "shows a target sources count" do
result = get_result [Source.new(""), Source.new("")]
result["summary"]["target_sources_count"].should eq 2
end
it "shows errors count" do
s1 = Source.new ""
s1.error DummyRule.new, 1, 2, "message1"
s1.error DummyRule.new, 1, 2, "message2"
s2 = Source.new ""
s2.error DummyRule.new, 1, 2, "message3"
result = get_result [s1, s2]
result["summary"]["errors_count"].should eq 3
end
end
end
end

View file

@ -18,6 +18,7 @@ class Ameba::Config
flycheck: Formatter::FlycheckFormatter,
silent: Formatter::BaseFormatter,
disabled: Formatter::DisabledFormatter,
json: Formatter::JSONFormatter,
}
PATH = ".ameba.yml"

View file

@ -0,0 +1,133 @@
require "json"
module Ameba::Formatter
# A formatter that produces the result in a json format.
#
# Example:
#
# ```
# {
# "metadata": {
# "ameba_version": "x.x.x",
# "crystal_version": "x.x.x",
# },
# "sources": [
# {
# "errors": [
# {
# "location": {
# "column": 7,
# "line": 17,
# },
# "message": "Useless assignment to variable `a`",
# "rule_name": "UselessAssign",
# },
# {
# "location": {
# "column": 7,
# "line": 18,
# },
# "message": "Useless assignment to variable `a`",
# "rule_name": "UselessAssign",
# },
# {
# "location": {
# "column": 7,
# "line": 19,
# },
# "message": "Useless assignment to variable `a`",
# "rule_name": "UselessAssign",
# },
# ],
# "path": "src/ameba/formatter/json_formatter.cr",
# },
# ],
# "summary": {
# "errors_count": 3,
# "target_sources_count": 1,
# },
# }
# ```
#
class JSONFormatter < BaseFormatter
def initialize(@output = STDOUT)
@result = AsJSON::Result.new
end
def started(sources)
@result.summary.target_sources_count = sources.size
end
def source_finished(source : Source)
json_source = AsJSON::Source.new source.path
source.errors.each do |e|
next if e.disabled?
json_source.errors << AsJSON::Error.new(e.rule.name, e.location, e.message)
@result.summary.errors_count += 1
end
@result.sources << json_source
end
def finished(sources)
@result.to_json @output
end
end
private module AsJSON
record Result,
sources = [] of Source,
metadata = Metadata.new,
summary = Summary.new do
def to_json(json)
{sources: sources, metadata: metadata, summary: summary}.to_json(json)
end
end
record Source,
path : String,
errors = [] of Error do
def to_json(json)
{path: path, errors: errors}.to_json(json)
end
end
record Error,
rule_name : String,
location : Crystal::Location?,
message : String do
def to_json(json)
json.object do
json.field :rule_name, rule_name
json.field :message, message
json.field :location,
{line: location.try &.line_number, column: location.try &.column_number}
end
end
end
record Metadata,
ameba_version : String = Ameba::VERSION,
crystal_version : String = Crystal::VERSION do
def to_json(json)
json.object do
json.field :ameba_version, ameba_version
json.field :crystal_version, crystal_version
end
end
end
class Summary
property target_sources_count = 0
property errors_count = 0
def to_json(json)
json.object do
json.field :target_sources_count, target_sources_count
json.field :errors_count, errors_count
end
end
end
end
end