From 3bc8bda008654234323565bc335aeecb5307725d Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Mon, 19 Dec 2022 17:36:57 +0100 Subject: [PATCH 1/2] Add `Lint/Formatting` rule --- spec/ameba/rule/lint/formatting_spec.cr | 48 ++++++++++++++++++ src/ameba/rule/lint/formatting.cr | 65 +++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 spec/ameba/rule/lint/formatting_spec.cr create mode 100644 src/ameba/rule/lint/formatting.cr diff --git a/spec/ameba/rule/lint/formatting_spec.cr b/spec/ameba/rule/lint/formatting_spec.cr new file mode 100644 index 00000000..8959280f --- /dev/null +++ b/spec/ameba/rule/lint/formatting_spec.cr @@ -0,0 +1,48 @@ +require "../../../spec_helper" + +module Ameba::Rule::Lint + describe Formatting do + subject = Formatting.new + + it "passes if source is formatted" do + expect_no_issues subject, <<-CRYSTAL + def method(a, b) + a + b + end + + CRYSTAL + end + + it "reports if source is not formatted" do + expect_issue subject, <<-CRYSTAL + def method(a,b) + # ^{} error: Use built-in formatter to format this source + end + CRYSTAL + end + + context "properties" do + context "#fail_on_error" do + it "passes on formatter errors by default" do + rule = Formatting.new + + expect_no_issues rule, <<-CRYSTAL + def method(a, b) + a + b + CRYSTAL + end + + it "reports on formatter errors when enabled" do + rule = Formatting.new + rule.fail_on_error = true + + expect_issue rule, <<-CRYSTAL + def method(a, b) + a + b + # ^ error: Error while formatting: expecting identifier 'end', not 'EOF' + CRYSTAL + end + end + end + end +end diff --git a/src/ameba/rule/lint/formatting.cr b/src/ameba/rule/lint/formatting.cr new file mode 100644 index 00000000..ea848ad2 --- /dev/null +++ b/src/ameba/rule/lint/formatting.cr @@ -0,0 +1,65 @@ +require "compiler/crystal/formatter" + +module Ameba::Rule::Lint + # A rule that verifies syntax formatting according to the + # Crystal's built-in formatter. + # + # For example, this syntax is invalid: + # + # def foo(a,b,c=0) + # #foobar + # a+b+c + # end + # + # And should be properly written: + # + # def foo(a, b, c = 0) + # # foobar + # a + b + c + # end + # + # YAML configuration example: + # + # ``` + # Lint/Formatting: + # Enabled: true + # FailOnError: false + # ``` + class Formatting < Base + properties do + description "Reports not formatted sources" + fail_on_error false + end + + MSG = "Use built-in formatter to format this source" + MSG_ERROR = "Error while formatting: %s" + + private LOCATION = {1, 1} + + def test(source) + source_code = source.code + result = Crystal.format(source_code, source.path) + return if result == source_code + + source_lines = source_code.lines + return if source_lines.empty? + + end_location = { + source_lines.size, + source_lines.last.size + 1, + } + + issue_for LOCATION, MSG do |corrector| + corrector.replace(LOCATION, end_location, result) + end + rescue ex : Crystal::SyntaxException + if fail_on_error? + issue_for({ex.line_number, ex.column_number}, MSG_ERROR % ex.message) + end + rescue ex + if fail_on_error? + issue_for(LOCATION, MSG_ERROR % ex.message) + end + end + end +end From d7154ad6d2ec14666ec44c6286d8f1ad16a710e2 Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Mon, 19 Dec 2022 17:53:43 +0100 Subject: [PATCH 2/2] Fix failing spec --- spec/ameba/runner_spec.cr | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/spec/ameba/runner_spec.cr b/spec/ameba/runner_spec.cr index f5ec70c7..316f2037 100644 --- a/spec/ameba/runner_spec.cr +++ b/spec/ameba/runner_spec.cr @@ -175,10 +175,11 @@ module Ameba it "depends on the level of severity" do rules = Rule.rules.map &.new.as(Rule::Base) - s = Source.new %q(WrongConstant = 5) - Runner.new(rules, [s], formatter, Severity::Error).run.success?.should be_true - Runner.new(rules, [s], formatter, Severity::Warning).run.success?.should be_true - Runner.new(rules, [s], formatter, Severity::Convention).run.success?.should be_false + source = Source.new "WrongConstant = 5\n" + + Runner.new(rules, [source], formatter, :error).run.success?.should be_true + Runner.new(rules, [source], formatter, :warning).run.success?.should be_true + Runner.new(rules, [source], formatter, :convention).run.success?.should be_false end it "returns false if issue is disabled" do