Class: Phlexing::TemplateGenerator

Inherits:
Object
  • Object
show all
Includes:
Helpers
Defined in:
lib/phlexing/template_generator.rb

Constant Summary

Constants included from Helpers

Helpers::KNOWN_ELEMENTS, Helpers::SVG_ELEMENTS

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helpers

#arg, #block, #blocklist, #braces, #children?, #interpolate, #known_rails_helpers, #multiple_children?, #newline, #output, #parens, #quote, #routes_helpers, #siblings?, #string_output?, #symbol, #tag_name, #unescape, #unwrap_erb, #whitespace

Constructor Details

#initialize(converter) ⇒ TemplateGenerator

Returns a new instance of TemplateGenerator.



17
18
19
20
21
# File 'lib/phlexing/template_generator.rb', line 17

def initialize(converter)
  @converter = converter
  @options = @converter.options
  @out = StringIO.new
end

Instance Attribute Details

#converterObject

Returns the value of attribute converter.



11
12
13
# File 'lib/phlexing/template_generator.rb', line 11

def converter
  @converter
end

#optionsObject

Returns the value of attribute options.



11
12
13
# File 'lib/phlexing/template_generator.rb', line 11

def options
  @options
end

#outObject

Returns the value of attribute out.



11
12
13
# File 'lib/phlexing/template_generator.rb', line 11

def out
  @out
end

Class Method Details

.call(converter, source) ⇒ Object



13
14
15
# File 'lib/phlexing/template_generator.rb', line 13

def self.call(converter, source)
  new(converter).call(source)
end

Instance Method Details

#call(source) ⇒ Object



23
24
25
26
27
28
29
30
# File 'lib/phlexing/template_generator.rb', line 23

def call(source)
  document = Parser.call(source)
  handle_node(document)

  Formatter.call(out.string.strip)
rescue StandardError
  out.string.strip
end

#handle_attribute(attribute) ⇒ Object



64
65
66
67
68
69
70
71
72
# File 'lib/phlexing/template_generator.rb', line 64

def handle_attribute(attribute)
  if attribute.name.start_with?(/data-erb-(\d+)+/)
    handle_erb_interpolation_in_tag(attribute)
  elsif attribute.name.start_with?("data-erb-")
    handle_erb_attribute_output(attribute)
  else
    handle_html_attribute_output(attribute)
  end
end

#handle_attributes(node) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
# File 'lib/phlexing/template_generator.rb', line 52

def handle_attributes(node)
  return "" if node.attributes.keys.none?

  attributes = []

  node.attribute_nodes.each do |attribute|
    attributes << handle_attribute(attribute)
  end

  parens(attributes.join(", "))
end

#handle_children(node, level) ⇒ Object



214
215
216
217
218
# File 'lib/phlexing/template_generator.rb', line 214

def handle_children(node, level)
  node.children.each do |child|
    handle_node(child, level + 1)
  end
end

#handle_document_node(node, level) ⇒ Object



210
211
212
# File 'lib/phlexing/template_generator.rb', line 210

def handle_document_node(node, level)
  handle_children(node, level)
end

#handle_element_node(node, level) ⇒ Object



181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/phlexing/template_generator.rb', line 181

def handle_element_node(node, level)
  case node
  in name: "erb", attributes: [{ name: "loud", value: "" }]
    handle_loud_erb_node(node)
  in name: "erb", attributes: [{ name: "silent", value: "" }]
    handle_silent_erb_node(node)
  else
    handle_html_element_node(node, level)
  end

  out << newline if level == 1
end

#handle_erb_attribute_output(attribute) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/phlexing/template_generator.rb', line 87

def handle_erb_attribute_output(attribute)
  String.new.tap { |s|
    s << arg(attribute.name.delete_prefix("data-erb-").underscore)

    s << if attribute.value.start_with?("<%=") && attribute.value.scan("<%").one? && attribute.value.end_with?("%>")
      value = unwrap_erb(attribute.value)
      value.include?(" ") ? parens(value) : value
    else
      transformed = Parser.call(attribute.value)
      attribute = StringIO.new

      transformed.children.each do |node|
        case node
        when Nokogiri::XML::Text
          attribute << node.text
        when Nokogiri::XML::Node
          if node.attributes["loud"]
            attribute << interpolate(node.text.strip)
          else
            attribute << interpolate("#{node.text.strip} && nil")
          end
        end
      end

      quote(attribute.string)
    end
  }
end

#handle_erb_comment_output(text) ⇒ Object



40
41
42
# File 'lib/phlexing/template_generator.rb', line 40

def handle_erb_comment_output(text)
  output("#", text)
end

#handle_erb_interpolation_in_tag(attribute) ⇒ Object



