Class: Herb::Engine::Validators::RenderValidator

Inherits:
Herb::Engine::Validator show all
Defined in:
lib/herb/engine/validators/render_validator.rb,
sig/herb/engine/validators/render_validator.rbs

Instance Attribute Summary

Attributes inherited from Herb::Engine::Validator

#diagnostics, #enabled

Instance Method Summary collapse

Methods inherited from Herb::Engine::Validator

#add_diagnostic, #clear_diagnostics, #diagnostic_count, #enabled?, #error, #errors, #errors?, #hint, #info, #validate, #warning, #warnings, #warnings?

Methods inherited from Visitor

#visit, #visit_all, #visit_cdata_node, #visit_child_nodes, #visit_document_node, #visit_erb_begin_node, #visit_erb_block_node, #visit_erb_case_match_node, #visit_erb_case_node, #visit_erb_content_node, #visit_erb_else_node, #visit_erb_end_node, #visit_erb_ensure_node, #visit_erb_for_node, #visit_erb_if_node, #visit_erb_in_node, #visit_erb_node, #visit_erb_open_tag_node, #visit_erb_rescue_node, #visit_erb_strict_locals_node, #visit_erb_unless_node, #visit_erb_until_node, #visit_erb_when_node, #visit_erb_while_node, #visit_erb_yield_node, #visit_html_attribute_name_node, #visit_html_attribute_node, #visit_html_attribute_value_node, #visit_html_close_tag_node, #visit_html_comment_node, #visit_html_conditional_element_node, #visit_html_conditional_open_tag_node, #visit_html_doctype_node, #visit_html_element_node, #visit_html_omitted_close_tag_node, #visit_html_open_tag_node, #visit_html_text_node, #visit_html_virtual_close_tag_node, #visit_literal_node, #visit_node, #visit_ruby_html_attributes_splat_node, #visit_ruby_literal_node, #visit_ruby_parameter_node, #visit_ruby_render_keywords_node, #visit_ruby_render_local_node, #visit_whitespace_node, #visit_xml_declaration_node

Methods included from AST::Helpers

#erb_comment?, #erb_graphql?, #erb_output?, #erb_outputs?, #inline_ruby_comment?

Constructor Details

#initialize(enabled: true, filename: nil, project_path: nil) ⇒ RenderValidator

Returns a new instance of RenderValidator.

Parameters:

  • enabled: (Object) (defaults to: true)
  • filename: (Object) (defaults to: nil)
  • project_path: (Object) (defaults to: nil)


9
10
11
12
13
14
15
# File 'lib/herb/engine/validators/render_validator.rb', line 9

def initialize(enabled: true, filename: nil, project_path: nil)
  super(enabled: enabled)

  @filename = filename
  @project_path = project_path
  @view_root = find_view_root
end

Instance Method Details

#find_view_rootObject

Returns:

  • (Object)


76
77
78
79
80
81
82
# File 'lib/herb/engine/validators/render_validator.rb', line 76

def find_view_root
  return nil unless @project_path

  view_root = @project_path.join("app", "views")

  view_root.directory? ? view_root : nil
end

#relative_to_project(path) ⇒ Object

Parameters:

  • path (Object)

Returns:

  • (Object)


84
85
86
87
88
# File 'lib/herb/engine/validators/render_validator.rb', line 84

def relative_to_project(path)
  path.relative_path_from(@project_path).to_s
rescue ArgumentError
  path.to_s
end

#validate_partial_exists(node) ⇒ Object

Parameters:

  • node (Object)

Returns:

  • (Object)


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/herb/engine/validators/render_validator.rb', line 34

def validate_partial_exists(node)
  return unless @filename

  source_directory = @project_path.join(@filename).dirname
  resolved = node.resolve(view_root: @view_root, source_directory: source_directory)

  return if resolved

  message = "Partial '#{node.partial_path}' could not be resolved."
  searched = node.candidate_paths(nil, @view_root, source_directory)

  if searched.any?
    relative_paths = searched.map { |path| relative_to_project(path) }.uniq
    message += "\n     Looked in:\n"

    relative_paths.each do |path|
      message += "       - #{path}\n"
    end
  end

  suggestions = node.similar_partials(view_root: @view_root, source_directory: source_directory)

  if suggestions.any?
    partial_suggestions, hint_suggestions = suggestions.partition { |suggestion| !suggestion.include?("exists as a template") }

    if partial_suggestions.any?
      message += "     Did you mean: #{partial_suggestions.map { |suggestion| "'#{suggestion}'" }.join(", ")}?\n"
    end

    hint_suggestions.each do |hint|
      message += "\n     Note: #{hint}\n"
    end
  end

  error(
    message,
    node.location,
    code: "RenderUnresolved",
    source: "RenderValidator"
  )
end

#visit_erb_render_node(node) ⇒ Object

Parameters:

  • node (Object)

Returns:

  • (Object)


17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/herb/engine/validators/render_validator.rb', line 17

def visit_erb_render_node(node)
  if node.dynamic?
    warning(
      "Dynamic render call cannot be statically resolved",
      node.location,
      code: "RenderDynamic",
      source: "RenderValidator"
    )
  elsif node.static_partial?
    validate_partial_exists(node)
  end

  super
end