herb 0.7.4-aarch64-linux-gnu → 0.8.0-aarch64-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 (176) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +8 -5
  3. data/config.yml +40 -20
  4. data/ext/herb/error_helpers.c +57 -3
  5. data/ext/herb/error_helpers.h +1 -1
  6. data/ext/herb/extconf.rb +1 -0
  7. data/ext/herb/extension.c +10 -24
  8. data/ext/herb/extension_helpers.c +12 -18
  9. data/ext/herb/extension_helpers.h +4 -4
  10. data/ext/herb/nodes.c +72 -37
  11. data/herb.gemspec +0 -2
  12. data/lib/herb/3.0/herb.so +0 -0
  13. data/lib/herb/3.1/herb.so +0 -0
  14. data/lib/herb/3.2/herb.so +0 -0
  15. data/lib/herb/3.3/herb.so +0 -0
  16. data/lib/herb/3.4/herb.so +0 -0
  17. data/lib/herb/ast/helpers.rb +11 -0
  18. data/lib/herb/ast/node.rb +15 -6
  19. data/lib/herb/ast/nodes.rb +609 -392
  20. data/lib/herb/cli.rb +31 -0
  21. data/lib/herb/colors.rb +82 -0
  22. data/lib/herb/engine/compiler.rb +140 -14
  23. data/lib/herb/engine/debug_visitor.rb +1 -5
  24. data/lib/herb/engine/parser_error_overlay.rb +1 -1
  25. data/lib/herb/engine.rb +18 -20
  26. data/lib/herb/errors.rb +166 -56
  27. data/lib/herb/location.rb +2 -2
  28. data/lib/herb/project.rb +86 -21
  29. data/lib/herb/token.rb +14 -2
  30. data/lib/herb/version.rb +1 -1
  31. data/lib/herb.rb +1 -0
  32. data/sig/herb/ast/helpers.rbs +3 -0
  33. data/sig/herb/ast/node.rbs +12 -5
  34. data/sig/herb/ast/nodes.rbs +124 -62
  35. data/sig/herb/colors.rbs +35 -0
  36. data/sig/herb/engine/compiler.rbs +23 -1
  37. data/sig/herb/errors.rbs +74 -20
  38. data/sig/herb/token.rbs +8 -0
  39. data/sig/herb_c_extension.rbs +1 -1
  40. data/sig/serialized_ast_errors.rbs +8 -0
  41. data/src/analyze.c +461 -249
  42. data/src/analyze_helpers.c +5 -0
  43. data/src/analyze_missing_end.c +147 -0
  44. data/src/analyze_transform.c +196 -0
  45. data/src/analyzed_ruby.c +23 -2
  46. data/src/ast_node.c +14 -17
  47. data/src/ast_nodes.c +179 -181
  48. data/src/ast_pretty_print.c +232 -232
  49. data/src/element_source.c +7 -6
  50. data/src/errors.c +272 -152
  51. data/src/extract.c +92 -34
  52. data/src/herb.c +37 -49
  53. data/src/html_util.c +34 -96
  54. data/src/include/analyze.h +10 -2
  55. data/src/include/analyze_helpers.h +3 -0
  56. data/src/include/analyzed_ruby.h +4 -2
  57. data/src/include/ast_node.h +4 -4
  58. data/src/include/ast_nodes.h +68 -67
  59. data/src/include/ast_pretty_print.h +2 -2
  60. data/src/include/element_source.h +3 -1
  61. data/src/include/errors.h +42 -26
  62. data/src/include/extract.h +4 -4
  63. data/src/include/herb.h +6 -7
  64. data/src/include/html_util.h +4 -5
  65. data/src/include/lexer.h +1 -3
  66. data/src/include/lexer_peek_helpers.h +21 -19
  67. data/src/include/lexer_struct.h +12 -10
  68. data/src/include/location.h +10 -13
  69. data/src/include/macros.h +4 -0
  70. data/src/include/parser.h +12 -6
  71. data/src/include/parser_helpers.h +26 -16
  72. data/src/include/position.h +3 -14
  73. data/src/include/pretty_print.h +38 -28
  74. data/src/include/prism_helpers.h +1 -1
  75. data/src/include/range.h +4 -13
  76. data/src/include/token.h +5 -11
  77. data/src/include/token_struct.h +2 -2
  78. data/src/include/utf8.h +3 -2
  79. data/src/include/util/hb_arena.h +31 -0
  80. data/src/include/util/hb_arena_debug.h +8 -0
  81. data/src/include/util/hb_array.h +33 -0
  82. data/src/include/util/hb_buffer.h +34 -0
  83. data/src/include/util/hb_string.h +29 -0
  84. data/src/include/util/hb_system.h +9 -0
  85. data/src/include/util.h +3 -14
  86. data/src/include/version.h +1 -1
  87. data/src/include/visitor.h +1 -1
  88. data/src/io.c +7 -4
  89. data/src/lexer.c +62 -88
  90. data/src/lexer_peek_helpers.c +42 -38
  91. data/src/location.c +9 -37
  92. data/src/main.c +19 -23
  93. data/src/parser.c +373 -313
  94. data/src/parser_helpers.c +60 -54
  95. data/src/parser_match_tags.c +316 -0
  96. data/src/pretty_print.c +88 -117
  97. data/src/prism_helpers.c +7 -7
  98. data/src/range.c +2 -35
  99. data/src/token.c +36 -87
  100. data/src/utf8.c +4 -4
  101. data/src/util/hb_arena.c +179 -0
  102. data/src/util/hb_arena_debug.c +237 -0
  103. data/src/{array.c → util/hb_array.c} +26 -27
  104. data/src/util/hb_buffer.c +203 -0
  105. data/src/util/hb_string.c +85 -0
  106. data/src/util/hb_system.c +30 -0
  107. data/src/util.c +29 -99
  108. data/src/visitor.c +54 -54
  109. data/templates/ext/herb/error_helpers.c.erb +3 -3
  110. data/templates/ext/herb/error_helpers.h.erb +1 -1
  111. data/templates/ext/herb/nodes.c.erb +11 -6
  112. data/templates/java/error_helpers.c.erb +75 -0
  113. data/templates/java/error_helpers.h.erb +20 -0
  114. data/templates/java/nodes.c.erb +97 -0
  115. data/templates/java/nodes.h.erb +23 -0
  116. data/templates/java/org/herb/ast/Errors.java.erb +121 -0
  117. data/templates/java/org/herb/ast/NodeVisitor.java.erb +14 -0
  118. data/templates/java/org/herb/ast/Nodes.java.erb +220 -0
  119. data/templates/java/org/herb/ast/Visitor.java.erb +56 -0
  120. data/templates/javascript/packages/core/src/visitor.ts.erb +29 -1
  121. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +8 -8
  122. data/templates/javascript/packages/node/extension/error_helpers.h.erb +1 -1
  123. data/templates/javascript/packages/node/extension/nodes.cpp.erb +9 -9
  124. data/templates/javascript/packages/node/extension/nodes.h.erb +1 -1
  125. data/templates/lib/herb/ast/nodes.rb.erb +28 -16
  126. data/templates/lib/herb/errors.rb.erb +17 -12
  127. data/templates/rust/src/ast/nodes.rs.erb +220 -0
  128. data/templates/rust/src/errors.rs.erb +216 -0
  129. data/templates/rust/src/nodes.rs.erb +374 -0
  130. data/templates/src/analyze_missing_end.c.erb +36 -0
  131. data/templates/src/analyze_transform.c.erb +24 -0
  132. data/templates/src/ast_nodes.c.erb +14 -16
  133. data/templates/src/ast_pretty_print.c.erb +36 -36
  134. data/templates/src/errors.c.erb +36 -38
  135. data/templates/src/include/ast_nodes.h.erb +11 -10
  136. data/templates/src/include/ast_pretty_print.h.erb +2 -2
  137. data/templates/src/include/errors.h.erb +9 -9
  138. data/templates/src/parser_match_tags.c.erb +38 -0
  139. data/templates/src/visitor.c.erb +4 -4
  140. data/templates/template.rb +22 -3
  141. data/templates/wasm/error_helpers.cpp.erb +9 -9
  142. data/templates/wasm/error_helpers.h.erb +1 -1
  143. data/templates/wasm/nodes.cpp.erb +9 -9
  144. data/templates/wasm/nodes.h.erb +1 -1
  145. data/vendor/prism/Rakefile +4 -1
  146. data/vendor/prism/config.yml +2 -1
  147. data/vendor/prism/include/prism/ast.h +31 -1
  148. data/vendor/prism/include/prism/diagnostic.h +1 -0
  149. data/vendor/prism/include/prism/version.h +3 -3
  150. data/vendor/prism/src/diagnostic.c +3 -1
  151. data/vendor/prism/src/prism.c +130 -71
  152. data/vendor/prism/src/util/pm_string.c +6 -8
  153. data/vendor/prism/templates/include/prism/ast.h.erb +2 -0
  154. data/vendor/prism/templates/java/org/prism/Loader.java.erb +2 -2
  155. data/vendor/prism/templates/javascript/src/deserialize.js.erb +2 -2
  156. data/vendor/prism/templates/lib/prism/serialize.rb.erb +2 -2
  157. data/vendor/prism/templates/sig/prism.rbs.erb +4 -0
  158. data/vendor/prism/templates/src/diagnostic.c.erb +1 -0
  159. metadata +34 -21
  160. data/lib/herb/libherb/array.rb +0 -51
  161. data/lib/herb/libherb/ast_node.rb +0 -50
  162. data/lib/herb/libherb/buffer.rb +0 -56
  163. data/lib/herb/libherb/extract_result.rb +0 -20
  164. data/lib/herb/libherb/lex_result.rb +0 -32
  165. data/lib/herb/libherb/libherb.rb +0 -52
  166. data/lib/herb/libherb/parse_result.rb +0 -20
  167. data/lib/herb/libherb/token.rb +0 -46
  168. data/lib/herb/libherb.rb +0 -35
  169. data/src/buffer.c +0 -232
  170. data/src/include/array.h +0 -33
  171. data/src/include/buffer.h +0 -39
  172. data/src/include/json.h +0 -28
  173. data/src/include/memory.h +0 -12
  174. data/src/json.c +0 -205
  175. data/src/memory.c +0 -53
  176. data/src/position.c +0 -33
