herb 0.11.0-arm-linux-gnu → 0.11.1-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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/config.yml +3 -0
  3. data/ext/herb/nodes.c +34 -17
  4. data/lib/herb/3.2/herb.so +0 -0
  5. data/lib/herb/3.3/herb.so +0 -0
  6. data/lib/herb/3.4/herb.so +0 -0
  7. data/lib/herb/4.0/herb.so +0 -0
  8. data/lib/herb/ast/nodes.rb +32 -6
  9. data/lib/herb/bootstrap.rb +6 -2
  10. data/lib/herb/dev/runner.rb +6 -1
  11. data/lib/herb/engine/compiler.rb +47 -11
  12. data/lib/herb/engine/slots/dynamics_compiler.rb +10 -0
  13. data/lib/herb/engine/slots/markers.rb +24 -0
  14. data/lib/herb/engine/slots/state_compiler.rb +1 -2
  15. data/lib/herb/engine/slots/visitor.rb +39 -28
  16. data/lib/herb/engine.rb +0 -2
  17. data/lib/herb/version.rb +1 -1
  18. data/sig/herb/ast/nodes.rbs +10 -4
  19. data/sig/herb/bootstrap.rbs +2 -0
  20. data/sig/herb/dev/runner.rbs +3 -0
  21. data/sig/herb/engine/compiler.rbs +14 -3
  22. data/sig/herb/engine/slots/dynamics_compiler.rbs +3 -0
  23. data/sig/herb/engine/slots/markers.rbs +14 -0
  24. data/sig/herb/engine/slots/visitor.rbs +17 -13
  25. data/sig/serialized_ast_nodes.rbs +1 -0
  26. data/src/analyze/action_view/tag_helper_node_builders.c +6 -3
  27. data/src/analyze/action_view/tag_helpers.c +76 -20
  28. data/src/analyze/analyze.c +5 -25
  29. data/src/analyze/analyze_helpers.c +94 -232
  30. data/src/analyze/analyzed_ruby.c +2 -0
  31. data/src/analyze/builders.c +1 -0
  32. data/src/analyze/control_type.c +17 -7
  33. data/src/analyze/prism_annotate.c +32 -9
  34. data/src/ast/ast_nodes.c +3 -1
  35. data/src/ast/ast_pretty_print.c +5 -1
  36. data/src/extract.c +204 -143
  37. data/src/include/analyze/analyze.h +0 -22
  38. data/src/include/analyze/analyzed_ruby.h +25 -0
  39. data/src/include/analyze/helpers.h +2 -22
  40. data/src/include/ast/ast_nodes.h +2 -1
  41. data/src/include/lexer/lexer.h +1 -0
  42. data/src/include/prism/herb_prism_node.h +6 -1
  43. data/src/include/version.h +1 -1
  44. data/src/lexer.c +32 -0
  45. data/src/prism/prism_helpers.c +91 -0
  46. data/templates/ext/herb/nodes.c.erb +1 -1
  47. data/templates/java/nodes.c.erb +1 -1
  48. data/templates/javascript/packages/core/src/nodes.ts.erb +21 -1
  49. data/templates/javascript/packages/node/extension/nodes.cpp.erb +1 -1
  50. data/templates/rust/src/ast/nodes.rs.erb +1 -4
  51. data/templates/wasm/nodes.cpp.erb +5 -15
  52. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28c51f69728155d005466de2eee9a4be0eabb5ac84d476884a532f4c0b59517c
4
- data.tar.gz: c666b72f5a6cf58572626446e54fc8cdd0c49c532785cbb1a18482072660f627
3
+ metadata.gz: c909ec1f68c66ff62e3cd2a17402ed4d59154334c7edbbc252a8708e276efe47
4
+ data.tar.gz: 6acd5e979521f52034f4011c58d4275a9dbb4571912eed54bd8862c89e65495b
5
5
  SHA512:
6
- metadata.gz: 7b2810ffb15ca2e27b564fecdacd60313df5621092be2452a98949ee655d1a37bb4051cd06cc425d8b5fdb1eef2d07e482abeba25b06ea83b19042f2bef3d28d
7
- data.tar.gz: b2572479f17787cad72270b4dee70baaf7de8a5bf81b02320e2c8ce9bb73ed954c932aa6f867f93b7bc61c22aa76d3dd9ff6cb528a7a7595bd6feedbacf09a76
6
+ metadata.gz: eb7679d9a101d75068ec7d3a35bbe275907aecffb40d75bc45f6a98a54f9ca012cf43d98e95c461b454dd19639f5d5a2fa3e4a93a9cb481eede5c3a531a9ea79
7
+ data.tar.gz: 29beb686a1d5289be4bb1a7e38f0409a50da0d4664ed4a09aeff46da837d281a26261111fd21471d3543280fb01282edec22aa30dd3e22919c90d76b5c3478b4
data/config.yml CHANGED
@@ -1739,6 +1739,9 @@ nodes:
1739
1739
  - name: "tag_closing"