116
117
118
# File 'lib/phlexing/template_generator.rb', line 116

def handle_erb_interpolation_in_tag(attribute)
  "**#{parens("#{unwrap_erb(unescape(attribute.value))}: true")}"
end

#handle_erb_safe_node(node) ⇒ Object



120
121
122
123
124
125
126
# File 'lib/phlexing/template_generator.rb', line 120

def handle_erb_safe_node(node)
  if siblings?(node) && string_output?(node)
    handle_text_output(node.text.strip)
  else
    handle_output(node.text.strip)
  end
end

#handle_erb_unsafe_output(text) ⇒ Object



44
45
46
# File 'lib/phlexing/template_generator.rb', line 44

def handle_erb_unsafe_output(text)
  output("unsafe_raw", text)
end

#handle_html_attribute_output(attribute) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/phlexing/template_generator.rb', line 74

def handle_html_attribute_output(attribute)
  String.new.tap { |s|
    s << arg(attribute.name.underscore)
    if attribute.value.blank? && !attribute.to_html.include?("=")
      # handling boolean attributes
      # eg. <input required> => input(required: true)
      s << "true"
    else
      s << quote(attribute.value)
    end
  }
end

#handle_html_comment_node(node) ⇒ Object



177
178
179
# File 'lib/phlexing/template_generator.rb', line 177

def handle_html_comment_node(node)
  handle_html_comment_output(node.text.strip)
end

#handle_html_comment_output(text) ⇒ Object



36
37
38
# File 'lib/phlexing/template_generator.rb', line 36

def handle_html_comment_output(text)
  output("comment", braces(quote(text)))
end

#handle_html_element_node(node, level) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/phlexing/template_generator.rb', line 146

def handle_html_element_node(node, level)
  out << tag_name(node)
  out << handle_attributes(node)

  params = node.name == "svg" ? options.svg_param : nil

  if node.children.any?
    block(params) { handle_children(node, level) }
  end

  out << newline
end

#handle_loud_erb_node(node) ⇒ Object



159
160
161
162
163
164
165
# File 'lib/phlexing/template_generator.rb', line 159

def handle_loud_erb_node(node)
  if node.text.start_with?("=")
    handle_erb_unsafe_output(node.text.from(1).strip)
  else
    handle_erb_safe_node(node)
  end
end

#handle_node(node, level = 0) ⇒ Object



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/phlexing/template_generator.rb', line 220

def handle_node(node, level = 0)
  case node
  in Nokogiri::XML::Text
    handle_text_node(node)
  in Nokogiri::XML::Element
    if node.name == "svg"
      handle_svg_node(node, level)
    else
      handle_element_node(node, level)
    end
  in Nokogiri::HTML4::Document | Nokogiri::HTML4::DocumentFragment | Nokogiri::XML::DTD
    handle_document_node(node, level)
  in Nokogiri::XML::Comment
    handle_html_comment_node(node)
  end
end

#handle_output(text) ⇒ Object



48
49
50
# File 'lib/phlexing/template_generator.rb', line 48

def handle_output(text)
  output("", unescape(text).strip)
end

#handle_silent_erb_node(node) ⇒ Object



167
168
169
170
171
172
173
174
175
# File 'lib/phlexing/template_generator.rb', line 167

def handle_silent_erb_node(node)
  if node.text.start_with?("#")
    handle_erb_comment_output(node.text.from(1).strip)
  elsif node.text.start_with?("-")
    handle_output(node.text.from(1).to(-2).strip)
  else
    handle_output(node.text.strip)
  end
end

#handle_svg_node(node, level) ⇒ Object



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/phlexing/template_generator.rb', line 194

def handle_svg_node(node, level)
  node.children.each do |child|
    child.traverse do |subchild|
      subchild.name = SVG_ELEMENTS[subchild.name] if SVG_ELEMENTS.key?(subchild.name)
      subchild.name = subchild.name.prepend("#{options.svg_param}.") # rubocop:disable Style/RedundantSelfAssignment
    end
  end

  whitespace_before = options.whitespace
  options.whitespace = false

  handle_element_node(node, level)

  options.whitespace = whitespace_before
end

#handle_text_node(node) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/phlexing/template_generator.rb', line 128

def handle_text_node(node)
  text = node.text

  if text.squish.empty? && text.length.positive?
    out << whitespace

    text.strip!
  end

  return if text.length.zero?

  if siblings?(node)
    handle_text_output(quote(node.text))
  else
    handle_output(quote(text))
  end
end

#handle_text_output(text) ⇒ Object



32
33
34
# File 'lib/phlexing/template_generator.rb', line 32

def handle_text_output(text)
  output("plain", text)
end