data/lib/herb/errors.rb CHANGED
@@ -42,13 +42,15 @@ module Herb
42
42
  to_hash.to_json(state)
43
43
  end
44
44
 
45
- #: (?Integer) -> String
46
- def tree_inspect(_indent = 0)
45
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
46
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
47
47
  raise NotImplementedError
48
48
  end
49
49
  end
50
50
 
51
51
  class UnexpectedError < Error
52
+ include Colors
53
+
52
54
  attr_reader :description #: String
53
55
  attr_reader :expected #: String
54
56
  attr_reader :found #: String
@@ -76,15 +78,15 @@ module Herb
76
78
  }) #: Herb::serialized_unexpected_error
77
79
  end
78
80
 
79
- #: (?Integer) -> String
80
- def tree_inspect(indent = 0)
81
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
82
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
81
83
  output = +""
82
84
 
83
- output += %(@ #{error_name} #{location.tree_inspect}\n)
84
- output += %(├── message: #{message.inspect}\n)
85
- output += %(├── description: #{description.inspect}\n)
86
- output += %(├── expected: #{expected.inspect}\n)
87
- output += %(└── found: #{found.inspect}\n)
85
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location.tree_inspect})\n")}")
86
+ output += white("├── message: #{green(message.inspect)}\n")
87
+ output += white("├── description: #{green(description.inspect)}\n")
88
+ output += white("├── expected: #{green(expected.inspect)}\n")
89
+ output += white("└── found: #{green(found.inspect)}\n")
88
90
  output += %(\n)
89
91
 
90
92
  output.gsub(/^/, " " * indent)
@@ -92,6 +94,8 @@ module Herb
92
94
  end
93
95
 
94
96
  class UnexpectedTokenError < Error
97
+ include Colors
98
+
95
99
  attr_reader :expected_type #: String
96
100
  attr_reader :found #: Herb::Token
97
101
 
@@ -116,14 +120,16 @@ module Herb
116
120
  }) #: Herb::serialized_unexpected_token_error
