herb 0.8.10-arm-linux-gnu → 0.9.1-arm-linux-gnu

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +11 -3
  3. data/README.md +64 -34
  4. data/Rakefile +48 -40
  5. data/config.yml +473 -34
  6. data/ext/herb/error_helpers.c +535 -140
  7. data/ext/herb/error_helpers.h +1 -0
  8. data/ext/herb/extconf.rb +67 -28
  9. data/ext/herb/extension.c +321 -51
  10. data/ext/herb/extension.h +1 -0
  11. data/ext/herb/extension_helpers.c +24 -14
  12. data/ext/herb/extension_helpers.h +2 -2
  13. data/ext/herb/nodes.c +647 -270
  14. data/ext/herb/nodes.h +1 -0
  15. data/herb.gemspec +3 -2
  16. data/lib/herb/3.0/herb.so +0 -0
  17. data/lib/herb/3.1/herb.so +0 -0
  18. data/lib/herb/3.2/herb.so +0 -0
  19. data/lib/herb/3.3/herb.so +0 -0
  20. data/lib/herb/3.4/herb.so +0 -0
  21. data/lib/herb/4.0/herb.so +0 -0
  22. data/lib/herb/ast/helpers.rb +3 -3
  23. data/lib/herb/ast/node.rb +15 -2
  24. data/lib/herb/ast/nodes.rb +1530 -179
  25. data/lib/herb/bootstrap.rb +87 -0
  26. data/lib/herb/cli.rb +341 -31
  27. data/lib/herb/configuration.rb +248 -0
  28. data/lib/herb/defaults.yml +32 -0
  29. data/lib/herb/engine/compiler.rb +78 -11
  30. data/lib/herb/engine/debug_visitor.rb +13 -3
  31. data/lib/herb/engine/error_formatter.rb +13 -9
  32. data/lib/herb/engine/parser_error_overlay.rb +10 -6
  33. data/lib/herb/engine/validator.rb +8 -3
  34. data/lib/herb/engine/validators/nesting_validator.rb +2 -2
  35. data/lib/herb/engine.rb +119 -43
  36. data/lib/herb/errors.rb +808 -88
  37. data/lib/herb/lex_result.rb +1 -0
  38. data/lib/herb/location.rb +7 -3
  39. data/lib/herb/parse_result.rb +12 -2
  40. data/lib/herb/parser_options.rb +62 -0
  41. data/lib/herb/position.rb +1 -0
  42. data/lib/herb/prism_inspect.rb +120 -0
  43. data/lib/herb/project.rb +923 -331
  44. data/lib/herb/range.rb +1 -0
  45. data/lib/herb/token.rb +7 -1
  46. data/lib/herb/version.rb +1 -1
  47. data/lib/herb/visitor.rb +47 -2
  48. data/lib/herb/warnings.rb +6 -1
  49. data/lib/herb.rb +35 -3
  50. data/sig/herb/ast/helpers.rbs +2 -2
  51. data/sig/herb/ast/node.rbs +12 -2
  52. data/sig/herb/ast/nodes.rbs +773 -128
  53. data/sig/herb/bootstrap.rbs +31 -0
  54. data/sig/herb/configuration.rbs +89 -0
  55. data/sig/herb/engine/compiler.rbs +9 -1
  56. data/sig/herb/engine/debug_visitor.rbs +2 -0
  57. data/sig/herb/engine/validator.rbs +5 -1
  58. data/sig/herb/engine.rbs +21 -3
  59. data/sig/herb/errors.rbs +372 -63
  60. data/sig/herb/location.rbs +4 -0
  61. data/sig/herb/parse_result.rbs +4 -2
  62. data/sig/herb/parser_options.rbs +46 -0
  63. data/sig/herb/position.rbs +1 -0
  64. data/sig/herb/prism_inspect.rbs +28 -0
  65. data/sig/herb/range.rbs +1 -0
  66. data/sig/herb/token.rbs +6 -0
  67. data/sig/herb/visitor.rbs +31 -4
  68. data/sig/herb/warnings.rbs +6 -1
  69. data/sig/herb.rbs +14 -0
  70. data/sig/herb_c_extension.rbs +5 -2
  71. data/sig/rubyvm.rbs +5 -0
  72. data/sig/serialized_ast_errors.rbs +82 -6
  73. data/sig/serialized_ast_nodes.rbs +91 -6
  74. data/src/analyze/action_view/attribute_extraction_helpers.c +303 -0
  75. data/src/analyze/action_view/content_tag.c +78 -0
  76. data/src/analyze/action_view/link_to.c +167 -0
  77. data/src/analyze/action_view/registry.c +83 -0
  78. data/src/analyze/action_view/tag.c +70 -0
  79. data/src/analyze/action_view/tag_helper_node_builders.c +305 -0
  80. data/src/analyze/action_view/tag_helpers.c +815 -0
  81. data/src/analyze/action_view/turbo_frame_tag.c +88 -0
  82. data/src/analyze/analyze.c +885 -0
  83. data/src/{analyzed_ruby.c → analyze/analyzed_ruby.c} +13 -11
  84. data/src/analyze/builders.c +343 -0
  85. data/src/analyze/conditional_elements.c +594 -0
  86. data/src/analyze/conditional_open_tags.c +640 -0
  87. data/src/analyze/control_type.c +250 -0
  88. data/src/{analyze_helpers.c → analyze/helpers.c} +48 -23
  89. data/src/analyze/invalid_structures.c +193 -0
  90. data/src/{analyze_missing_end.c → analyze/missing_end.c} +33 -22
  91. data/src/analyze/parse_errors.c +84 -0
  92. data/src/analyze/prism_annotate.c +399 -0
  93. data/src/analyze/render_nodes.c +761 -0
  94. data/src/{analyze_transform.c → analyze/transform.c} +24 -3
  95. data/src/ast_node.c +17 -7
  96. data/src/ast_nodes.c +759 -387
  97. data/src/ast_pretty_print.c +264 -6
  98. data/src/errors.c +1454 -519
  99. data/src/extract.c +145 -49
  100. data/src/herb.c +52 -34
  101. data/src/html_util.c +241 -12
  102. data/src/include/analyze/action_view/attribute_extraction_helpers.h +36 -0
  103. data/src/include/analyze/action_view/tag_helper_handler.h +43 -0
  104. data/src/include/analyze/action_view/tag_helper_node_builders.h +70 -0
  105. data/src/include/analyze/action_view/tag_helpers.h +38 -0
  106. data/src/include/{analyze.h → analyze/analyze.h} +14 -4
  107. data/src/include/{analyzed_ruby.h → analyze/analyzed_ruby.h} +3 -3
  108. data/src/include/analyze/builders.h +27 -0
  109. data/src/include/analyze/conditional_elements.h +9 -0
  110. data/src/include/analyze/conditional_open_tags.h +9 -0
  111. data/src/include/analyze/control_type.h +14 -0
  112. data/src/include/{analyze_helpers.h → analyze/helpers.h} +4 -2
  113. data/src/include/analyze/invalid_structures.h +11 -0
  114. data/src/include/analyze/prism_annotate.h +16 -0
  115. data/src/include/analyze/render_nodes.h +11 -0
  116. data/src/include/ast_node.h +11 -5
  117. data/src/include/ast_nodes.h +154 -38
  118. data/src/include/ast_pretty_print.h +5 -0
  119. data/src/include/element_source.h +3 -8
  120. data/src/include/errors.h +206 -55
  121. data/src/include/extract.h +21 -5
  122. data/src/include/herb.h +18 -6
  123. data/src/include/herb_prism_node.h +13 -0
  124. data/src/include/html_util.h +7 -2
  125. data/src/include/io.h +3 -1
  126. data/src/include/lex_helpers.h +29 -0
  127. data/src/include/lexer.h +1 -1
  128. data/src/include/lexer_peek_helpers.h +87 -13
  129. data/src/include/lexer_struct.h +2 -0
  130. data/src/include/location.h +2 -1
  131. data/src/include/parser.h +28 -2
  132. data/src/include/parser_helpers.h +19 -3
  133. data/src/include/pretty_print.h +10 -5
  134. data/src/include/prism_context.h +45 -0
  135. data/src/include/prism_helpers.h +10 -7
  136. data/src/include/prism_serialized.h +12 -0
  137. data/src/include/token.h +16 -4
  138. data/src/include/token_struct.h +10 -3
  139. data/src/include/utf8.h +2 -1
  140. data/src/include/util/hb_allocator.h +78 -0
  141. data/src/include/util/hb_arena.h +6 -1
  142. data/src/include/util/hb_arena_debug.h +12 -1
  143. data/src/include/util/hb_array.h +7 -3
  144. data/src/include/util/hb_buffer.h +6 -4
  145. data/src/include/util/hb_foreach.h +79 -0
  146. data/src/include/util/hb_narray.h +8 -4
  147. data/src/include/util/hb_string.h +56 -9
  148. data/src/include/util.h +6 -3
  149. data/src/include/version.h +1 -1
  150. data/src/io.c +3 -2
  151. data/src/lexer.c +42 -30
  152. data/src/lexer_peek_helpers.c +12 -74
  153. data/src/location.c +2 -2
  154. data/src/main.c +53 -28
  155. data/src/parser.c +784 -247
  156. data/src/parser_helpers.c +110 -23
  157. data/src/parser_match_tags.c +129 -48
  158. data/src/pretty_print.c +29 -24
  159. data/src/prism_helpers.c +30 -27
  160. data/src/ruby_parser.c +2 -0
  161. data/src/token.c +151 -66
  162. data/src/token_matchers.c +0 -1
  163. data/src/utf8.c +7 -6
  164. data/src/util/hb_allocator.c +341 -0
  165. data/src/util/hb_arena.c +81 -56
  166. data/src/util/hb_arena_debug.c +32 -17
  167. data/src/util/hb_array.c +30 -15
  168. data/src/util/hb_buffer.c +17 -21
  169. data/src/util/hb_narray.c +22 -7
  170. data/src/util/hb_string.c +49 -35
  171. data/src/util.c +21 -11
  172. data/src/visitor.c +67 -0
  173. data/templates/ext/herb/error_helpers.c.erb +24 -11
  174. data/templates/ext/herb/error_helpers.h.erb +1 -0
  175. data/templates/ext/herb/nodes.c.erb +50 -16
  176. data/templates/ext/herb/nodes.h.erb +1 -0
  177. data/templates/java/error_helpers.c.erb +1 -1
  178. data/templates/java/nodes.c.erb +30 -8
  179. data/templates/java/org/herb/ast/Errors.java.erb +24 -1
  180. data/templates/java/org/herb/ast/Nodes.java.erb +80 -21
  181. data/templates/javascript/packages/core/src/errors.ts.erb +16 -3
  182. data/templates/javascript/packages/core/src/node-type-guards.ts.erb +3 -1
  183. data/templates/javascript/packages/core/src/nodes.ts.erb +109 -32
  184. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +13 -4
  185. data/templates/javascript/packages/node/extension/nodes.cpp.erb +43 -4
  186. data/templates/lib/herb/ast/nodes.rb.erb +95 -32
  187. data/templates/lib/herb/errors.rb.erb +15 -3
  188. data/templates/lib/herb/visitor.rb.erb +2 -2
  189. data/templates/rust/src/ast/nodes.rs.erb +97 -44
  190. data/templates/rust/src/errors.rs.erb +2 -1
  191. data/templates/rust/src/nodes.rs.erb +168 -16
  192. data/templates/rust/src/union_types.rs.erb +60 -0
  193. data/templates/rust/src/visitor.rs.erb +81 -0
  194. data/templates/src/{analyze_missing_end.c.erb → analyze/missing_end.c.erb} +9 -6
  195. data/templates/src/{analyze_transform.c.erb → analyze/transform.c.erb} +2 -2
  196. data/templates/src/ast_nodes.c.erb +34 -26
  197. data/templates/src/ast_pretty_print.c.erb +24 -5
  198. data/templates/src/errors.c.erb +60 -54
  199. data/templates/src/include/ast_nodes.h.erb +6 -2
  200. data/templates/src/include/ast_pretty_print.h.erb +5 -0
  201. data/templates/src/include/errors.h.erb +15 -11
  202. data/templates/src/include/util/hb_foreach.h.erb +20 -0
  203. data/templates/src/parser_match_tags.c.erb +10 -4
  204. data/templates/src/visitor.c.erb +2 -2
  205. data/templates/template.rb +204 -29
  206. data/templates/wasm/error_helpers.cpp.erb +9 -5
  207. data/templates/wasm/nodes.cpp.erb +41 -4
  208. metadata +60 -16
  209. data/src/analyze.c +0 -1608
  210. data/src/element_source.c +0 -12
  211. data/src/include/util/hb_system.h +0 -9
  212. data/src/util/hb_system.c +0 -30
@@ -4,23 +4,52 @@
4
4
  # NOTE: This file is generated by the templates/template.rb script and should not be
5
5
  # modified manually. See /home/runner/work/herb/herb/templates/lib/herb/ast/nodes.rb.erb
6
6
 
7
+ require_relative "../prism_inspect"
8
+
7
9
  module Herb
8
10
  module AST
11
+ #: type serialized_document_node = {
12
+ #| children: Array[Herb::AST::Node],
13
+ #| prism_context: nil,
14
+ #| prism_node: String?,
15
+ #| }
9
16
  class DocumentNode < Node
10
17
  include Colors
11
18
 
12
19
  attr_reader :children #: Array[Herb::AST::Node]
20
+ attr_reader :prism_context #: nil
21
+ attr_reader :prism_node #: String?
13
22
 
14
- #: (String, Location, Array[Herb::Errors::Error], Array[Herb::AST::Node]) -> void
15
- def initialize(type, location, errors, children)
23
+ #: (String, Location, Array[Herb::Errors::Error], Array[Herb::AST::Node], nil, String) -> void
24
+ def initialize(type, location, errors, children, prism_context, prism_node)
16
25
  super(type, location, errors)
17
26
  @children = children
27
+ @prism_context = prism_context
28
+ @prism_node = prism_node
29
+ end
30
+
31
+ #: () -> Prism::node?
32
+ def deserialized_prism_node
33
+ prism_node = @prism_node
34
+ return nil unless prism_node
35
+ return nil unless source
36
+
37
+ begin
38
+ require "prism"
39
+ rescue LoadError
40
+ warn "The 'prism' gem is required to deserialize Prism nodes. Add it to your Gemfile or install it with: gem install prism"
41
+ return nil
42
+ end
43
+
44
+ Prism.load(source, prism_node).value
18
45
  end
19
46
 
20
47
  #: () -> serialized_document_node
21
48
  def to_hash
22
49
  super.merge({
23
50
  children: children,
51
+ prism_context: prism_context,
52
+ prism_node: prism_node,
24
53
  }) #: Herb::serialized_document_node
25
54
  end
26
55
 
@@ -31,7 +60,7 @@ module Herb
31
60
 
32
61
  #: () -> Array[Herb::AST::Node?]
33
62
  def child_nodes
34
- [*children]
63
+ [*(children || [])]
35
64
  end
36
65
 
37
66
  #: () -> Array[Herb::AST::Node]
@@ -59,23 +88,33 @@ module Herb
59
88
 
60
89
  output += inspect_errors(prefix: "│ ")
61
90
 
