herb 0.8.10-arm-linux-gnu → 0.9.0-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.
- checksums.yaml +4 -4
- data/Makefile +11 -3
- data/README.md +64 -34
- data/Rakefile +48 -40
- data/config.yml +317 -34
- data/ext/herb/error_helpers.c +367 -140
- data/ext/herb/error_helpers.h +1 -0
- data/ext/herb/extconf.rb +67 -28
- data/ext/herb/extension.c +317 -51
- data/ext/herb/extension.h +1 -0
- data/ext/herb/extension_helpers.c +23 -14
- data/ext/herb/extension_helpers.h +2 -2
- data/ext/herb/nodes.c +537 -270
- data/ext/herb/nodes.h +1 -0
- data/herb.gemspec +3 -2
- data/lib/herb/3.0/herb.so +0 -0
- data/lib/herb/3.1/herb.so +0 -0
- data/lib/herb/3.2/herb.so +0 -0
- data/lib/herb/3.3/herb.so +0 -0
- data/lib/herb/3.4/herb.so +0 -0
- data/lib/herb/4.0/herb.so +0 -0
- data/lib/herb/ast/helpers.rb +3 -3
- data/lib/herb/ast/node.rb +15 -2
- data/lib/herb/ast/nodes.rb +1132 -157
- data/lib/herb/bootstrap.rb +87 -0
- data/lib/herb/cli.rb +341 -31
- data/lib/herb/configuration.rb +248 -0
- data/lib/herb/defaults.yml +32 -0
- data/lib/herb/engine/compiler.rb +78 -11
- data/lib/herb/engine/debug_visitor.rb +13 -3
- data/lib/herb/engine/error_formatter.rb +13 -9
- data/lib/herb/engine/parser_error_overlay.rb +10 -6
- data/lib/herb/engine/validator.rb +8 -3
- data/lib/herb/engine/validators/nesting_validator.rb +2 -2
- data/lib/herb/engine.rb +82 -35
- data/lib/herb/errors.rb +563 -88
- data/lib/herb/lex_result.rb +1 -0
- data/lib/herb/location.rb +7 -3
- data/lib/herb/parse_result.rb +12 -2
- data/lib/herb/parser_options.rb +57 -0
- data/lib/herb/position.rb +1 -0
- data/lib/herb/prism_inspect.rb +116 -0
- data/lib/herb/project.rb +923 -331
- data/lib/herb/range.rb +1 -0
- data/lib/herb/token.rb +7 -1
- data/lib/herb/version.rb +1 -1
- data/lib/herb/visitor.rb +37 -2
- data/lib/herb/warnings.rb +6 -1
- data/lib/herb.rb +35 -3
- data/sig/herb/ast/helpers.rbs +2 -2
- data/sig/herb/ast/node.rbs +12 -2
- data/sig/herb/ast/nodes.rbs +641 -128
- data/sig/herb/bootstrap.rbs +31 -0
- data/sig/herb/configuration.rbs +89 -0
- data/sig/herb/engine/compiler.rbs +9 -1
- data/sig/herb/engine/debug_visitor.rbs +2 -0
- data/sig/herb/engine/validator.rbs +5 -1
- data/sig/herb/engine.rbs +17 -3
- data/sig/herb/errors.rbs +258 -63
- data/sig/herb/location.rbs +4 -0
- data/sig/herb/parse_result.rbs +4 -2
- data/sig/herb/parser_options.rbs +42 -0
- data/sig/herb/position.rbs +1 -0
- data/sig/herb/prism_inspect.rbs +28 -0
- data/sig/herb/range.rbs +1 -0
- data/sig/herb/token.rbs +6 -0
- data/sig/herb/visitor.rbs +25 -4
- data/sig/herb/warnings.rbs +6 -1
- data/sig/herb.rbs +14 -0
- data/sig/herb_c_extension.rbs +5 -2
- data/sig/serialized_ast_errors.rbs +54 -6
- data/sig/serialized_ast_nodes.rbs +60 -6
- data/src/analyze/action_view/attribute_extraction_helpers.c +290 -0
- data/src/analyze/action_view/content_tag.c +70 -0
- data/src/analyze/action_view/link_to.c +143 -0
- data/src/analyze/action_view/registry.c +60 -0
- data/src/analyze/action_view/tag.c +64 -0
- data/src/analyze/action_view/tag_helper_node_builders.c +305 -0
- data/src/analyze/action_view/tag_helpers.c +748 -0
- data/src/analyze/action_view/turbo_frame_tag.c +88 -0
- data/src/analyze/analyze.c +882 -0
- data/src/{analyzed_ruby.c → analyze/analyzed_ruby.c} +13 -11
- data/src/analyze/builders.c +343 -0
- data/src/analyze/conditional_elements.c +594 -0
- data/src/analyze/conditional_open_tags.c +640 -0
- data/src/analyze/control_type.c +250 -0
- data/src/{analyze_helpers.c → analyze/helpers.c} +48 -23
- data/src/analyze/invalid_structures.c +193 -0
- data/src/{analyze_missing_end.c → analyze/missing_end.c} +33 -22
- data/src/analyze/parse_errors.c +84 -0
- data/src/analyze/prism_annotate.c +397 -0
- data/src/{analyze_transform.c → analyze/transform.c} +17 -3
- data/src/ast_node.c +17 -7
- data/src/ast_nodes.c +662 -387
- data/src/ast_pretty_print.c +190 -6
- data/src/errors.c +1076 -520
- data/src/extract.c +145 -49
- data/src/herb.c +52 -34
- data/src/html_util.c +241 -12
- data/src/include/analyze/action_view/attribute_extraction_helpers.h +36 -0
- data/src/include/analyze/action_view/tag_helper_handler.h +41 -0
- data/src/include/analyze/action_view/tag_helper_node_builders.h +70 -0
- data/src/include/analyze/action_view/tag_helpers.h +38 -0
- data/src/include/{analyze.h → analyze/analyze.h} +14 -4
- data/src/include/{analyzed_ruby.h → analyze/analyzed_ruby.h} +3 -3
- data/src/include/analyze/builders.h +27 -0
- data/src/include/analyze/conditional_elements.h +9 -0
- data/src/include/analyze/conditional_open_tags.h +9 -0
- data/src/include/analyze/control_type.h +14 -0
- data/src/include/{analyze_helpers.h → analyze/helpers.h} +4 -2
- data/src/include/analyze/invalid_structures.h +11 -0
- data/src/include/analyze/prism_annotate.h +16 -0
- data/src/include/ast_node.h +11 -5
- data/src/include/ast_nodes.h +117 -38
- data/src/include/ast_pretty_print.h +5 -0
- data/src/include/element_source.h +3 -8
- data/src/include/errors.h +148 -55
- data/src/include/extract.h +21 -5
- data/src/include/herb.h +18 -6
- data/src/include/herb_prism_node.h +13 -0
- data/src/include/html_util.h +7 -2
- data/src/include/io.h +3 -1
- data/src/include/lex_helpers.h +29 -0
- data/src/include/lexer.h +1 -1
- data/src/include/lexer_peek_helpers.h +87 -13
- data/src/include/lexer_struct.h +2 -0
- data/src/include/location.h +2 -1
- data/src/include/parser.h +27 -2
- data/src/include/parser_helpers.h +19 -3
- data/src/include/pretty_print.h +10 -5
- data/src/include/prism_context.h +45 -0
- data/src/include/prism_helpers.h +10 -7
- data/src/include/prism_serialized.h +12 -0
- data/src/include/token.h +16 -4
- data/src/include/token_struct.h +10 -3
- data/src/include/utf8.h +2 -1
- data/src/include/util/hb_allocator.h +78 -0
- data/src/include/util/hb_arena.h +6 -1
- data/src/include/util/hb_arena_debug.h +12 -1
- data/src/include/util/hb_array.h +7 -3
- data/src/include/util/hb_buffer.h +6 -4
- data/src/include/util/hb_foreach.h +79 -0
- data/src/include/util/hb_narray.h +8 -4
- data/src/include/util/hb_string.h +56 -9
- data/src/include/util.h +6 -3
- data/src/include/version.h +1 -1
- data/src/io.c +3 -2
- data/src/lexer.c +42 -30
- data/src/lexer_peek_helpers.c +12 -74
- data/src/location.c +2 -2
- data/src/main.c +53 -28
- data/src/parser.c +783 -247
- data/src/parser_helpers.c +110 -23
- data/src/parser_match_tags.c +109 -48
- data/src/pretty_print.c +29 -24
- data/src/prism_helpers.c +30 -27
- data/src/ruby_parser.c +2 -0
- data/src/token.c +151 -66
- data/src/token_matchers.c +0 -1
- data/src/utf8.c +7 -6
- data/src/util/hb_allocator.c +341 -0
- data/src/util/hb_arena.c +81 -56
- data/src/util/hb_arena_debug.c +32 -17
- data/src/util/hb_array.c +30 -15
- data/src/util/hb_buffer.c +17 -21
- data/src/util/hb_narray.c +22 -7
- data/src/util/hb_string.c +49 -35
- data/src/util.c +21 -11
- data/src/visitor.c +47 -0
- data/templates/ext/herb/error_helpers.c.erb +24 -11
- data/templates/ext/herb/error_helpers.h.erb +1 -0
- data/templates/ext/herb/nodes.c.erb +50 -16
- data/templates/ext/herb/nodes.h.erb +1 -0
- data/templates/java/error_helpers.c.erb +1 -1
- data/templates/java/nodes.c.erb +30 -8
- data/templates/java/org/herb/ast/Errors.java.erb +24 -1
- data/templates/java/org/herb/ast/Nodes.java.erb +80 -21
- data/templates/javascript/packages/core/src/errors.ts.erb +16 -3
- data/templates/javascript/packages/core/src/node-type-guards.ts.erb +3 -1
- data/templates/javascript/packages/core/src/nodes.ts.erb +109 -32
- data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +13 -4
- data/templates/javascript/packages/node/extension/nodes.cpp.erb +43 -4
- data/templates/lib/herb/ast/nodes.rb.erb +88 -31
- data/templates/lib/herb/errors.rb.erb +15 -3
- data/templates/lib/herb/visitor.rb.erb +2 -2
- data/templates/rust/src/ast/nodes.rs.erb +97 -44
- data/templates/rust/src/errors.rs.erb +2 -1
- data/templates/rust/src/nodes.rs.erb +167 -15
- data/templates/rust/src/union_types.rs.erb +60 -0
- data/templates/rust/src/visitor.rs.erb +81 -0
- data/templates/src/{analyze_missing_end.c.erb → analyze/missing_end.c.erb} +9 -6
- data/templates/src/{analyze_transform.c.erb → analyze/transform.c.erb} +2 -2
- data/templates/src/ast_nodes.c.erb +34 -26
- data/templates/src/ast_pretty_print.c.erb +24 -5
- data/templates/src/errors.c.erb +60 -54
- data/templates/src/include/ast_nodes.h.erb +6 -2
- data/templates/src/include/ast_pretty_print.h.erb +5 -0
- data/templates/src/include/errors.h.erb +15 -11
- data/templates/src/include/util/hb_foreach.h.erb +20 -0
- data/templates/src/parser_match_tags.c.erb +10 -4
- data/templates/src/visitor.c.erb +2 -2
- data/templates/template.rb +204 -29
- data/templates/wasm/error_helpers.cpp.erb +9 -5
- data/templates/wasm/nodes.cpp.erb +41 -4
- metadata +57 -16
- data/src/analyze.c +0 -1608
- data/src/element_source.c +0 -12
- data/src/include/util/hb_system.h +0 -9
- data/src/util/hb_system.c +0 -30
data/lib/herb/engine.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
# typed: false
|
|
2
3
|
|
|
3
4
|
require "json"
|
|
4
5
|
require "time"
|
|
@@ -17,7 +18,7 @@ require_relative "engine/validators/accessibility_validator"
|
|
|
17
18
|
module Herb
|
|
18
19
|
class Engine
|
|
19
20
|
attr_reader :src, :filename, :project_path, :relative_file_path, :bufvar, :debug, :content_for_head,
|
|
20
|
-
:validation_error_template, :visitors
|
|
21
|
+
:validation_error_template, :visitors, :enabled_validators
|
|
21
22
|
|
|
22
23
|
ESCAPE_TABLE = {
|
|
23
24
|
"&" => "&",
|
|
@@ -30,6 +31,16 @@ module Herb
|
|
|
30
31
|
class CompilationError < StandardError
|
|
31
32
|
end
|
|
32
33
|
|
|
34
|
+
class InvalidRubyError < CompilationError
|
|
35
|
+
attr_reader :compiled_source
|
|
36
|
+
|
|
37
|
+
def initialize(message, compiled_source: nil)
|
|
38
|
+
@compiled_source = compiled_source
|
|
39
|
+
|
|
40
|
+
super(message)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
33
44
|
def initialize(input, properties = {})
|
|
34
45
|
@filename = properties[:filename] ? ::Pathname.new(properties[:filename]) : nil
|
|
35
46
|
@project_path = ::Pathname.new(properties[:project_path] || Dir.pwd)
|
|
@@ -51,6 +62,8 @@ module Herb
|
|
|
51
62
|
@content_for_head = properties[:content_for_head]
|
|
52
63
|
@validation_error_template = nil
|
|
53
64
|
@validation_mode = properties.fetch(:validation_mode, :raise)
|
|
65
|
+
@enabled_validators = Herb.configuration.enabled_validators(properties[:validators] || {})
|
|
66
|
+
@strict = properties.fetch(:strict, true)
|
|
54
67
|
@visitors = properties.fetch(:visitors, default_visitors)
|
|
55
68
|
|
|
56
69
|
if @debug && @visitors.empty?
|
|
@@ -75,6 +88,8 @@ module Herb
|
|
|
75
88
|
preamble = properties[:preamble] || "#{@bufvar} = #{bufval};"
|
|
76
89
|
postamble = properties[:postamble] || "#{@bufvar}.to_s\n"
|
|
77
90
|
|
|
91
|
+
preamble = "#{preamble}; " unless preamble.empty? || preamble.end_with?(";", " ", "\n")
|
|
92
|
+
|
|
78
93
|
@src << "# frozen_string_literal: true\n" if @freeze
|
|
79
94
|
|
|
80
95
|
if properties[:ensure]
|
|
@@ -89,7 +104,7 @@ module Herb
|
|
|
89
104
|
@src << "__herb = ::Herb::Engine; " if @escape && @escapefunc == "__herb.h"
|
|
90
105
|
@src << preamble
|
|
91
106
|
|
|
92
|
-
parse_result = ::Herb.parse(input, track_whitespace: true)
|
|
107
|
+
parse_result = ::Herb.parse(input, track_whitespace: true, strict: @strict)
|
|
93
108
|
ast = parse_result.value
|
|
94
109
|
parser_errors = parse_result.errors
|
|
95
110
|
|
|
@@ -104,12 +119,12 @@ module Herb
|
|
|
104
119
|
# Skip both errors and compilation, but still need minimal Ruby code
|
|
105
120
|
end
|
|
106
121
|
else
|
|
107
|
-
|
|
108
|
-
all_errors = parser_errors + (validation_errors || [])
|
|
122
|
+
validators = run_validation(ast) unless @validation_mode == :none
|
|
109
123
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
124
|
+
if validators
|
|
125
|
+
handle_validation_errors(validators, input) if @validation_mode == :raise
|
|
126
|
+
add_validation_overlay(validators, input) if @validation_mode == :overlay
|
|
127
|
+
end
|
|
113
128
|
|
|
114
129
|
@visitors.each do |visitor|
|
|
115
130
|
ast.accept(visitor)
|
|
@@ -132,6 +147,18 @@ module Herb
|
|
|
132
147
|
|
|
133
148
|
@src << "; ensure\n #{@bufvar} = __original_outvar\nend\n" if properties[:ensure]
|
|
134
149
|
|
|
150
|
+
if properties.fetch(:validate_ruby, false)
|
|
151
|
+
require "prism"
|
|
152
|
+
|
|
153
|
+
prism_result = Prism.parse(@src)
|
|
154
|
+
syntax_errors = prism_result.errors.reject { |e| e.type == :invalid_yield }
|
|
155
|
+
|
|
156
|
+
if syntax_errors.any?
|
|
157
|
+
details = syntax_errors.map { |e| " - #{e.message} (line #{e.location.start_line})" }.join("\n")
|
|
158
|
+
raise InvalidRubyError.new("Compiled template produced invalid Ruby:\n#{details}", compiled_source: @src)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
135
162
|
@src.freeze
|
|
136
163
|
freeze
|
|
137
164
|
end
|
|
@@ -172,6 +199,14 @@ module Herb
|
|
|
172
199
|
end
|
|
173
200
|
end
|
|
174
201
|
|
|
202
|
+
def self.comment?(code)
|
|
203
|
+
code.include?("#")
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def self.heredoc?(code)
|
|
207
|
+
code.match?(/<<[~-]?\s*['"`]?\w/)
|
|
208
|
+
end
|
|
209
|
+
|
|
175
210
|
protected
|
|
176
211
|
|
|
177
212
|
def add_text(text)
|
|
@@ -193,8 +228,8 @@ module Herb
|
|
|
193
228
|
@src << " " << code
|
|
194
229
|
|
|
195
230
|
# TODO: rework and check for Prism::InlineComment as soon as we expose the Prism Nodes in the Herb AST
|
|
196
|
-
if code.
|
|
197
|
-
@src << "\n"
|
|
231
|
+
if self.class.comment?(code) || self.class.heredoc?(code)
|
|
232
|
+
@src << "\n" unless code[-1] == "\n"
|
|
198
233
|
else
|
|
199
234
|
@src << ";" unless code[-1] == "\n"
|
|
200
235
|
end
|
|
@@ -213,13 +248,13 @@ module Herb
|
|
|
213
248
|
|
|
214
249
|
def add_expression_result(code)
|
|
215
250
|
with_buffer {
|
|
216
|
-
@src << " << (" << code <<
|
|
251
|
+
@src << " << (" << code << trailing_newline(code) << ").to_s"
|
|
217
252
|
}
|
|
218
253
|
end
|
|
219
254
|
|
|
220
255
|
def add_expression_result_escaped(code)
|
|
221
256
|
with_buffer {
|
|
222
|
-
@src << " << " << @escapefunc << "((" << code <<
|
|
257
|
+
@src << " << " << @escapefunc << "((" << code << trailing_newline(code) << "))"
|
|
223
258
|
}
|
|
224
259
|
end
|
|
225
260
|
|
|
@@ -233,18 +268,37 @@ module Herb
|
|
|
233
268
|
|
|
234
269
|
def add_expression_block_result(code)
|
|
235
270
|
with_buffer {
|
|
236
|
-
@src << " << " << code <<
|
|
271
|
+
@src << " << (" << code << trailing_newline(code)
|
|
237
272
|
}
|
|
238
273
|
end
|
|
239
274
|
|
|
240
275
|
def add_expression_block_result_escaped(code)
|
|
241
276
|
with_buffer {
|
|
242
|
-
@src << " << " << @escapefunc << "(" << code <<
|
|
277
|
+
@src << " << " << @escapefunc << "((" << code << trailing_newline(code)
|
|
243
278
|
}
|
|
244
279
|
end
|
|
245
280
|
|
|
246
|
-
def
|
|
247
|
-
|
|
281
|
+
def add_expression_block_end(code, escaped: false)
|
|
282
|
+
terminate_expression
|
|
283
|
+
|
|
284
|
+
trailing_newline = code.end_with?("\n")
|
|
285
|
+
code_stripped = code.chomp
|
|
286
|
+
|
|
287
|
+
@src.chomp! if @src.end_with?("\n") && code_stripped.start_with?(" ")
|
|
288
|
+
|
|
289
|
+
@src << " " << code_stripped
|
|
290
|
+
@src << "\n" if self.class.comment?(code_stripped)
|
|
291
|
+
@src << (escaped ? "))" : ")")
|
|
292
|
+
@src << (trailing_newline ? "\n" : ";")
|
|
293
|
+
|
|
294
|
+
@buffer_on_stack = false
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def trailing_newline(code)
|
|
298
|
+
return "\n" if self.class.comment?(code)
|
|
299
|
+
return "\n" if self.class.heredoc?(code)
|
|
300
|
+
|
|
301
|
+
""
|
|
248
302
|
end
|
|
249
303
|
|
|
250
304
|
def add_postamble(postamble)
|
|
@@ -272,19 +326,16 @@ module Herb
|
|
|
272
326
|
|
|
273
327
|
def run_validation(ast)
|
|
274
328
|
validators = [
|
|
275
|
-
Validators::SecurityValidator.new,
|
|
276
|
-
Validators::NestingValidator.new,
|
|
277
|
-
Validators::AccessibilityValidator.new
|
|
329
|
+
Validators::SecurityValidator.new(enabled: @enabled_validators[:security]),
|
|
330
|
+
Validators::NestingValidator.new(enabled: @enabled_validators[:nesting]),
|
|
331
|
+
Validators::AccessibilityValidator.new(enabled: @enabled_validators[:accessibility])
|
|
278
332
|
]
|
|
279
333
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
validators.each do |validator|
|
|
334
|
+
validators.select(&:enabled?).each do |validator|
|
|
283
335
|
ast.accept(validator)
|
|
284
|
-
errors.concat(validator.errors)
|
|
285
336
|
end
|
|
286
337
|
|
|
287
|
-
|
|
338
|
+
validators
|
|
288
339
|
end
|
|
289
340
|
|
|
290
341
|
def handle_parser_errors(parser_errors, input, _ast)
|
|
@@ -304,24 +355,19 @@ module Herb
|
|
|
304
355
|
end
|
|
305
356
|
end
|
|
306
357
|
|
|
307
|
-
def handle_validation_errors(
|
|
358
|
+
def handle_validation_errors(validators, input)
|
|
359
|
+
errors = validators.select(&:enabled?).flat_map(&:errors)
|
|
308
360
|
return unless errors.any?
|
|
309
361
|
|
|
310
|
-
security_error = errors.find { |error|
|
|
311
|
-
error.is_a?(Hash) && error[:source] == "SecurityValidator"
|
|
312
|
-
}
|
|
362
|
+
security_error = errors.find { |error| error[:source] == "SecurityValidator" }
|
|
313
363
|
|
|
314
364
|
if security_error
|
|
315
|
-
line = security_error[:location]&.start&.line
|
|
316
|
-
column = security_error[:location]&.start&.column
|
|
317
|
-
suggestion = security_error[:suggestion]
|
|
318
|
-
|
|
319
365
|
raise SecurityError.new(
|
|
320
366
|
security_error[:message],
|
|
321
|
-
line: line,
|
|
322
|
-
column: column,
|
|
367
|
+
line: security_error[:location]&.start&.line,
|
|
368
|
+
column: security_error[:location]&.start&.column,
|
|
323
369
|
filename: @filename,
|
|
324
|
-
suggestion: suggestion
|
|
370
|
+
suggestion: security_error[:suggestion]
|
|
325
371
|
)
|
|
326
372
|
end
|
|
327
373
|
|
|
@@ -330,7 +376,8 @@ module Herb
|
|
|
330
376
|
raise CompilationError, "\n#{message}"
|
|
331
377
|
end
|
|
332
378
|
|
|
333
|
-
def add_validation_overlay(
|
|
379
|
+
def add_validation_overlay(validators, input = nil)
|
|
380
|
+
errors = validators.select(&:enabled?).flat_map(&:errors)
|
|
334
381
|
return unless errors.any?
|
|
335
382
|
|
|
336
383
|
templates = errors.map { |error|
|