117
121
  end
118
122
 
119
- #: (?Integer) -> String
120
- def tree_inspect(indent = 0)
123
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
124
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
121
125
  output = +""
122
126
 
123
- output += %(@ #{error_name} #{location.tree_inspect}\n)
124
- output += %(├── message: #{message.inspect}\n)
125
- output += %(├── expected_type: #{expected_type.inspect}\n)
126
- output += %(└── found: #{found ? found.tree_inspect : "∅"}\n)
127
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location.tree_inspect})\n")}")
128
+ output += white("├── message: #{green(message.inspect)}\n")
129
+ output += white("├── expected_type: #{green(expected_type.inspect)}\n")
130
+ output += white("└── found: ")
131
+ output += found ? found.tree_inspect : magenta("∅")
132
+ output += "\n"
127
133
  output += %(\n)
128
134
 
129
135
  output.gsub(/^/, " " * indent)
@@ -131,6 +137,8 @@ module Herb
131
137
  end
132
138
 
133
139
  class MissingOpeningTagError < Error
140
+ include Colors
141
+
134
142
  attr_reader :closing_tag #: Herb::Token
135
143
 
136
144
  #: (String, Location, String, Herb::Token) -> void
@@ -152,13 +160,15 @@ module Herb
152
160
  }) #: Herb::serialized_missing_opening_tag_error
153
161
  end
154
162
 
155
- #: (?Integer) -> String
156
- def tree_inspect(indent = 0)
163
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
164
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
157
165
  output = +""