62
- output += white("└── children: ")
63
- output += inspect_array(children, prefix: " ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
91
+ dynamic_symbol = prism_node ? "├──" : "└──"
92
+ dynamic_prefix = prism_node ? "" : " "
93
+ output += white("#{dynamic_symbol} children: ")
94
+ output += inspect_array(children, prefix: dynamic_prefix, indent: indent, depth: depth + 1, depth_limit: depth_limit)
95
+ if prism_node && source
96
+ output += white("└── prism_node: ")
97
+ output += Herb::PrismInspect.inspect_prism_serialized(prism_node, source, " ")
98
+ output += "\n"
99
+ end
64
100
  output += "\n"
65
101
 
66
102
  output.gsub(/^/, " " * indent)
67
103
  end
68
104
  end
69
105
 
106
+ #: type serialized_literal_node = {
107
+ #| content: String?,
108
+ #| }
70
109
  class LiteralNode < Node
71
110
  include Colors
72
111
 
73
- attr_reader :content #: String
112
+ attr_reader :content #: String?
74
113
 
75
114
  #: (String, Location, Array[Herb::Errors::Error], String) -> void
76
115
  def initialize(type, location, errors, content)
77
116
  super(type, location, errors)
78
- @content = content.force_encoding("utf-8")
117
+ @content = content&.force_encoding("utf-8")
79
118
  end
80
119
 
81
120
  #: () -> serialized_literal_node
@@ -127,12 +166,19 @@ module Herb
127
166
  end
128
167
  end
129
168
 
169
+ #: type serialized_html_open_tag_node = {
170
+ #| tag_opening: Herb::Token?,
171
+ #| tag_name: Herb::Token?,
172
+ #| tag_closing: Herb::Token?,
173
+ #| children: Array[Herb::AST::Node],
174
+ #| is_void: bool,
175
+ #| }
130
176
  class HTMLOpenTagNode < Node
131
177
  include Colors
132
178
 
133
- attr_reader :tag_opening #: Herb::Token
134
- attr_reader :tag_name #: Herb::Token
135
- attr_reader :tag_closing #: Herb::Token
179
+ attr_reader :tag_opening #: Herb::Token?
180
+ attr_reader :tag_name #: Herb::Token?
181
+ attr_reader :tag_closing #: Herb::Token?
136
182
  attr_reader :children #: Array[Herb::AST::Node]
137
183
  attr_reader :is_void #: bool
138
184
 
@@ -164,7 +210,7 @@ module Herb
164
210
 
165
211
  #: () -> Array[Herb::AST::Node?]
166
212
  def child_nodes
167
- [*children]
213
+ [*(children || [])]
168
214
  end
169
215
 
170
216
  #: () -> Array[Herb::AST::Node]
@@ -212,15 +258,105 @@ module Herb
212
258
  end
213
259
  end
214
260
 
261
+ #: type serialized_html_conditional_open_tag_node = {
262
+ #| conditional: (Herb::AST::ERBIfNode | Herb::AST::ERBUnlessNode)?,
263
+ #| tag_name: Herb::Token?,
264
+ #| is_void: bool,
265
+ #| }
266
+ class HTMLConditionalOpenTagNode < Node
267
+ include Colors
268
+
269
+ attr_reader :conditional #: (Herb::AST::ERBIfNode | Herb::AST::ERBUnlessNode)?
270
+ attr_reader :tag_name #: Herb::Token?
271
+ attr_reader :is_void #: bool
272
+
273
+ #: (String, Location, Array[Herb::Errors::Error], (Herb::AST::ERBIfNode | Herb::AST::ERBUnlessNode), Herb::Token, bool) -> void
274
+ def initialize(type, location, errors, conditional, tag_name, is_void)
275
+ super(type, location, errors)
276
+ @conditional = conditional
277
+ @tag_name = tag_name
278
+ @is_void = is_void
279
+ end
280
+
281
+ #: () -> serialized_html_conditional_open_tag_node
282
+ def to_hash
283
+ super.merge({
284
+ conditional: conditional,
285
+ tag_name: tag_name,
286
+ is_void: is_void,
287
+ }) #: Herb::serialized_html_conditional_open_tag_node
288
+ end
289
+
290
+ #: (Visitor) -> void
291
+ def accept(visitor)
292
+ visitor.visit_html_conditional_open_tag_node(self)
293
+ end
294
+
295
+ #: () -> Array[Herb::AST::Node?]
296
+ def child_nodes
297
+ [conditional]
298
+ end
299
+
300
+ #: () -> Array[Herb::AST::Node]
301
+ def compact_child_nodes
302
+ child_nodes.compact
303
+ end
304
+
305
+ #: () -> String
306
+ def inspect
307
+ tree_inspect.rstrip.gsub(/\s+$/, "")
308
+ end
309
+
310
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
311
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 10)
312
+ output = +""
313
+
314
+ output += white("@ #{bold(yellow(node_name.to_s))} #{dimmed("(location: #{location.tree_inspect})")}")
315
+ output += "\n"
316
+
317
+ if depth >= depth_limit
318
+ output += dimmed("└── [depth limit reached ...]\n\n")
319
+
320
+ return output.gsub(/^/, " " * indent)
321
+ end
322
+
323
+ output += inspect_errors(prefix: "│ ")
324
+
325
+ output += white("├── conditional: ")
326
+ if conditional
327
+ output += "\n"
328
+ output += "│ └── "
329
+ output += conditional.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, "│ ").delete_prefix("│ ")
330
+ else
331
+ output += magenta("∅\n")
332
+ end
333
+ output += white("├── tag_name: ")
334
+ output += tag_name ? tag_name.tree_inspect : magenta("∅")
335
+ output += "\n"
336
+ output += white("└── is_void: ")
337
+ output += [true, false].include?(is_void) ? bold(magenta(is_void.to_s)) : magenta("∅")
338
+ output += "\n"
339
+ output += "\n"
340
+
341
+ output.gsub(/^/, " " * indent)
342
+ end
343
+ end
344
+
345
+ #: type serialized_html_close_tag_node = {
346
+ #| tag_opening: Herb::Token?,
347
+ #| tag_name: Herb::Token?,
348
+ #| children: Array[Herb::AST::WhitespaceNode]?,
349
+ #| tag_closing: Herb::Token?,
350
+ #| }
215
351
  class HTMLCloseTagNode < Node
216
352
  include Colors
217
353
 
218
- attr_reader :tag_opening #: Herb::Token
219
- attr_reader :tag_name #: Herb::Token
220
- attr_reader :children #: Array[Herb::AST::Node]
221
- attr_reader :tag_closing #: Herb::Token
354
+ attr_reader :tag_opening #: Herb::Token?
355
+ attr_reader :tag_name #: Herb::Token?
356
+ attr_reader :children #: Array[Herb::AST::WhitespaceNode]?
357
+ attr_reader :tag_closing #: Herb::Token?
222
358
 
223
- #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Array[Herb::AST::Node], Herb::Token) -> void
359
+ #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Array[Herb::AST::WhitespaceNode], Herb::Token) -> void
224
360
  def initialize(type, location, errors, tag_opening, tag_name, children, tag_closing)
225
361
  super(type, location, errors)
226
362
  @tag_opening = tag_opening
@@ -246,7 +382,7 @@ module Herb
246
382
 
247
383
  #: () -> Array[Herb::AST::Node?]
248
384
  def child_nodes
249
- [*children]
385
+ [*(children || [])]
250
386
  end
251
387
 
252
388
  #: () -> Array[Herb::AST::Node]
@@ -291,25 +427,163 @@ module Herb
291
427
  end
292
428
  end
293
429
 
430
+ #: type serialized_html_omitted_close_tag_node = {
431
+ #| tag_name: Herb::Token?,
432
+ #| }
433
+ class HTMLOmittedCloseTagNode < Node
434
+ include Colors
435
+
436
+ attr_reader :tag_name #: Herb::Token?
437
+
438
+ #: (String, Location, Array[Herb::Errors::Error], Herb::Token) -> void
439
+ def initialize(type, location, errors, tag_name)
440
+ super(type, location, errors)
441
+ @tag_name = tag_name
442
+ end
443
+
444
+ #: () -> serialized_html_omitted_close_tag_node
445
+ def to_hash
446
+ super.merge({
447
+ tag_name: tag_name,
448
+ }) #: Herb::serialized_html_omitted_close_tag_node
449
+ end
450
+
451
+ #: (Visitor) -> void
452
+ def accept(visitor)
453
+ visitor.visit_html_omitted_close_tag_node(self)
454
+ end
455
+
456
+ #: () -> Array[Herb::AST::Node?]
457
+ def child_nodes
458
+ []
459
+ end
460
+
461
+ #: () -> Array[Herb::AST::Node]
462
+ def compact_child_nodes
463
+ child_nodes.compact
464
+ end
465
+
466
+ #: () -> String
467
+ def inspect
468
+ tree_inspect.rstrip.gsub(/\s+$/, "")
469
+ end
470
+
471
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
472
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 10)
473
+ output = +""
474
+
475
+ output += white("@ #{bold(yellow(node_name.to_s))} #{dimmed("(location: #{location.tree_inspect})")}")
476
+ output += "\n"
477
+
478
+ if depth >= depth_limit
479
+ output += dimmed("└── [depth limit reached ...]\n\n")
480
+
481
+ return output.gsub(/^/, " " * indent)
482
+ end
483
+
484
+ output += inspect_errors(prefix: "│ ")
485
+
486
+ output += white("└── tag_name: ")
487
+ output += tag_name ? tag_name.tree_inspect : magenta("∅")
488
+ output += "\n"
489
+ output += "\n"
490
+
491
+ output.gsub(/^/, " " * indent)
492
+ end
493
+ end
494
+
495
+ #: type serialized_html_virtual_close_tag_node = {
496
+ #| tag_name: Herb::Token?,
497
+ #| }
498
+ class HTMLVirtualCloseTagNode < Node
499
+ include Colors
500
+
501
+ attr_reader :tag_name #: Herb::Token?
502
+
503
+ #: (String, Location, Array[Herb::Errors::Error], Herb::Token) -> void
504
+ def initialize(type, location, errors, tag_name)
505
+ super(type, location, errors)
506
+ @tag_name = tag_name
507
+ end
508
+
509
+ #: () -> serialized_html_virtual_close_tag_node
510
+ def to_hash
511
+ super.merge({
512
+ tag_name: tag_name,
513
+ }) #: Herb::serialized_html_virtual_close_tag_node
514
+ end
515
+
516
+ #: (Visitor) -> void
517
+ def accept(visitor)
518
+ visitor.visit_html_virtual_close_tag_node(self)
519
+ end
520
+
521
+ #: () -> Array[Herb::AST::Node?]
522
+ def child_nodes
523
+ []
524
+ end
525
+
526
+ #: () -> Array[Herb::AST::Node]
527
+ def compact_child_nodes
528
+ child_nodes.compact
529
+ end
530
+
531
+ #: () -> String
532
+ def inspect
533
+ tree_inspect.rstrip.gsub(/\s+$/, "")
534
+ end
535
+
536
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
537
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 10)
538
+ output = +""
539
+
540
+ output += white("@ #{bold(yellow(node_name.to_s))} #{dimmed("(location: #{location.tree_inspect})")}")
541
+ output += "\n"
542
+
543
+ if depth >= depth_limit
544
+ output += dimmed("└── [depth limit reached ...]\n\n")
545
+
546
+ return output.gsub(/^/, " " * indent)
547
+ end
548
+
549
+ output += inspect_errors(prefix: "│ ")
550
+
551
+ output += white("└── tag_name: ")
552
+ output += tag_name ? tag_name.tree_inspect : magenta("∅")
553
+ output += "\n"
554
+ output += "\n"
555
+
556
+ output.gsub(/^/, " " * indent)
557
+ end
558
+ end
559
+
560
+ #: type serialized_html_element_node = {
561
+ #| open_tag: (Herb::AST::HTMLOpenTagNode | Herb::AST::HTMLConditionalOpenTagNode | Herb::AST::ERBOpenTagNode)?,
562
+ #| tag_name: Herb::Token?,
563
+ #| body: Array[Herb::AST::Node],
564
+ #| close_tag: (Herb::AST::HTMLCloseTagNode | Herb::AST::HTMLOmittedCloseTagNode | Herb::AST::HTMLVirtualCloseTagNode | Herb::AST::ERBEndNode)?,
565
+ #| is_void: bool,
566
+ #| element_source: String?,
567
+ #| }
294
568
  class HTMLElementNode < Node
295
569
  include Colors
296
570
 
297
- attr_reader :open_tag #: Herb::AST::HTMLOpenTagNode
298
- attr_reader :tag_name #: Herb::Token
571
+ attr_reader :open_tag #: (Herb::AST::HTMLOpenTagNode | Herb::AST::HTMLConditionalOpenTagNode | Herb::AST::ERBOpenTagNode)?
572
+ attr_reader :tag_name #: Herb::Token?
299
573
  attr_reader :body #: Array[Herb::AST::Node]
300
- attr_reader :close_tag #: Herb::AST::HTMLCloseTagNode
574
+ attr_reader :close_tag #: (Herb::AST::HTMLCloseTagNode | Herb::AST::HTMLOmittedCloseTagNode | Herb::AST::HTMLVirtualCloseTagNode | Herb::AST::ERBEndNode)?
301
575
  attr_reader :is_void #: bool
302
- attr_reader :source #: String
576
+ attr_reader :element_source #: String?
303
577
 
304
- #: (String, Location, Array[Herb::Errors::Error], Herb::AST::HTMLOpenTagNode, Herb::Token, Array[Herb::AST::Node], Herb::AST::HTMLCloseTagNode, bool, String) -> void
305
- def initialize(type, location, errors, open_tag, tag_name, body, close_tag, is_void, source)
578
+ #: (String, Location, Array[Herb::Errors::Error], (Herb::AST::HTMLOpenTagNode | Herb::AST::HTMLConditionalOpenTagNode | Herb::AST::ERBOpenTagNode), Herb::Token, Array[Herb::AST::Node], (Herb::AST::HTMLCloseTagNode | Herb::AST::HTMLOmittedCloseTagNode | Herb::AST::HTMLVirtualCloseTagNode | Herb::AST::ERBEndNode), bool, String) -> void
579
+ def initialize(type, location, errors, open_tag, tag_name, body, close_tag, is_void, element_source)
306
580
  super(type, location, errors)
307
581
  @open_tag = open_tag
308
582
  @tag_name = tag_name
309
583
  @body = body
310
584
  @close_tag = close_tag
311
585
  @is_void = is_void
312
- @source = source
586
+ @element_source = element_source
313
587
  end
314
588
 
315
589
  #: () -> serialized_html_element_node
@@ -320,7 +594,7 @@ module Herb
320
594
  body: body,
321
595
  close_tag: close_tag,
322
596
  is_void: is_void,
323
- source: source,
597
+ element_source: element_source,
324
598
  }) #: Herb::serialized_html_element_node
325
599
  end
326
600
 
@@ -331,7 +605,7 @@ module Herb
331
605
 
332
606
  #: () -> Array[Herb::AST::Node?]
333
607
  def child_nodes
334
- [open_tag, *body, close_tag]
608
+ [open_tag, *(body || []), close_tag]
335
609
  end
336
610
 
337
611
  #: () -> Array[Herb::AST::Node]
@@ -383,19 +657,154 @@ module Herb
383
657
  output += white("├── is_void: ")
384
658
  output += [true, false].include?(is_void) ? bold(magenta(is_void.to_s)) : magenta("∅")
385
659
  output += "\n"
386
- output += white("└── source: #{green(source.inspect)}\n")
660
+ output += white("└── element_source: #{green(element_source.inspect)}\n")
387
661
  output += "\n"
388
662
 
389
663
  output.gsub(/^/, " " * indent)
390
664
  end
391
665
  end
392
666
 
667
+ #: type serialized_html_conditional_element_node = {
668
+ #| condition: String?,
669
+ #| open_conditional: (Herb::AST::ERBIfNode | Herb::AST::ERBUnlessNode)?,
670
+ #| open_tag: Herb::AST::HTMLOpenTagNode?,
671
+ #| body: Array[Herb::AST::Node],
672
+ #| close_tag: (Herb::AST::HTMLCloseTagNode | Herb::AST::HTMLOmittedCloseTagNode)?,
673
+ #| close_conditional: (Herb::AST::ERBIfNode | Herb::AST::ERBUnlessNode)?,
674
+ #| tag_name: Herb::Token?,
675
+ #| element_source: String?,
676
+ #| }
677
+ class HTMLConditionalElementNode < Node
678
+ include Colors
679
+
680
+ attr_reader :condition #: String?
681
+ attr_reader :open_conditional #: (Herb::AST::ERBIfNode | Herb::AST::ERBUnlessNode)?
682
+ attr_reader :open_tag #: Herb::AST::HTMLOpenTagNode?
683
+ attr_reader :body #: Array[Herb::AST::Node]
684
+ attr_reader :close_tag #: (Herb::AST::HTMLCloseTagNode | Herb::AST::HTMLOmittedCloseTagNode)?
685
+ attr_reader :close_conditional #: (Herb::AST::ERBIfNode | Herb::AST::ERBUnlessNode)?
686
+ attr_reader :tag_name #: Herb::Token?
687
+ attr_reader :element_source #: String?
688
+
689
+ #: (String, Location, Array[Herb::Errors::Error], String, (Herb::AST::ERBIfNode | Herb::AST::ERBUnlessNode), Herb::AST::HTMLOpenTagNode, Array[Herb::AST::Node], (Herb::AST::HTMLCloseTagNode | Herb::AST::HTMLOmittedCloseTagNode), (Herb::AST::ERBIfNode | Herb::AST::ERBUnlessNode), Herb::Token, String) -> void
690
+ def initialize(type, location, errors, condition, open_conditional, open_tag, body, close_tag, close_conditional, tag_name, element_source)
691
+ super(type, location, errors)
692
+ @condition = condition&.force_encoding("utf-8")
693
+ @open_conditional = open_conditional
694
+ @open_tag = open_tag
695
+ @body = body
696
+ @close_tag = close_tag
697
+ @close_conditional = close_conditional
698
+ @tag_name = tag_name
699
+ @element_source = element_source
700
+ end
701
+
702
+ #: () -> serialized_html_conditional_element_node
703
+ def to_hash
704
+ super.merge({
705
+ condition: condition,
706
+ open_conditional: open_conditional,
707
+ open_tag: open_tag,
708
+ body: body,
709
+ close_tag: close_tag,
710
+ close_conditional: close_conditional,
711
+ tag_name: tag_name,
712
+ element_source: element_source,
713
+ }) #: Herb::serialized_html_conditional_element_node
714
+ end
715
+
716
+ #: (Visitor) -> void
717
+ def accept(visitor)
718
+ visitor.visit_html_conditional_element_node(self)
719
+ end
720
+
721
+ #: () -> Array[Herb::AST::Node?]
722
+ def child_nodes
723
+ [open_conditional, open_tag, *(body || []), close_tag, close_conditional]
724
+ end
725
+
726
+ #: () -> Array[Herb::AST::Node]
727
+ def compact_child_nodes
728
+ child_nodes.compact
729
+ end
730
+
731
+ #: () -> String
732
+ def inspect
733
+ tree_inspect.rstrip.gsub(/\s+$/, "")
734
+ end
735
+
736
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
737
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 10)
738
+ output = +""
739
+
740
+ output += white("@ #{bold(yellow(node_name.to_s))} #{dimmed("(location: #{location.tree_inspect})")}")
741
+ output += "\n"
742
+
743
+ if depth >= depth_limit
744
+ output += dimmed("└── [depth limit reached ...]\n\n")
745
+
746
+ return output.gsub(/^/, " " * indent)
747
+ end
748
+
749
+ output += inspect_errors(prefix: "│ ")
750
+
751
+ output += white("├── condition: ") + green("#{condition.inspect}\n")
752
+ output += white("├── open_conditional: ")
753
+ if open_conditional
754
+ output += "\n"
755
+ output += "│ └── "
756
+ output += open_conditional.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, "│ ").delete_prefix("│ ")
757
+ else
758
+ output += magenta("∅\n")
759
+ end
760
+ output += white("├── open_tag: ")
761
+ if open_tag
762
+ output += "\n"
763
+ output += "│ └── "
764
+ output += open_tag.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, "│ ").delete_prefix("│ ")
765
+ else
766
+ output += magenta("∅\n")
767
+ end
768
+ output += white("├── body: ")
769
+ output += inspect_array(body, prefix: "│ ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
770
+ output += white("├── close_tag: ")
771
+ if close_tag
772
+ output += "\n"
773
+ output += "│ └── "
774
+ output += close_tag.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, "│ ").delete_prefix("│ ")
775
+ else
776
+ output += magenta("∅\n")
777
+ end
778
+ output += white("├── close_conditional: ")
779
+ if close_conditional
780
+ output += "\n"
781
+ output += "│ └── "
782
+ output += close_conditional.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, "│ ").delete_prefix("│ ")
783
+ else
784
+ output += magenta("∅\n")
785
+ end
786
+ output += white("├── tag_name: ")
787
+ output += tag_name ? tag_name.tree_inspect : magenta("∅")
788
+ output += "\n"
789
+ output += white("└── element_source: #{green(element_source.inspect)}\n")
790
+ output += "\n"
791
+
792
+ output.gsub(/^/, " " * indent)
793
+ end
794
+ end
795
+
796
+ #: type serialized_html_attribute_value_node = {
797
+ #| open_quote: Herb::Token?,
798
+ #| children: Array[Herb::AST::Node],
799
+ #| close_quote: Herb::Token?,
800
+ #| quoted: bool,
801
+ #| }
393
802
  class HTMLAttributeValueNode < Node
