herb 0.11.0-aarch64-linux-gnu → 0.11.2-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.
- checksums.yaml +4 -4
- data/Rakefile +4 -2
- data/config.yml +9 -0
- data/ext/herb/extconf.rb +8 -31
- data/ext/herb/nodes.c +90 -73
- data/ext/herb/parser_options_helpers.c +26 -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/analysis/partial_index.rb +1 -1
- data/lib/herb/analysis/partial_resolution.rb +27 -0
- data/lib/herb/ast/helpers.rb +1 -1
- data/lib/herb/ast/nodes.rb +32 -6
- data/lib/herb/bootstrap.rb +6 -2
- data/lib/herb/configuration.rb +11 -1
- data/lib/herb/dev/classifier.rb +1 -1
- data/lib/herb/dev/runner.rb +6 -1
- data/lib/herb/engine/compiler.rb +52 -19
- data/lib/herb/engine/slots/dynamics_compiler.rb +63 -14
- data/lib/herb/engine/slots/markers.rb +24 -0
- data/lib/herb/engine/slots/state_compiler.rb +1 -2
- data/lib/herb/engine/slots/subtree_compiler.rb +1 -1
- data/lib/herb/engine/slots/visitor.rb +71 -32
- data/lib/herb/engine/visitors/instrumentation_visitor.rb +18 -6
- data/lib/herb/engine.rb +0 -2
- data/lib/herb/parser_options.rb +6 -3
- data/lib/herb/project.rb +19 -8
- data/lib/herb/version.rb +1 -1
- data/lib/herb.rb +1 -1
- data/sig/herb/analysis/partial_resolution.rbs +8 -0
- data/sig/herb/ast/nodes.rbs +10 -4
- data/sig/herb/bootstrap.rbs +2 -0
- data/sig/herb/configuration.rbs +3 -0
- data/sig/herb/dev/runner.rbs +3 -0
- data/sig/herb/engine/compiler.rbs +14 -3
- data/sig/herb/engine/slots/dynamics_compiler.rbs +27 -7
- data/sig/herb/engine/slots/markers.rbs +14 -0
- data/sig/herb/engine/slots/visitor.rbs +31 -13
- data/sig/herb/engine/visitors/instrumentation_visitor.rbs +5 -1
- data/sig/herb/parser_options.rbs +6 -4
- data/sig/herb.rbs +2 -2
- data/sig/serialized_ast_nodes.rbs +1 -0
- data/src/analyze/action_view/attribute_extraction_helpers.c +40 -21
- data/src/analyze/action_view/generated_handlers.c +36 -36
- data/src/analyze/action_view/image_tag.c +7 -3
- data/src/analyze/action_view/javascript_include_tag.c +6 -3
- data/src/analyze/action_view/link_to.c +23 -23
- data/src/analyze/action_view/registry.c +7 -3
- data/src/analyze/action_view/tag_helper_node_builders.c +12 -16
- data/src/analyze/action_view/tag_helpers.c +215 -110
- data/src/analyze/action_view/turbo_frame_tag.c +5 -4
- data/src/analyze/analyze.c +41 -45
- data/src/analyze/analyze_helpers.c +240 -405
- data/src/analyze/analyzed_ruby.c +10 -7
- data/src/analyze/builders.c +1 -0
- data/src/analyze/control_type.c +46 -29
- data/src/analyze/herb_directives.c +16 -20
- data/src/analyze/iteration_nodes.c +69 -24
- data/src/analyze/parse_errors.c +32 -22
- data/src/analyze/postfix_conditionals.c +23 -13
- data/src/analyze/prism_annotate.c +56 -32
- data/src/analyze/render_nodes.c +51 -41
- data/src/analyze/strict_locals.c +14 -15
- data/src/analyze/ternary_conditionals.c +14 -10
- data/src/ast/ast_nodes.c +3 -1
- data/src/ast/ast_pretty_print.c +5 -1
- data/src/extract.c +204 -143
- data/src/herb.c +10 -8
- data/src/include/analyze/action_view/tag_helper_handler.h +1 -1
- data/src/include/analyze/action_view/tag_helper_node_builders.h +1 -0
- data/src/include/analyze/action_view/tag_helpers.h +1 -1
- data/src/include/analyze/analyze.h +3 -24
- data/src/include/analyze/analyzed_ruby.h +29 -2
- data/src/include/analyze/helpers.h +7 -27
- data/src/include/ast/ast_nodes.h +2 -1
- data/src/include/herb.h +3 -2
- data/src/include/lexer/lexer.h +1 -0
- data/src/include/parser/parser_options.h +5 -0
- data/src/include/prism/herb_prism_node.h +6 -1
- data/src/include/prism/prism_context.h +12 -12
- data/src/include/prism/prism_helpers.h +30 -0
- data/src/include/prism_version.h +11 -0
- data/src/include/version.h +1 -1
- data/src/lexer.c +32 -0
- data/src/parser/parser_helpers.c +1 -2
- data/src/parser.c +6 -7
- data/src/parser_options_defaults.c +1 -0
- data/src/prism/prism_helpers.c +167 -42
- data/src/prism/ruby_parser.c +20 -20
- data/templates/ext/herb/nodes.c.erb +5 -5
- data/templates/ext/herb/parser_options_helpers.c.erb +33 -0
- data/templates/java/nodes.c.erb +6 -6
- data/templates/java/parser_options_helpers.c.erb +41 -2
- data/templates/java/parser_options_helpers.h.erb +2 -1
- data/templates/javascript/packages/core/src/nodes.ts.erb +21 -1
- data/templates/javascript/packages/node/extension/nodes.cpp.erb +5 -5
- data/templates/javascript/packages/node/extension/parser_options_helpers.cpp.erb +34 -2
- data/templates/javascript/packages/node/extension/parser_options_helpers.h.erb +1 -1
- data/templates/lib/herb/parser_options.rb.erb +1 -1
- data/templates/rust/src/ast/nodes.rs.erb +1 -4
- data/templates/rust/src/prism/generated_deserialize.rs.erb +90 -44
- data/templates/rust/src/prism/generated_prettyprint.rs.erb +18 -27
- data/templates/src/analyze/action_view/generated_handlers.c.erb +23 -22
- data/templates/src/include/parser/parser_options.h.erb +10 -0
- data/templates/src/include/prism_version.h.erb +17 -0
- data/templates/src/parser_options_defaults.c.erb +1 -1
- data/templates/template.rb +17 -2
- data/templates/wasm/nodes.cpp.erb +8 -18
- data/templates/wasm/parser_options_helpers.cpp.erb +24 -0
- data/vendor/prism/Rakefile +76 -7
- data/vendor/prism/config.yml +174 -161
- data/vendor/prism/include/prism/arena.h +45 -0
- data/vendor/prism/include/prism/arena.hpp +42 -0
- data/vendor/prism/include/prism/ast.h +2738 -611
- data/vendor/prism/include/prism/ast.hpp +641 -0
- data/vendor/prism/include/prism/buffer.h +60 -0
- data/vendor/prism/include/prism/buffer.hpp +55 -0
- data/vendor/prism/include/prism/comments.h +72 -0
- data/vendor/prism/include/prism/compiler/accel.h +26 -0
- data/vendor/prism/include/prism/compiler/align.h +36 -0
- data/vendor/prism/include/prism/compiler/assume.h +25 -0
- data/vendor/prism/include/prism/compiler/branch.h +26 -0
- data/vendor/prism/include/prism/compiler/bswap.h +46 -0
- data/vendor/prism/include/prism/compiler/cplusplus.hpp +16 -0
- data/vendor/prism/include/prism/compiler/endianness.h +34 -0
- data/vendor/prism/include/prism/compiler/exceptions.hpp +17 -0
- data/vendor/prism/include/prism/compiler/exported.h +24 -0
- data/vendor/prism/include/prism/compiler/fallthrough.h +22 -0
- data/vendor/prism/include/prism/compiler/filesystem.h +32 -0
- data/vendor/prism/include/prism/compiler/flex_array.h +19 -0
- data/vendor/prism/include/prism/compiler/force_inline.h +21 -0
- data/vendor/prism/include/prism/compiler/format.h +27 -0
- data/vendor/prism/include/prism/compiler/inline.h +17 -0
- data/vendor/prism/include/prism/compiler/lifetimebound.hpp +25 -0
- data/vendor/prism/include/prism/compiler/nodiscard.h +22 -0
- data/vendor/prism/include/prism/compiler/nonnull.h +18 -0
- data/vendor/prism/include/prism/compiler/unused.h +18 -0
- data/vendor/prism/include/prism/constant_pool.h +106 -0
- data/vendor/prism/include/prism/diagnostic.h +55 -402
- data/vendor/prism/include/prism/errors_format.h +61 -0
- data/vendor/prism/include/prism/excludes.h +29 -0
- data/vendor/prism/include/prism/integer.h +41 -0
- data/vendor/prism/include/prism/internal/allocator.h +68 -0
- data/vendor/prism/include/prism/internal/allocator_debug.h +88 -0
- data/vendor/prism/include/prism/internal/arena.h +108 -0
- data/vendor/prism/include/prism/internal/bit.h +42 -0
- data/vendor/prism/include/prism/internal/buffer.h +94 -0
- data/vendor/prism/include/prism/internal/char.h +145 -0
- data/vendor/prism/include/prism/internal/comments.h +54 -0
- data/vendor/prism/include/prism/internal/constant_pool.h +152 -0
- data/vendor/prism/include/prism/internal/diagnostic.h +389 -0
- data/vendor/prism/include/prism/{encoding.h → internal/encoding.h} +27 -68
- data/vendor/prism/include/prism/internal/integer.h +68 -0
- data/vendor/prism/include/prism/internal/isinf.h +16 -0
- data/vendor/prism/include/prism/internal/line_offset_list.h +34 -0
- data/vendor/prism/include/prism/{util/pm_list.h → internal/list.h} +11 -52
- data/vendor/prism/include/prism/internal/magic_comments.h +23 -0
- data/vendor/prism/include/prism/internal/memchr.h +15 -0
- data/vendor/prism/include/prism/internal/node.h +42 -0
- data/vendor/prism/include/prism/internal/options.h +232 -0
- data/vendor/prism/include/prism/internal/parser.h +1015 -0
- data/vendor/prism/include/prism/internal/regexp.h +26 -0
- data/vendor/prism/include/prism/internal/serialize.h +39 -0
- data/vendor/prism/include/prism/internal/source.h +72 -0
- data/vendor/prism/include/prism/internal/static_literals.h +60 -0
- data/vendor/prism/include/prism/internal/stringy.h +30 -0
- data/vendor/prism/include/prism/{util/pm_strncasecmp.h → internal/strncasecmp.h} +3 -17
- data/vendor/prism/include/prism/{util/pm_strpbrk.h → internal/strpbrk.h} +7 -20
- data/vendor/prism/include/prism/internal/tokens.h +11 -0
- data/vendor/prism/include/prism/internal/xxh3.h +16 -0
- data/vendor/prism/include/prism/json.h +40 -0
- data/vendor/prism/include/prism/line_offset_list.h +69 -0
- data/vendor/prism/include/prism/magic_comments.h +53 -0
- data/vendor/prism/include/prism/node.h +59 -49
- data/vendor/prism/include/prism/node.hpp +272 -0
- data/vendor/prism/include/prism/node_type.hpp +38 -0
- data/vendor/prism/include/prism/options.h +154 -279
- data/vendor/prism/include/prism/options.hpp +43 -0
- data/vendor/prism/include/prism/parser.h +367 -870
- data/vendor/prism/include/prism/parser.hpp +274 -0
- data/vendor/prism/include/prism/prettyprint.h +14 -9
- data/vendor/prism/include/prism/serialize.h +123 -0
- data/vendor/prism/include/prism/source.h +163 -0
- data/vendor/prism/include/prism/stream.h +36 -0
- data/vendor/prism/include/prism/string_query.h +82 -0
- data/vendor/prism/include/prism/stringy.h +61 -0
- data/vendor/prism/include/prism/stringy.hpp +31 -0
- data/vendor/prism/include/prism/version.h +20 -3
- data/vendor/prism/include/prism.h +35 -320
- data/vendor/prism/include/prism.hpp +24 -0
- data/vendor/prism/src/arena.c +122 -0
- data/vendor/prism/src/{util/pm_buffer.c → buffer.c} +53 -21
- data/vendor/prism/src/{util/pm_char.c → char.c} +28 -57
- data/vendor/prism/src/comments.c +455 -0
- data/vendor/prism/src/constant_pool.c +406 -0
- data/vendor/prism/src/diagnostic.c +120 -68
- data/vendor/prism/src/encoding.c +8 -3
- data/vendor/prism/src/errors_format.c +519 -0
- data/vendor/prism/src/{util/pm_integer.c → integer.c} +38 -22
- data/vendor/prism/src/json.c +5733 -0
- data/vendor/prism/src/line_offset_list.c +100 -0
- data/vendor/prism/src/list.c +24 -0
- data/vendor/prism/src/{util/pm_memchr.c → memchr.c} +8 -6
- data/vendor/prism/src/node.c +3465 -7787
- data/vendor/prism/src/options.c +161 -54
- data/vendor/prism/src/parser.c +371 -0
- data/vendor/prism/src/prettyprint.c +421 -354
- data/vendor/prism/src/prism.c +8522 -7280
- data/vendor/prism/src/regexp.c +960 -45
- data/vendor/prism/src/serialize.c +2434 -2048
- data/vendor/prism/src/source.c +524 -0
- data/vendor/prism/src/static_literals.c +303 -360
- data/vendor/prism/src/string_query.c +180 -0
- data/vendor/prism/src/stringy.c +61 -0
- data/vendor/prism/src/{util/pm_strncasecmp.c → strncasecmp.c} +5 -4
- data/vendor/prism/src/strpbrk.c +447 -0
- data/vendor/prism/src/{token_type.c → tokens.c} +39 -18
- data/vendor/prism/src/xxh3.c +292 -0
- data/vendor/prism/templates/ext/prism/api_node.c.erb +58 -44
- data/vendor/prism/templates/include/prism/ast.h.erb +67 -17
- data/vendor/prism/templates/include/prism/ast.hpp.erb +31 -0
- data/vendor/prism/templates/include/prism/internal/diagnostic.h.erb +60 -0
- data/vendor/prism/templates/java/{org → api/src/main/java-templates/org/ruby_lang}/prism/AbstractNodeVisitor.java.erb +1 -1
- data/vendor/prism/templates/java/{org → api/src/main/java-templates/org/ruby_lang}/prism/Loader.java.erb +232 -133
- data/vendor/prism/templates/java/{org → api/src/main/java-templates/org/ruby_lang}/prism/Nodes.java.erb +62 -23
- data/vendor/prism/templates/javascript/src/deserialize.js.erb +153 -146
- data/vendor/prism/templates/javascript/src/nodes.js.erb +4 -9
- data/vendor/prism/templates/lib/prism/compiler.rb.erb +14 -5
- data/vendor/prism/templates/lib/prism/dispatcher.rb.erb +20 -12
- data/vendor/prism/templates/lib/prism/dot_visitor.rb.erb +37 -11
- data/vendor/prism/templates/lib/prism/dsl.rb.erb +43 -4
- data/vendor/prism/templates/lib/prism/inspect_visitor.rb.erb +26 -10
- data/vendor/prism/templates/lib/prism/mutation_compiler.rb.erb +5 -2
- data/vendor/prism/templates/lib/prism/node.rb.erb +283 -105
- data/vendor/prism/templates/lib/prism/reflection.rb.erb +11 -2
- data/vendor/prism/templates/lib/prism/serialize.rb.erb +291 -134
- data/vendor/prism/templates/lib/prism/visitor.rb.erb +18 -0
- data/vendor/prism/templates/src/diagnostic.c.erb +114 -63
- data/vendor/prism/templates/src/json.c.erb +130 -0
- data/vendor/prism/templates/src/node.c.erb +79 -236
- data/vendor/prism/templates/src/prettyprint.c.erb +24 -13
- data/vendor/prism/templates/src/serialize.c.erb +369 -183
- data/vendor/prism/templates/src/{token_type.c.erb → tokens.c.erb} +22 -11
- data/vendor/prism/templates/template.rb +193 -91
- metadata +100 -42
- data/vendor/prism/include/prism/defines.h +0 -260
- data/vendor/prism/include/prism/pack.h +0 -163
- data/vendor/prism/include/prism/regexp.h +0 -43
- data/vendor/prism/include/prism/static_literals.h +0 -121
- data/vendor/prism/include/prism/util/pm_buffer.h +0 -236
- data/vendor/prism/include/prism/util/pm_char.h +0 -204
- data/vendor/prism/include/prism/util/pm_constant_pool.h +0 -218
- data/vendor/prism/include/prism/util/pm_integer.h +0 -130
- data/vendor/prism/include/prism/util/pm_memchr.h +0 -29
- data/vendor/prism/include/prism/util/pm_newline_list.h +0 -113
- data/vendor/prism/include/prism/util/pm_string.h +0 -200
- data/vendor/prism/src/pack.c +0 -509
- data/vendor/prism/src/util/pm_constant_pool.c +0 -342
- data/vendor/prism/src/util/pm_list.c +0 -49
- data/vendor/prism/src/util/pm_newline_list.c +0 -125
- data/vendor/prism/src/util/pm_string.c +0 -381
- data/vendor/prism/src/util/pm_strpbrk.c +0 -206
- data/vendor/prism/templates/include/prism/diagnostic.h.erb +0 -130
- data/vendor/prism/templates/rbi/prism/dsl.rbi.erb +0 -68
- data/vendor/prism/templates/rbi/prism/node.rbi.erb +0 -167
- data/vendor/prism/templates/rbi/prism/visitor.rbi.erb +0 -18
- data/vendor/prism/templates/sig/prism/_private/dot_visitor.rbs.erb +0 -45
- data/vendor/prism/templates/sig/prism/dsl.rbs.erb +0 -31
- data/vendor/prism/templates/sig/prism/mutation_compiler.rbs.erb +0 -7
- data/vendor/prism/templates/sig/prism/node.rbs.erb +0 -136
- data/vendor/prism/templates/sig/prism/visitor.rbs.erb +0 -17
- data/vendor/prism/templates/sig/prism.rbs.erb +0 -92
data/lib/herb/ast/nodes.rb
CHANGED
|
@@ -4964,6 +4964,7 @@ module Herb
|
|
|
4964
4964
|
#| tag_opening: Herb::Token?,
|
|
4965
4965
|
#| content: Herb::Token?,
|
|
4966
4966
|
#| tag_closing: Herb::Token?,
|
|
4967
|
+
#| prism_node: String?,
|
|
4967
4968
|
#| }
|
|
4968
4969
|
class ERBYieldNode < Node
|
|
4969
4970
|
include Colors
|
|
@@ -4971,13 +4972,15 @@ module Herb
|
|
|
4971
4972
|
attr_reader :tag_opening #: Herb::Token?
|
|
4972
4973
|
attr_reader :content #: Herb::Token?
|
|
4973
4974
|
attr_reader :tag_closing #: Herb::Token?
|
|
4975
|
+
attr_reader :prism_node #: String?
|
|
4974
4976
|
|
|
4975
|
-
#: (String, Location, Array[Herb::Errors::Error], Herb::Token?, Herb::Token?, Herb::Token?) -> void
|
|
4976
|
-
def initialize(type, location, errors, tag_opening, content, tag_closing)
|
|
4977
|
+
#: (String, Location, Array[Herb::Errors::Error], Herb::Token?, Herb::Token?, Herb::Token?, String?) -> void
|
|
4978
|
+
def initialize(type, location, errors, tag_opening, content, tag_closing, prism_node)
|
|
4977
4979
|
super(type, location, errors)
|
|
4978
4980
|
@tag_opening = tag_opening
|
|
4979
4981
|
@content = content
|
|
4980
4982
|
@tag_closing = tag_closing
|
|
4983
|
+
@prism_node = prism_node
|
|
4981
4984
|
end
|
|
4982
4985
|
|
|
4983
4986
|
#: () -> String
|
|
@@ -4985,9 +4988,25 @@ module Herb
|
|
|
4985
4988
|
"AST_ERB_YIELD_NODE"
|
|
4986
4989
|
end
|
|
4987
4990
|
|
|
4988
|
-
#: (?tag_opening: Herb::Token?, ?content: Herb::Token?, ?tag_closing: Herb::Token?, ?location: Location, ?errors: Array[Herb::Errors::Error]) -> ERBYieldNode
|
|
4989
|
-
def self.build(tag_opening: nil, content: nil, tag_closing: nil, location: Location.zero, errors: [])
|
|
4990
|
-
new(type, location, errors, tag_opening, content, tag_closing)
|
|
4991
|
+
#: (?tag_opening: Herb::Token?, ?content: Herb::Token?, ?tag_closing: Herb::Token?, ?prism_node: String?, ?location: Location, ?errors: Array[Herb::Errors::Error]) -> ERBYieldNode
|
|
4992
|
+
def self.build(tag_opening: nil, content: nil, tag_closing: nil, prism_node: nil, location: Location.zero, errors: [])
|
|
4993
|
+
new(type, location, errors, tag_opening, content, tag_closing, prism_node)
|
|
4994
|
+
end
|
|
4995
|
+
|
|
4996
|
+
#: () -> Prism::node?
|
|
4997
|
+
def deserialized_prism_node
|
|
4998
|
+
prism_node = @prism_node
|
|
4999
|
+
return nil unless prism_node
|
|
5000
|
+
return nil unless source
|
|
5001
|
+
|
|
5002
|
+
begin
|
|
5003
|
+
require "prism"
|
|
5004
|
+
rescue LoadError
|
|
5005
|
+
warn "The 'prism' gem is required to deserialize Prism nodes. Add it to your Gemfile or install it with: gem install prism"
|
|
5006
|
+
return nil
|
|
5007
|
+
end
|
|
5008
|
+
|
|
5009
|
+
Prism.load(source, prism_node).value
|
|
4991
5010
|
end
|
|
4992
5011
|
|
|
4993
5012
|
#: () -> serialized_erb_yield_node
|
|
@@ -4996,6 +5015,7 @@ module Herb
|
|
|
4996
5015
|
tag_opening: tag_opening,
|
|
4997
5016
|
content: content,
|
|
4998
5017
|
tag_closing: tag_closing,
|
|
5018
|
+
prism_node: prism_node,
|
|
4999
5019
|
}) #: Herb::serialized_erb_yield_node
|
|
5000
5020
|
end
|
|
5001
5021
|
|
|
@@ -5042,9 +5062,15 @@ module Herb
|
|
|
5042
5062
|
output += white("├── content: ")
|
|
5043
5063
|
output += content ? content.tree_inspect : magenta("∅")
|
|
5044
5064
|
output += "\n"
|
|
5045
|
-
|
|
5065
|
+
dynamic_symbol = prism_node ? "├──" : "└──"
|
|
5066
|
+
output += white("#{dynamic_symbol} tag_closing: ")
|
|
5046
5067
|
output += tag_closing ? tag_closing.tree_inspect : magenta("∅")
|
|
5047
5068
|
output += "\n"
|
|
5069
|
+
if prism_node && source
|
|
5070
|
+
output += white("└── prism_node: ")
|
|
5071
|
+
output += Herb::PrismInspect.inspect_prism_serialized(prism_node, source, " ")
|
|
5072
|
+
output += "\n"
|
|
5073
|
+
end
|
|
5048
5074
|
output += "\n"
|
|
5049
5075
|
|
|
5050
5076
|
output.gsub(/^/, " " * indent)
|
data/lib/herb/bootstrap.rb
CHANGED
|
@@ -70,13 +70,17 @@ module Herb
|
|
|
70
70
|
bundler_gems_dir = File.expand_path("..", ROOT_PATH)
|
|
71
71
|
candidates = Dir.glob(File.join(bundler_gems_dir, "prism-*"))
|
|
72
72
|
|
|
73
|
-
candidates.find { |path|
|
|
73
|
+
candidates.find { |path| prism_source?(path) }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def self.prism_source?(path)
|
|
77
|
+
File.directory?(File.join(path, "src")) && File.exist?(File.join(path, "config.yml"))
|
|
74
78
|
end
|
|
75
79
|
|
|
76
80
|
def self.find_prism_from_gem_spec
|
|
77
81
|
Gem::Specification.find_all_by_name("prism")
|
|
78
82
|
.map(&:full_gem_path)
|
|
79
|
-
.find { |path|
|
|
83
|
+
.find { |path| prism_source?(path) }
|
|
80
84
|
end
|
|
81
85
|
end
|
|
82
86
|
end
|
data/lib/herb/configuration.rb
CHANGED
|
@@ -100,11 +100,21 @@ module Herb
|
|
|
100
100
|
parser["erb_openers"] || []
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
+
#: () -> String?
|
|
104
|
+
def ruby_version
|
|
105
|
+
parser["ruby_version"]
|
|
106
|
+
end
|
|
107
|
+
|
|
103
108
|
#: () -> Hash[Symbol, untyped]
|
|
104
109
|
def parser_options
|
|
110
|
+
options = {} #: Hash[Symbol, untyped]
|
|
105
111
|
openers = erb_openers
|
|
112
|
+
version = ruby_version
|
|
113
|
+
|
|
114
|
+
options[:erb_openers] = openers unless openers.empty?
|
|
115
|
+
options[:ruby_version] = version if version
|
|
106
116
|
|
|
107
|
-
|
|
117
|
+
options
|
|
108
118
|
end
|
|
109
119
|
|
|
110
120
|
def linter
|
data/lib/herb/dev/classifier.rb
CHANGED
|
@@ -61,7 +61,7 @@ module Herb
|
|
|
61
61
|
|
|
62
62
|
return classification(:whitespace, operations: operations) if significant.empty?
|
|
63
63
|
|
|
64
|
-
kind = self.class.can_patch?(significant) && @parser_options.empty? ? :static : :dynamic
|
|
64
|
+
kind = self.class.can_patch?(significant) && @parser_options.except(:ruby_version).empty? ? :static : :dynamic
|
|
65
65
|
|
|
66
66
|
classification(kind, operations: operations, node_path: covering_path(significant))
|
|
67
67
|
end
|
data/lib/herb/dev/runner.rb
CHANGED
data/lib/herb/engine/compiler.rb
CHANGED
|
@@ -238,6 +238,10 @@ module Herb
|
|
|
238
238
|
process_erb_tag(node)
|
|
239
239
|
end
|
|
240
240
|
|
|
241
|
+
def visit_erb_strict_locals_node(node)
|
|
242
|
+
process_erb_tag(node)
|
|
243
|
+
end
|
|
244
|
+
|
|
241
245
|
def visit_erb_control_node(node, &)
|
|
242
246
|
if node.content
|
|
243
247
|
if node.tag_opening && erb_escaped?(node.tag_opening.value)
|
|
@@ -282,7 +286,7 @@ module Herb
|
|
|
282
286
|
end
|
|
283
287
|
|
|
284
288
|
def visit_erb_case_node(node)
|
|
285
|
-
|
|
289
|
+
visit_erb_case_parts(node)
|
|
286
290
|
end
|
|
287
291
|
|
|
288
292
|
def visit_erb_when_node(node)
|
|
@@ -318,7 +322,7 @@ module Herb
|
|
|
318
322
|
end
|
|
319
323
|
|
|
320
324
|
def visit_erb_case_match_node(node)
|
|
321
|
-
|
|
325
|
+
visit_erb_case_parts(node)
|
|
322
326
|
end
|
|
323
327
|
|
|
324
328
|
def visit_erb_in_node(node)
|
|
@@ -389,14 +393,18 @@ module Herb
|
|
|
389
393
|
end
|
|
390
394
|
end
|
|
391
395
|
|
|
392
|
-
def
|
|
396
|
+
def visit_erb_case_parts(node)
|
|
393
397
|
parts = [:conditions, :else_clause, :end_node]
|
|
394
398
|
|
|
395
|
-
|
|
399
|
+
return visit_erb_control_with_parts(node, :children, *parts) if erb_escaped?(node.tag_opening.value)
|
|
400
|
+
|
|
401
|
+
visit_erb_control_with_parts(node, *parts) { skip_case_children(node.children) }
|
|
396
402
|
end
|
|
397
403
|
|
|
398
|
-
def visit_erb_control_with_parts(node, *parts)
|
|
404
|
+
def visit_erb_control_with_parts(node, *parts, &)
|
|
399
405
|
visit_erb_control_node(node) do
|
|
406
|
+
yield if block_given?
|
|
407
|
+
|
|
400
408
|
parts.each do |part|
|
|
401
409
|
value = node.send(part)
|
|
402
410
|
case value
|
|
@@ -813,15 +821,17 @@ module Herb
|
|
|
813
821
|
|
|
814
822
|
return true if trailing_indentation?(text)
|
|
815
823
|
|
|
816
|
-
whitespace_only?(text) && (
|
|
824
|
+
whitespace_only?(text) && (preceding_token_value_ends_with_newline? || @last_trim_consumed_newline)
|
|
817
825
|
end
|
|
818
826
|
|
|
819
|
-
def
|
|
827
|
+
def preceding_token_value_ends_with_newline?
|
|
820
828
|
return true unless @tokens.length >= 2
|
|
821
829
|
|
|
822
830
|
preceding = @tokens[-2]
|
|
823
831
|
|
|
824
|
-
|
|
832
|
+
return @last_trim_consumed_newline if EXPRESSION_TOKEN_TYPES.include?(preceding[0])
|
|
833
|
+
|
|
834
|
+
preceding[1].end_with?("\n")
|
|
825
835
|
end
|
|
826
836
|
|
|
827
837
|
def extract_and_remove_leading_space!
|
|
@@ -846,8 +856,11 @@ module Herb
|
|
|
846
856
|
|
|
847
857
|
follows_newline = leading_space_follows_newline?
|
|
848
858
|
removed_whitespace = left_trim?(node) ? remove_trailing_whitespace_from_last_token! : ""
|
|
859
|
+
line_start = at_line_start?
|
|
849
860
|
|
|
850
|
-
if
|
|
861
|
+
drop_pending_trim_newline! if follows_trimmed_statement_tag?(node)
|
|
862
|
+
|
|
863
|
+
if line_start
|
|
851
864
|
leading_space = extract_and_remove_leading_space!
|
|
852
865
|
effective_leading_space = leading_space.empty? ? removed_whitespace : leading_space
|
|
853
866
|
right_space = if Herb::Engine::Helpers.heredoc?(code)
|
|
@@ -858,15 +871,12 @@ module Herb
|
|
|
858
871
|
" \n"
|
|
859
872
|
end
|
|
860
873
|
|
|
861
|
-
|
|
862
|
-
@pending_leading_whitespace = effective_leading_space if !effective_leading_space.empty? && follows_newline
|
|
874
|
+
save_pending_leading_whitespace!(effective_leading_space) if !effective_leading_space.empty? && follows_newline
|
|
863
875
|
@tokens << [:code, "#{effective_leading_space}#{code}#{right_space}", current_context]
|
|
864
876
|
@trim_next_whitespace = true
|
|
865
877
|
|
|
866
|
-
if right_space.end_with?(" \n")
|
|
867
|
-
|
|
868
|
-
@pending_trim_owns_next_whitespace = true
|
|
869
|
-
end
|
|
878
|
+
@pending_trim_newline_index = @tokens.length - 1 if right_space.end_with?(" \n")
|
|
879
|
+
@pending_trim_owns_next_whitespace = true if right_space.end_with?(" \n") || without_source?(node)
|
|
870
880
|
else
|
|
871
881
|
@tokens << [:code, code, current_context]
|
|
872
882
|
end
|
|
@@ -899,20 +909,43 @@ module Herb
|
|
|
899
909
|
#: (bool) -> void
|
|
900
910
|
def settle_pending_trim_newline!(keep)
|
|
901
911
|
index = @pending_trim_newline_index
|
|
902
|
-
|
|
903
|
-
return unless index
|
|
904
|
-
|
|
905
912
|
owned = @pending_trim_owns_next_whitespace
|
|
906
913
|
|
|
914
|
+
return unless index || owned
|
|
915
|
+
|
|
907
916
|
@pending_trim_newline_index = nil
|
|
908
917
|
@pending_trim_owns_next_whitespace = false
|
|
909
918
|
|
|
910
919
|
return if keep
|
|
911
920
|
|
|
912
|
-
@tokens[index][1] = @tokens[index][1].chomp
|
|
921
|
+
@tokens[index][1] = @tokens[index][1].chomp if index
|
|
913
922
|
@trim_next_whitespace = false if owned
|
|
914
923
|
end
|
|
915
924
|
|
|
925
|
+
#: (Array[untyped]) -> void
|
|
926
|
+
def skip_case_children(children)
|
|
927
|
+
text = children.grep(Herb::AST::HTMLTextNode).map(&:content).join
|
|
928
|
+
|
|
929
|
+
settle_pending_trim_newline!(true) if text.match?(/\A[ \t]*\r?\n/)
|
|
930
|
+
end
|
|
931
|
+
|
|
932
|
+
#: (untyped) -> bool
|
|
933
|
+
def follows_trimmed_statement_tag?(node)
|
|
934
|
+
return false if without_source?(node)
|
|
935
|
+
|
|
936
|
+
!@pending_trim_newline_index.nil? && @pending_trim_newline_index == @tokens.length - 1
|
|
937
|
+
end
|
|
938
|
+
|
|
939
|
+
#: () -> void
|
|
940
|
+
def drop_pending_trim_newline!
|
|
941
|
+
index = @pending_trim_newline_index
|
|
942
|
+
return unless index
|
|
943
|
+
|
|
944
|
+
@tokens[index][1] = @tokens[index][1].chomp
|
|
945
|
+
@pending_trim_newline_index = nil
|
|
946
|
+
@pending_trim_owns_next_whitespace = false
|
|
947
|
+
end
|
|
948
|
+
|
|
916
949
|
def save_pending_leading_whitespace!(whitespace)
|
|
917
950
|
@pending_leading_whitespace = whitespace
|
|
918
951
|
@pending_leading_whitespace_insert_index = @tokens.length
|
|
@@ -71,7 +71,8 @@ module Herb
|
|
|
71
71
|
# An item is keyed by the key its template declares, through `herb-key` or `id` or a
|
|
72
72
|
# `<%# herb:key %>` directive, which is what makes it survive being reordered. `Visitor`
|
|
73
73
|
# decides what that key is and this evaluates it, so an item arrives under the same key the
|
|
74
|
-
# marker around it carries. A collection that declares none falls back to position
|
|
74
|
+
# marker around it carries. A collection that declares none falls back to position, counting
|
|
75
|
+
# from the first iteration, so a change re-renders every row from the first one that differs.
|
|
75
76
|
#
|
|
76
77
|
# ## A partial keeps its own values
|
|
77
78
|
#
|
|
@@ -94,7 +95,7 @@ module Herb
|
|
|
94
95
|
#
|
|
95
96
|
# ## Blocks
|
|
96
97
|
#
|
|
97
|
-
# A tag that takes a block, such as `<%= form_with do |f| %>`, owns an entry holding
|
|
98
|
+
# A tag that takes a block, such as `<%= form_with do |f| %>`, owns an entry holding the markup
|
|
98
99
|
# the block rendered, because the helper wraps that output in markup of its own that only the
|
|
99
100
|
# helper can produce. What the template wrote inside the block keeps its own indices alongside:
|
|
100
101
|
#
|
|
@@ -105,6 +106,20 @@ module Herb
|
|
|
105
106
|
# and the whole block. Slot 1 is inside slot 0, which the client already has to reason about
|
|
106
107
|
# for conditionals and collections.
|
|
107
108
|
#
|
|
109
|
+
# A partial inside a block is the exception to that fallback. It keeps its own values on its slot,
|
|
110
|
+
# and the block's entry is a String that cannot hold them, so the entry leaves the partial's
|
|
111
|
+
# markup out:
|
|
112
|
+
#
|
|
113
|
+
# <%= form_with(model: @user) do |f| %><%= render "card" %><% end %>
|
|
114
|
+
# #=> { 0 => "<form></form>", 1 => { template: "app/views/_card.html.erb", ... } }
|
|
115
|
+
#
|
|
116
|
+
# That entry cannot stand in for the block, so it must not be written over a block holding a
|
|
117
|
+
# partial. The client never writes a block's entry while the page marks slots inside that block.
|
|
118
|
+
# It reports the block as deferred instead, even when nothing in the block changed.
|
|
119
|
+
#
|
|
120
|
+
# A render that comes back as markup, because its template is not compiled for slots, is written
|
|
121
|
+
# into the entry as usual, and the entry stays whole.
|
|
122
|
+
#
|
|
108
123
|
# A block yielding more than once is the exception, since one index cannot stand for the several
|
|
109
124
|
# values its interior took. `each` and the other iterations are compiled as collections for that
|
|
110
125
|
# reason, and a helper that yields repeatedly reports the last value its interior took.
|
|
@@ -117,6 +132,7 @@ module Herb
|
|
|
117
132
|
ITEMS_BUFFER = "__herb_items" #: String
|
|
118
133
|
KEY_BUFFER = "__herb_key" #: String
|
|
119
134
|
OCCURRENCE_BUFFER = "__herb_occurrence" #: String
|
|
135
|
+
RENDERED_BUFFER = "__herb_rendered" #: String
|
|
120
136
|
|
|
121
137
|
BRANCHING_NODES = [
|
|
122
138
|
"AST_ERB_IF_NODE",
|
|
@@ -189,6 +205,16 @@ module Herb
|
|
|
189
205
|
@current_node = previous
|
|
190
206
|
end
|
|
191
207
|
|
|
208
|
+
#: (untyped) -> void
|
|
209
|
+
def visit_ruby_literal_node(node)
|
|
210
|
+
previous = @current_node
|
|
211
|
+
@current_node = node
|
|
212
|
+
|
|
213
|
+
super
|
|
214
|
+
ensure
|
|
215
|
+
@current_node = previous
|
|
216
|
+
end
|
|
217
|
+
|
|
192
218
|
#: (untyped) -> void
|
|
193
219
|
def visit_erb_yield_node(node)
|
|
194
220
|
previous = @current_node
|
|
@@ -287,14 +313,15 @@ module Herb
|
|
|
287
313
|
|
|
288
314
|
return super if erb_escaped?(opening)
|
|
289
315
|
|
|
290
|
-
|
|
316
|
+
rendering = node.is_a?(Herb::AST::ERBRenderNode)
|
|
317
|
+
should_escape = !rendering && should_escape_output?(opening)
|
|
291
318
|
index = claim(node)
|
|
292
319
|
|
|
293
320
|
@tokens << [
|
|
294
321
|
should_escape ? :expr_block_escaped : :expr_block,
|
|
295
322
|
node.content.value.strip,
|
|
296
323
|
current_context,
|
|
297
|
-
index
|
|
324
|
+
[index, rendering]
|
|
298
325
|
]
|
|
299
326
|
|
|
300
327
|
@last_trim_consumed_newline = false
|
|
@@ -325,7 +352,9 @@ module Herb
|
|
|
325
352
|
|
|
326
353
|
@engine.send(:add_dynamic, value, context, index, escaped, nested: nested)
|
|
327
354
|
when :expr_block, :expr_block_escaped
|
|
328
|
-
|
|
355
|
+
index, rendering = extra
|
|
356
|
+
|
|
357
|
+
@engine.send(:add_dynamic_block, value, index, type == :expr_block_escaped, rendering: rendering)
|
|
329
358
|
when :expr_block_end
|
|
330
359
|
@engine.send(:add_expression_block_end, value, escaped: extra)
|
|
331
360
|
end
|
|
@@ -451,7 +480,7 @@ module Herb
|
|
|
451
480
|
|
|
452
481
|
#: (Integer) -> String?
|
|
453
482
|
def item_key(index)
|
|
454
|
-
@slot_visitor.slots[index]&.
|
|
483
|
+
@slot_visitor.slots[index]&.item_key
|
|
455
484
|
end
|
|
456
485
|
|
|
457
486
|
#: (untyped, Symbol) -> void
|
|
@@ -531,6 +560,7 @@ module Herb
|
|
|
531
560
|
#: (String, ?Hash[Symbol, untyped]) -> void
|
|
532
561
|
def initialize(input, properties = {})
|
|
533
562
|
@block_depth = 0
|
|
563
|
+
@nested_renders = [] #: Array[[Integer?]?]
|
|
534
564
|
@scopes = [] #: Array[Integer]
|
|
535
565
|
@withheld = {} #: Hash[Integer, bool]
|
|
536
566
|
@input = input
|
|
@@ -589,6 +619,8 @@ module Herb
|
|
|
589
619
|
return add_block_dynamic("(#{assignment(index, value)}).fetch(-1)")
|
|
590
620
|
end
|
|
591
621
|
|
|
622
|
+
return add_block_render(index ? assignment(index, value) : value) if nested
|
|
623
|
+
|
|
592
624
|
return add_block_dynamic(index ? assignment(index, value) : value)
|
|
593
625
|
end
|
|
594
626
|
return if index.nil?
|
|
@@ -601,19 +633,24 @@ module Herb
|
|
|
601
633
|
@slot_visitor.slots[index]&.type == :boolean_attribute
|
|
602
634
|
end
|
|
603
635
|
|
|
604
|
-
#: (String, Integer?, bool) -> void
|
|
605
|
-
def add_dynamic_block(code, index, escaped)
|
|
636
|
+
#: (String, Integer?, bool, ?rendering: bool) -> void
|
|
637
|
+
def add_dynamic_block(code, index, escaped, rendering: false)
|
|
606
638
|
@_in_expression_block = true
|
|
607
639
|
@_expression_block_open_paren = true
|
|
608
640
|
|
|
609
641
|
opening = escaped ? "#{@escapefunc}((" : "("
|
|
642
|
+
nested_render = rendering && !@block_depth.zero?
|
|
610
643
|
|
|
611
644
|
@src << if @block_depth.zero?
|
|
612
645
|
"; #{current_scope}[#{index}] = #{opening}#{code}"
|
|
646
|
+
elsif nested_render
|
|
647
|
+
"; #{RENDERED_BUFFER} = #{opening}#{code}"
|
|
613
648
|
else
|
|
614
649
|
"; #{@bufvar} << #{opening}#{code}"
|
|
615
650
|
end
|
|
616
651
|
|
|
652
|
+
@nested_renders.push(nested_render ? [index] : nil)
|
|
653
|
+
|
|
617
654
|
open_block
|
|
618
655
|
end
|
|
619
656
|
|
|
@@ -624,6 +661,14 @@ module Herb
|
|
|
624
661
|
close_block
|
|
625
662
|
|
|
626
663
|
super
|
|
664
|
+
|
|
665
|
+
nested_render = @nested_renders.pop
|
|
666
|
+
|
|
667
|
+
return unless nested_render
|
|
668
|
+
|
|
669
|
+
index = nested_render.first
|
|
670
|
+
|
|
671
|
+
add_block_render(index ? assignment(index, RENDERED_BUFFER) : RENDERED_BUFFER)
|
|
627
672
|
end
|
|
628
673
|
|
|
629
674
|
#: () -> String
|
|
@@ -728,6 +773,10 @@ module Herb
|
|
|
728
773
|
#: (Integer) -> void
|
|
729
774
|
def scope_open_collection(index)
|
|
730
775
|
@src << "; #{ITEMS_BUFFER}#{index} = ::Hash.new;"
|
|
776
|
+
|
|
777
|
+
slot = @slot_visitor.slots[index]
|
|
778
|
+
|
|
779
|
+
@src << "; #{slot.position_variable} = -1;" if slot&.positional?
|
|
731
780
|
end
|
|
732
781
|
|
|
733
782
|
#: (Integer, ?String?) -> void
|
|
@@ -742,17 +791,12 @@ module Herb
|
|
|
742
791
|
def scope_item_end(index)
|
|
743
792
|
leave_scope(index)
|
|
744
793
|
|
|
745
|
-
return unless
|
|
794
|
+
return unless @slot_visitor.slots[index]&.item_key
|
|
746
795
|
|
|
747
796
|
@src << item_seeds(index)
|
|
748
797
|
@src << "; #{ITEMS_BUFFER}#{index}[#{KEY_BUFFER}#{index}.to_s] = #{SCOPE_BUFFER}#{index};"
|
|
749
798
|
end
|
|
750
799
|
|
|
751
|
-
#: (Integer) -> bool
|
|
752
|
-
def keyed?(index)
|
|
753
|
-
!@slot_visitor.slots[index]&.key_expression.nil?
|
|
754
|
-
end
|
|
755
|
-
|
|
756
800
|
#: (Integer) -> String
|
|
757
801
|
def item_seeds(index)
|
|
758
802
|
names = @slot_visitor.seeded_item_states[index]
|
|
@@ -816,6 +860,11 @@ module Herb
|
|
|
816
860
|
@slot_visitor.slots[index]&.interpolated? || false
|
|
817
861
|
end
|
|
818
862
|
|
|
863
|
+
#: (String) -> void
|
|
864
|
+
def add_block_render(value)
|
|
865
|
+
add_block_dynamic("::Hash === (#{RENDERED_BUFFER} = (#{value})) ? \"\" : #{RENDERED_BUFFER}.to_s")
|
|
866
|
+
end
|
|
867
|
+
|
|
819
868
|
#: (String) -> void
|
|
820
869
|
def add_block_dynamic(value)
|
|
821
870
|
@src << "; " << @bufvar << " << (" << value << ");"
|
|
@@ -10,6 +10,10 @@ module Herb
|
|
|
10
10
|
SEED_VALUE_TYPES = "[true, false, ::Integer, ::String, ::Symbol, nil]" #: String
|
|
11
11
|
PREFIX = "herb-" #: String
|
|
12
12
|
COMMENT = %r{\A<!--/?#{PREFIX}} #: Regexp
|
|
13
|
+
FOREIGN_ATTRIBUTE = "data-herb-foreign" #: String
|
|
14
|
+
FOREIGN_ROOTS = { svg: "svg", math: "math" }.freeze #: Hash[Symbol, String]
|
|
15
|
+
SVG_INTEGRATION_POINTS = ["foreignobject", "desc", "title"].freeze #: Array[String]
|
|
16
|
+
MATH_INTEGRATION_POINTS = ["mi", "mo", "mn", "ms", "mtext"].freeze #: Array[String]
|
|
13
17
|
|
|
14
18
|
#: (String) -> bool
|
|
15
19
|
def self.marker?(text)
|
|
@@ -21,6 +25,18 @@ module Herb
|
|
|
21
25
|
"{ #{pairs} }.select { |_, v| #{SEED_VALUE_TYPES}.any? { |t| t === v } }.transform_values { |v| v.is_a?(::Symbol) ? v.to_s : v }"
|
|
22
26
|
end
|
|
23
27
|
|
|
28
|
+
#: (Symbol, String) -> Symbol
|
|
29
|
+
def self.namespace_within(namespace, tag_name)
|
|
30
|
+
case namespace
|
|
31
|
+
when :svg
|
|
32
|
+
SVG_INTEGRATION_POINTS.include?(tag_name) ? :html : :svg
|
|
33
|
+
when :math
|
|
34
|
+
MATH_INTEGRATION_POINTS.include?(tag_name) ? :html : :math
|
|
35
|
+
else
|
|
36
|
+
FOREIGN_ROOTS.key(tag_name) || :html
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
24
40
|
#: (Integer, Symbol) -> String
|
|
25
41
|
def slot_open(index, type)
|
|
26
42
|
return "<!--#{PREFIX}slot:#{index}-->" if type == DEFAULT_TYPE
|
|
@@ -28,6 +44,14 @@ module Herb
|
|
|
28
44
|
"<!--#{PREFIX}slot:#{index}:#{type}-->"
|
|
29
45
|
end
|
|
30
46
|
|
|
47
|
+
#: (String, Symbol) -> String
|
|
48
|
+
def foreign(markup, namespace)
|
|
49
|
+
root = FOREIGN_ROOTS[namespace]
|
|
50
|
+
return markup unless root
|
|
51
|
+
|
|
52
|
+
%(<#{root} #{FOREIGN_ATTRIBUTE}>#{markup}</#{root}>)
|
|
53
|
+
end
|
|
54
|
+
|
|
31
55
|
#: (Array[[Integer, Symbol, String?]]) -> String
|
|
32
56
|
def element_anchors(anchors)
|
|
33
57
|
anchors.map { |index, type, name| name ? "#{index}:#{type}:#{name}" : "#{index}:#{type}" }.join(" ")
|
|
@@ -1311,8 +1311,7 @@ module Herb
|
|
|
1311
1311
|
return nil unless position
|
|
1312
1312
|
|
|
1313
1313
|
condition = StateDirectives.condition_source(read)
|
|
1314
|
-
|
|
1315
|
-
replacement = @visitor.erb_output_node(%[("#{spacing}#{slot.attribute}" if #{condition})])
|
|
1314
|
+
replacement = @visitor.erb_output_node(%[("#{@visitor.attribute_spacing(children, position)}#{slot.attribute}" if #{condition})])
|
|
1316
1315
|
|
|
1317
1316
|
children[position] = replacement
|
|
1318
1317
|
|