158
166
 
159
- output += %(@ #{error_name} #{location.tree_inspect}\n)
160
- output += %(├── message: #{message.inspect}\n)
161
- output += %(└── closing_tag: #{closing_tag ? closing_tag.tree_inspect : "∅"}\n)
167
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location.tree_inspect})\n")}")
168
+ output += white("├── message: #{green(message.inspect)}\n")
169
+ output += white("└── closing_tag: ")
170
+ output += closing_tag ? closing_tag.tree_inspect : magenta("∅")
171
+ output += "\n"
162
172
  output += %(\n)
163
173
 
164
174
  output.gsub(/^/, " " * indent)
@@ -166,6 +176,8 @@ module Herb
166
176
  end
167
177
 
168
178
  class MissingClosingTagError < Error
179
+ include Colors
180
+
169
181
  attr_reader :opening_tag #: Herb::Token
170
182
 
171
183
  #: (String, Location, String, Herb::Token) -> void
@@ -187,13 +199,15 @@ module Herb
187
199
  }) #: Herb::serialized_missing_closing_tag_error
188
200
  end
189
201
 
190
- #: (?Integer) -> String
191
- def tree_inspect(indent = 0)
202
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
203
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
192
204
  output = +""
193
205
 
194
- output += %(@ #{error_name} #{location.tree_inspect}\n)
195
- output += %(├── message: #{message.inspect}\n)
196
- output += %(└── opening_tag: #{opening_tag ? opening_tag.tree_inspect : "∅"}\n)
206
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location.tree_inspect})\n")}")
207
+ output += white("├── message: #{green(message.inspect)}\n")
208
+ output += white("└── opening_tag: ")
209
+ output += opening_tag ? opening_tag.tree_inspect : magenta("∅")
210
+ output += "\n"
197
211
  output += %(\n)
198
212
 
199
213
  output.gsub(/^/, " " * indent)
@@ -201,6 +215,8 @@ module Herb
201
215
  end
202
216
 
203
217
  class TagNamesMismatchError < Error
218
+ include Colors
219
+
204
220
  attr_reader :opening_tag #: Herb::Token
205
221
  attr_reader :closing_tag #: Herb::Token
206
222
 
@@ -225,14 +241,18 @@ module Herb
225
241
  }) #: Herb::serialized_tag_names_mismatch_error
226
242
  end
227
243
 
228
- #: (?Integer) -> String
229
- def tree_inspect(indent = 0)
244
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
245
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
230
246
  output = +""
231
247
 
232
- output += %(@ #{error_name} #{location.tree_inspect}\n)
233
- output += %(├── message: #{message.inspect}\n)
234
- output += %(├── opening_tag: #{opening_tag ? opening_tag.tree_inspect : "∅"}\n)
235
- output += %(└── closing_tag: #{closing_tag ? closing_tag.tree_inspect : "∅"}\n)
248
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location.tree_inspect})\n")}")
249
+ output += white("├── message: #{green(message.inspect)}\n")
250
+ output += white("├── opening_tag: ")
251
+ output += opening_tag ? opening_tag.tree_inspect : magenta("∅")
252
+ output += "\n"
253
+ output += white("└── closing_tag: ")
254
+ output += closing_tag ? closing_tag.tree_inspect : magenta("∅")
255
+ output += "\n"
236
256
  output += %(\n)
237
257
 
238
258
  output.gsub(/^/, " " * indent)
@@ -240,6 +260,8 @@ module Herb
240
260
  end
241
261
 
242
262
  class QuotesMismatchError < Error
263
+ include Colors
264
+
243
265
  attr_reader :opening_quote #: Herb::Token
244
266
  attr_reader :closing_quote #: Herb::Token
245
267
 
@@ -264,14 +286,18 @@ module Herb
264
286
  }) #: Herb::serialized_quotes_mismatch_error
265
287
  end
266
288
 
267
- #: (?Integer) -> String
268
- def tree_inspect(indent = 0)
289
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
290
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
269
291
  output = +""
270
292
 
