From 504017bd7588980ac47992cb3631f885718c73bc Mon Sep 17 00:00:00 2001 From: Margret Riegert Date: Wed, 15 Jan 2025 11:58:45 -0500 Subject: [PATCH] Add support for linting ECR files (pt. 2) (#541) * Add support for linting ECR files Requires Crystal >= 1.15.0 * Apply suggestions from code review Co-authored-by: Sijawusz Pur Rahnama * Add some specs related to ECR files * Remove unnecessary ECR specs * Macro helper method for ECR support --------- Co-authored-by: Sijawusz Pur Rahnama --- README.md | 1 + spec/ameba/source_spec.cr | 26 ++++++++++++++++++++++++++ src/ameba.cr | 22 ++++++++++++++-------- src/ameba/config.cr | 7 ++++++- src/ameba/glob_utils.cr | 9 ++++++++- src/ameba/source.cr | 18 ++++++++++++++++++ 6 files changed, 73 insertions(+), 10 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..b653a8c8d 100644 --- a/spec/ameba/source_spec.cr +++ b/spec/ameba/source_spec.cr @@ -70,5 +70,31 @@ module Ameba CRYSTAL end end + + Ameba.ecr_supported? do + 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..9f4d689e9 100644 --- a/src/ameba.cr +++ b/src/ameba.cr @@ -1,11 +1,3 @@ -require "./ameba/*" -require "./ameba/ast/**" -require "./ameba/ext/**" -require "./ameba/rule/**" -require "./ameba/formatter/*" -require "./ameba/presenter/*" -require "./ameba/source/**" - # Ameba's entry module. # # To run the linter with default parameters: @@ -40,4 +32,18 @@ module Ameba def run(config = Config.load) Runner.new(config).run end + + macro ecr_supported?(&) + {% if compare_versions(Crystal::VERSION, "1.15.0") >= 0 %} + {{ yield }} + {% end %} + end end + +require "./ameba/*" +require "./ameba/ast/**" +require "./ameba/ext/**" +require "./ameba/rule/**" +require "./ameba/formatter/*" +require "./ameba/presenter/*" +require "./ameba/source/**" diff --git a/src/ameba/config.cr b/src/ameba/config.cr index 89a710e53..d09fff347 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 ) + Ameba.ecr_supported? do + 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..cee311b46 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" + + Ameba.ecr_supported? do + glob += "/**/*.ecr" + end + end + Dir[glob] end .uniq! diff --git a/src/ameba/source.cr b/src/ameba/source.cr index 29d9d1990..89255de0c 100644 --- a/src/ameba/source.cr +++ b/src/ameba/source.cr @@ -57,6 +57,24 @@ module Ameba # source.ast # ``` getter ast : Crystal::ASTNode do + code = @code + + Ameba.ecr_supported? do + if @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 + end + Crystal::Parser.new(code) .tap(&.wants_doc = true) .tap(&.filename = path)