diff --git a/lib/erb_lint/linters/allowed_script_type.rb b/lib/erb_lint/linters/allowed_script_type.rb index 64a55c2..1fff3ff 100644 --- a/lib/erb_lint/linters/allowed_script_type.rb +++ b/lib/erb_lint/linters/allowed_script_type.rb @@ -23,9 +23,12 @@ class ConfigSchema < LinterConfig def run(processed_source) parser = processed_source.parser parser.nodes_with_type(:tag).each do |tag_node| + # Fast path: check tag name from AST node directly before creating Tag object + tag_name_node = tag_node.to_a[1] + next unless tag_name_node&.loc&.source == "script" + tag = BetterHtml::Tree::Tag.from_node(tag_node) next if tag.closing? - next unless tag.name == "script" if @config.disallow_inline_scripts? name_node = tag_node.to_a[1] diff --git a/lib/erb_lint/linters/no_javascript_tag_helper.rb b/lib/erb_lint/linters/no_javascript_tag_helper.rb index 3c25dd6..28efcde 100644 --- a/lib/erb_lint/linters/no_javascript_tag_helper.rb +++ b/lib/erb_lint/linters/no_javascript_tag_helper.rb @@ -25,6 +25,9 @@ def run(processed_source) source = code_node.loc.source + # Fast path: skip expensive parsing if source can't contain the target method + next unless source.include?("javascript_tag") + ruby_node = begin BetterHtml::TestHelper::RubyNode.parse(source) diff --git a/lib/erb_lint/linters/require_input_autocomplete.rb b/lib/erb_lint/linters/require_input_autocomplete.rb index 4a779e5..3d747c9 100644 --- a/lib/erb_lint/linters/require_input_autocomplete.rb +++ b/lib/erb_lint/linters/require_input_autocomplete.rb @@ -52,6 +52,10 @@ def run(processed_source) def find_html_input_tags(parser) parser.nodes_with_type(:tag).each do |tag_node| + # Fast path: check tag name from AST node directly before creating Tag object + tag_name_node = tag_node.to_a[1] + next unless tag_name_node&.loc&.source == "input" + tag = BetterHtml::Tree::Tag.from_node(tag_node) autocomplete_attribute = tag.attributes["autocomplete"] @@ -82,10 +86,16 @@ def html_type_requires_autocomplete_attribute?(type_attribute) type_present && HTML_INPUT_TYPES_REQUIRING_AUTOCOMPLETE.include?(type_attribute.value) end + FORM_HELPER_NAMES_PATTERN = Regexp.union(FORM_HELPERS_REQUIRING_AUTOCOMPLETE.map(&:to_s)).freeze + def find_rails_helper_input_tags(parser) parser.ast.descendants(:erb).each do |erb_node| indicator_node, _, code_node, _ = *erb_node source = code_node.loc.source + + # Fast path: skip expensive parsing if source can't contain any form helper name + next unless source.match?(FORM_HELPER_NAMES_PATTERN) + ruby_node = extract_ruby_node(source) send_node = ruby_node&.descendants(:send)&.first diff --git a/lib/erb_lint/linters/require_script_nonce.rb b/lib/erb_lint/linters/require_script_nonce.rb index e575dfb..76d3a59 100644 --- a/lib/erb_lint/linters/require_script_nonce.rb +++ b/lib/erb_lint/linters/require_script_nonce.rb @@ -21,6 +21,10 @@ def run(processed_source) def find_html_script_tags(parser) parser.nodes_with_type(:tag).each do |tag_node| + # Fast path: check tag name from AST node directly before creating Tag object + tag_name_node = tag_node.to_a[1] + next unless tag_name_node&.loc&.source == "script" + tag = BetterHtml::Tree::Tag.from_node(tag_node) nonce_attribute = tag.attributes["nonce"] @@ -52,10 +56,16 @@ def html_javascript_type_attribute?(tag) type_attribute.value_node.to_a[1] != "application/javascript" end + TAG_HELPER_PATTERN = /javascript_tag|javascript_include_tag|javascript_pack_tag/ + def find_rails_helper_script_tags(parser) parser.ast.descendants(:erb).each do |erb_node| indicator_node, _, code_node, _ = *erb_node source = code_node.loc.source + + # Fast path: skip expensive parsing if source can't contain any tag helper name + next unless source.match?(TAG_HELPER_PATTERN) + ruby_node = extract_ruby_node(source) send_node = ruby_node&.descendants(:send)&.first