herb 0.9.3-arm-linux-gnu → 0.9.5-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/config.yml +57 -21
- data/ext/herb/nodes.c +93 -55
- 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/nodes.rb +212 -78
- data/lib/herb/engine/compiler.rb +52 -26
- data/lib/herb/engine.rb +3 -0
- data/lib/herb/project.rb +58 -17
- data/lib/herb/version.rb +1 -1
- data/lib/herb/visitor.rb +8 -2
- data/sig/herb/ast/nodes.rbs +85 -34
- data/sig/herb/engine/compiler.rbs +16 -0
- data/sig/herb/engine.rbs +3 -0
- data/sig/herb/visitor.rbs +5 -2
- data/sig/serialized_ast_nodes.rbs +20 -9
- data/src/analyze/action_view/javascript_tag.c +38 -0
- data/src/analyze/action_view/tag_helper_node_builders.c +23 -2
- data/src/analyze/action_view/tag_helpers.c +53 -14
- data/src/analyze/analyze.c +23 -3
- data/src/analyze/analyze_helpers.c +406 -0
- data/src/analyze/builders.c +1 -0
- data/src/analyze/missing_end.c +16 -0
- data/src/analyze/parse_errors.c +43 -1
- data/src/analyze/render_nodes.c +231 -35
- data/src/analyze/strict_locals.c +22 -324
- data/src/analyze/transform.c +23 -2
- data/src/ast/ast_nodes.c +114 -57
- data/src/ast/ast_pretty_print.c +109 -25
- data/src/include/analyze/action_view/tag_helper_handler.h +3 -0
- data/src/include/analyze/action_view/tag_helper_node_builders.h +7 -0
- data/src/include/analyze/analyze.h +6 -1
- data/src/include/analyze/helpers.h +18 -0
- data/src/include/ast/ast_nodes.h +27 -13
- data/src/include/version.h +1 -1
- data/src/parser/match_tags.c +37 -6
- data/src/parser.c +8 -0
- data/src/visitor.c +50 -7
- metadata +1 -1
data/lib/herb/ast/nodes.rb
CHANGED
|
@@ -2128,6 +2128,7 @@ module Herb
|
|
|
2128
2128
|
#| tag_closing: Herb::Token?,
|
|
2129
2129
|
#| prism_node: String?,
|
|
2130
2130
|
#| body: Array[Herb::AST::Node],
|
|
2131
|
+
#| block_arguments: Array[Herb::AST::RubyParameterNode]?,
|
|
2131
2132
|
#| rescue_clause: Herb::AST::ERBRescueNode?,
|
|
2132
2133
|
#| else_clause: Herb::AST::ERBElseNode?,
|
|
2133
2134
|
#| ensure_clause: Herb::AST::ERBEnsureNode?,
|
|
@@ -2141,19 +2142,21 @@ module Herb
|
|
|
2141
2142
|
attr_reader :tag_closing #: Herb::Token?
|
|
2142
2143
|
attr_reader :prism_node #: String?
|
|
2143
2144
|
attr_reader :body #: Array[Herb::AST::Node]
|
|
2145
|
+
attr_reader :block_arguments #: Array[Herb::AST::RubyParameterNode]?
|
|
2144
2146
|
attr_reader :rescue_clause #: Herb::AST::ERBRescueNode?
|
|
2145
2147
|
attr_reader :else_clause #: Herb::AST::ERBElseNode?
|
|
2146
2148
|
attr_reader :ensure_clause #: Herb::AST::ERBEnsureNode?
|
|
2147
2149
|
attr_reader :end_node #: Herb::AST::ERBEndNode?
|
|
2148
2150
|
|
|
2149
|
-
#: (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
|
|
2150
|
-
def initialize(type, location, errors, tag_opening, content, tag_closing, prism_node, body, rescue_clause, else_clause, ensure_clause, end_node)
|
|
2151
|
+
#: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, String, Array[Herb::AST::Node], Array[Herb::AST::RubyParameterNode], Herb::AST::ERBRescueNode, Herb::AST::ERBElseNode, Herb::AST::ERBEnsureNode, Herb::AST::ERBEndNode) -> void
|
|
2152
|
+
def initialize(type, location, errors, tag_opening, content, tag_closing, prism_node, body, block_arguments, rescue_clause, else_clause, ensure_clause, end_node)
|
|
2151
2153
|
super(type, location, errors)
|
|
2152
2154
|
@tag_opening = tag_opening
|
|
2153
2155
|
@content = content
|
|
2154
2156
|
@tag_closing = tag_closing
|
|
2155
2157
|
@prism_node = prism_node
|
|
2156
2158
|
@body = body
|
|
2159
|
+
@block_arguments = block_arguments
|
|
2157
2160
|
@rescue_clause = rescue_clause
|
|
2158
2161
|
@else_clause = else_clause
|
|
2159
2162
|
@ensure_clause = ensure_clause
|
|
@@ -2184,6 +2187,7 @@ module Herb
|
|
|
2184
2187
|
tag_closing: tag_closing,
|
|
2185
2188
|
prism_node: prism_node,
|
|
2186
2189
|
body: body,
|
|
2190
|
+
block_arguments: block_arguments,
|
|
2187
2191
|
rescue_clause: rescue_clause,
|
|
2188
2192
|
else_clause: else_clause,
|
|
2189
2193
|
ensure_clause: ensure_clause,
|
|
@@ -2198,7 +2202,7 @@ module Herb
|
|
|
2198
2202
|
|
|
2199
2203
|
#: () -> Array[Herb::AST::Node?]
|
|
2200
2204
|
def child_nodes
|
|
2201
|
-
[*(body || []), rescue_clause, else_clause, ensure_clause, end_node]
|
|
2205
|
+
[*(body || []), *(block_arguments || []), rescue_clause, else_clause, ensure_clause, end_node]
|
|
2202
2206
|
end
|
|
2203
2207
|
|
|
2204
2208
|
#: () -> Array[Herb::AST::Node]
|
|
@@ -2242,6 +2246,8 @@ module Herb
|
|
|
2242
2246
|
end
|
|
2243
2247
|
output += white("├── body: ")
|
|
2244
2248
|
output += inspect_array(body, prefix: "│ ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
|
|
2249
|
+
output += white("├── block_arguments: ")
|
|
2250
|
+
output += inspect_array(block_arguments, prefix: "│ ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
|
|
2245
2251
|
output += white("├── rescue_clause: ")
|
|
2246
2252
|
if rescue_clause
|
|
2247
2253
|
output += "\n"
|
|
@@ -3576,12 +3582,7 @@ module Herb
|
|
|
3576
3582
|
end
|
|
3577
3583
|
end
|
|
3578
3584
|
|
|
3579
|
-
#: type
|
|
3580
|
-
#| tag_opening: Herb::Token?,
|
|
3581
|
-
#| content: Herb::Token?,
|
|
3582
|
-
#| tag_closing: Herb::Token?,
|
|
3583
|
-
#| analyzed_ruby: nil,
|
|
3584
|
-
#| prism_node: String?,
|
|
3585
|
+
#: type serialized_ruby_render_keywords_node = {
|
|
3585
3586
|
#| partial: Herb::Token?,
|
|
3586
3587
|
#| template_path: Herb::Token?,
|
|
3587
3588
|
#| layout: Herb::Token?,
|
|
@@ -3601,14 +3602,9 @@ module Herb
|
|
|
3601
3602
|
#| content_type: Herb::Token?,
|
|
3602
3603
|
#| locals: Array[Herb::AST::RubyRenderLocalNode]?,
|
|
3603
3604
|
#| }
|
|
3604
|
-
class
|
|
3605
|
+
class RubyRenderKeywordsNode < Node
|
|
3605
3606
|
include Colors
|
|
3606
3607
|
|
|
3607
|
-
attr_reader :tag_opening #: Herb::Token?
|
|
3608
|
-
attr_reader :content #: Herb::Token?
|
|
3609
|
-
attr_reader :tag_closing #: Herb::Token?
|
|
3610
|
-
attr_reader :analyzed_ruby #: nil
|
|
3611
|
-
attr_reader :prism_node #: String?
|
|
3612
3608
|
attr_reader :partial #: Herb::Token?
|
|
3613
3609
|
attr_reader :template_path #: Herb::Token?
|
|
3614
3610
|
attr_reader :layout #: Herb::Token?
|
|
@@ -3628,14 +3624,9 @@ module Herb
|
|
|
3628
3624
|
attr_reader :content_type #: Herb::Token?
|
|
3629
3625
|
attr_reader :locals #: Array[Herb::AST::RubyRenderLocalNode]?
|
|
3630
3626
|
|
|
3631
|
-
#: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token,
|
|
3632
|
-
def initialize(type, location, errors,
|
|
3627
|
+
#: (String, Location, Array[Herb::Errors::Error], 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
|
|
3628
|
+
def initialize(type, location, errors, partial, template_path, layout, file, inline_template, body, plain, html, renderable, collection, object, as_name, spacer_template, formats, variants, handlers, content_type, locals)
|
|
3633
3629
|
super(type, location, errors)
|
|
3634
|
-
@tag_opening = tag_opening
|
|
3635
|
-
@content = content
|
|
3636
|
-
@tag_closing = tag_closing
|
|
3637
|
-
@analyzed_ruby = analyzed_ruby
|
|
3638
|
-
@prism_node = prism_node
|
|
3639
3630
|
@partial = partial
|
|
3640
3631
|
@template_path = template_path
|
|
3641
3632
|
@layout = layout
|
|
@@ -3656,30 +3647,9 @@ module Herb
|
|
|
3656
3647
|
@locals = locals
|
|
3657
3648
|
end
|
|
3658
3649
|
|
|
3659
|
-
#: () ->
|
|
3660
|
-
def deserialized_prism_node
|
|
3661
|
-
prism_node = @prism_node
|
|
3662
|
-
return nil unless prism_node
|
|
3663
|
-
return nil unless source
|
|
3664
|
-
|
|
3665
|
-
begin
|
|
3666
|
-
require "prism"
|
|
3667
|
-
rescue LoadError
|
|
3668
|
-
warn "The 'prism' gem is required to deserialize Prism nodes. Add it to your Gemfile or install it with: gem install prism"
|
|
3669
|
-
return nil
|
|
3670
|
-
end
|
|
3671
|
-
|
|
3672
|
-
Prism.load(source, prism_node).value
|
|
3673
|
-
end
|
|
3674
|
-
|
|
3675
|
-
#: () -> serialized_erb_render_node
|
|
3650
|
+
#: () -> serialized_ruby_render_keywords_node
|
|
3676
3651
|
def to_hash
|
|
3677
3652
|
super.merge({
|
|
3678
|
-
tag_opening: tag_opening,
|
|
3679
|
-
content: content,
|
|
3680
|
-
tag_closing: tag_closing,
|
|
3681
|
-
analyzed_ruby: analyzed_ruby,
|
|
3682
|
-
prism_node: prism_node,
|
|
3683
3653
|
partial: partial,
|
|
3684
3654
|
template_path: template_path,
|
|
3685
3655
|
layout: layout,
|
|
@@ -3698,12 +3668,12 @@ module Herb
|
|
|
3698
3668
|
handlers: handlers,
|
|
3699
3669
|
content_type: content_type,
|
|
3700
3670
|
locals: locals,
|
|
3701
|
-
}) #: Herb::
|
|
3671
|
+
}) #: Herb::serialized_ruby_render_keywords_node
|
|
3702
3672
|
end
|
|
3703
3673
|
|
|
3704
3674
|
#: (Visitor) -> void
|
|
3705
3675
|
def accept(visitor)
|
|
3706
|
-
visitor.
|
|
3676
|
+
visitor.visit_ruby_render_keywords_node(self)
|
|
3707
3677
|
end
|
|
3708
3678
|
|
|
3709
3679
|
#: () -> Array[Herb::AST::Node?]
|
|
@@ -3736,20 +3706,6 @@ module Herb
|
|
|
3736
3706
|
|
|
3737
3707
|
output += inspect_errors(prefix: "│ ")
|
|
3738
3708
|
|
|
3739
|
-
output += white("├── tag_opening: ")
|
|
3740
|
-
output += tag_opening ? tag_opening.tree_inspect : magenta("∅")
|
|
3741
|
-
output += "\n"
|
|
3742
|
-
output += white("├── content: ")
|
|
3743
|
-
output += content ? content.tree_inspect : magenta("∅")
|
|
3744
|
-
output += "\n"
|
|
3745
|
-
output += white("├── tag_closing: ")
|
|
3746
|
-
output += tag_closing ? tag_closing.tree_inspect : magenta("∅")
|
|
3747
|
-
output += "\n"
|
|
3748
|
-
if prism_node && source
|
|
3749
|
-
output += white("├── prism_node: ")
|
|
3750
|
-
output += Herb::PrismInspect.inspect_prism_serialized(prism_node, source, "│ ")
|
|
3751
|
-
output += "\n"
|
|
3752
|
-
end
|
|
3753
3709
|
output += white("├── partial: ")
|
|
3754
3710
|
output += partial ? partial.tree_inspect : magenta("∅")
|
|
3755
3711
|
output += "\n"
|
|
@@ -3809,42 +3765,222 @@ module Herb
|
|
|
3809
3765
|
end
|
|
3810
3766
|
end
|
|
3811
3767
|
|
|
3812
|
-
#: type
|
|
3768
|
+
#: type serialized_erb_render_node = {
|
|
3769
|
+
#| tag_opening: Herb::Token?,
|
|
3770
|
+
#| content: Herb::Token?,
|
|
3771
|
+
#| tag_closing: Herb::Token?,
|
|
3772
|
+
#| analyzed_ruby: nil,
|
|
3773
|
+
#| prism_node: String?,
|
|
3774
|
+
#| keywords: Herb::AST::RubyRenderKeywordsNode?,
|
|
3775
|
+
#| body: Array[Herb::AST::Node],
|
|
3776
|
+
#| block_arguments: Array[Herb::AST::RubyParameterNode]?,
|
|
3777
|
+
#| rescue_clause: Herb::AST::ERBRescueNode?,
|
|
3778
|
+
#| else_clause: Herb::AST::ERBElseNode?,
|
|
3779
|
+
#| ensure_clause: Herb::AST::ERBEnsureNode?,
|
|
3780
|
+
#| end_node: Herb::AST::ERBEndNode?,
|
|
3781
|
+
#| }
|
|
3782
|
+
class ERBRenderNode < Node
|
|
3783
|
+
include Colors
|
|
3784
|
+
|
|
3785
|
+
attr_reader :tag_opening #: Herb::Token?
|
|
3786
|
+
attr_reader :content #: Herb::Token?
|
|
3787
|
+
attr_reader :tag_closing #: Herb::Token?
|
|
3788
|
+
attr_reader :analyzed_ruby #: nil
|
|
3789
|
+
attr_reader :prism_node #: String?
|
|
3790
|
+
attr_reader :keywords #: Herb::AST::RubyRenderKeywordsNode?
|
|
3791
|
+
attr_reader :body #: Array[Herb::AST::Node]
|
|
3792
|
+
attr_reader :block_arguments #: Array[Herb::AST::RubyParameterNode]?
|
|
3793
|
+
attr_reader :rescue_clause #: Herb::AST::ERBRescueNode?
|
|
3794
|
+
attr_reader :else_clause #: Herb::AST::ERBElseNode?
|
|
3795
|
+
attr_reader :ensure_clause #: Herb::AST::ERBEnsureNode?
|
|
3796
|
+
attr_reader :end_node #: Herb::AST::ERBEndNode?
|
|
3797
|
+
|
|
3798
|
+
#: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, nil, String, Herb::AST::RubyRenderKeywordsNode, Array[Herb::AST::Node], Array[Herb::AST::RubyParameterNode], Herb::AST::ERBRescueNode, Herb::AST::ERBElseNode, Herb::AST::ERBEnsureNode, Herb::AST::ERBEndNode) -> void
|
|
3799
|
+
def initialize(type, location, errors, tag_opening, content, tag_closing, analyzed_ruby, prism_node, keywords, body, block_arguments, rescue_clause, else_clause, ensure_clause, end_node)
|
|
3800
|
+
super(type, location, errors)
|
|
3801
|
+
@tag_opening = tag_opening
|
|
3802
|
+
@content = content
|
|
3803
|
+
@tag_closing = tag_closing
|
|
3804
|
+
@analyzed_ruby = analyzed_ruby
|
|
3805
|
+
@prism_node = prism_node
|
|
3806
|
+
@keywords = keywords
|
|
3807
|
+
@body = body
|
|
3808
|
+
@block_arguments = block_arguments
|
|
3809
|
+
@rescue_clause = rescue_clause
|
|
3810
|
+
@else_clause = else_clause
|
|
3811
|
+
@ensure_clause = ensure_clause
|
|
3812
|
+
@end_node = end_node
|
|
3813
|
+
end
|
|
3814
|
+
|
|
3815
|
+
#: () -> Prism::node?
|
|
3816
|
+
def deserialized_prism_node
|
|
3817
|
+
prism_node = @prism_node
|
|
3818
|
+
return nil unless prism_node
|
|
3819
|
+
return nil unless source
|
|
3820
|
+
|
|
3821
|
+
begin
|
|
3822
|
+
require "prism"
|
|
3823
|
+
rescue LoadError
|
|
3824
|
+
warn "The 'prism' gem is required to deserialize Prism nodes. Add it to your Gemfile or install it with: gem install prism"
|
|
3825
|
+
return nil
|
|
3826
|
+
end
|
|
3827
|
+
|
|
3828
|
+
Prism.load(source, prism_node).value
|
|
3829
|
+
end
|
|
3830
|
+
|
|
3831
|
+
#: () -> serialized_erb_render_node
|
|
3832
|
+
def to_hash
|
|
3833
|
+
super.merge({
|
|
3834
|
+
tag_opening: tag_opening,
|
|
3835
|
+
content: content,
|
|
3836
|
+
tag_closing: tag_closing,
|
|
3837
|
+
analyzed_ruby: analyzed_ruby,
|
|
3838
|
+
prism_node: prism_node,
|
|
3839
|
+
keywords: keywords,
|
|
3840
|
+
body: body,
|
|
3841
|
+
block_arguments: block_arguments,
|
|
3842
|
+
rescue_clause: rescue_clause,
|
|
3843
|
+
else_clause: else_clause,
|
|
3844
|
+
ensure_clause: ensure_clause,
|
|
3845
|
+
end_node: end_node,
|
|
3846
|
+
}) #: Herb::serialized_erb_render_node
|
|
3847
|
+
end
|
|
3848
|
+
|
|
3849
|
+
#: (Visitor) -> void
|
|
3850
|
+
def accept(visitor)
|
|
3851
|
+
visitor.visit_erb_render_node(self)
|
|
3852
|
+
end
|
|
3853
|
+
|
|
3854
|
+
#: () -> Array[Herb::AST::Node?]
|
|
3855
|
+
def child_nodes
|
|
3856
|
+
[keywords, *(body || []), *(block_arguments || []), rescue_clause, else_clause, ensure_clause, end_node]
|
|
3857
|
+
end
|
|
3858
|
+
|
|
3859
|
+
#: () -> Array[Herb::AST::Node]
|
|
3860
|
+
def compact_child_nodes
|
|
3861
|
+
child_nodes.compact
|
|
3862
|
+
end
|
|
3863
|
+
|
|
3864
|
+
#: () -> String
|
|
3865
|
+
def inspect
|
|
3866
|
+
tree_inspect.rstrip.gsub(/\s+$/, "")
|
|
3867
|
+
end
|
|
3868
|
+
|
|
3869
|
+
#: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
3870
|
+
def tree_inspect(indent: 0, depth: 0, depth_limit: 10)
|
|
3871
|
+
output = +""
|
|
3872
|
+
|
|
3873
|
+
output += white("@ #{bold(yellow(node_name.to_s))} #{dimmed("(location: #{location.tree_inspect})")}")
|
|
3874
|
+
output += "\n"
|
|
3875
|
+
|
|
3876
|
+
if depth >= depth_limit
|
|
3877
|
+
output += dimmed("└── [depth limit reached ...]\n\n")
|
|
3878
|
+
|
|
3879
|
+
return output.gsub(/^/, " " * indent)
|
|
3880
|
+
end
|
|
3881
|
+
|
|
3882
|
+
output += inspect_errors(prefix: "│ ")
|
|
3883
|
+
|
|
3884
|
+
output += white("├── tag_opening: ")
|
|
3885
|
+
output += tag_opening ? tag_opening.tree_inspect : magenta("∅")
|
|
3886
|
+
output += "\n"
|
|
3887
|
+
output += white("├── content: ")
|
|
3888
|
+
output += content ? content.tree_inspect : magenta("∅")
|
|
3889
|
+
output += "\n"
|
|
3890
|
+
output += white("├── tag_closing: ")
|
|
3891
|
+
output += tag_closing ? tag_closing.tree_inspect : magenta("∅")
|
|
3892
|
+
output += "\n"
|
|
3893
|
+
if prism_node && source
|
|
3894
|
+
output += white("├── prism_node: ")
|
|
3895
|
+
output += Herb::PrismInspect.inspect_prism_serialized(prism_node, source, "│ ")
|
|
3896
|
+
output += "\n"
|
|
3897
|
+
end
|
|
3898
|
+
output += white("├── keywords: ")
|
|
3899
|
+
if keywords
|
|
3900
|
+
output += "\n"
|
|
3901
|
+
output += "│ └── "
|
|
3902
|
+
output += keywords.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, "│ ").delete_prefix("│ ")
|
|
3903
|
+
else
|
|
3904
|
+
output += magenta("∅\n")
|
|
3905
|
+
end
|
|
3906
|
+
output += white("├── body: ")
|
|
3907
|
+
output += inspect_array(body, prefix: "│ ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
|
|
3908
|
+
output += white("├── block_arguments: ")
|
|
3909
|
+
output += inspect_array(block_arguments, prefix: "│ ", indent: indent, depth: depth + 1, depth_limit: depth_limit)
|
|
3910
|
+
output += white("├── rescue_clause: ")
|
|
3911
|
+
if rescue_clause
|
|
3912
|
+
output += "\n"
|
|
3913
|
+
output += "│ └── "
|
|
3914
|
+
output += rescue_clause.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, "│ ").delete_prefix("│ ")
|
|
3915
|
+
else
|
|
3916
|
+
output += magenta("∅\n")
|
|
3917
|
+
end
|
|
3918
|
+
output += white("├── else_clause: ")
|
|
3919
|
+
if else_clause
|
|
3920
|
+
output += "\n"
|
|
3921
|
+
output += "│ └── "
|
|
3922
|
+
output += else_clause.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, "│ ").delete_prefix("│ ")
|
|
3923
|
+
else
|
|
3924
|
+
output += magenta("∅\n")
|
|
3925
|
+
end
|
|
3926
|
+
output += white("├── ensure_clause: ")
|
|
3927
|
+
if ensure_clause
|
|
3928
|
+
output += "\n"
|
|
3929
|
+
output += "│ └── "
|
|
3930
|
+
output += ensure_clause.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, "│ ").delete_prefix("│ ")
|
|
3931
|
+
else
|
|
3932
|
+
output += magenta("∅\n")
|
|
3933
|
+
end
|
|
3934
|
+
output += white("└── end_node: ")
|
|
3935
|
+
if end_node
|
|
3936
|
+
output += "\n"
|
|
3937
|
+
output += " └── "
|
|
3938
|
+
output += end_node.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, " ").delete_prefix(" ")
|
|
3939
|
+
else
|
|
3940
|
+
output += magenta("∅\n")
|
|
3941
|
+
end
|
|
3942
|
+
output += "\n"
|
|
3943
|
+
|
|
3944
|
+
output.gsub(/^/, " " * indent)
|
|
3945
|
+
end
|
|
3946
|
+
end
|
|
3947
|
+
|
|
3948
|
+
#: type serialized_ruby_parameter_node = {
|
|
3813
3949
|
#| name: Herb::Token?,
|
|
3814
3950
|
#| default_value: Herb::AST::RubyLiteralNode?,
|
|
3951
|
+
#| kind: String?,
|
|
3815
3952
|
#| required: bool,
|
|
3816
|
-
#| double_splat: bool,
|
|
3817
3953
|
#| }
|
|
3818
|
-
class
|
|
3954
|
+
class RubyParameterNode < Node
|
|
3819
3955
|
include Colors
|
|
3820
3956
|
|
|
3821
3957
|
attr_reader :name #: Herb::Token?
|
|
3822
3958
|
attr_reader :default_value #: Herb::AST::RubyLiteralNode?
|
|
3959
|
+
attr_reader :kind #: String?
|
|
3823
3960
|
attr_reader :required #: bool
|
|
3824
|
-
attr_reader :double_splat #: bool
|
|
3825
3961
|
|
|
3826
|
-
#: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::AST::RubyLiteralNode,
|
|
3827
|
-
def initialize(type, location, errors, name, default_value,
|
|
3962
|
+
#: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::AST::RubyLiteralNode, String, bool) -> void
|
|
3963
|
+
def initialize(type, location, errors, name, default_value, kind, required)
|
|
3828
3964
|
super(type, location, errors)
|
|
3829
3965
|
@name = name
|
|
3830
3966
|
@default_value = default_value
|
|
3967
|
+
@kind = kind&.force_encoding("utf-8")
|
|
3831
3968
|
@required = required
|
|
3832
|
-
@double_splat = double_splat
|
|
3833
3969
|
end
|
|
3834
3970
|
|
|
3835
|
-
#: () ->
|
|
3971
|
+
#: () -> serialized_ruby_parameter_node
|
|
3836
3972
|
def to_hash
|
|
3837
3973
|
super.merge({
|
|
3838
3974
|
name: name,
|
|
3839
3975
|
default_value: default_value,
|
|
3976
|
+
kind: kind,
|
|
3840
3977
|
required: required,
|
|
3841
|
-
|
|
3842
|
-
}) #: Herb::serialized_ruby_strict_local_node
|
|
3978
|
+
}) #: Herb::serialized_ruby_parameter_node
|
|
3843
3979
|
end
|
|
3844
3980
|
|
|
3845
3981
|
#: (Visitor) -> void
|
|
3846
3982
|
def accept(visitor)
|
|
3847
|
-
visitor.
|
|
3983
|
+
visitor.visit_ruby_parameter_node(self)
|
|
3848
3984
|
end
|
|
3849
3985
|
|
|
3850
3986
|
#: () -> Array[Herb::AST::Node?]
|
|
@@ -3888,12 +4024,10 @@ module Herb
|
|
|
3888
4024
|
else
|
|
3889
4025
|
output += magenta("∅\n")
|
|
3890
4026
|
end
|
|
3891
|
-
output += white("├──
|
|
4027
|
+
output += white("├── kind: ") + green("#{kind.inspect}\n")
|
|
4028
|
+
output += white("└── required: ")
|
|
3892
4029
|
output += [true, false].include?(required) ? bold(magenta(required.to_s)) : magenta("∅")
|
|
3893
4030
|
output += "\n"
|
|
3894
|
-
output += white("└── double_splat: ")
|
|
3895
|
-
output += [true, false].include?(double_splat) ? bold(magenta(double_splat.to_s)) : magenta("∅")
|
|
3896
|
-
output += "\n"
|
|
3897
4031
|
output += "\n"
|
|
3898
4032
|
|
|
3899
4033
|
output.gsub(/^/, " " * indent)
|
|
@@ -3906,7 +4040,7 @@ module Herb
|
|
|
3906
4040
|
#| tag_closing: Herb::Token?,
|
|
3907
4041
|
#| analyzed_ruby: nil,
|
|
3908
4042
|
#| prism_node: String?,
|
|
3909
|
-
#| locals: Array[Herb::AST::
|
|
4043
|
+
#| locals: Array[Herb::AST::RubyParameterNode]?,
|
|
3910
4044
|
#| }
|
|
3911
4045
|
class ERBStrictLocalsNode < Node
|
|
3912
4046
|
include Colors
|
|
@@ -3916,9 +4050,9 @@ module Herb
|
|
|
3916
4050
|
attr_reader :tag_closing #: Herb::Token?
|
|
3917
4051
|
attr_reader :analyzed_ruby #: nil
|
|
3918
4052
|
attr_reader :prism_node #: String?
|
|
3919
|
-
attr_reader :locals #: Array[Herb::AST::
|
|
4053
|
+
attr_reader :locals #: Array[Herb::AST::RubyParameterNode]?
|
|
3920
4054
|
|
|
3921
|
-
#: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, nil, String, Array[Herb::AST::
|
|
4055
|
+
#: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, nil, String, Array[Herb::AST::RubyParameterNode]) -> void
|
|
3922
4056
|
def initialize(type, location, errors, tag_opening, content, tag_closing, analyzed_ruby, prism_node, locals)
|
|
3923
4057
|
super(type, location, errors)
|
|
3924
4058
|
@tag_opening = tag_opening
|
data/lib/herb/engine/compiler.rb
CHANGED
|
@@ -5,6 +5,12 @@ module Herb
|
|
|
5
5
|
class Compiler < ::Herb::Visitor
|
|
6
6
|
EXPRESSION_TOKEN_TYPES = [:expr, :expr_escaped, :expr_block, :expr_block_escaped].freeze
|
|
7
7
|
|
|
8
|
+
TRAILING_WHITESPACE = /[ \t]+\z/
|
|
9
|
+
TRAILING_INDENTATION = /\n[ \t]+\z/
|
|
10
|
+
TRAILING_INDENTATION_CAPTURE = /\n([ \t]+)\z/
|
|
11
|
+
WHITESPACE_ONLY = /\A[ \t]+\z/
|
|
12
|
+
WHITESPACE_ONLY_CAPTURE = /\A([ \t]+)\z/
|
|
13
|
+
|
|
8
14
|
attr_reader :tokens
|
|
9
15
|
|
|
10
16
|
def initialize(engine, options = {})
|
|
@@ -93,11 +99,9 @@ module Herb
|
|
|
93
99
|
def visit_html_attribute_value_node(node)
|
|
94
100
|
push_context(:attribute_value)
|
|
95
101
|
|
|
96
|
-
add_text(node.open_quote&.value) if node.quoted
|
|
97
|
-
|
|
102
|
+
add_text(node.open_quote&.value || '"') if node.quoted
|
|
98
103
|
visit_all(node.children)
|
|
99
|
-
|
|
100
|
-
add_text(node.close_quote&.value) if node.quoted
|
|
104
|
+
add_text(node.close_quote&.value || '"') if node.quoted
|
|
101
105
|
|
|
102
106
|
pop_context
|
|
103
107
|
end
|
|
@@ -150,9 +154,9 @@ module Herb
|
|
|
150
154
|
end
|
|
151
155
|
|
|
152
156
|
def visit_cdata_node(node)
|
|
153
|
-
add_text(node.
|
|
157
|
+
add_text(node.tag_opening.value)
|
|
154
158
|
visit_all(node.children)
|
|
155
|
-
add_text(node.
|
|
159
|
+
add_text(node.tag_closing.value)
|
|
156
160
|
end
|
|
157
161
|
|
|
158
162
|
def visit_erb_content_node(node)
|
|
@@ -242,6 +246,8 @@ module Herb
|
|
|
242
246
|
def visit_erb_block_node(node)
|
|
243
247
|
opening = node.tag_opening.value
|
|
244
248
|
|
|
249
|
+
check_for_escaped_erb_tag!(opening)
|
|
250
|
+
|
|
245
251
|
if opening.include?("=")
|
|
246
252
|
should_escape = should_escape_output?(opening)
|
|
247
253
|
code = node.content.value.strip
|
|
@@ -251,7 +257,9 @@ module Herb
|
|
|
251
257
|
else
|
|
252
258
|
[:expr_block, code, current_context]
|
|
253
259
|
end
|
|
260
|
+
|
|
254
261
|
@last_trim_consumed_newline = false
|
|
262
|
+
@trim_next_whitespace = true if right_trim?(node)
|
|
255
263
|
|
|
256
264
|
visit_all(node.body)
|
|
257
265
|
visit_erb_block_end_node(node.end_node, escaped: should_escape)
|
|
@@ -267,9 +275,7 @@ module Herb
|
|
|
267
275
|
end
|
|
268
276
|
|
|
269
277
|
def visit_erb_block_end_node(node, escaped: false)
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
remove_trailing_whitespace_from_last_token! if has_left_trim
|
|
278
|
+
remove_trailing_whitespace_from_last_token! if left_trim?(node)
|
|
273
279
|
|
|
274
280
|
code = node.content.value.strip
|
|
275
281
|
|
|
@@ -302,6 +308,15 @@ module Herb
|
|
|
302
308
|
|
|
303
309
|
private
|
|
304
310
|
|
|
311
|
+
def check_for_escaped_erb_tag!(opening)
|
|
312
|
+
return unless opening.start_with?("<%%")
|
|
313
|
+
|
|
314
|
+
raise Herb::Engine::GeneratorTemplateError,
|
|
315
|
+
"This file appears to be a generator template (a template used to generate ERB files) " \
|
|
316
|
+
"rather than a standard ERB template. It contains escaped ERB tags like <%%= %> which " \
|
|
317
|
+
"produce literal ERB output in the generated file."
|
|
318
|
+
end
|
|
319
|
+
|
|
305
320
|
def current_context
|
|
306
321
|
@context_stack.last
|
|
307
322
|
end
|
|
@@ -336,10 +351,11 @@ module Herb
|
|
|
336
351
|
def process_erb_tag(node, skip_comment_check: false)
|
|
337
352
|
opening = node.tag_opening.value
|
|
338
353
|
|
|
354
|
+
check_for_escaped_erb_tag!(opening)
|
|
355
|
+
|
|
339
356
|
if !skip_comment_check && erb_comment?(opening)
|
|
340
|
-
has_left_trim = opening.start_with?("<%-")
|
|
341
357
|
follows_newline = leading_space_follows_newline?
|
|
342
|
-
remove_trailing_whitespace_from_last_token! if
|
|
358
|
+
remove_trailing_whitespace_from_last_token! if left_trim?(node)
|
|
343
359
|
|
|
344
360
|
if at_line_start?
|
|
345
361
|
leading_space = extract_and_remove_leading_space!
|
|
@@ -485,10 +501,9 @@ module Herb
|
|
|
485
501
|
@last_trim_consumed_newline = false
|
|
486
502
|
end
|
|
487
503
|
|
|
488
|
-
has_right_trim = node.tag_closing&.value == "-%>"
|
|
489
504
|
should_escape = should_escape_output?(opening)
|
|
490
505
|
add_expression_with_escaping(code, should_escape)
|
|
491
|
-
@trim_next_whitespace = true if
|
|
506
|
+
@trim_next_whitespace = true if right_trim?(node)
|
|
492
507
|
end
|
|
493
508
|
|
|
494
509
|
def indicator_for(type)
|
|
@@ -521,7 +536,7 @@ module Herb
|
|
|
521
536
|
last_value = @tokens.last[1]
|
|
522
537
|
|
|
523
538
|
if last_type == :text
|
|
524
|
-
last_value.empty? || last_value.end_with?("\n") || (last_value =~
|
|
539
|
+
last_value.empty? || last_value.end_with?("\n") || (last_value =~ WHITESPACE_ONLY && preceding_token_ends_with_newline?) || last_value =~ TRAILING_INDENTATION
|
|
525
540
|
elsif EXPRESSION_TOKEN_TYPES.include?(last_type)
|
|
526
541
|
@last_trim_consumed_newline
|
|
527
542
|
else
|
|
@@ -540,6 +555,14 @@ module Herb
|
|
|
540
555
|
preceding[1].end_with?("\n")
|
|
541
556
|
end
|
|
542
557
|
|
|
558
|
+
def left_trim?(node)
|
|
559
|
+
node.tag_opening.value == "<%-"
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
def right_trim?(node)
|
|
563
|
+
node.tag_closing&.value == "-%>"
|
|
564
|
+
end
|
|
565
|
+
|
|
543
566
|
def last_text_token
|
|
544
567
|
return unless @tokens.last && @tokens.last[0] == :text
|
|
545
568
|
|
|
@@ -552,7 +575,7 @@ module Herb
|
|
|
552
575
|
|
|
553
576
|
text = token[1]
|
|
554
577
|
|
|
555
|
-
return Regexp.last_match(1) if text =~
|
|
578
|
+
return Regexp.last_match(1) if text =~ TRAILING_INDENTATION_CAPTURE || text =~ WHITESPACE_ONLY_CAPTURE
|
|
556
579
|
|
|
557
580
|
""
|
|
558
581
|
end
|
|
@@ -561,7 +584,12 @@ module Herb
|
|
|
561
584
|
token = last_text_token
|
|
562
585
|
return false unless token
|
|
563
586
|
|
|
564
|
-
token[1]
|
|
587
|
+
text = token[1]
|
|
588
|
+
|
|
589
|
+
return true if text.match?(TRAILING_INDENTATION)
|
|
590
|
+
return true if @last_trim_consumed_newline && text.match?(WHITESPACE_ONLY)
|
|
591
|
+
|
|
592
|
+
false
|
|
565
593
|
end
|
|
566
594
|
|
|
567
595
|
def extract_and_remove_leading_space!
|
|
@@ -570,9 +598,9 @@ module Herb
|
|
|
570
598
|
|
|
571
599
|
text = @tokens.last[1]
|
|
572
600
|
|
|
573
|
-
if text =~
|
|
574
|
-
text.sub!(
|
|
575
|
-
elsif text =~
|
|
601
|
+
if text =~ TRAILING_INDENTATION
|
|
602
|
+
text.sub!(TRAILING_WHITESPACE, "")
|
|
603
|
+
elsif text =~ WHITESPACE_ONLY
|
|
576
604
|
text.replace("")
|
|
577
605
|
end
|
|
578
606
|
|
|
@@ -582,10 +610,8 @@ module Herb
|
|
|
582
610
|
end
|
|
583
611
|
|
|
584
612
|
def apply_trim(node, code)
|
|
585
|
-
has_left_trim = node.tag_opening.value.start_with?("<%-")
|
|
586
|
-
|
|
587
613
|
follows_newline = leading_space_follows_newline?
|
|
588
|
-
removed_whitespace =
|
|
614
|
+
removed_whitespace = left_trim?(node) ? remove_trailing_whitespace_from_last_token! : ""
|
|
589
615
|
|
|
590
616
|
if at_line_start?
|
|
591
617
|
leading_space = extract_and_remove_leading_space!
|
|
@@ -617,12 +643,12 @@ module Herb
|
|
|
617
643
|
return "" unless token
|
|
618
644
|
|
|
619
645
|
text = token[1]
|
|
620
|
-
removed = text[
|
|
646
|
+
removed = text[TRAILING_WHITESPACE] || ""
|
|
621
647
|
|
|
622
|
-
if text =~
|
|
623
|
-
text.sub!(
|
|
648
|
+
if text =~ TRAILING_INDENTATION
|
|
649
|
+
text.sub!(TRAILING_WHITESPACE, "")
|
|
624
650
|
token[1] = text
|
|
625
|
-
elsif text =~
|
|
651
|
+
elsif text =~ WHITESPACE_ONLY
|
|
626
652
|
text.replace("")
|
|
627
653
|
token[1] = text
|
|
628
654
|
end
|