271
- output += %(@ #{error_name} #{location.tree_inspect}\n)
272
- output += %(├── message: #{message.inspect}\n)
273
- output += %(├── opening_quote: #{opening_quote ? opening_quote.tree_inspect : "∅"}\n)
274
- output += %(└── closing_quote: #{closing_quote ? closing_quote.tree_inspect : "∅"}\n)
293
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location.tree_inspect})\n")}")
294
+ output += white("├── message: #{green(message.inspect)}\n")
295
+ output += white("├── opening_quote: ")
296
+ output += opening_quote ? opening_quote.tree_inspect : magenta("∅")
297
+ output += "\n"
298
+ output += white("└── closing_quote: ")
299
+ output += closing_quote ? closing_quote.tree_inspect : magenta("∅")
300
+ output += "\n"
275
301
  output += %(\n)
276
302
 
277
303
  output.gsub(/^/, " " * indent)
@@ -279,6 +305,8 @@ module Herb
279
305
  end
280
306
 
281
307
  class VoidElementClosingTagError < Error
308
+ include Colors
309
+
282
310
  attr_reader :tag_name #: Herb::Token
283
311
  attr_reader :expected #: String
284
312
  attr_reader :found #: String
@@ -306,15 +334,17 @@ module Herb
306
334
  }) #: Herb::serialized_void_element_closing_tag_error
307
335
  end
308
336
 
309
- #: (?Integer) -> String
310
- def tree_inspect(indent = 0)
337
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
338
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
311
339
  output = +""
312
340
 
313
- output += %(@ #{error_name} #{location.tree_inspect}\n)
314
- output += %(├── message: #{message.inspect}\n)
315
- output += %(├── tag_name: #{tag_name ? tag_name.tree_inspect : "∅"}\n)
316
- output += %(├── expected: #{expected.inspect}\n)
317
- output += %(└── found: #{found.inspect}\n)
341
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location.tree_inspect})\n")}")
342
+ output += white("├── message: #{green(message.inspect)}\n")
343
+ output += white("├── tag_name: ")
344
+ output += tag_name ? tag_name.tree_inspect : magenta("∅")
345
+ output += "\n"
346
+ output += white("├── expected: #{green(expected.inspect)}\n")
347
+ output += white("└── found: #{green(found.inspect)}\n")
318
348
  output += %(\n)
319
349
 
320
350
  output.gsub(/^/, " " * indent)
@@ -322,6 +352,8 @@ module Herb
322
352
  end
323
353
 
324
354
  class UnclosedElementError < Error
355
+ include Colors
356
+
325
357
  attr_reader :opening_tag #: Herb::Token
326
358
 
327
359
  #: (String, Location, String, Herb::Token) -> void
@@ -343,13 +375,15 @@ module Herb
343
375
  }) #: Herb::serialized_unclosed_element_error
344
376
  end
345
377
 
346
- #: (?Integer) -> String
347
- def tree_inspect(indent = 0)
378
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
379
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
348
380
  output = +""
349
381
 
350
- output += %(@ #{error_name} #{location.tree_inspect}\n)
351
- output += %(├── message: #{message.inspect}\n)
352
- output += %(└── opening_tag: #{opening_tag ? opening_tag.tree_inspect : "∅"}\n)
382
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location.tree_inspect})\n")}")
383
+ output += white("├── message: #{green(message.inspect)}\n")
384
+ output += white("└── opening_tag: ")
385
+ output += opening_tag ? opening_tag.tree_inspect : magenta("∅")
386
+ output += "\n"
353
387
  output += %(\n)
354
388
 
355
389
  output.gsub(/^/, " " * indent)
@@ -357,6 +391,8 @@ module Herb
357
391
  end
358
392
 
359
393
  class RubyParseError < Error
394
+ include Colors
395
+
360
396
  attr_reader :error_message #: String
361
397
  attr_reader :diagnostic_id #: String
362
398
  attr_reader :level #: String
@@ -384,15 +420,89 @@ module Herb
384
420
  }) #: Herb::serialized_ruby_parse_error
385
421
  end
386
422
 
