From 371414e8557eab9f4c5efd4f4f60f1472052f732 Mon Sep 17 00:00:00 2001 From: Margret Riegert Date: Wed, 15 Jan 2025 00:18:01 -0500 Subject: [PATCH] Add support for linting ECR files (#536) --- README.md | 1 + spec/ameba/source_spec.cr | 26 ++++++++++++++++++++++++++ src/ameba.cr | 4 ++++ src/ameba/config.cr | 7 ++++++- src/ameba/glob_utils.cr | 9 ++++++++- src/ameba/source.cr | 16 ++++++++++++++++ 6 files changed, 61 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 58b74e6e0..729ecfca0 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,7 @@ In this example we define default globs and exclude `src/compiler` folder: ``` yaml Globs: - "**/*.cr" + - "**/*.ecr" - "!lib" Excluded: diff --git a/spec/ameba/source_spec.cr b/spec/ameba/source_spec.cr index 8c8b1a1b4..4b1cd4e3b 100644 --- a/spec/ameba/source_spec.cr +++ b/spec/ameba/source_spec.cr @@ -70,5 +70,31 @@ module Ameba CRYSTAL end end + + if Ameba.ecr_supported? + describe "#ast" do + it "parses an ECR file" do + source = Source.new <<-ECR, "filename.ecr" + hello <%= "world" %> + ECR + + source.ast.to_s.should eq(<<-CRYSTAL) + __str__ << "hello " + ("world").to_s(__str__) + + CRYSTAL + end + + it "raises an exception when ECR parsing fails" do + source = Source.new <<-ECR, "filename.ecr" + hello <%= "world" > + ECR + + expect_raises(Crystal::SyntaxException) do + source.ast + end + end + end + end end end diff --git a/src/ameba.cr b/src/ameba.cr index e675939ac..94b9f141c 100644 --- a/src/ameba.cr +++ b/src/ameba.cr @@ -40,4 +40,8 @@ module Ameba def run(config = Config.load) Runner.new(config).run end + + def self.ecr_supported? : Bool + {{ compare_versions(Crystal::VERSION, "1.15.0") >= 0 }} + end end diff --git a/src/ameba/config.cr b/src/ameba/config.cr index 89a710e53..6b82e7aba 100644 --- a/src/ameba/config.cr +++ b/src/ameba/config.cr @@ -1,5 +1,6 @@ require "semantic_version" require "yaml" +require "ecr/processor" require "./glob_utils" # A configuration entry for `Ameba::Runner`. @@ -62,6 +63,10 @@ class Ameba::Config !lib ) + if Ameba.ecr_supported? + DEFAULT_GLOBS << "**/*.ecr" + end + getter rules : Array(Rule::Base) property severity = Severity::Convention @@ -167,7 +172,7 @@ class Ameba::Config # ``` # config = Ameba::Config.load # config.sources # => list of default sources - # config.globs = ["**/*.cr"] + # config.globs = ["**/*.cr", "**/*.ecr"] # config.excluded = ["spec"] # config.sources # => list of sources pointing to files found by the wildcards # ``` diff --git a/src/ameba/glob_utils.cr b/src/ameba/glob_utils.cr index 63dd67cc7..ef6c6c6f9 100644 --- a/src/ameba/glob_utils.cr +++ b/src/ameba/glob_utils.cr @@ -24,7 +24,14 @@ module Ameba def expand(globs) globs .flat_map do |glob| - glob += "/**/*.cr" if File.directory?(glob) + if File.directory?(glob) + glob += "/**/*.cr" + + if Ameba.ecr_supported? + glob += "/**/*.ecr" + end + end + Dir[glob] end .uniq! diff --git a/src/ameba/source.cr b/src/ameba/source.cr index 29d9d1990..010638feb 100644 --- a/src/ameba/source.cr +++ b/src/ameba/source.cr @@ -57,6 +57,22 @@ module Ameba # source.ast # ``` getter ast : Crystal::ASTNode do + code = @code + + if Ameba.ecr_supported? && @path.ends_with?(".ecr") + begin + code = ECR.process_string(code, @path) + rescue ex : ECR::Lexer::SyntaxException + # Need to rescue to add the filename + raise Crystal::SyntaxException.new( + ex.message, + ex.line_number, + ex.column_number, + @path + ) + end + end + Crystal::Parser.new(code) .tap(&.wants_doc = true) .tap(&.filename = path)