1740
1740
  type: "token"
1741
1741
 
1742
+ - name: "prism_node"
1743
+ type: "prism_node"
1744
+
1742
1745
  - name: "ERBInNode"
1743
1746
  fields:
1744
1747
  - name: "tag_opening"
data/ext/herb/nodes.c CHANGED
@@ -141,7 +141,7 @@ static VALUE rb_document_node_from_c_struct(AST_DOCUMENT_NODE_T* document_node,
141
141
  VALUE document_node_prism_node;
142
142
  if (document_node->prism_node.node != NULL && document_node->prism_node.parser != NULL) {
143
143
  pm_buffer_t pm_buffer = { 0 };
144
- pm_serialize(document_node->prism_node.parser, document_node->prism_node.node, &pm_buffer);
144
+ herb_prism_node_serialize(document_node->prism_node, &pm_buffer);
145
145
 
146
146
  if (pm_buffer.length > 0) {
147
147
  document_node_prism_node = rb_str_new(pm_buffer.value, pm_buffer.length);
@@ -821,7 +821,7 @@ static VALUE rb_erb_content_node_from_c_struct(AST_ERB_CONTENT_NODE_T* erb_conte
821
821
  VALUE erb_content_node_prism_node;
822
822
  if (erb_content_node->prism_node.node != NULL && erb_content_node->prism_node.parser != NULL) {
823
823
  pm_buffer_t pm_buffer = { 0 };
824
- pm_serialize(erb_content_node->prism_node.parser, erb_content_node->prism_node.node, &pm_buffer);
824
+ herb_prism_node_serialize(erb_content_node->prism_node, &pm_buffer);
825
825
 
826
826
  if (pm_buffer.length > 0) {
827
827
  erb_content_node_prism_node = rb_str_new(pm_buffer.value, pm_buffer.length);
@@ -934,7 +934,7 @@ static VALUE rb_erb_if_node_from_c_struct(AST_ERB_IF_NODE_T* erb_if_node, const
934
934
  VALUE erb_if_node_prism_node;
935
935
  if (erb_if_node->prism_node.node != NULL && erb_if_node->prism_node.parser != NULL) {
936
936
  pm_buffer_t pm_buffer = { 0 };
937
- pm_serialize(erb_if_node->prism_node.parser, erb_if_node->prism_node.node, &pm_buffer);
937
+ herb_prism_node_serialize(erb_if_node->prism_node, &pm_buffer);
938
938
 
939
939
  if (pm_buffer.length > 0) {
940
940
  erb_if_node_prism_node = rb_str_new(pm_buffer.value, pm_buffer.length);
@@ -988,7 +988,7 @@ static VALUE rb_erb_block_node_from_c_struct(AST_ERB_BLOCK_NODE_T* erb_block_nod
988
988
  VALUE erb_block_node_prism_node;
989
989
  if (erb_block_node->prism_node.node != NULL && erb_block_node->prism_node.parser != NULL) {
990
990
  pm_buffer_t pm_buffer = { 0 };
991
- pm_serialize(erb_block_node->prism_node.parser, erb_block_node->prism_node.node, &pm_buffer);
991
+ herb_prism_node_serialize(erb_block_node->prism_node, &pm_buffer);
992
992
 
993
993
  if (pm_buffer.length > 0) {
994
994
  erb_block_node_prism_node = rb_str_new(pm_buffer.value, pm_buffer.length);
@@ -1047,7 +1047,7 @@ static VALUE rb_erb_iteration_block_node_from_c_struct(AST_ERB_ITERATION_BLOCK_N
1047
1047
  VALUE erb_iteration_block_node_prism_node;
1048
1048
  if (erb_iteration_block_node->prism_node.node != NULL && erb_iteration_block_node->prism_node.parser != NULL) {
1049
1049
  pm_buffer_t pm_buffer = { 0 };
1050
- pm_serialize(erb_iteration_block_node->prism_node.parser, erb_iteration_block_node->prism_node.node, &pm_buffer);
1050
+ herb_prism_node_serialize(erb_iteration_block_node->prism_node, &pm_buffer);
1051
1051
 
1052
1052
  if (pm_buffer.length > 0) {
1053
1053
  erb_iteration_block_node_prism_node = rb_str_new(pm_buffer.value, pm_buffer.length);
@@ -1151,7 +1151,7 @@ static VALUE rb_erb_case_node_from_c_struct(AST_ERB_CASE_NODE_T* erb_case_node,
1151
1151
  VALUE erb_case_node_prism_node;
1152
1152
  if (erb_case_node->prism_node.node != NULL && erb_case_node->prism_node.parser != NULL) {
1153
1153
  pm_buffer_t pm_buffer = { 0 };
1154
- pm_serialize(erb_case_node->prism_node.parser, erb_case_node->prism_node.node, &pm_buffer);
1154
+ herb_prism_node_serialize(erb_case_node->prism_node, &pm_buffer);
1155
1155
 
1156
1156
  if (pm_buffer.length > 0) {
1157
1157
  erb_case_node_prism_node = rb_str_new(pm_buffer.value, pm_buffer.length);
@@ -1206,7 +1206,7 @@ static VALUE rb_erb_case_match_node_from_c_struct(AST_ERB_CASE_MATCH_NODE_T* erb
1206
1206
  VALUE erb_case_match_node_prism_node;
1207
1207
  if (erb_case_match_node->prism_node.node != NULL && erb_case_match_node->prism_node.parser != NULL) {
1208
1208
  pm_buffer_t pm_buffer = { 0 };
1209
- pm_serialize(erb_case_match_node->prism_node.parser, erb_case_match_node->prism_node.node, &pm_buffer);
1209
+ herb_prism_node_serialize(erb_case_match_node->prism_node, &pm_buffer);
1210
1210
 
1211
1211
  if (pm_buffer.length > 0) {
1212
1212
  erb_case_match_node_prism_node = rb_str_new(pm_buffer.value, pm_buffer.length);
@@ -1260,7 +1260,7 @@ static VALUE rb_erb_while_node_from_c_struct(AST_ERB_WHILE_NODE_T* erb_while_nod
1260
1260
  VALUE erb_while_node_prism_node;
1261
1261
  if (erb_while_node->prism_node.node != NULL && erb_while_node->prism_node.parser != NULL) {
1262
1262
  pm_buffer_t pm_buffer = { 0 };
1263
- pm_serialize(erb_while_node->prism_node.parser, erb_while_node->prism_node.node, &pm_buffer);
1263
+ herb_prism_node_serialize(erb_while_node->prism_node, &pm_buffer);
1264
1264
 
1265
1265
  if (pm_buffer.length > 0) {
1266
1266
  erb_while_node_prism_node = rb_str_new(pm_buffer.value, pm_buffer.length);
@@ -1311,7 +1311,7 @@ static VALUE rb_erb_until_node_from_c_struct(AST_ERB_UNTIL_NODE_T* erb_until_nod
1311
1311
  VALUE erb_until_node_prism_node;
1312
1312
  if (erb_until_node->prism_node.node != NULL && erb_until_node->prism_node.parser != NULL) {
1313
1313
  pm_buffer_t pm_buffer = { 0 };
1314
- pm_serialize(erb_until_node->prism_node.parser, erb_until_node->prism_node.node, &pm_buffer);
1314
+ herb_prism_node_serialize(erb_until_node->prism_node, &pm_buffer);
1315
1315
 
1316
1316
  if (pm_buffer.length > 0) {
1317
1317
  erb_until_node_prism_node = rb_str_new(pm_buffer.value, pm_buffer.length);
@@ -1362,7 +1362,7 @@ static VALUE rb_erb_for_node_from_c_struct(AST_ERB_FOR_NODE_T* erb_for_node, con
1362
1362
  VALUE erb_for_node_prism_node;
1363
1363
  if (erb_for_node->prism_node.node != NULL && erb_for_node->prism_node.parser != NULL) {
1364
1364
  pm_buffer_t pm_buffer = { 0 };
1365
- pm_serialize(erb_for_node->prism_node.parser, erb_for_node->prism_node.node, &pm_buffer);
1365
+ herb_prism_node_serialize(erb_for_node->prism_node, &pm_buffer);
1366
1366
 
1367
1367
  if (pm_buffer.length > 0) {
1368
1368
  erb_for_node_prism_node = rb_str_new(pm_buffer.value, pm_buffer.length);
@@ -1479,7 +1479,7 @@ static VALUE rb_erb_begin_node_from_c_struct(AST_ERB_BEGIN_NODE_T* erb_begin_nod
1479
1479
  VALUE erb_begin_node_prism_node;
1480
1480
  if (erb_begin_node->prism_node.node != NULL && erb_begin_node->prism_node.parser != NULL) {
1481
1481
  pm_buffer_t pm_buffer = { 0 };
1482
- pm_serialize(erb_begin_node->prism_node.parser, erb_begin_node->prism_node.node, &pm_buffer);
1482
+ herb_prism_node_serialize(erb_begin_node->prism_node, &pm_buffer);
1483
1483
 
1484
1484
  if (pm_buffer.length > 0) {
1485
1485
  erb_begin_node_prism_node = rb_str_new(pm_buffer.value, pm_buffer.length);
@@ -1537,7 +1537,7 @@ static VALUE rb_erb_unless_node_from_c_struct(AST_ERB_UNLESS_NODE_T* erb_unless_
1537
1537
  VALUE erb_unless_node_prism_node;
1538
1538
  if (erb_unless_node->prism_node.node != NULL && erb_unless_node->prism_node.parser != NULL) {
1539
1539
  pm_buffer_t pm_buffer = { 0 };
1540
- pm_serialize(erb_unless_node->prism_node.parser, erb_unless_node->prism_node.node, &pm_buffer);
1540
+ herb_prism_node_serialize(erb_unless_node->prism_node, &pm_buffer);
1541
1541
 
1542
1542
  if (pm_buffer.length > 0) {
1543
1543
  erb_unless_node_prism_node = rb_str_new(pm_buffer.value, pm_buffer.length);
@@ -1685,7 +1685,7 @@ static VALUE rb_erb_render_node_from_c_struct(AST_ERB_RENDER_NODE_T* erb_render_
1685
1685
  VALUE erb_render_node_prism_node;
1686
1686
  if (erb_render_node->prism_node.node != NULL && erb_render_node->prism_node.parser != NULL) {
1687
1687
  pm_buffer_t pm_buffer = { 0 };
1688
- pm_serialize(erb_render_node->prism_node.parser, erb_render_node->prism_node.node, &pm_buffer);
1688
+ herb_prism_node_serialize(erb_render_node->prism_node, &pm_buffer);
1689
1689
 
1690
1690
  if (pm_buffer.length > 0) {
1691
1691
  erb_render_node_prism_node = rb_str_new(pm_buffer.value, pm_buffer.length);
@@ -1781,7 +1781,7 @@ static VALUE rb_erb_strict_locals_node_from_c_struct(AST_ERB_STRICT_LOCALS_NODE_
1781
1781
  VALUE erb_strict_locals_node_prism_node;
1782
1782
  if (erb_strict_locals_node->prism_node.node != NULL && erb_strict_locals_node->prism_node.parser != NULL) {
1783
1783
  pm_buffer_t pm_buffer = { 0 };
1784
- pm_serialize(erb_strict_locals_node->prism_node.parser, erb_strict_locals_node->prism_node.node, &pm_buffer);
1784
+ herb_prism_node_serialize(erb_strict_locals_node->prism_node, &pm_buffer);
1785
1785
 
1786
1786
  if (pm_buffer.length > 0) {
1787
1787
  erb_strict_locals_node_prism_node = rb_str_new(pm_buffer.value, pm_buffer.length);
@@ -1828,17 +1828,34 @@ static VALUE rb_erb_yield_node_from_c_struct(AST_ERB_YIELD_NODE_T* erb_yield_nod
1828
1828
  VALUE erb_yield_node_tag_opening = rb_token_from_c_struct(erb_yield_node->tag_opening, options);
1829
1829
  VALUE erb_yield_node_content = rb_token_from_c_struct(erb_yield_node->content, options);
1830
1830
  VALUE erb_yield_node_tag_closing = rb_token_from_c_struct(erb_yield_node->tag_closing, options);
1831
+ VALUE erb_yield_node_prism_node;
1832
+ if (erb_yield_node->prism_node.node != NULL && erb_yield_node->prism_node.parser != NULL) {
1833
+ pm_buffer_t pm_buffer = { 0 };
1834
+ herb_prism_node_serialize(erb_yield_node->prism_node, &pm_buffer);
1831
1835
 
1832
- VALUE args[6] = {
1836
+ if (pm_buffer.length > 0) {
1837
+ erb_yield_node_prism_node = rb_str_new(pm_buffer.value, pm_buffer.length);
1838
+ rb_enc_associate(erb_yield_node_prism_node, rb_ascii8bit_encoding());
1839
+ OBJ_FREEZE(erb_yield_node_prism_node);
1840
+ } else {
1841
+ erb_yield_node_prism_node = Qnil;
1842
+ }
1843
+ pm_buffer_free(&pm_buffer);
1844
+ } else {
1845
+ erb_yield_node_prism_node = Qnil;
1846
+ }
1847
+
1848
+ VALUE args[7] = {
1833
1849
  type,
1834
1850
  location,
1835
1851
  errors,
1836
1852
  erb_yield_node_tag_opening,
1837
1853
  erb_yield_node_content,
1838
- erb_yield_node_tag_closing
1854
+ erb_yield_node_tag_closing,
1855
+ erb_yield_node_prism_node
1839
1856
  };
1840
1857
 
1841
- return rb_class_new_instance(6, args, cERBYieldNode);
1858
+ return rb_class_new_instance(7, args, cERBYieldNode);
1842
1859
  };
1843
1860
 
1844
1861
  static VALUE rb_erb_in_node_from_c_struct(AST_ERB_IN_NODE_T* erb_in_node, const parser_options_T* options) {
data/lib/herb/3.2/herb.so CHANGED
Binary file
data/lib/herb/3.3/herb.so CHANGED
Binary file
data/lib/herb/3.4/herb.so CHANGED
Binary file
data/lib/herb/4.0/herb.so CHANGED
Binary file
@@ -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
- output += white("└── tag_closing: ")
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)
@@ -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| File.directory?(File.join(path, "src")) }
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| File.directory?(File.join(path, "src")) }
83
+ .find { |path| prism_source?(path) }
80
84
  end
81
85
  end
82
86
  end
@@ -146,7 +146,12 @@ module Herb
146
146
 
147
147
  #: () -> bool
148
148
  def interactive?
149
- $stdout.tty?
149
+ $stdout.tty? && !process_manager?
150
+ end
151
+
152
+ #: () -> bool
153
+ def process_manager?
154
+ ENV.key?("PS")
150
155
  end
151
156
 
152
157
  #: (String) -> void
@@ -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
- visit_erb_control_with_parts(node, *case_parts(node))
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
- visit_erb_control_with_parts(node, *case_parts(node))
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 case_parts(node)
396
+ def visit_erb_case_parts(node)
393
397
  parts = [:conditions, :else_clause, :end_node]
394
398
 
395
- erb_escaped?(node.tag_opening.value) ? [:children, *parts] : parts
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) && (preceding_text_ends_with_newline? || @last_trim_consumed_newline)
824
+ whitespace_only?(text) && (preceding_token_value_ends_with_newline? || @last_trim_consumed_newline)
817
825
  end
818
826
 
819
- def preceding_text_ends_with_newline?
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
- preceding[0] == :text && preceding[1].end_with?("\n")
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?
860
+
861
+ drop_pending_trim_newline! if follows_trimmed_statement_tag?(node)
849
862
 
850
- if at_line_start?
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,8 +871,7 @@ module Herb
858
871
  " \n"
859
872
  end
860
873
 
861
- @pending_leading_whitespace_insert_index = @tokens.length
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
 
@@ -913,6 +925,30 @@ module Herb
913
925
  @trim_next_whitespace = false if owned
914
926
  end
915
927
 
928
+ #: (Array[untyped]) -> void
929
+ def skip_case_children(children)
930
+ text = children.grep(Herb::AST::HTMLTextNode).map(&:content).join
931
+
932
+ settle_pending_trim_newline!(true) if text.match?(/\A[ \t]*\r?\n/)
933
+ end
934
+
935
+ #: (untyped) -> bool
936
+ def follows_trimmed_statement_tag?(node)
937
+ return false if without_source?(node)
938
+
939
+ !@pending_trim_newline_index.nil? && @pending_trim_newline_index == @tokens.length - 1
940
+ end
941
+
942
+ #: () -> void
943
+ def drop_pending_trim_newline!
944
+ index = @pending_trim_newline_index
945
+ return unless index
946
+
947
+ @tokens[index][1] = @tokens[index][1].chomp
948
+ @pending_trim_newline_index = nil
949
+ @pending_trim_owns_next_whitespace = false
950
+ end
951
+
916
952
  def save_pending_leading_whitespace!(whitespace)
917
953
  @pending_leading_whitespace = whitespace
918
954
  @pending_leading_whitespace_insert_index = @tokens.length
@@ -189,6 +189,16 @@ module Herb
189
189
  @current_node = previous
190
190
  end
191
191
 
192
+ #: (untyped) -> void
193
+ def visit_ruby_literal_node(node)
194
+ previous = @current_node
195
+ @current_node = node
196
+
197
+ super
198
+ ensure
199
+ @current_node = previous
200
+ end
201
+
192
202
  #: (untyped) -> void
193
203
  def visit_erb_yield_node(node)
194
204
  previous = @current_node
@@ -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
- spacing = open_tag.is_a?(Herb::AST::ERBOpenTagNode) ? " " : ""
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