herb 0.7.5 → 0.8.0
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.
- checksums.yaml +4 -4
- data/Makefile +8 -5
- data/config.yml +26 -6
- data/ext/herb/error_helpers.c +57 -3
- data/ext/herb/error_helpers.h +1 -1
- data/ext/herb/extconf.rb +1 -0
- data/ext/herb/extension.c +10 -24
- data/ext/herb/extension_helpers.c +3 -3
- data/ext/herb/extension_helpers.h +1 -1
- data/ext/herb/nodes.c +72 -37
- data/herb.gemspec +0 -2
- data/lib/herb/ast/helpers.rb +11 -0
- data/lib/herb/ast/node.rb +15 -6
- data/lib/herb/ast/nodes.rb +609 -392
- data/lib/herb/cli.rb +31 -0
- data/lib/herb/colors.rb +82 -0
- data/lib/herb/engine/compiler.rb +140 -14
- data/lib/herb/engine/debug_visitor.rb +1 -5
- data/lib/herb/engine/parser_error_overlay.rb +1 -1
- data/lib/herb/engine.rb +8 -14
- data/lib/herb/errors.rb +166 -56
- data/lib/herb/location.rb +2 -2
- data/lib/herb/project.rb +86 -21
- data/lib/herb/token.rb +14 -2
- data/lib/herb/version.rb +1 -1
- data/lib/herb.rb +1 -0
- data/sig/herb/ast/helpers.rbs +3 -0
- data/sig/herb/ast/node.rbs +12 -5
- data/sig/herb/ast/nodes.rbs +124 -62
- data/sig/herb/colors.rbs +35 -0
- data/sig/herb/engine/compiler.rbs +23 -1
- data/sig/herb/errors.rbs +74 -20
- data/sig/herb/token.rbs +8 -0
- data/sig/herb_c_extension.rbs +1 -1
- data/sig/serialized_ast_errors.rbs +8 -0
- data/src/analyze.c +420 -171
- data/src/analyze_helpers.c +5 -0
- data/src/analyze_missing_end.c +147 -0
- data/src/analyze_transform.c +196 -0
- data/src/analyzed_ruby.c +23 -2
- data/src/ast_node.c +5 -5
- data/src/ast_nodes.c +179 -179
- data/src/ast_pretty_print.c +232 -232
- data/src/element_source.c +7 -6
- data/src/errors.c +246 -126
- data/src/extract.c +92 -34
- data/src/herb.c +37 -49
- data/src/html_util.c +34 -96
- data/src/include/analyze.h +10 -2
- data/src/include/analyze_helpers.h +3 -0
- data/src/include/analyzed_ruby.h +4 -2
- data/src/include/ast_node.h +2 -2
- data/src/include/ast_nodes.h +67 -66
- data/src/include/ast_pretty_print.h +2 -2
- data/src/include/element_source.h +3 -1
- data/src/include/errors.h +30 -14
- data/src/include/extract.h +4 -4
- data/src/include/herb.h +6 -7
- data/src/include/html_util.h +4 -5
- data/src/include/lexer.h +1 -3
- data/src/include/lexer_peek_helpers.h +14 -14
- data/src/include/lexer_struct.h +3 -2
- data/src/include/macros.h +4 -0
- data/src/include/parser.h +12 -6
- data/src/include/parser_helpers.h +25 -15
- data/src/include/pretty_print.h +38 -28
- data/src/include/token.h +5 -8
- data/src/include/utf8.h +3 -2
- data/src/include/util/hb_arena.h +31 -0
- data/src/include/util/hb_arena_debug.h +8 -0
- data/src/include/util/hb_array.h +33 -0
- data/src/include/util/hb_buffer.h +34 -0
- data/src/include/util/hb_string.h +29 -0
- data/src/include/util/hb_system.h +9 -0
- data/src/include/util.h +3 -14
- data/src/include/version.h +1 -1
- data/src/include/visitor.h +1 -1
- data/src/io.c +7 -4
- data/src/lexer.c +61 -88
- data/src/lexer_peek_helpers.c +35 -37
- data/src/main.c +19 -23
- data/src/parser.c +282 -201
- data/src/parser_helpers.c +46 -40
- data/src/parser_match_tags.c +316 -0
- data/src/pretty_print.c +82 -106
- data/src/token.c +18 -65
- data/src/utf8.c +4 -4
- data/src/util/hb_arena.c +179 -0
- data/src/util/hb_arena_debug.c +237 -0
- data/src/{array.c → util/hb_array.c} +26 -27
- data/src/util/hb_buffer.c +203 -0
- data/src/util/hb_string.c +85 -0
- data/src/util/hb_system.c +30 -0
- data/src/util.c +29 -99
- data/src/visitor.c +54 -54
- data/templates/ext/herb/error_helpers.c.erb +3 -3
- data/templates/ext/herb/error_helpers.h.erb +1 -1
- data/templates/ext/herb/nodes.c.erb +11 -6
- data/templates/java/error_helpers.c.erb +75 -0
- data/templates/java/error_helpers.h.erb +20 -0
- data/templates/java/nodes.c.erb +97 -0
- data/templates/java/nodes.h.erb +23 -0
- data/templates/java/org/herb/ast/Errors.java.erb +121 -0
- data/templates/java/org/herb/ast/NodeVisitor.java.erb +14 -0
- data/templates/java/org/herb/ast/Nodes.java.erb +220 -0
- data/templates/java/org/herb/ast/Visitor.java.erb +56 -0
- data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +8 -8
- data/templates/javascript/packages/node/extension/error_helpers.h.erb +1 -1
- data/templates/javascript/packages/node/extension/nodes.cpp.erb +9 -9
- data/templates/javascript/packages/node/extension/nodes.h.erb +1 -1
- data/templates/lib/herb/ast/nodes.rb.erb +28 -16
- data/templates/lib/herb/errors.rb.erb +17 -12
- data/templates/rust/src/ast/nodes.rs.erb +220 -0
- data/templates/rust/src/errors.rs.erb +216 -0
- data/templates/rust/src/nodes.rs.erb +374 -0
- data/templates/src/analyze_missing_end.c.erb +36 -0
- data/templates/src/analyze_transform.c.erb +24 -0
- data/templates/src/ast_nodes.c.erb +14 -14
- data/templates/src/ast_pretty_print.c.erb +36 -36
- data/templates/src/errors.c.erb +31 -31
- data/templates/src/include/ast_nodes.h.erb +10 -9
- data/templates/src/include/ast_pretty_print.h.erb +2 -2
- data/templates/src/include/errors.h.erb +6 -6
- data/templates/src/parser_match_tags.c.erb +38 -0
- data/templates/src/visitor.c.erb +4 -4
- data/templates/template.rb +22 -3
- data/templates/wasm/error_helpers.cpp.erb +9 -9
- data/templates/wasm/error_helpers.h.erb +1 -1
- data/templates/wasm/nodes.cpp.erb +9 -9
- data/templates/wasm/nodes.h.erb +1 -1
- data/vendor/prism/Rakefile +4 -1
- data/vendor/prism/config.yml +2 -1
- data/vendor/prism/include/prism/ast.h +31 -1
- data/vendor/prism/include/prism/diagnostic.h +1 -0
- data/vendor/prism/include/prism/version.h +3 -3
- data/vendor/prism/src/diagnostic.c +3 -1
- data/vendor/prism/src/prism.c +130 -71
- data/vendor/prism/src/util/pm_string.c +6 -8
- data/vendor/prism/templates/include/prism/ast.h.erb +2 -0
- data/vendor/prism/templates/java/org/prism/Loader.java.erb +2 -2
- data/vendor/prism/templates/javascript/src/deserialize.js.erb +2 -2
- data/vendor/prism/templates/lib/prism/serialize.rb.erb +2 -2
- data/vendor/prism/templates/sig/prism.rbs.erb +4 -0
- data/vendor/prism/templates/src/diagnostic.c.erb +1 -0
- metadata +34 -20
- data/lib/herb/libherb/array.rb +0 -51
- data/lib/herb/libherb/ast_node.rb +0 -50
- data/lib/herb/libherb/buffer.rb +0 -56
- data/lib/herb/libherb/extract_result.rb +0 -20
- data/lib/herb/libherb/lex_result.rb +0 -32
- data/lib/herb/libherb/libherb.rb +0 -52
- data/lib/herb/libherb/parse_result.rb +0 -20
- data/lib/herb/libherb/token.rb +0 -46
- data/lib/herb/libherb.rb +0 -35
- data/src/buffer.c +0 -241
- data/src/include/array.h +0 -33
- data/src/include/buffer.h +0 -39
- data/src/include/json.h +0 -28
- data/src/include/memory.h +0 -12
- data/src/json.c +0 -205
- data/src/memory.c +0 -53
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(
|
|
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
|
|
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 +=
|
|
84
|
-
output +=
|
|
85
|
-
output +=
|
|
86
|
-
output +=
|
|
87
|
-
output +=
|
|
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
|
|
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 +=
|
|
124
|
-
output +=
|
|
125
|
-
output +=
|
|
126
|
-
output +=
|
|
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
|
|
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 +=
|
|
160
|
-
output +=
|
|
161
|
-
output +=
|
|
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
|
|
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 +=
|
|
195
|
-
output +=
|
|
196
|
-
output +=
|
|
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
|
|
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 +=
|
|
233
|
-
output +=
|
|
234
|
-
output +=
|
|
235
|
-
output +=
|
|
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
|
|
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 +=
|
|
272
|
-
output +=
|
|
273
|
-
output +=
|
|
274
|
-
output +=
|
|
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
|
|
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 +=
|
|
314
|
-
output +=
|
|
315
|
-
output +=
|
|
316
|
-
output +=
|
|
317
|
-
output +=
|
|
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
|
|
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 +=
|
|
351
|
-
output +=
|
|
352
|
-
output +=
|
|
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
|
|
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 +=
|
|
392
|
-
output +=
|
|
393
|
-
output +=
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
252
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
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
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
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
|
|
408
|
+
next unless compilation_errors[file]
|
|
351
409
|
|
|
352
|
-
log.puts "\n#{heading("
|
|
410
|
+
log.puts "\n#{heading("COMPILATION ERROR")}"
|
|
353
411
|
log.puts "```"
|
|
354
|
-
log.puts
|
|
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
|
-
|
|
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
|
-
|
|
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
data/lib/herb.rb
CHANGED
data/sig/herb/ast/helpers.rbs
CHANGED
data/sig/herb/ast/node.rbs
CHANGED
|
@@ -27,11 +27,18 @@ module Herb
|
|
|
27
27
|
# : (?prefix: String) -> String
|
|
28
28
|
def inspect_errors: (?prefix: String) -> String
|
|
29
29
|
|
|
30
|
-
# : (
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
# :
|
|
34
|
-
|
|
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
|