387
- #: (?Integer) -> String
388
- def tree_inspect(indent = 0)
423
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
424
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
425
+ output = +""
426
+
427
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location.tree_inspect})\n")}")
428
+ output += white("├── message: #{green(message.inspect)}\n")
429
+ output += white("├── error_message: #{green(error_message.inspect)}\n")
430
+ output += white("├── diagnostic_id: #{green(diagnostic_id.inspect)}\n")
431
+ output += white("└── level: #{green(level.inspect)}\n")
432
+ output += %(\n)
433
+
434
+ output.gsub(/^/, " " * indent)
435
+ end
436
+ end
437
+
438
+ class ERBControlFlowScopeError < Error
439
+ include Colors
440
+
441
+ attr_reader :keyword #: String
442
+
443
+ #: (String, Location, String, String) -> void
444
+ def initialize(type, location, message, keyword)
445
+ super(type, location, message)
446
+
447
+ @keyword = keyword
448
+ end
449
+
450
+ #: () -> String
451
+ def inspect
452
+ tree_inspect.rstrip.gsub(/\s+$/, "")
453
+ end
454
+
455
+ #: () -> serialized_erb_control_flow_scope_error
456
+ def to_hash
457
+ super.merge({
458
+ keyword: keyword,
459
+ }) #: Herb::serialized_erb_control_flow_scope_error
460
+ end
461
+
462
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
463
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
464
+ output = +""
465
+
466
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location.tree_inspect})\n")}")
467
+ output += white("├── message: #{green(message.inspect)}\n")
468
+ output += white("└── keyword: #{green(keyword.inspect)}\n")
469
+ output += %(\n)
470
+
471
+ output.gsub(/^/, " " * indent)
472
+ end
473
+ end
474
+
475
+ class MissingERBEndTagError < Error
476
+ include Colors
477
+
478
+ attr_reader :keyword #: String
479
+
480
+ #: (String, Location, String, String) -> void
481
+ def initialize(type, location, message, keyword)
482
+ super(type, location, message)
483
+
484
+ @keyword = keyword
485
+ end
486
+
487
+ #: () -> String
488
+ def inspect
489
+ tree_inspect.rstrip.gsub(/\s+$/, "")
490
+ end
491
+
492
+ #: () -> serialized_missingerb_end_tag_error
493
+ def to_hash
494
+ super.merge({
495
+ keyword: keyword,
496
+ }) #: Herb::serialized_missingerb_end_tag_error
497
+ end
498
+
499
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
500
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
389
501
  output = +""
390
502
 
391
- output += %(@ #{error_name} #{location.tree_inspect}\n)
392
- output += %(├── message: #{message.inspect}\n)
393
- output += %(├── error_message: #{error_message.inspect}\n)
394
- output += %(├── diagnostic_id: #{diagnostic_id.inspect}\n)
395
- output += %(└── level: #{level.inspect}\n)
503
+ output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location.tree_inspect})\n")}")
504
+ output += white("├── message: #{green(message.inspect)}\n")
505
+ output += white("└── keyword: #{green(keyword.inspect)}\n")
396
506
  output += %(\n)
397
507
 
398
508
  output.gsub(/^/, " " * indent)
data/lib/herb/location.rb CHANGED
@@ -40,12 +40,12 @@ module Herb
40
40
 
41
41
  #: () -> String
42
42
  def tree_inspect
43
- %((location: #{start.tree_inspect}-#{self.end.tree_inspect}))
43
+ "#{start.tree_inspect}-#{self.end.tree_inspect}"
44
44
  end
45
45
 
46
46
  #: () -> String
47
47
  def inspect
48
- %(#<Herb::Location #{tree_inspect}>)
48
+ %(#<Herb::Location (location: #{tree_inspect})>)
49
49
  end
50
50
  end
51
51
  end
data/lib/herb/project.rb CHANGED
@@ -30,7 +30,7 @@ module Herb
30
30
  end
31
31
 
32
32
  def glob
33
- "**/*.html.erb"
33
+ "**/*.{html,rhtml,html.erb,html+*.erb,turbo_stream.erb}"
34
34
  end
35
35
 
36
36
  def full_path_glob
@@ -78,19 +78,23 @@ module Herb
78
78
  failed_files = []
79
79
  timeout_files = []
80
80
  error_files = []
81
+ compilation_failed_files = []
81
82
  error_outputs = {}
82
83
  file_contents = {}
83
84
  parse_errors = {}
85
+ compilation_errors = {}
84
86
 
85
87
  files.each_with_index do |file_path, index|
86
88
  total_failed = failed_files.count
87
89
  total_timeout = timeout_files.count
88
90
  total_errors = error_files.count
91
+ total_compilation_failed = compilation_failed_files.count
89
92
 
90
- lines_to_clear = 6 + total_failed + total_timeout + total_errors
93
+ lines_to_clear = 6 + total_failed + total_timeout + total_errors + total_compilation_failed
91
94
  lines_to_clear += 3 if total_failed.positive?
92
95
  lines_to_clear += 3 if total_timeout.positive?
93
96
  lines_to_clear += 3 if total_errors.positive?
97
+ lines_to_clear += 3 if total_compilation_failed.positive?
94
98
 
95
99
  lines_to_clear.times { print "\e[1A\e[K" } if index.positive? && interactive?
96
100
 
@@ -129,6 +133,13 @@ module Herb
129
133
  error_files.each { |file| puts " - #{file}" }
130
134
  puts
131
135
  end
136
+
137
+ if compilation_failed_files.any?
138
+ puts
139
+ puts "Files with compilation errors:"
140
+ compilation_failed_files.each { |file| puts " - #{file}" }
141
+ puts
142
+ end
132
143
  end
133
144
 
134
145
  begin
@@ -173,7 +184,33 @@ module Herb
173
184
  case $CHILD_STATUS.exitstatus
174
185
  when 0
175
186
  log.puts "✅ Parsed #{file_path} successfully"
176
- successful_files << file_path
187
+
188
+ begin
189
+ Herb::Engine.new(file_content, filename: file_path, escape: true)
190
+
191
+ log.puts "✅ Compiled #{file_path} successfully"
192
+ successful_files << file_path
193
+ rescue Herb::Engine::CompilationError => e
194
+ log.puts "❌ Compilation failed for #{file_path}"
195
+
196
+ compilation_failed_files << file_path
197
+ compilation_errors[file_path] = {
198
+ error: e.message,
199
+ backtrace: e.backtrace&.first(10) || [],
200
+ }
201
+
202
+ file_contents[file_path] = file_content
203
+ rescue StandardError => e
204
+ log.puts "❌ Unexpected compilation error for #{file_path}: #{e.class}: #{e.message}"
205
+
206
+ compilation_failed_files << file_path
207
+ compilation_errors[file_path] = {
208
+ error: "#{e.class}: #{e.message}",
209
+ backtrace: e.backtrace&.first(10) || [],
210
+ }
211
+
212
+ file_contents[file_path] = file_content
213
+ end
177
214
  when 2
178
215
  message = "⚠️ Parsing #{file_path} completed with errors"
179
216
  log.puts message
@@ -248,8 +285,11 @@ module Herb
248
285
  summary = [
249
286
  heading("Summary"),
250
287
  "Total files: #{files.count}",
251
- "✅ Successful: #{successful_files.count} (#{percentage(successful_files.count, files.count)}%)",
252
- "❌ Failed: #{failed_files.count} (#{percentage(failed_files.count, files.count)}%)",
288
+ "✅ Successful (parsed & compiled): #{successful_files.count} (#{percentage(successful_files.count,
289
+ files.count)}%)",
290
+ "❌ Compilation errors: #{compilation_failed_files.count} (#{percentage(compilation_failed_files.count,
291
+ files.count)}%)",
292
+ "❌ Failed to parse: #{failed_files.count} (#{percentage(failed_files.count, files.count)}%)",
253
293
  "⚠️ Parse errors: #{error_files.count} (#{percentage(error_files.count, files.count)}%)",
254
294
  "⏱️ Timed out: #{timeout_files.count} (#{percentage(timeout_files.count, files.count)}%)"
255
295
  ]