394
803
  include Colors
395
804
 
396
- attr_reader :open_quote #: Herb::Token
805
+ attr_reader :open_quote #: Herb::Token?
397
806
  attr_reader :children #: Array[Herb::AST::Node]
398
- attr_reader :close_quote #: Herb::Token
807
+ attr_reader :close_quote #: Herb::Token?
399
808
  attr_reader :quoted #: bool
400
809
 
401
810
  #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Array[Herb::AST::Node], Herb::Token, bool) -> void
@@ -424,7 +833,7 @@ module Herb
424
833
 
425
834
  #: () -> Array[Herb::AST::Node?]
426
835
  def child_nodes
427
- [*children]
836
+ [*(children || [])]
428
837
  end
429
838
 
430
839
  #: () -> Array[Herb::AST::Node]
@@ -469,12 +878,15 @@ module Herb
469
878
  end
470
879
  end
471
880
 
881
+ #: type serialized_html_attribute_name_node = {
882
+ #| children: Array[(Herb::AST::LiteralNode | Herb::AST::ERBContentNode)]?,
883
+ #| }
472
884
  class HTMLAttributeNameNode < Node
473
885
  include Colors
474
886
 
475
- attr_reader :children #: Array[Herb::AST::Node]
887
+ attr_reader :children #: Array[(Herb::AST::LiteralNode | Herb::AST::ERBContentNode)]?
476
888
 
477
- #: (String, Location, Array[Herb::Errors::Error], Array[Herb::AST::Node]) -> void
889
+ #: (String, Location, Array[Herb::Errors::Error], Array[(Herb::AST::LiteralNode | Herb::AST::ERBContentNode)]) -> void
478
890
  def initialize(type, location, errors, children)
479
891
  super(type, location, errors)
480
892
  @children = children
@@ -494,7 +906,7 @@ module Herb
494
906
 
495
907
  #: () -> Array[Herb::AST::Node?]
496
908
  def child_nodes
497
- [*children]
909
+ [*(children || [])]
498
910
  end
499
911
 
500
912
  #: () -> Array[Herb::AST::Node]
@@ -530,12 +942,17 @@ module Herb
530
942
  end
531
943
  end
532
944
 
945
+ #: type serialized_html_attribute_node = {
946
+ #| name: Herb::AST::HTMLAttributeNameNode?,
947
+ #| equals: Herb::Token?,
948
+ #| value: Herb::AST::HTMLAttributeValueNode?,
949
+ #| }
533
950
  class HTMLAttributeNode < Node
534
951
  include Colors
535
952
 
536
- attr_reader :name #: Herb::AST::HTMLAttributeNameNode
537
- attr_reader :equals #: Herb::Token
538
- attr_reader :value #: Herb::AST::HTMLAttributeValueNode
953
+ attr_reader :name #: Herb::AST::HTMLAttributeNameNode?
954
+ attr_reader :equals #: Herb::Token?
955
+ attr_reader :value #: Herb::AST::HTMLAttributeValueNode?
539
956
 
540
957
  #: (String, Location, Array[Herb::Errors::Error], Herb::AST::HTMLAttributeNameNode, Herb::Token, Herb::AST::HTMLAttributeValueNode) -> void
541
958
  def initialize(type, location, errors, name, equals, value)
@@ -556,12 +973,240 @@ module Herb
556
973
 
557
974
  #: (Visitor) -> void
558
975
  def accept(visitor)
