-
Notifications
You must be signed in to change notification settings - Fork 128
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #279 from issyl0/lint-erb-comment-syntax
lib/erb_lint/linters: Add a new CommentSyntax linter
- Loading branch information
Showing
4 changed files
with
141 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# frozen_string_literal: true | ||
|
||
module ERBLint | ||
module Linters | ||
# Detects comment syntax that isn't valid ERB. | ||
class CommentSyntax < Linter | ||
include LinterRegistry | ||
|
||
def initialize(file_loader, config) | ||
super | ||
end | ||
|
||
def run(processed_source) | ||
file_content = processed_source.file_content | ||
return if file_content.empty? | ||
|
||
processed_source.ast.descendants(:erb).each do |erb_node| | ||
indicator_node, _, code_node, _ = *erb_node | ||
next if code_node.nil? | ||
|
||
indicator_node_str = indicator_node&.deconstruct&.last | ||
next if indicator_node_str == "#" | ||
|
||
code_node_str = code_node.deconstruct.last | ||
next unless code_node_str.start_with?(" #") | ||
|
||
range = find_range(erb_node, code_node_str) | ||
source_range = processed_source.to_source_range(range) | ||
|
||
correct_erb_tag = indicator_node_str == "=" ? "<%#=" : "<%#" | ||
|
||
add_offense( | ||
source_range, | ||
<<~EOF.chomp | ||
Bad ERB comment syntax. Should be #{correct_erb_tag} without a space between. | ||
Leaving a space between ERB tags and the Ruby comment character can cause parser errors. | ||
EOF | ||
) | ||
end | ||
end | ||
|
||
def find_range(node, str) | ||
match = node.loc.source.match(Regexp.new(Regexp.quote(str.strip))) | ||
return unless match | ||
|
||
range_begin = match.begin(0) + node.loc.begin_pos | ||
range_end = match.end(0) + node.loc.begin_pos | ||
(range_begin...range_end) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# frozen_string_literal: true | ||
|
||
require "spec_helper" | ||
|
||
describe ERBLint::Linters::CommentSyntax do | ||
let(:linter_config) { described_class.config_schema.new } | ||
|
||
let(:file_loader) { ERBLint::FileLoader.new(".") } | ||
let(:linter) { described_class.new(file_loader, linter_config) } | ||
let(:processed_source) { ERBLint::ProcessedSource.new("file.rb", file) } | ||
|
||
subject { linter.offenses } | ||
before { linter.run(processed_source) } | ||
|
||
context "when the ERB comment syntax is correct" do | ||
let(:file) { <<~FILE } | ||
<%# good comment %> | ||
FILE | ||
|
||
it "does not report any offenses" do | ||
expect(subject.size).to(eq(0)) | ||
end | ||
end | ||
|
||
context "when the ERB multi-line comment syntax is correct" do | ||
let(:file) { <<~FILE } | ||
<% | ||
# good comment | ||
%> | ||
FILE | ||
|
||
it "does not report any offenses" do | ||
expect(subject.size).to(eq(0)) | ||
end | ||
end | ||
|
||
context "when the ERB comment syntax is incorrect" do | ||
let(:file) { <<~FILE } | ||
<% # bad comment %> | ||
FILE | ||
|
||
it "reports one offense" do | ||
expect(subject.size).to(eq(1)) | ||
end | ||
|
||
it "reports the suggested fix" do | ||
expect(subject.first.message).to(include("Bad ERB comment syntax. Should be <%# without a space between.")) | ||
end | ||
end | ||
|
||
context "when the ERB comment syntax is incorrect multiple times in one file" do | ||
let(:file) { <<~FILE } | ||
<% # first bad comment %> | ||
<%= # second bad comment %> | ||
FILE | ||
|
||
it "reports two offenses" do | ||
expect(subject.size).to(eq(2)) | ||
end | ||
|
||
it "reports the suggested fixes" do | ||
expect(subject.first.message).to(include("Bad ERB comment syntax. Should be <%# without a space between.")) | ||
expect(subject.last.message).to(include("Bad ERB comment syntax. Should be <%#= without a space between.")) | ||
end | ||
end | ||
end |