@@ -289,7 +329,17 @@ module Herb
289
329
  end
290
330
  end
291
331
 
292
- problem_files = failed_files + timeout_files + error_files
332
+ if compilation_failed_files.any?
333
+ log.puts "\n#{heading("Files with compilation errors")}"
334
+ puts "\nFiles with compilation errors:"
335
+
336
+ compilation_failed_files.each do |f|
337
+ log.puts f
338
+ puts " - #{f}"
339
+ end
340
+ end
341
+
342
+ problem_files = failed_files + timeout_files + error_files + compilation_failed_files
293
343
 
294
344
  if problem_files.any?
295
345
  log.puts "\n#{heading("FILE CONTENTS AND DETAILS")}"
@@ -331,28 +381,43 @@ module Herb
331
381
  end
332
382
  end
333
383
 
334
- next unless parse_errors[file]
384
+ if parse_errors[file]
385
+ if parse_errors[file][:stdout].strip.length.positive?
386
+ log.puts "\n#{heading("STANDARD OUTPUT")}"
387
+ log.puts "```"
388
+ log.puts parse_errors[file][:stdout]
389
+ log.puts "```"
390
+ end
335
391
 
336
- if parse_errors[file][:stdout].strip.length.positive?
337
- log.puts "\n#{heading("STANDARD OUTPUT")}"
338
- log.puts "```"
339
- log.puts parse_errors[file][:stdout]
340
- log.puts "```"
341
- end
392
+ if parse_errors[file][:stderr].strip.length.positive?
393
+ log.puts "\n#{heading("ERROR OUTPUT")}"
394
+ log.puts "```"
395
+ log.puts parse_errors[file][:stderr]
396
+ log.puts "```"
397
+ end
342
398
 
343
- if parse_errors[file][:stderr].strip.length.positive?
344
- log.puts "\n#{heading("ERROR OUTPUT")}"
345
- log.puts "```"
346
- log.puts parse_errors[file][:stderr]
347
- log.puts "```"
399
+ if parse_errors[file][:ast]
400
+ log.puts "\n#{heading("AST")}"
401
+ log.puts "```"
402
+ log.puts parse_errors[file][:ast]
403
+ log.puts "```"
404
+ log.puts
405
+ end
348
406
  end