559
- visitor.visit_html_attribute_node(self)
976
+ visitor.visit_html_attribute_node(self)
977
+ end
978
+
979
+ #: () -> Array[Herb::AST::Node?]
980
+ def child_nodes
981
+ [name, value]
982
+ end
983
+
984
+ #: () -> Array[Herb::AST::Node]
985
+ def compact_child_nodes
986
+ child_nodes.compact
987
+ end
988
+
989
+ #: () -> String
990
+ def inspect
991
+ tree_inspect.rstrip.gsub(/\s+$/, "")
992
+ end
993
+
994
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
995
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 10)
996
+ output = +""
997
+
998
+ output += white("@ #{bold(yellow(node_name.to_s))} #{dimmed("(location: #{location.tree_inspect})")}")
999
+ output += "\n"
1000
+
1001
+ if depth >= depth_limit
1002
+ output += dimmed("└── [depth limit reached ...]\n\n")
1003
+
1004
+ return output.gsub(/^/, " " * indent)
1005
+ end
1006
+
1007
+ output += inspect_errors(prefix: "│ ")
1008
+
1009
+ output += white("├── name: ")
1010
+ if name
1011
+ output += "\n"
1012
+ output += "│ └── "
1013
+ output += name.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, "│ ").delete_prefix("│ ")
1014
+ else
1015
+ output += magenta("∅\n")
1016
+ end
1017
+ output += white("├── equals: ")
1018
+ output += equals ? equals.tree_inspect : magenta("∅")
1019
+ output += "\n"
1020
+ output += white("└── value: ")
1021
+ if value
1022
+ output += "\n"
1023
+ output += " └── "
1024
+ output += value.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, " ").delete_prefix(" ")
1025
+ else
1026
+ output += magenta("∅\n")
1027
+ end
1028
+ output += "\n"
1029
+
1030
+ output.gsub(/^/, " " * indent)
1031
+ end
1032
+ end
1033
+
1034
+ #: type serialized_ruby_literal_node = {
1035
+ #| content: String?,
1036
+ #| }
1037
+ class RubyLiteralNode < Node
1038
+ include Colors
1039
+
1040
+ attr_reader :content #: String?
1041
+
1042
+ #: (String, Location, Array[Herb::Errors::Error], String) -> void
1043
+ def initialize(type, location, errors, content)
1044
+ super(type, location, errors)
1045
+ @content = content&.force_encoding("utf-8")
1046
+ end
1047
+
1048
+ #: () -> serialized_ruby_literal_node
1049
+ def to_hash
1050
+ super.merge({
1051
+ content: content,
1052
+ }) #: Herb::serialized_ruby_literal_node
1053
+ end
1054
+
1055
+ #: (Visitor) -> void
1056
+ def accept(visitor)
1057
+ visitor.visit_ruby_literal_node(self)
1058
+ end
1059
+
1060
+ #: () -> Array[Herb::AST::Node?]
1061
+ def child_nodes
1062
+ []
1063
+ end
1064
+
1065
+ #: () -> Array[Herb::AST::Node]
1066
+ def compact_child_nodes
1067
+ child_nodes.compact
1068
+ end
1069
+
1070
+ #: () -> String
1071
+ def inspect
1072
+ tree_inspect.rstrip.gsub(/\s+$/, "")
1073
+ end
1074
+
1075
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
1076
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 10)
1077
+ output = +""
1078
+
1079
+ output += white("@ #{bold(yellow(node_name.to_s))} #{dimmed("(location: #{location.tree_inspect})")}")
1080
+ output += "\n"
1081
+
1082
+ if depth >= depth_limit
1083
+ output += dimmed("└── [depth limit reached ...]\n\n")
1084
+
1085
+ return output.gsub(/^/, " " * indent)
1086
+ end
1087
+
1088
+ output += inspect_errors(prefix: "│ ")
1089
+
1090
+ output += white("└── content: ") + green("#{content.inspect}\n")
1091
+ output += "\n"
1092
+
1093
+ output.gsub(/^/, " " * indent)
1094
+ end
1095
+ end
1096
+
1097
+ #: type serialized_ruby_html_attributes_splat_node = {
1098
+ #| content: String?,
1099
+ #| prefix: String?,
1100
+ #| }
1101
+ class RubyHTMLAttributesSplatNode < Node
1102
+ include Colors
1103
+
1104
+ attr_reader :content #: String?
1105
+ attr_reader :prefix #: String?
1106
+
1107
+ #: (String, Location, Array[Herb::Errors::Error], String, String) -> void
1108
+ def initialize(type, location, errors, content, prefix)
1109
+ super(type, location, errors)
1110
+ @content = content&.force_encoding("utf-8")
1111
+ @prefix = prefix&.force_encoding("utf-8")
1112
+ end
1113
+
1114
+ #: () -> serialized_ruby_html_attributes_splat_node
1115
+ def to_hash
1116
+ super.merge({
1117
+ content: content,
1118
+ prefix: prefix,
1119
+ }) #: Herb::serialized_ruby_html_attributes_splat_node
1120
+ end
1121
+
1122
+ #: (Visitor) -> void
1123
+ def accept(visitor)
1124
+ visitor.visit_ruby_html_attributes_splat_node(self)
1125
+ end
1126
+
1127
+ #: () -> Array[Herb::AST::Node?]
1128
+ def child_nodes
1129
+ []
1130
+ end
1131
+
1132
+ #: () -> Array[Herb::AST::Node]
1133
+ def compact_child_nodes
1134
+ child_nodes.compact
1135
+ end
1136
+
1137
+ #: () -> String
1138
+ def inspect
1139
+ tree_inspect.rstrip.gsub(/\s+$/, "")
1140
+ end
1141
+
1142
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
1143
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 10)
1144
+ output = +""
1145
+
1146
+ output += white("@ #{bold(yellow(node_name.to_s))} #{dimmed("(location: #{location.tree_inspect})")}")
1147
+ output += "\n"
1148
+
1149
+ if depth >= depth_limit
1150
+ output += dimmed("└── [depth limit reached ...]\n\n")
1151
+
1152
+ return output.gsub(/^/, " " * indent)
1153
+ end
1154
+
1155
+ output += inspect_errors(prefix: "│ ")
1156
+
1157
+ output += white("├── content: ") + green("#{content.inspect}\n")
1158
+ output += white("└── prefix: ") + green("#{prefix.inspect}\n")
1159
+ output += "\n"
1160
+
1161
+ output.gsub(/^/, " " * indent)
1162
+ end
1163
+ end
1164
+
1165
+ #: type serialized_erb_open_tag_node = {
1166
+ #| tag_opening: Herb::Token?,
1167
+ #| content: Herb::Token?,
1168
+ #| tag_closing: Herb::Token?,
1169
+ #| tag_name: Herb::Token?,
1170
+ #| children: Array[Herb::AST::Node],
1171
+ #| }
1172
+ class ERBOpenTagNode < Node
1173
+ include Colors
1174
+
1175
+ attr_reader :tag_opening #: Herb::Token?
1176
+ attr_reader :content #: Herb::Token?
1177
+ attr_reader :tag_closing #: Herb::Token?
1178
+ attr_reader :tag_name #: Herb::Token?
1179
+ attr_reader :children #: Array[Herb::AST::Node]
1180
+
1181
+ #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Herb::Token, Array[Herb::AST::Node]) -> void
1182
+ def initialize(type, location, errors, tag_opening, content, tag_closing, tag_name, children)
1183
+ super(type, location, errors)
1184
+ @tag_opening = tag_opening
1185
+ @content = content
1186
+ @tag_closing = tag_closing
1187
+ @tag_name = tag_name
1188
+ @children = children
1189
+ end
1190
+
1191
+ #: () -> serialized_erb_open_tag_node
1192
+ def to_hash
1193
+ super.merge({
1194
+ tag_opening: tag_opening,
1195
+ content: content,
1196
+ tag_closing: tag_closing,
1197
+ tag_name: tag_name,
1198
+ children: children,
1199
+ }) #: Herb::serialized_erb_open_tag_node
1200
+ end
1201
+
1202
+ #: (Visitor) -> void
1203
+ def accept(visitor)
1204
+ visitor.visit_erb_open_tag_node(self)
560
1205
  end
561
1206
 
562
1207
  #: () -> Array[Herb::AST::Node?]
563
1208
  def child_nodes
564
- [name, value]
1209
+ [*(children || [])]
565
1210
  end
566
1211
 
567
1212
  #: () -> Array[Herb::AST::Node]
@@ -589,40 +1234,38 @@ module Herb
589
1234
 
590
1235
  output += inspect_errors(prefix: "│ ")
591
1236
 
592
- output += white("├── name: ")
593
- if name
594
- output += "\n"
595
- output += "│ └── "
596
- output += name.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, "│ ").delete_prefix("│ ")
597
- else
598
- output += magenta("∅\n")
599
- end
600
- output += white("├── equals: ")
601
- output += equals ? equals.tree_inspect : magenta("∅")
1237
+ output += white("├── tag_opening: ")
1238
+ output += tag_opening ? tag_opening.tree_inspect : magenta("∅")
602
1239
  output += "\n"
603
- output += white("└── value: ")
604
- if value
605
- output += "\n"
606
- output += " └── "
607
- output += value.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, " ").delete_prefix(" ")
608
- else
609
- output += magenta("∅\n")
610
- end
1240
+ output += white("├── content: ")
1241
+ output += content ? content.tree_inspect : magenta("∅")
1242
+ output += "\n"
1243
+ output += white("├── tag_closing: ")
1244
+ output += tag_closing ? tag_closing.tree_inspect : magenta("")
1245
+ output += "\n"
1246
+ output += white("├── tag_name: ")
1247
+ output += tag_name ? tag_name.tree_inspect : magenta("∅")
1248
+ output += "\n"
1249
+ output += white("└── children: ")
1250
+ output += inspect_array(children, prefix: " ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
611
1251
  output += "\n"
612
1252
 
613
1253
  output.gsub(/^/, " " * indent)
614
1254
  end
615
1255
  end
616
1256
 
1257
+ #: type serialized_html_text_node = {
1258
+ #| content: String?,
1259
+ #| }
617
1260
  class HTMLTextNode < Node
618
1261
  include Colors
619
1262
 
620
- attr_reader :content #: String
1263
+ attr_reader :content #: String?
621
1264
 
622
1265
  #: (String, Location, Array[Herb::Errors::Error], String) -> void
623
1266
  def initialize(type, location, errors, content)
624
1267
  super(type, location, errors)
625
- @content = content.force_encoding("utf-8")
1268
+ @content = content&.force_encoding("utf-8")
626
1269
  end
627
1270
 
628
1271
  #: () -> serialized_html_text_node
@@ -674,12 +1317,17 @@ module Herb
674
1317
  end
675
1318
  end
676
1319
 
1320
+ #: type serialized_html_comment_node = {
1321
+ #| comment_start: Herb::Token?,
1322
+ #| children: Array[Herb::AST::Node],
1323
+ #| comment_end: Herb::Token?,
1324
+ #| }
677
1325
  class HTMLCommentNode < Node
678
1326
  include Colors
679
1327
 
680
- attr_reader :comment_start #: Herb::Token
1328
+ attr_reader :comment_start #: Herb::Token?
681
1329
  attr_reader :children #: Array[Herb::AST::Node]
682
- attr_reader :comment_end #: Herb::Token
1330
+ attr_reader :comment_end #: Herb::Token?
683
1331
 
684
1332
  #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Array[Herb::AST::Node], Herb::Token) -> void
685
1333
  def initialize(type, location, errors, comment_start, children, comment_end)
@@ -705,7 +1353,7 @@ module Herb
705
1353
 
706
1354
  #: () -> Array[Herb::AST::Node?]
707
1355
  def child_nodes
708
- [*children]
1356
+ [*(children || [])]
709
1357
  end
710
1358
 
711
1359
  #: () -> Array[Herb::AST::Node]
@@ -747,12 +1395,17 @@ module Herb
747
1395
  end
748
1396
  end
749
1397
 
1398
+ #: type serialized_html_doctype_node = {
1399
+ #| tag_opening: Herb::Token?,
1400
+ #| children: Array[Herb::AST::Node],
1401
+ #| tag_closing: Herb::Token?,
1402
+ #| }
750
1403
  class HTMLDoctypeNode < Node
751
1404
  include Colors
752
1405
 
753
- attr_reader :tag_opening #: Herb::Token
1406
+ attr_reader :tag_opening #: Herb::Token?
754
1407
  attr_reader :children #: Array[Herb::AST::Node]
755
- attr_reader :tag_closing #: Herb::Token
1408
+ attr_reader :tag_closing #: Herb::Token?
756
1409
 
757
1410
  #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Array[Herb::AST::Node], Herb::Token) -> void
758
1411
  def initialize(type, location, errors, tag_opening, children, tag_closing)
@@ -778,7 +1431,7 @@ module Herb
778
1431
 
779
1432
  #: () -> Array[Herb::AST::Node?]
780
1433
  def child_nodes
781
- [*children]
1434
+ [*(children || [])]
782
1435
  end
783
1436
 
784
1437
  #: () -> Array[Herb::AST::Node]
@@ -820,12 +1473,17 @@ module Herb
820
1473
  end
821
1474
  end
822
1475
 
1476
+ #: type serialized_xml_declaration_node = {
1477
+ #| tag_opening: Herb::Token?,
1478
+ #| children: Array[Herb::AST::Node],
1479
+ #| tag_closing: Herb::Token?,
1480
+ #| }
823
1481
  class XMLDeclarationNode < Node
824
1482
  include Colors
825
1483
 
826
- attr_reader :tag_opening #: Herb::Token
1484
+ attr_reader :tag_opening #: Herb::Token?
827
1485
  attr_reader :children #: Array[Herb::AST::Node]
828
- attr_reader :tag_closing #: Herb::Token
1486
+ attr_reader :tag_closing #: Herb::Token?
829
1487
 
830
1488
  #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Array[Herb::AST::Node], Herb::Token) -> void
831
1489
  def initialize(type, location, errors, tag_opening, children, tag_closing)
@@ -851,7 +1509,7 @@ module Herb
851
1509
 
852
1510
  #: () -> Array[Herb::AST::Node?]
853
1511
  def child_nodes
854
- [*children]
1512
+ [*(children || [])]
855
1513
  end
856
1514
 
857
1515
  #: () -> Array[Herb::AST::Node]
@@ -893,12 +1551,17 @@ module Herb
893
1551
  end
894
1552
  end
895
1553
 
1554
+ #: type serialized_cdata_node = {
1555
+ #| tag_opening: Herb::Token?,
1556
+ #| children: Array[Herb::AST::Node],
1557
+ #| tag_closing: Herb::Token?,
1558
+ #| }
896
1559
  class CDATANode < Node
897
1560
  include Colors
898
1561
 
899
- attr_reader :tag_opening #: Herb::Token
1562
+ attr_reader :tag_opening #: Herb::Token?
900
1563
  attr_reader :children #: Array[Herb::AST::Node]
901
- attr_reader :tag_closing #: Herb::Token
1564
+ attr_reader :tag_closing #: Herb::Token?
902
1565
 
903
1566
  #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Array[Herb::AST::Node], Herb::Token) -> void
904
1567
  def initialize(type, location, errors, tag_opening, children, tag_closing)
@@ -924,7 +1587,7 @@ module Herb
924
1587
 
925
1588
  #: () -> Array[Herb::AST::Node?]
926
1589
  def child_nodes
927
- [*children]
1590
+ [*(children || [])]
928
1591
  end
929
1592
 
930
1593
  #: () -> Array[Herb::AST::Node]
@@ -966,10 +1629,13 @@ module Herb
966
1629
  end
967
1630
  end
968
1631
 
1632
+ #: type serialized_whitespace_node = {
1633
+ #| value: Herb::Token?,
1634
+ #| }
969
1635
  class WhitespaceNode < Node
970
1636
  include Colors
971
1637
 
972
- attr_reader :value #: Herb::Token
1638
+ attr_reader :value #: Herb::Token?
973
1639
 
974
1640
  #: (String, Location, Array[Herb::Errors::Error], Herb::Token) -> void
975
1641
  def initialize(type, location, errors, value)
@@ -1028,18 +1694,28 @@ module Herb
1028
1694
  end
1029
1695
  end
1030
1696
 
1697
+ #: type serialized_erb_content_node = {
1698
+ #| tag_opening: Herb::Token?,
1699
+ #| content: Herb::Token?,
1700
+ #| tag_closing: Herb::Token?,
1701
+ #| analyzed_ruby: nil,
1702
+ #| parsed: bool,
1703
+ #| valid: bool,
1704
+ #| prism_node: String?,
1705
+ #| }
1031
1706
  class ERBContentNode < Node
1032
1707
  include Colors
1033
1708
 
1034
- attr_reader :tag_opening #: Herb::Token
1035
- attr_reader :content #: Herb::Token
1036
- attr_reader :tag_closing #: Herb::Token
1709
+ attr_reader :tag_opening #: Herb::Token?
1710
+ attr_reader :content #: Herb::Token?
1711
+ attr_reader :tag_closing #: Herb::Token?
1037
1712
  attr_reader :analyzed_ruby #: nil
1038
1713
  attr_reader :parsed #: bool
1039
1714
  attr_reader :valid #: bool
1715
+ attr_reader :prism_node #: String?
1040
1716
 
1041
- #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, nil, bool, bool) -> void
1042
- def initialize(type, location, errors, tag_opening, content, tag_closing, analyzed_ruby, parsed, valid)
1717
+ #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, nil, bool, bool, String) -> void
1718
+ def initialize(type, location, errors, tag_opening, content, tag_closing, analyzed_ruby, parsed, valid, prism_node)
1043
1719
  super(type, location, errors)
1044
1720
  @tag_opening = tag_opening
1045
1721
  @content = content
@@ -1047,6 +1723,23 @@ module Herb
1047
1723
  @analyzed_ruby = analyzed_ruby
1048
1724
  @parsed = parsed
1049
1725
  @valid = valid
1726
+ @prism_node = prism_node
1727
+ end
1728
+
1729
+ #: () -> Prism::node?
1730
+ def deserialized_prism_node
1731
+ prism_node = @prism_node
1732
+ return nil unless prism_node
1733
+ return nil unless source
1734
+
1735
+ begin
1736
+ require "prism"
1737
+ rescue LoadError
1738
+ warn "The 'prism' gem is required to deserialize Prism nodes. Add it to your Gemfile or install it with: gem install prism"
1739
+ return nil
1740
+ end
1741
+
1742
+ Prism.load(source, prism_node).value
1050
1743
  end
1051
1744
 
1052
1745
  #: () -> serialized_erb_content_node
@@ -1058,6 +1751,7 @@ module Herb
1058
1751
  analyzed_ruby: analyzed_ruby,
1059
1752
  parsed: parsed,
1060
1753
  valid: valid,
1754
+ prism_node: prism_node,
1061
1755
  }) #: Herb::serialized_erb_content_node
1062
1756
  end
1063
1757
 
@@ -1105,25 +1799,35 @@ module Herb
1105
1799
  output += white("├── tag_closing: ")
1106
1800
  output += tag_closing ? tag_closing.tree_inspect : magenta("∅")
1107
1801
  output += "\n"
1108
- # no-op for analyzed_ruby
1109
1802
  output += white("├── parsed: ")
1110
1803
  output += [true, false].include?(parsed) ? bold(magenta(parsed.to_s)) : magenta("∅")
1111
1804
  output += "\n"
1112
- output += white("└── valid: ")
1805
+ dynamic_symbol = prism_node ? "├──" : "└──"
1806
+ output += white("#{dynamic_symbol} valid: ")
1113
1807
  output += [true, false].include?(valid) ? bold(magenta(valid.to_s)) : magenta("∅")
1114
1808
  output += "\n"
1809
+ if prism_node && source
1810
+ output += white("└── prism_node: ")
1811
+ output += Herb::PrismInspect.inspect_prism_serialized(prism_node, source, " ")
1812
+ output += "\n"
1813
+ end
1115
1814
  output += "\n"
1116
1815
 
1117
1816
  output.gsub(/^/, " " * indent)
1118
1817
  end
1119
1818
  end
1120
1819
 
1820
+ #: type serialized_erb_end_node = {
1821
+ #| tag_opening: Herb::Token?,
1822
+ #| content: Herb::Token?,
1823
+ #| tag_closing: Herb::Token?,
1824
+ #| }
1121
1825
  class ERBEndNode < Node
1122
1826
  include Colors
1123
1827
 
1124
- attr_reader :tag_opening #: Herb::Token
1125
- attr_reader :content #: Herb::Token
1126
- attr_reader :tag_closing #: Herb::Token
1828
+ attr_reader :tag_opening #: Herb::Token?
1829
+ attr_reader :content #: Herb::Token?
1830
+ attr_reader :tag_closing #: Herb::Token?
1127
1831
 
1128
1832
  #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token) -> void
1129
1833
  def initialize(type, location, errors, tag_opening, content, tag_closing)
@@ -1192,12 +1896,18 @@ module Herb
1192
1896
  end
1193
1897
  end
1194
1898
 
1899
+ #: type serialized_erb_else_node = {
1900
+ #| tag_opening: Herb::Token?,
1901
+ #| content: Herb::Token?,
1902
+ #| tag_closing: Herb::Token?,
1903
+ #| statements: Array[Herb::AST::Node],
1904
+ #| }
1195
1905
  class ERBElseNode < Node
1196
1906
  include Colors
1197
1907
 
1198
- attr_reader :tag_opening #: Herb::Token
1199
- attr_reader :content #: Herb::Token
1200
- attr_reader :tag_closing #: Herb::Token
1908
+ attr_reader :tag_opening #: Herb::Token?
1909
+ attr_reader :content #: Herb::Token?
1910
+ attr_reader :tag_closing #: Herb::Token?
1201
1911
  attr_reader :statements #: Array[Herb::AST::Node]
1202
1912
 
1203
1913
  #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Array[Herb::AST::Node]) -> void
@@ -1226,7 +1936,7 @@ module Herb
1226
1936
 
1227
1937
  #: () -> Array[Herb::AST::Node?]
1228
1938
  def child_nodes
1229
- [*statements]
1939
+ [*(statements || [])]
1230
1940
  end
1231
1941
 
1232
1942
  #: () -> Array[Herb::AST::Node]
@@ -1271,29 +1981,57 @@ module Herb
1271
1981
  end
1272
1982
  end
1273
1983
 
1984
+ #: type serialized_erb_if_node = {
1985
+ #| tag_opening: Herb::Token?,
1986
+ #| content: Herb::Token?,
1987
+ #| tag_closing: Herb::Token?,
1988
+ #| then_keyword: Herb::Location?,
1989
+ #| prism_node: String?,
1990
+ #| statements: Array[Herb::AST::Node],
1991
+ #| subsequent: (Herb::AST::ERBIfNode | Herb::AST::ERBElseNode)?,
1992
+ #| end_node: Herb::AST::ERBEndNode?,
1993
+ #| }
1274
1994
  class ERBIfNode < Node
1275
1995
  include Colors
1276
1996
 
1277
- attr_reader :tag_opening #: Herb::Token
1278
- attr_reader :content #: Herb::Token
1279
- attr_reader :tag_closing #: Herb::Token
1280
- attr_reader :then_keyword #: Herb::Location
1997
+ attr_reader :tag_opening #: Herb::Token?
1998
+ attr_reader :content #: Herb::Token?
1999
+ attr_reader :tag_closing #: Herb::Token?
2000
+ attr_reader :then_keyword #: Herb::Location?
2001
+ attr_reader :prism_node #: String?
1281
2002
  attr_reader :statements #: Array[Herb::AST::Node]
1282
- attr_reader :subsequent #: Herb::AST::Node
1283
- attr_reader :end_node #: Herb::AST::ERBEndNode
2003
+ attr_reader :subsequent #: (Herb::AST::ERBIfNode | Herb::AST::ERBElseNode)?
2004
+ attr_reader :end_node #: Herb::AST::ERBEndNode?
1284
2005
 
1285
- #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Herb::Location, Array[Herb::AST::Node], Herb::AST::Node, Herb::AST::ERBEndNode) -> void
1286
- def initialize(type, location, errors, tag_opening, content, tag_closing, then_keyword, statements, subsequent, end_node)
2006
+ #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Herb::Location, String, Array[Herb::AST::Node], (Herb::AST::ERBIfNode | Herb::AST::ERBElseNode), Herb::AST::ERBEndNode) -> void
2007
+ def initialize(type, location, errors, tag_opening, content, tag_closing, then_keyword, prism_node, statements, subsequent, end_node)
1287
2008
  super(type, location, errors)
1288
2009
  @tag_opening = tag_opening
1289
2010
  @content = content
1290
2011
  @tag_closing = tag_closing
1291
2012
  @then_keyword = then_keyword
2013
+ @prism_node = prism_node
1292
2014
  @statements = statements
1293
2015
  @subsequent = subsequent
1294
2016
  @end_node = end_node
1295
2017
  end
1296
2018
 
2019
+ #: () -> Prism::node?
2020
+ def deserialized_prism_node
2021
+ prism_node = @prism_node
2022
+ return nil unless prism_node
2023
+ return nil unless source
2024
+
2025
+ begin
2026
+ require "prism"
2027
+ rescue LoadError
2028
+ warn "The 'prism' gem is required to deserialize Prism nodes. Add it to your Gemfile or install it with: gem install prism"
2029
+ return nil
2030
+ end
2031
+
2032
+ Prism.load(source, prism_node).value
2033
+ end
2034
+
1297
2035
  #: () -> serialized_erb_if_node
1298
2036
  def to_hash