349
407
 
350
- next unless parse_errors[file][:ast]
408
+ next unless compilation_errors[file]
351
409
 
352
- log.puts "\n#{heading("AST")}"
410
+ log.puts "\n#{heading("COMPILATION ERROR")}"
353
411
  log.puts "```"
354
- log.puts parse_errors[file][:ast]
412
+ log.puts compilation_errors[file][:error]
355
413
  log.puts "```"
414
+
415
+ if compilation_errors[file][:backtrace].any?
416
+ log.puts "\n#{heading("BACKTRACE")}"
417
+ log.puts "```"
418
+ log.puts compilation_errors[file][:backtrace].join("\n")
419
+ log.puts "```"
420
+ end
356
421
  log.puts
357
422
  end
358
423
  end
data/lib/herb/token.rb CHANGED
@@ -3,6 +3,8 @@
3
3
 
4
4
  module Herb
5
5
  class Token
6
+ include Colors
7
+
6
8
  attr_reader :value #: String
7
9
  attr_reader :range #: Range
8
10
  attr_reader :location #: Location
@@ -33,7 +35,7 @@ module Herb
33
35
 
34
36
  #: () -> String
35
37
  def tree_inspect
36
- %("#{value.force_encoding("utf-8")}" #{location.tree_inspect})
38
+ "#{green("\"#{value.force_encoding("utf-8")}\"")} #{dimmed("(location: #{location.tree_inspect})")}"
37
39
  end
38
40
 
39
41
  #: () -> String
@@ -45,9 +47,19 @@ module Herb
45
47
  end
46
48
  end
47
49
 
50
+ #: () -> String
51
+ def colorize_range
52
+ white("[") + cyan(range.from.to_s) + white(", ") + cyan(range.to.to_s) + white("]")
53
+ end
54
+
55
+ #: (Position) -> String
56
+ def colorize_position(position)
57
+ white("(") + cyan(position.line.to_s) + white(":") + cyan(position.column.to_s) + white(")")
58
+ end
59
+
48
60
  #: () -> String
49
61
  def inspect
50
- %(#<Herb::Token type="#{type}" value=#{value_inspect} range=#{range.tree_inspect} start=#{location.start.tree_inspect} end=#{location.end.tree_inspect}>)
62
+ "#{white("#<")}#{bold(yellow("Herb::Token"))} #{white("type=")}#{bright_magenta("\"#{type}\"")} #{white("value=")}#{green(value_inspect)} #{white("range=")}#{colorize_range} #{white("start=")}#{colorize_position(location.start)} #{white("end=")}#{colorize_position(location.end)}#{white(">")}"
51
63
  end
52
64
  end
53
65
  end
data/lib/herb/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # typed: true
3
3
 
4
4
  module Herb
5
- VERSION = "0.7.4"
5
+ VERSION = "0.8.0"
6
6
  end
data/lib/herb.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  # typed: false
3
3
 
4
+ require_relative "herb/colors"
4
5
  require_relative "herb/range"
5
6
  require_relative "herb/position"
6
7
  require_relative "herb/location"
@@ -11,6 +11,9 @@ module Herb
11
11
 
12
12
  # : (String) -> bool
13
13
  def erb_output?: (String) -> bool
14
+
15
+ # : (Herb::AST::ERBContentNode) -> bool
16
+ def inline_ruby_comment?: (Herb::AST::ERBContentNode) -> bool
14
17
  end
15
18
  end
16
19
  end
@@ -27,11 +27,18 @@ module Herb
27
27
  # : (?prefix: String) -> String
28
28
  def inspect_errors: (?prefix: String) -> String
29
29
 
30
- # : (Array[Herb::AST::Node|Herb::Errors::Error], ?item_name: String, ?prefix: String) -> String
31
- def inspect_array: (Array[Herb::AST::Node | Herb::Errors::Error], ?item_name: String, ?prefix: String) -> String
32
-
33
- # : (?Integer) -> String
34
- def tree_inspect: (?Integer) -> String
30
+ # : (
31
+ # | Array[Herb::AST::Node|Herb::Errors::Error],
32
+ # | ?item_name: String,
33
+ # | ?prefix: String,
34
+ # | ?indent: Integer,
35
+ # | ?depth: Integer,
36
+ # | ?depth_limit: Integer
37
+ # | ) -> String
38
+ def inspect_array: (untyped array, ?item_name: untyped, ?prefix: untyped, ?indent: untyped, ?depth: untyped, ?depth_limit: untyped) -> untyped
39
+
40
+ # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
41
+ def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
35
42
 
36
43
  # : (Visitor) -> void
37
44
  def accept: (Visitor) -> void