1299
2037
  super.merge({
@@ -1301,6 +2039,7 @@ module Herb
1301
2039
  content: content,
1302
2040
  tag_closing: tag_closing,
1303
2041
  then_keyword: then_keyword,
2042
+ prism_node: prism_node,
1304
2043
  statements: statements,
1305
2044
  subsequent: subsequent,
1306
2045
  end_node: end_node,
@@ -1314,7 +2053,7 @@ module Herb
1314
2053
 
1315
2054
  #: () -> Array[Herb::AST::Node?]
1316
2055
  def child_nodes
1317
- [*statements, subsequent, end_node]
2056
+ [*(statements || []), subsequent, end_node]
1318
2057
  end
1319
2058
 
1320
2059
  #: () -> Array[Herb::AST::Node]
@@ -1354,6 +2093,11 @@ module Herb
1354
2093
  output += white("├── then_keyword: ")
1355
2094
  output += then_keyword ? dimmed("(location: #{then_keyword.tree_inspect})") : magenta("∅")
1356
2095
  output += "\n"
2096
+ if prism_node && source
2097
+ output += white("├── prism_node: ")
2098
+ output += Herb::PrismInspect.inspect_prism_serialized(prism_node, source, "│ ")
2099
+ output += "\n"
2100
+ end
1357
2101
  output += white("├── statements: ")
1358
2102
  output += inspect_array(statements, prefix: "│ ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
1359
2103
  output += white("├── subsequent: ")
@@ -1378,31 +2122,58 @@ module Herb
1378
2122
  end
1379
2123
  end
1380
2124
 
2125
+ #: type serialized_erb_block_node = {
2126
+ #| tag_opening: Herb::Token?,
2127
+ #| content: Herb::Token?,
2128
+ #| tag_closing: Herb::Token?,
2129
+ #| prism_node: String?,
2130
+ #| body: Array[Herb::AST::Node],
2131
+ #| end_node: Herb::AST::ERBEndNode?,
2132
+ #| }
1381
2133
  class ERBBlockNode < Node
1382
2134
  include Colors
1383
2135
 
1384
- attr_reader :tag_opening #: Herb::Token
1385
- attr_reader :content #: Herb::Token
1386
- attr_reader :tag_closing #: Herb::Token
2136
+ attr_reader :tag_opening #: Herb::Token?
2137
+ attr_reader :content #: Herb::Token?
2138
+ attr_reader :tag_closing #: Herb::Token?
2139
+ attr_reader :prism_node #: String?
1387
2140
  attr_reader :body #: Array[Herb::AST::Node]
1388
- attr_reader :end_node #: Herb::AST::ERBEndNode
2141
+ attr_reader :end_node #: Herb::AST::ERBEndNode?
1389
2142
 
1390
- #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Array[Herb::AST::Node], Herb::AST::ERBEndNode) -> void
1391
- def initialize(type, location, errors, tag_opening, content, tag_closing, body, end_node)
2143
+ #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, String, Array[Herb::AST::Node], Herb::AST::ERBEndNode) -> void
2144
+ def initialize(type, location, errors, tag_opening, content, tag_closing, prism_node, body, end_node)
1392
2145
  super(type, location, errors)
1393
2146
  @tag_opening = tag_opening
1394
2147
  @content = content
1395
2148
  @tag_closing = tag_closing
2149
+ @prism_node = prism_node
1396
2150
  @body = body
1397
2151
  @end_node = end_node
1398
2152
  end
1399
2153
 
2154
+ #: () -> Prism::node?
2155
+ def deserialized_prism_node
2156
+ prism_node = @prism_node
2157
+ return nil unless prism_node
2158
+ return nil unless source
2159
+
2160
+ begin
2161
+ require "prism"
2162
+ rescue LoadError
2163
+ warn "The 'prism' gem is required to deserialize Prism nodes. Add it to your Gemfile or install it with: gem install prism"
2164
+ return nil
2165
+ end
2166
+
2167
+ Prism.load(source, prism_node).value
2168
+ end
2169
+
1400
2170
  #: () -> serialized_erb_block_node
1401
2171
  def to_hash
1402
2172
  super.merge({
1403
2173
  tag_opening: tag_opening,
1404
2174
  content: content,
1405
2175
  tag_closing: tag_closing,
2176
+ prism_node: prism_node,
1406
2177
  body: body,
1407
2178
  end_node: end_node,
1408
2179
  }) #: Herb::serialized_erb_block_node
@@ -1415,7 +2186,7 @@ module Herb
1415
2186
 
1416
2187
  #: () -> Array[Herb::AST::Node?]
1417
2188
  def child_nodes
1418
- [*body, end_node]
2189
+ [*(body || []), end_node]
1419
2190
  end
1420
2191
 
1421
2192
  #: () -> Array[Herb::AST::Node]
@@ -1452,6 +2223,11 @@ module Herb
1452
2223
  output += white("├── tag_closing: ")
1453
2224
  output += tag_closing ? tag_closing.tree_inspect : magenta("∅")
1454
2225
  output += "\n"
2226
+ if prism_node && source
2227
+ output += white("├── prism_node: ")
2228
+ output += Herb::PrismInspect.inspect_prism_serialized(prism_node, source, "│ ")
2229
+ output += "\n"
2230
+ end
1455
2231
  output += white("├── body: ")
1456
2232
  output += inspect_array(body, prefix: "│ ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
1457
2233
  output += white("└── end_node: ")
@@ -1468,13 +2244,20 @@ module Herb
1468
2244
  end
1469
2245
  end
1470
2246
 
2247
+ #: type serialized_erb_when_node = {
2248
+ #| tag_opening: Herb::Token?,
2249
+ #| content: Herb::Token?,
2250
+ #| tag_closing: Herb::Token?,
2251
+ #| then_keyword: Herb::Location?,
2252
+ #| statements: Array[Herb::AST::Node],
2253
+ #| }
1471
2254
  class ERBWhenNode < Node
1472
2255
  include Colors
1473
2256
 
1474
- attr_reader :tag_opening #: Herb::Token
1475
- attr_reader :content #: Herb::Token
1476
- attr_reader :tag_closing #: Herb::Token
1477
- attr_reader :then_keyword #: Herb::Location
2257
+ attr_reader :tag_opening #: Herb::Token?
2258
+ attr_reader :content #: Herb::Token?
2259
+ attr_reader :tag_closing #: Herb::Token?
2260
+ attr_reader :then_keyword #: Herb::Location?
1478
2261
  attr_reader :statements #: Array[Herb::AST::Node]
1479
2262
 
1480
2263
  #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Herb::Location, Array[Herb::AST::Node]) -> void
@@ -1505,7 +2288,7 @@ module Herb
1505
2288
 
1506
2289
  #: () -> Array[Herb::AST::Node?]
1507
2290
  def child_nodes
1508
- [*statements]
2291
+ [*(statements || [])]
1509
2292
  end
1510
2293
 
1511
2294
  #: () -> Array[Herb::AST::Node]
@@ -1553,29 +2336,57 @@ module Herb
1553
2336
  end
1554
2337
  end
1555
2338
 
2339
+ #: type serialized_erb_case_node = {
2340
+ #| tag_opening: Herb::Token?,
2341
+ #| content: Herb::Token?,
2342
+ #| tag_closing: Herb::Token?,
2343
+ #| children: Array[Herb::AST::Node],
2344
+ #| prism_node: String?,
2345
+ #| conditions: Array[Herb::AST::ERBWhenNode],
2346
+ #| else_clause: Herb::AST::ERBElseNode?,
2347
+ #| end_node: Herb::AST::ERBEndNode?,
2348
+ #| }
1556
2349
  class ERBCaseNode < Node
1557
2350
  include Colors
1558
2351
 
1559
- attr_reader :tag_opening #: Herb::Token
1560
- attr_reader :content #: Herb::Token
1561
- attr_reader :tag_closing #: Herb::Token
2352
+ attr_reader :tag_opening #: Herb::Token?
2353
+ attr_reader :content #: Herb::Token?
2354
+ attr_reader :tag_closing #: Herb::Token?
1562
2355
  attr_reader :children #: Array[Herb::AST::Node]
2356
+ attr_reader :prism_node #: String?
1563
2357
  attr_reader :conditions #: Array[Herb::AST::ERBWhenNode]
1564
- attr_reader :else_clause #: Herb::AST::ERBElseNode
1565
- attr_reader :end_node #: Herb::AST::ERBEndNode
2358
+ attr_reader :else_clause #: Herb::AST::ERBElseNode?
2359
+ attr_reader :end_node #: Herb::AST::ERBEndNode?
1566
2360
 
1567
- #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Array[Herb::AST::Node], Array[Herb::AST::ERBWhenNode], Herb::AST::ERBElseNode, Herb::AST::ERBEndNode) -> void
1568
- def initialize(type, location, errors, tag_opening, content, tag_closing, children, conditions, else_clause, end_node)
2361
+ #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Array[Herb::AST::Node], String, Array[Herb::AST::ERBWhenNode], Herb::AST::ERBElseNode, Herb::AST::ERBEndNode) -> void
2362
+ def initialize(type, location, errors, tag_opening, content, tag_closing, children, prism_node, conditions, else_clause, end_node)
1569
2363
  super(type, location, errors)
1570
2364
  @tag_opening = tag_opening
1571
2365
  @content = content
1572
2366
  @tag_closing = tag_closing
1573
2367
  @children = children
2368
+ @prism_node = prism_node
1574
2369
  @conditions = conditions
1575
2370
  @else_clause = else_clause
1576
2371
  @end_node = end_node
1577
2372
  end
1578
2373
 
2374
+ #: () -> Prism::node?
2375
+ def deserialized_prism_node
2376
+ prism_node = @prism_node
2377
+ return nil unless prism_node
2378
+ return nil unless source
2379
+
2380
+ begin
2381
+ require "prism"
2382
+ rescue LoadError
2383
+ warn "The 'prism' gem is required to deserialize Prism nodes. Add it to your Gemfile or install it with: gem install prism"
2384
+ return nil
2385
+ end
2386
+
2387
+ Prism.load(source, prism_node).value
2388
+ end
2389
+
1579
2390
  #: () -> serialized_erb_case_node
1580
2391
  def to_hash
1581
2392
  super.merge({
@@ -1583,6 +2394,7 @@ module Herb
1583
2394
  content: content,
1584
2395
  tag_closing: tag_closing,
1585
2396
  children: children,
2397
+ prism_node: prism_node,
1586
2398
  conditions: conditions,
1587
2399
  else_clause: else_clause,
1588
2400
  end_node: end_node,
@@ -1596,7 +2408,7 @@ module Herb
1596
2408
 
1597
2409
  #: () -> Array[Herb::AST::Node?]
1598
2410
  def child_nodes
1599
- [*children, *conditions, else_clause, end_node]
2411
+ [*(children || []), *(conditions || []), else_clause, end_node]
1600
2412
  end
1601
2413
 
1602
2414
  #: () -> Array[Herb::AST::Node]
@@ -1635,6 +2447,11 @@ module Herb
1635
2447
  output += "\n"
1636
2448
  output += white("├── children: ")
1637
2449
  output += inspect_array(children, prefix: "│ ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
2450
+ if prism_node && source
2451
+ output += white("├── prism_node: ")
2452
+ output += Herb::PrismInspect.inspect_prism_serialized(prism_node, source, "│ ")
2453
+ output += "\n"
2454
+ end
1638
2455
  output += white("├── conditions: ")
1639
2456
  output += inspect_array(conditions, prefix: "│ ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
1640
2457
  output += white("├── else_clause: ")
@@ -1659,29 +2476,57 @@ module Herb
1659
2476
  end
1660
2477
  end
1661
2478
 
2479
+ #: type serialized_erb_case_match_node = {
2480
+ #| tag_opening: Herb::Token?,
2481
+ #| content: Herb::Token?,
2482
+ #| tag_closing: Herb::Token?,
2483
+ #| children: Array[Herb::AST::Node],
2484
+ #| prism_node: String?,
2485
+ #| conditions: Array[Herb::AST::ERBInNode],
2486
+ #| else_clause: Herb::AST::ERBElseNode?,
2487
+ #| end_node: Herb::AST::ERBEndNode?,
2488
+ #| }
1662
2489
  class ERBCaseMatchNode < Node
1663
2490
  include Colors
1664
2491
 
1665
- attr_reader :tag_opening #: Herb::Token
1666
- attr_reader :content #: Herb::Token
1667
- attr_reader :tag_closing #: Herb::Token
2492
+ attr_reader :tag_opening #: Herb::Token?
2493
+ attr_reader :content #: Herb::Token?
2494
+ attr_reader :tag_closing #: Herb::Token?
1668
2495
  attr_reader :children #: Array[Herb::AST::Node]
2496
+ attr_reader :prism_node #: String?
1669
2497
  attr_reader :conditions #: Array[Herb::AST::ERBInNode]
1670
- attr_reader :else_clause #: Herb::AST::ERBElseNode
1671
- attr_reader :end_node #: Herb::AST::ERBEndNode
2498
+ attr_reader :else_clause #: Herb::AST::ERBElseNode?
2499
+ attr_reader :end_node #: Herb::AST::ERBEndNode?
1672
2500
 
1673
- #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Array[Herb::AST::Node], Array[Herb::AST::ERBInNode], Herb::AST::ERBElseNode, Herb::AST::ERBEndNode) -> void
1674
- def initialize(type, location, errors, tag_opening, content, tag_closing, children, conditions, else_clause, end_node)
2501
+ #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Array[Herb::AST::Node], String, Array[Herb::AST::ERBInNode], Herb::AST::ERBElseNode, Herb::AST::ERBEndNode) -> void
2502
+ def initialize(type, location, errors, tag_opening, content, tag_closing, children, prism_node, conditions, else_clause, end_node)
1675
2503
  super(type, location, errors)
1676
2504
  @tag_opening = tag_opening
1677
2505
  @content = content
1678
2506
  @tag_closing = tag_closing
1679
2507
  @children = children
2508
+ @prism_node = prism_node
1680
2509
  @conditions = conditions
1681
2510
  @else_clause = else_clause
1682
2511
  @end_node = end_node
1683
2512
  end
1684
2513
 
2514
+ #: () -> Prism::node?
2515
+ def deserialized_prism_node
2516
+ prism_node = @prism_node
2517
+ return nil unless prism_node
2518
+ return nil unless source
2519
+
2520
+ begin
2521
+ require "prism"
2522
+ rescue LoadError
2523
+ warn "The 'prism' gem is required to deserialize Prism nodes. Add it to your Gemfile or install it with: gem install prism"
2524
+ return nil
2525
+ end
2526
+
2527
+ Prism.load(source, prism_node).value
2528
+ end
2529
+
1685
2530
  #: () -> serialized_erb_case_match_node
1686
2531
  def to_hash
1687
2532
  super.merge({
@@ -1689,6 +2534,7 @@ module Herb
1689
2534
  content: content,
1690
2535
  tag_closing: tag_closing,
1691
2536
  children: children,
2537
+ prism_node: prism_node,
1692
2538
  conditions: conditions,
1693
2539
  else_clause: else_clause,
1694
2540
  end_node: end_node,
@@ -1702,7 +2548,7 @@ module Herb
1702
2548
 
1703
2549
  #: () -> Array[Herb::AST::Node?]
1704
2550
  def child_nodes
1705
- [*children, *conditions, else_clause, end_node]
2551
+ [*(children || []), *(conditions || []), else_clause, end_node]
1706
2552
  end
1707
2553
 
1708
2554
  #: () -> Array[Herb::AST::Node]
@@ -1741,6 +2587,11 @@ module Herb
1741
2587
  output += "\n"
1742
2588
  output += white("├── children: ")
1743
2589
  output += inspect_array(children, prefix: "│ ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
2590
+ if prism_node && source
2591
+ output += white("├── prism_node: ")
2592
+ output += Herb::PrismInspect.inspect_prism_serialized(prism_node, source, "│ ")
2593
+ output += "\n"
2594
+ end
1744
2595
  output += white("├── conditions: ")
1745
2596
  output += inspect_array(conditions, prefix: "│ ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
1746
2597
  output += white("├── else_clause: ")
@@ -1765,31 +2616,58 @@ module Herb
1765
2616
  end
1766
2617
  end
1767
2618
 
2619
+ #: type serialized_erb_while_node = {
2620
+ #| tag_opening: Herb::Token?,
2621
+ #| content: Herb::Token?,
2622
+ #| tag_closing: Herb::Token?,
2623
+ #| prism_node: String?,
2624
+ #| statements: Array[Herb::AST::Node],
2625
+ #| end_node: Herb::AST::ERBEndNode?,
2626
+ #| }
1768
2627
  class ERBWhileNode < Node
1769
2628
  include Colors
1770
2629
 
1771
- attr_reader :tag_opening #: Herb::Token
1772
- attr_reader :content #: Herb::Token
1773
- attr_reader :tag_closing #: Herb::Token
2630
+ attr_reader :tag_opening #: Herb::Token?
2631
+ attr_reader :content #: Herb::Token?
2632
+ attr_reader :tag_closing #: Herb::Token?
2633
+ attr_reader :prism_node #: String?
1774
2634
  attr_reader :statements #: Array[Herb::AST::Node]
1775
- attr_reader :end_node #: Herb::AST::ERBEndNode
2635
+ attr_reader :end_node #: Herb::AST::ERBEndNode?
1776
2636
 
1777
- #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Array[Herb::AST::Node], Herb::AST::ERBEndNode) -> void
1778
- def initialize(type, location, errors, tag_opening, content, tag_closing, statements, end_node)
2637
+ #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, String, Array[Herb::AST::Node], Herb::AST::ERBEndNode) -> void
2638
+ def initialize(type, location, errors, tag_opening, content, tag_closing, prism_node, statements, end_node)
1779
2639
  super(type, location, errors)
1780
2640
  @tag_opening = tag_opening
1781
2641
  @content = content
1782
2642
  @tag_closing = tag_closing
2643
+ @prism_node = prism_node
1783
2644
  @statements = statements
1784
2645
  @end_node = end_node
1785
2646
  end
1786
2647
 
2648
+ #: () -> Prism::node?
2649
+ def deserialized_prism_node
2650
+ prism_node = @prism_node
2651
+ return nil unless prism_node
2652
+ return nil unless source
2653
+
2654
+ begin
2655
+ require "prism"
2656
+ rescue LoadError
2657
+ warn "The 'prism' gem is required to deserialize Prism nodes. Add it to your Gemfile or install it with: gem install prism"
2658
+ return nil
2659
+ end
2660
+
2661
+ Prism.load(source, prism_node).value
2662
+ end
2663
+
1787
2664
  #: () -> serialized_erb_while_node
1788
2665
  def to_hash
1789
2666
  super.merge({
1790
2667
  tag_opening: tag_opening,
1791
2668
  content: content,
1792
2669
  tag_closing: tag_closing,
2670
+ prism_node: prism_node,
1793
2671
  statements: statements,
1794
2672
  end_node: end_node,
1795
2673
  }) #: Herb::serialized_erb_while_node
@@ -1802,7 +2680,7 @@ module Herb
1802
2680
 
1803
2681
  #: () -> Array[Herb::AST::Node?]
1804
2682
  def child_nodes
1805
- [*statements, end_node]
2683
+ [*(statements || []), end_node]
1806
2684
  end
1807
2685
 
1808
2686
  #: () -> Array[Herb::AST::Node]
@@ -1839,6 +2717,11 @@ module Herb
1839
2717
  output += white("├── tag_closing: ")
1840
2718
  output += tag_closing ? tag_closing.tree_inspect : magenta("∅")
1841
2719
  output += "\n"
2720
+ if prism_node && source
2721
+ output += white("├── prism_node: ")
2722
+ output += Herb::PrismInspect.inspect_prism_serialized(prism_node, source, "│ ")
2723
+ output += "\n"
2724
+ end
1842
2725
  output += white("├── statements: ")
1843
2726
  output += inspect_array(statements, prefix: "│ ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
1844
2727
  output += white("└── end_node: ")
@@ -1855,31 +2738,58 @@ module Herb
1855
2738
  end
1856
2739
  end
1857
2740
 
2741
+ #: type serialized_erb_until_node = {
2742
+ #| tag_opening: Herb::Token?,
2743
+ #| content: Herb::Token?,
2744
+ #| tag_closing: Herb::Token?,
2745
+ #| prism_node: String?,
2746
+ #| statements: Array[Herb::AST::Node],
2747
+ #| end_node: Herb::AST::ERBEndNode?,
2748
+ #| }
1858
2749
  class ERBUntilNode < Node
1859
2750
  include Colors
1860
2751
 
1861
- attr_reader :tag_opening #: Herb::Token
1862
- attr_reader :content #: Herb::Token
1863
- attr_reader :tag_closing #: Herb::Token
2752
+ attr_reader :tag_opening #: Herb::Token?
2753
+ attr_reader :content #: Herb::Token?
2754
+ attr_reader :tag_closing #: Herb::Token?
2755
+ attr_reader :prism_node #: String?
1864
2756
  attr_reader :statements #: Array[Herb::AST::Node]
1865
- attr_reader :end_node #: Herb::AST::ERBEndNode
2757
+ attr_reader :end_node #: Herb::AST::ERBEndNode?
1866
2758
 
1867
- #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Array[Herb::AST::Node], Herb::AST::ERBEndNode) -> void
1868
- def initialize(type, location, errors, tag_opening, content, tag_closing, statements, end_node)
2759
+ #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, String, Array[Herb::AST::Node], Herb::AST::ERBEndNode) -> void
2760
+ def initialize(type, location, errors, tag_opening, content, tag_closing, prism_node, statements, end_node)
1869
2761
  super(type, location, errors)
1870
2762
  @tag_opening = tag_opening
1871
2763
  @content = content
1872
2764
  @tag_closing = tag_closing
2765
+ @prism_node = prism_node
1873
2766
  @statements = statements
1874
2767
  @end_node = end_node
1875
2768
  end
1876
2769
 
2770
+ #: () -> Prism::node?
2771
+ def deserialized_prism_node
2772
+ prism_node = @prism_node
2773
+ return nil unless prism_node
2774
+ return nil unless source
2775
+
2776
+ begin
2777
+ require "prism"
2778
+ rescue LoadError
2779
+ warn "The 'prism' gem is required to deserialize Prism nodes. Add it to your Gemfile or install it with: gem install prism"
2780
+ return nil
2781
+ end
2782
+
2783
+ Prism.load(source, prism_node).value
2784
+ end
2785
+
1877
2786
  #: () -> serialized_erb_until_node
1878
2787
  def to_hash
1879
2788
  super.merge({
1880
2789
  tag_opening: tag_opening,
1881
2790
  content: content,
1882
2791
  tag_closing: tag_closing,
2792
+ prism_node: prism_node,
1883
2793
  statements: statements,
1884
2794
  end_node: end_node,
1885
2795
  }) #: Herb::serialized_erb_until_node
@@ -1892,7 +2802,7 @@ module Herb
1892
2802
 
1893
2803
  #: () -> Array[Herb::AST::Node?]
1894
2804
  def child_nodes
1895
- [*statements, end_node]
2805
+ [*(statements || []), end_node]
1896
2806
  end
1897
2807
 
1898
2808
  #: () -> Array[Herb::AST::Node]
@@ -1929,6 +2839,11 @@ module Herb
1929
2839
  output += white("├── tag_closing: ")
1930
2840
  output += tag_closing ? tag_closing.tree_inspect : magenta("∅")
1931
2841
  output += "\n"
2842
+ if prism_node && source
2843
+ output += white("├── prism_node: ")
2844
+ output += Herb::PrismInspect.inspect_prism_serialized(prism_node, source, "│ ")
2845
+ output += "\n"
2846
+ end
1932
2847
  output += white("├── statements: ")
1933
2848
  output += inspect_array(statements, prefix: "│ ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
1934
2849
  output += white("└── end_node: ")
@@ -1945,31 +2860,58 @@ module Herb
1945
2860
  end
1946
2861
  end
1947
2862
 
2863
+ #: type serialized_erb_for_node = {
2864
+ #| tag_opening: Herb::Token?,
2865
+ #| content: Herb::Token?,
2866
+ #| tag_closing: Herb::Token?,
2867
+ #| prism_node: String?,
2868
+ #| statements: Array[Herb::AST::Node],
2869
+ #| end_node: Herb::AST::ERBEndNode?,
2870
+ #| }
1948
2871
  class ERBForNode < Node
1949
2872
  include Colors
1950
2873
 
1951
- attr_reader :tag_opening #: Herb::Token
1952
- attr_reader :content #: Herb::Token
1953
- attr_reader :tag_closing #: Herb::Token
2874
+ attr_reader :tag_opening #: Herb::Token?
2875
+ attr_reader :content #: Herb::Token?
2876
+ attr_reader :tag_closing #: Herb::Token?
2877
+ attr_reader :prism_node #: String?
1954
2878
  attr_reader :statements #: Array[Herb::AST::Node]
1955
- attr_reader :end_node #: Herb::AST::ERBEndNode
2879
+ attr_reader :end_node #: Herb::AST::ERBEndNode?
1956
2880
 
1957
- #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Array[Herb::AST::Node], Herb::AST::ERBEndNode) -> void
1958
- def initialize(type, location, errors, tag_opening, content, tag_closing, statements, end_node)
2881
+ #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, String, Array[Herb::AST::Node], Herb::AST::ERBEndNode) -> void
2882
+ def initialize(type, location, errors, tag_opening, content, tag_closing, prism_node, statements, end_node)
1959
2883
  super(type, location, errors)
1960
2884
  @tag_opening = tag_opening
1961
2885
  @content = content
1962
2886
  @tag_closing = tag_closing
2887
+ @prism_node = prism_node
1963
2888
  @statements = statements
1964
2889
  @end_node = end_node
1965
2890
  end
1966
2891
 
2892
+ #: () -> Prism::node?
2893
+ def deserialized_prism_node
2894
+ prism_node = @prism_node
2895
+ return nil unless prism_node
2896
+ return nil unless source
2897
+
2898
+ begin
2899
+ require "prism"
2900
+ rescue LoadError
2901
+ warn "The 'prism' gem is required to deserialize Prism nodes. Add it to your Gemfile or install it with: gem install prism"
2902
+ return nil
2903
+ end
2904
+
2905
+ Prism.load(source, prism_node).value
2906
+ end
2907
+
1967
2908
  #: () -> serialized_erb_for_node
1968
2909
  def to_hash
1969
2910
  super.merge({
1970
2911
  tag_opening: tag_opening,
1971
2912
  content: content,
1972
2913
  tag_closing: tag_closing,
2914
+ prism_node: prism_node,
1973
2915
  statements: statements,
1974
2916
  end_node: end_node,
1975
2917
  }) #: Herb::serialized_erb_for_node
@@ -1982,7 +2924,7 @@ module Herb
1982
2924
 
1983
2925
  #: () -> Array[Herb::AST::Node?]
1984
2926
  def child_nodes
1985
- [*statements, end_node]
2927
+ [*(statements || []), end_node]
1986
2928
  end
1987
2929
 
1988
2930
  #: () -> Array[Herb::AST::Node]
@@ -2019,6 +2961,11 @@ module Herb
2019
2961
  output += white("├── tag_closing: ")
2020
2962
  output += tag_closing ? tag_closing.tree_inspect : magenta("∅")
2021
2963
  output += "\n"
2964
+ if prism_node && source
2965
+ output += white("├── prism_node: ")
2966
+ output += Herb::PrismInspect.inspect_prism_serialized(prism_node, source, "│ ")
2967
+ output += "\n"
2968
+ end
2022
2969
  output += white("├── statements: ")
2023
2970
  output += inspect_array(statements, prefix: "│ ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
2024
2971
  output += white("└── end_node: ")
@@ -2035,14 +2982,21 @@ module Herb
2035
2982
  end
2036
2983
  end
2037
2984
 
2985
+ #: type serialized_erb_rescue_node = {
2986
+ #| tag_opening: Herb::Token?,
2987
+ #| content: Herb::Token?,
2988
+ #| tag_closing: Herb::Token?,
2989
+ #| statements: Array[Herb::AST::Node],
2990
+ #| subsequent: Herb::AST::ERBRescueNode?,
2991
+ #| }
2038
2992
  class ERBRescueNode < Node
2039
2993
  include Colors
2040
2994
 
2041
- attr_reader :tag_opening #: Herb::Token
2042
- attr_reader :content #: Herb::Token
2043
- attr_reader :tag_closing #: Herb::Token
2995
+ attr_reader :tag_opening #: Herb::Token?
2996
+ attr_reader :content #: Herb::Token?
2997
+ attr_reader :tag_closing #: Herb::Token?
2044
2998
  attr_reader :statements #: Array[Herb::AST::Node]
2045
- attr_reader :subsequent #: Herb::AST::ERBRescueNode
2999
+ attr_reader :subsequent #: Herb::AST::ERBRescueNode?
2046
3000
 
2047
3001
  #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Array[Herb::AST::Node], Herb::AST::ERBRescueNode) -> void
2048
3002
  def initialize(type, location, errors, tag_opening, content, tag_closing, statements, subsequent)
@@ -2072,7 +3026,7 @@ module Herb
2072
3026
 
2073
3027
  #: () -> Array[Herb::AST::Node?]
2074
3028
  def child_nodes
2075
- [*statements, subsequent]
3029
+ [*(statements || []), subsequent]
2076
3030
  end
2077
3031
 
2078
3032
  #: () -> Array[Herb::AST::Node]
@@ -2125,12 +3079,18 @@ module Herb
2125
3079
  end
2126
3080
  end
2127
3081
 
3082
+ #: type serialized_erb_ensure_node = {
3083
+ #| tag_opening: Herb::Token?,
3084
+ #| content: Herb::Token?,
3085
+ #| tag_closing: Herb::Token?,
3086
+ #| statements: Array[Herb::AST::Node],
3087
+ #| }
2128
3088
  class ERBEnsureNode < Node
2129
3089
  include Colors
2130
3090
 
2131
- attr_reader :tag_opening #: Herb::Token
2132
- attr_reader :content #: Herb::Token
2133
- attr_reader :tag_closing #: Herb::Token
3091
+ attr_reader :tag_opening #: Herb::Token?
3092
+ attr_reader :content #: Herb::Token?
3093
+ attr_reader :tag_closing #: Herb::Token?
2134
3094
  attr_reader :statements #: Array[Herb::AST::Node]
2135
3095
 
2136
3096
  #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Array[Herb::AST::Node]) -> void
@@ -2159,7 +3119,7 @@ module Herb
2159
3119
 
2160
3120
  #: () -> Array[Herb::AST::Node?]
2161
3121
  def child_nodes
2162
- [*statements]
3122
+ [*(statements || [])]
2163
3123
  end
2164
3124
 
2165
3125
  #: () -> Array[Herb::AST::Node]
@@ -2204,24 +3164,37 @@ module Herb
2204
3164
  end
2205
3165
  end
2206
3166
 
3167
+ #: type serialized_erb_begin_node = {
3168
+ #| tag_opening: Herb::Token?,
3169
+ #| content: Herb::Token?,
3170
+ #| tag_closing: Herb::Token?,
3171
+ #| prism_node: String?,
3172
+ #| statements: Array[Herb::AST::Node],
3173
+ #| rescue_clause: Herb::AST::ERBRescueNode?,
3174
+ #| else_clause: Herb::AST::ERBElseNode?,
3175
+ #| ensure_clause: Herb::AST::ERBEnsureNode?,
3176
+ #| end_node: Herb::AST::ERBEndNode?,
3177
+ #| }
2207
3178
  class ERBBeginNode < Node
2208
3179
  include Colors
2209
3180
 
2210
- attr_reader :tag_opening #: Herb::Token
2211
- attr_reader :content #: Herb::Token
2212
- attr_reader :tag_closing #: Herb::Token
3181
+ attr_reader :tag_opening #: Herb::Token?
3182
+ attr_reader :content #: Herb::Token?
3183
+ attr_reader :tag_closing #: Herb::Token?
3184
+ attr_reader :prism_node #: String?
2213
3185
  attr_reader :statements #: Array[Herb::AST::Node]
2214
- attr_reader :rescue_clause #: Herb::AST::ERBRescueNode
2215
- attr_reader :else_clause #: Herb::AST::ERBElseNode
2216
- attr_reader :ensure_clause #: Herb::AST::ERBEnsureNode
2217
- attr_reader :end_node #: Herb::AST::ERBEndNode
3186
+ attr_reader :rescue_clause #: Herb::AST::ERBRescueNode?
3187
+ attr_reader :else_clause #: Herb::AST::ERBElseNode?
3188
+ attr_reader :ensure_clause #: Herb::AST::ERBEnsureNode?
3189
+ attr_reader :end_node #: Herb::AST::ERBEndNode?
2218
3190
 
2219
- #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Array[Herb::AST::Node], Herb::AST::ERBRescueNode, Herb::AST::ERBElseNode, Herb::AST::ERBEnsureNode, Herb::AST::ERBEndNode) -> void
2220
- def initialize(type, location, errors, tag_opening, content, tag_closing, statements, rescue_clause, else_clause, ensure_clause, end_node)
3191
+ #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, String, Array[Herb::AST::Node], Herb::AST::ERBRescueNode, Herb::AST::ERBElseNode, Herb::AST::ERBEnsureNode, Herb::AST::ERBEndNode) -> void
3192
+ def initialize(type, location, errors, tag_opening, content, tag_closing, prism_node, statements, rescue_clause, else_clause, ensure_clause, end_node)
2221
3193
  super(type, location, errors)
2222
3194
  @tag_opening = tag_opening
2223
3195
  @content = content
2224
3196
  @tag_closing = tag_closing
3197
+ @prism_node = prism_node
2225
3198
  @statements = statements
2226
3199
  @rescue_clause = rescue_clause
2227
3200
  @else_clause = else_clause
@@ -2229,12 +3202,29 @@ module Herb
2229
3202
  @end_node = end_node
2230
3203
  end
2231
3204
 
3205
+ #: () -> Prism::node?
3206
+ def deserialized_prism_node
3207
+ prism_node = @prism_node
3208
+ return nil unless prism_node
3209
+ return nil unless source
3210
+
3211
+ begin
3212
+ require "prism"
3213
+ rescue LoadError
3214
+ warn "The 'prism' gem is required to deserialize Prism nodes. Add it to your Gemfile or install it with: gem install prism"
3215
+ return nil
3216
+ end
3217
+
3218
+ Prism.load(source, prism_node).value
3219
+ end
3220
+
2232
3221
  #: () -> serialized_erb_begin_node
2233
3222
  def to_hash
2234
3223
  super.merge({
2235
3224
  tag_opening: tag_opening,
2236
3225
  content: content,
2237
3226
  tag_closing: tag_closing,
3227
+ prism_node: prism_node,
2238
3228
  statements: statements,
2239
3229
  rescue_clause: rescue_clause,
2240
3230
  else_clause: else_clause,
@@ -2250,7 +3240,7 @@ module Herb
2250
3240
 
2251
3241
  #: () -> Array[Herb::AST::Node?]
2252
3242
  def child_nodes
2253
- [*statements, rescue_clause, else_clause, ensure_clause, end_node]
3243
+ [*(statements || []), rescue_clause, else_clause, ensure_clause, end_node]
2254
3244
  end
2255
3245
 
2256
3246
  #: () -> Array[Herb::AST::Node]
@@ -2287,6 +3277,11 @@ module Herb
2287
3277
  output += white("├── tag_closing: ")
2288
3278
  output += tag_closing ? tag_closing.tree_inspect : magenta("∅")
2289
3279
  output += "\n"
3280
+ if prism_node && source
3281
+ output += white("├── prism_node: ")
3282
+ output += Herb::PrismInspect.inspect_prism_serialized(prism_node, source, "│ ")
3283
+ output += "\n"
3284
+ end
2290
3285
  output += white("├── statements: ")
2291
3286
  output += inspect_array(statements, prefix: "│ ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
2292
3287
  output += white("├── rescue_clause: ")
@@ -2327,29 +3322,57 @@ module Herb
2327
3322
  end
2328
3323
  end
2329
3324
 
3325
+ #: type serialized_erb_unless_node = {
3326
+ #| tag_opening: Herb::Token?,
3327
+ #| content: Herb::Token?,
3328
+ #| tag_closing: Herb::Token?,
3329
+ #| then_keyword: Herb::Location?,
3330
+ #| prism_node: String?,
3331
+ #| statements: Array[Herb::AST::Node],
3332
+ #| else_clause: Herb::AST::ERBElseNode?,
3333
+ #| end_node: Herb::AST::ERBEndNode?,
3334
+ #| }
2330
3335
  class ERBUnlessNode < Node
2331
3336
  include Colors
2332
3337
 
2333
- attr_reader :tag_opening #: Herb::Token
2334
- attr_reader :content #: Herb::Token
2335
- attr_reader :tag_closing #: Herb::Token
2336
- attr_reader :then_keyword #: Herb::Location
3338
+ attr_reader :tag_opening #: Herb::Token?
3339
+ attr_reader :content #: Herb::Token?
3340
+ attr_reader :tag_closing #: Herb::Token?
3341
+ attr_reader :then_keyword #: Herb::Location?
3342
+ attr_reader :prism_node #: String?
2337
3343
  attr_reader :statements #: Array[Herb::AST::Node]
2338
- attr_reader :else_clause #: Herb::AST::ERBElseNode
2339
- attr_reader :end_node #: Herb::AST::ERBEndNode
3344
+ attr_reader :else_clause #: Herb::AST::ERBElseNode?
3345
+ attr_reader :end_node #: Herb::AST::ERBEndNode?
2340
3346
 
2341
- #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Herb::Location, Array[Herb::AST::Node], Herb::AST::ERBElseNode, Herb::AST::ERBEndNode) -> void
2342
- def initialize(type, location, errors, tag_opening, content, tag_closing, then_keyword, statements, else_clause, end_node)
3347
+ #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Herb::Location, String, Array[Herb::AST::Node], Herb::AST::ERBElseNode, Herb::AST::ERBEndNode) -> void
3348
+ def initialize(type, location, errors, tag_opening, content, tag_closing, then_keyword, prism_node, statements, else_clause, end_node)
2343
3349
  super(type, location, errors)
2344
3350
  @tag_opening = tag_opening
2345
3351
  @content = content
2346
3352
  @tag_closing = tag_closing
2347
3353
  @then_keyword = then_keyword
3354
+ @prism_node = prism_node
2348
3355
  @statements = statements
2349
3356
  @else_clause = else_clause
2350
3357
  @end_node = end_node
2351
3358
  end
2352
3359
 
3360
+ #: () -> Prism::node?
3361
+ def deserialized_prism_node
3362
+ prism_node = @prism_node
3363
+ return nil unless prism_node
3364
+ return nil unless source
3365
+
3366
+ begin
3367
+ require "prism"
3368
+ rescue LoadError
3369
+ warn "The 'prism' gem is required to deserialize Prism nodes. Add it to your Gemfile or install it with: gem install prism"
3370
+ return nil
3371
+ end
3372
+
3373
+ Prism.load(source, prism_node).value
3374
+ end
3375
+
2353
3376
  #: () -> serialized_erb_unless_node
2354
3377
  def to_hash
2355
3378
  super.merge({
@@ -2357,6 +3380,7 @@ module Herb
2357
3380
  content: content,
2358
3381
  tag_closing: tag_closing,
2359
3382
  then_keyword: then_keyword,
3383
+ prism_node: prism_node,
2360
3384
  statements: statements,
2361
3385
  else_clause: else_clause,
2362
3386
  end_node: end_node,
@@ -2370,7 +3394,7 @@ module Herb
2370
3394
 
2371
3395
  #: () -> Array[Herb::AST::Node?]
2372
3396
  def child_nodes
2373
- [*statements, else_clause, end_node]
3397
+ [*(statements || []), else_clause, end_node]
2374
3398
  end
2375
3399
 
2376
3400
  #: () -> Array[Herb::AST::Node]
@@ -2410,6 +3434,11 @@ module Herb
2410
3434
  output += white("├── then_keyword: ")
2411
3435
  output += then_keyword ? dimmed("(location: #{then_keyword.tree_inspect})") : magenta("∅")
2412
3436
  output += "\n"
3437
+ if prism_node && source
3438
+ output += white("├── prism_node: ")
3439
+ output += Herb::PrismInspect.inspect_prism_serialized(prism_node, source, "│ ")
3440
+ output += "\n"
3441
+ end
2413
3442
  output += white("├── statements: ")
2414
3443
  output += inspect_array(statements, prefix: "│ ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
2415
3444
  output += white("├── else_clause: ")
@@ -2434,12 +3463,327 @@ module Herb
2434
3463
  end
2435
3464
  end
2436
3465
 
3466
+ #: type serialized_ruby_render_local_node = {
3467
+ #| name: Herb::Token?,
3468
+ #| value: Herb::AST::RubyLiteralNode?,
3469
+ #| }
3470
+ class RubyRenderLocalNode < Node
3471
+ include Colors
3472
+
3473
+ attr_reader :name #: Herb::Token?
3474
+ attr_reader :value #: Herb::AST::RubyLiteralNode?
3475
+
3476
+ #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::AST::RubyLiteralNode) -> void
3477
+ def initialize(type, location, errors, name, value)
3478
+ super(type, location, errors)
3479
+ @name = name
3480
+ @value = value
3481
+ end
3482
+
3483
+ #: () -> serialized_ruby_render_local_node
3484
+ def to_hash
3485
+ super.merge({
3486
+ name: name,
3487
+ value: value,
3488
+ }) #: Herb::serialized_ruby_render_local_node
3489
+ end
3490
+
3491
+ #: (Visitor) -> void
3492
+ def accept(visitor)
3493
+ visitor.visit_ruby_render_local_node(self)
3494
+ end
3495
+
3496
+ #: () -> Array[Herb::AST::Node?]
3497
+ def child_nodes
3498
+ [value]
3499
+ end
3500
+
3501
+ #: () -> Array[Herb::AST::Node]
3502
+ def compact_child_nodes
3503
+ child_nodes.compact
3504
+ end
3505
+
3506
+ #: () -> String
3507
+ def inspect
3508
+ tree_inspect.rstrip.gsub(/\s+$/, "")
3509
+ end
3510
+
3511
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
3512
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 10)
3513
+ output = +""
3514
+
3515
+ output += white("@ #{bold(yellow(node_name.to_s))} #{dimmed("(location: #{location.tree_inspect})")}")
3516
+ output += "\n"
3517
+
3518
+ if depth >= depth_limit
3519
+ output += dimmed("└── [depth limit reached ...]\n\n")
3520
+
3521
+ return output.gsub(/^/, " " * indent)
3522
+ end
3523
+
3524
+ output += inspect_errors(prefix: "│ ")
3525
+
3526
+ output += white("├── name: ")
3527
+ output += name ? name.tree_inspect : magenta("∅")
3528
+ output += "\n"
3529
+ output += white("└── value: ")
3530
+ if value
3531
+ output += "\n"
3532
+ output += " └── "
3533
+ output += value.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, " ").delete_prefix(" ")
3534
+ else
3535
+ output += magenta("∅\n")
3536
+ end
3537
+ output += "\n"
3538
+
3539
+ output.gsub(/^/, " " * indent)
3540
+ end
3541
+ end
3542
+
3543
+ #: type serialized_erb_render_node = {
3544
+ #| tag_opening: Herb::Token?,
3545
+ #| content: Herb::Token?,
3546
+ #| tag_closing: Herb::Token?,
3547
+ #| analyzed_ruby: nil,
3548
+ #| prism_node: String?,
3549
+ #| partial: Herb::Token?,
3550
+ #| template_path: Herb::Token?,
3551
+ #| layout: Herb::Token?,
3552
+ #| file: Herb::Token?,
3553
+ #| inline_template: Herb::Token?,
3554
+ #| body: Herb::Token?,
3555
+ #| plain: Herb::Token?,
3556
+ #| html: Herb::Token?,
3557
+ #| renderable: Herb::Token?,
3558
+ #| collection: Herb::Token?,
3559
+ #| object: Herb::Token?,
3560
+ #| as_name: Herb::Token?,
3561
+ #| spacer_template: Herb::Token?,
3562
+ #| formats: Herb::Token?,
3563
+ #| variants: Herb::Token?,
3564
+ #| handlers: Herb::Token?,
3565
+ #| content_type: Herb::Token?,
3566
+ #| locals: Array[Herb::AST::RubyRenderLocalNode]?,
3567
+ #| }
3568
+ class ERBRenderNode < Node
3569
+ include Colors
3570
+
3571
+ attr_reader :tag_opening #: Herb::Token?
3572
+ attr_reader :content #: Herb::Token?
3573
+ attr_reader :tag_closing #: Herb::Token?
3574
+ attr_reader :analyzed_ruby #: nil
3575
+ attr_reader :prism_node #: String?
3576
+ attr_reader :partial #: Herb::Token?
3577
+ attr_reader :template_path #: Herb::Token?
3578
+ attr_reader :layout #: Herb::Token?
3579
+ attr_reader :file #: Herb::Token?
3580
+ attr_reader :inline_template #: Herb::Token?
3581
+ attr_reader :body #: Herb::Token?
3582
+ attr_reader :plain #: Herb::Token?
3583
+ attr_reader :html #: Herb::Token?
3584
+ attr_reader :renderable #: Herb::Token?
3585
+ attr_reader :collection #: Herb::Token?
3586
+ attr_reader :object #: Herb::Token?
3587
+ attr_reader :as_name #: Herb::Token?
3588
+ attr_reader :spacer_template #: Herb::Token?
3589
+ attr_reader :formats #: Herb::Token?
3590
+ attr_reader :variants #: Herb::Token?
3591
+ attr_reader :handlers #: Herb::Token?
3592
+ attr_reader :content_type #: Herb::Token?
3593
+ attr_reader :locals #: Array[Herb::AST::RubyRenderLocalNode]?
3594
+
3595
+ #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, nil, String, Herb::Token, Herb::Token, Herb::Token, Herb::Token, Herb::Token, Herb::Token, Herb::Token, Herb::Token, Herb::Token, Herb::Token, Herb::Token, Herb::Token, Herb::Token, Herb::Token, Herb::Token, Herb::Token, Herb::Token, Array[Herb::AST::RubyRenderLocalNode]) -> void
3596
+ def initialize(type, location, errors, tag_opening, content, tag_closing, analyzed_ruby, prism_node, partial, template_path, layout, file, inline_template, body, plain, html, renderable, collection, object, as_name, spacer_template, formats, variants, handlers, content_type, locals)
3597
+ super(type, location, errors)
3598
+ @tag_opening = tag_opening
3599
+ @content = content
3600
+ @tag_closing = tag_closing
3601
+ @analyzed_ruby = analyzed_ruby
3602
+ @prism_node = prism_node
3603
+ @partial = partial
3604
+ @template_path = template_path
3605
+ @layout = layout
3606
+ @file = file
3607
+ @inline_template = inline_template
3608
+ @body = body
3609
+ @plain = plain
3610
+ @html = html
3611
+ @renderable = renderable
3612
+ @collection = collection
3613
+ @object = object
3614
+ @as_name = as_name
3615
+ @spacer_template = spacer_template
3616
+ @formats = formats
3617
+ @variants = variants
3618
+ @handlers = handlers
3619
+ @content_type = content_type
3620
+ @locals = locals
3621
+ end
3622
+
3623
+ #: () -> Prism::node?
3624
+ def deserialized_prism_node
3625
+ prism_node = @prism_node
3626
+ return nil unless prism_node
3627
+ return nil unless source
3628
+
3629
+ begin
3630
+ require "prism"
3631
+ rescue LoadError
3632
+ warn "The 'prism' gem is required to deserialize Prism nodes. Add it to your Gemfile or install it with: gem install prism"
3633
+ return nil
3634
+ end
3635
+
3636
+ Prism.load(source, prism_node).value
3637
+ end
3638
+
3639
+ #: () -> serialized_erb_render_node
3640
+ def to_hash
3641
+ super.merge({
3642
+ tag_opening: tag_opening,
3643
+ content: content,
3644
+ tag_closing: tag_closing,
3645
+ analyzed_ruby: analyzed_ruby,
3646
+ prism_node: prism_node,
3647
+ partial: partial,
3648
+ template_path: template_path,
3649
+ layout: layout,
3650
+ file: file,
3651
+ inline_template: inline_template,
3652
+ body: body,
3653
+ plain: plain,
3654
+ html: html,
3655
+ renderable: renderable,
3656
+ collection: collection,
3657
+ object: object,
3658
+ as_name: as_name,
3659
+ spacer_template: spacer_template,
3660
+ formats: formats,
3661
+ variants: variants,
3662
+ handlers: handlers,
3663
+ content_type: content_type,
3664
+ locals: locals,
3665
+ }) #: Herb::serialized_erb_render_node
3666
+ end
3667
+
3668
+ #: (Visitor) -> void
3669
+ def accept(visitor)
3670
+ visitor.visit_erb_render_node(self)
3671
+ end
3672
+
3673
+ #: () -> Array[Herb::AST::Node?]
3674
+ def child_nodes
3675
+ [*(locals || [])]
3676
+ end
3677
+
3678
+ #: () -> Array[Herb::AST::Node]
3679
+ def compact_child_nodes
3680
+ child_nodes.compact
3681
+ end
3682
+
3683
+ #: () -> String
3684
+ def inspect
3685
+ tree_inspect.rstrip.gsub(/\s+$/, "")
3686
+ end
3687
+
3688
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
3689
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 10)
3690
+ output = +""
3691
+
3692
+ output += white("@ #{bold(yellow(node_name.to_s))} #{dimmed("(location: #{location.tree_inspect})")}")
3693
+ output += "\n"
3694
+
3695
+ if depth >= depth_limit
3696
+ output += dimmed("└── [depth limit reached ...]\n\n")
3697
+
3698
+ return output.gsub(/^/, " " * indent)
3699
+ end
3700
+
3701
+ output += inspect_errors(prefix: "│ ")
3702
+
3703
+ output += white("├── tag_opening: ")
3704
+ output += tag_opening ? tag_opening.tree_inspect : magenta("∅")
3705
+ output += "\n"
3706
+ output += white("├── content: ")
3707
+ output += content ? content.tree_inspect : magenta("∅")
3708
+ output += "\n"
3709
+ output += white("├── tag_closing: ")
3710
+ output += tag_closing ? tag_closing.tree_inspect : magenta("∅")
3711
+ output += "\n"
3712
+ if prism_node && source
3713
+ output += white("├── prism_node: ")
3714
+ output += Herb::PrismInspect.inspect_prism_serialized(prism_node, source, "│ ")
3715
+ output += "\n"
3716
+ end
3717
+ output += white("├── partial: ")
3718
+ output += partial ? partial.tree_inspect : magenta("∅")
3719
+ output += "\n"
3720
+ output += white("├── template_path: ")
3721
+ output += template_path ? template_path.tree_inspect : magenta("∅")
3722
+ output += "\n"
3723
+ output += white("├── layout: ")
3724
+ output += layout ? layout.tree_inspect : magenta("∅")
3725
+ output += "\n"
3726
+ output += white("├── file: ")
3727
+ output += file ? file.tree_inspect : magenta("∅")
3728
+ output += "\n"
3729
+ output += white("├── inline_template: ")
3730
+ output += inline_template ? inline_template.tree_inspect : magenta("∅")
3731
+ output += "\n"
3732
+ output += white("├── body: ")
3733
+ output += body ? body.tree_inspect : magenta("∅")
3734
+ output += "\n"
3735
+ output += white("├── plain: ")
3736
+ output += plain ? plain.tree_inspect : magenta("∅")
3737
+ output += "\n"
3738
+ output += white("├── html: ")
3739
+ output += html ? html.tree_inspect : magenta("∅")
3740
+ output += "\n"
3741
+ output += white("├── renderable: ")
3742
+ output += renderable ? renderable.tree_inspect : magenta("∅")
3743
+ output += "\n"
3744
+ output += white("├── collection: ")
3745
+ output += collection ? collection.tree_inspect : magenta("∅")
3746
+ output += "\n"
3747
+ output += white("├── object: ")
3748
+ output += object ? object.tree_inspect : magenta("∅")
3749
+ output += "\n"
3750
+ output += white("├── as_name: ")
3751
+ output += as_name ? as_name.tree_inspect : magenta("∅")
3752
+ output += "\n"
3753
+ output += white("├── spacer_template: ")
3754
+ output += spacer_template ? spacer_template.tree_inspect : magenta("∅")
3755
+ output += "\n"
3756
+ output += white("├── formats: ")
3757
+ output += formats ? formats.tree_inspect : magenta("∅")
3758
+ output += "\n"
3759
+ output += white("├── variants: ")
3760
+ output += variants ? variants.tree_inspect : magenta("∅")
3761
+ output += "\n"
3762
+ output += white("├── handlers: ")
3763
+ output += handlers ? handlers.tree_inspect : magenta("∅")
3764
+ output += "\n"
3765
+ output += white("├── content_type: ")
3766
+ output += content_type ? content_type.tree_inspect : magenta("∅")
3767
+ output += "\n"
3768
+ output += white("└── locals: ")
3769
+ output += inspect_array(locals, prefix: " ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
3770
+ output += "\n"
3771
+
3772
+ output.gsub(/^/, " " * indent)
3773
+ end
3774
+ end
3775
+
3776
+ #: type serialized_erb_yield_node = {
3777
+ #| tag_opening: Herb::Token?,
3778
+ #| content: Herb::Token?,
3779
+ #| tag_closing: Herb::Token?,
3780
+ #| }
2437
3781
  class ERBYieldNode < Node
2438
3782
  include Colors
2439
3783
 
2440
- attr_reader :tag_opening #: Herb::Token
2441
- attr_reader :content #: Herb::Token
2442
- attr_reader :tag_closing #: Herb::Token
3784
+ attr_reader :tag_opening #: Herb::Token?
3785
+ attr_reader :content #: Herb::Token?
3786
+ attr_reader :tag_closing #: Herb::Token?
2443
3787
 
2444
3788
  #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token) -> void
2445
3789
  def initialize(type, location, errors, tag_opening, content, tag_closing)
@@ -2508,13 +3852,20 @@ module Herb
2508
3852
  end
2509
3853
  end
2510
3854
 
3855
+ #: type serialized_erb_in_node = {
3856
+ #| tag_opening: Herb::Token?,
3857
+ #| content: Herb::Token?,
3858
+ #| tag_closing: Herb::Token?,
3859
+ #| then_keyword: Herb::Location?,
3860
+ #| statements: Array[Herb::AST::Node],
3861
+ #| }
2511
3862
  class ERBInNode < Node
2512
3863
  include Colors
2513
3864
 
2514
- attr_reader :tag_opening #: Herb::Token
2515
- attr_reader :content #: Herb::Token
2516
- attr_reader :tag_closing #: Herb::Token
2517
- attr_reader :then_keyword #: Herb::Location
3865
+ attr_reader :tag_opening #: Herb::Token?
3866
+ attr_reader :content #: Herb::Token?
3867
+ attr_reader :tag_closing #: Herb::Token?
3868
+ attr_reader :then_keyword #: Herb::Location?
2518
3869
  attr_reader :statements #: Array[Herb::AST::Node]
2519
3870
 
2520
3871
  #: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, Herb::Location, Array[Herb::AST::Node]) -> void
@@ -2545,7 +3896,7 @@ module Herb
2545
3896
 
2546
3897
  #: () -> Array[Herb::AST::Node?]
2547
3898
  def child_nodes
2548
- [*statements]
3899
+ [*(statements || [])]
2549
3900
  end
2550
3901
 
2551
3902
  #: () -> Array[Herb::AST::Node]