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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/config.yml +57 -21
  3. data/ext/herb/nodes.c +93 -55
  4. data/lib/herb/3.0/herb.so +0 -0
  5. data/lib/herb/3.1/herb.so +0 -0
  6. data/lib/herb/3.2/herb.so +0 -0
  7. data/lib/herb/3.3/herb.so +0 -0
  8. data/lib/herb/3.4/herb.so +0 -0
  9. data/lib/herb/4.0/herb.so +0 -0
  10. data/lib/herb/ast/nodes.rb +212 -78
  11. data/lib/herb/engine/compiler.rb +52 -26
  12. data/lib/herb/engine.rb +3 -0
  13. data/lib/herb/project.rb +58 -17
  14. data/lib/herb/version.rb +1 -1
  15. data/lib/herb/visitor.rb +8 -2
  16. data/sig/herb/ast/nodes.rbs +85 -34
  17. data/sig/herb/engine/compiler.rbs +16 -0
  18. data/sig/herb/engine.rbs +3 -0
  19. data/sig/herb/visitor.rbs +5 -2
  20. data/sig/serialized_ast_nodes.rbs +20 -9
  21. data/src/analyze/action_view/javascript_tag.c +38 -0
  22. data/src/analyze/action_view/tag_helper_node_builders.c +23 -2
  23. data/src/analyze/action_view/tag_helpers.c +53 -14
  24. data/src/analyze/analyze.c +23 -3
  25. data/src/analyze/analyze_helpers.c +406 -0
  26. data/src/analyze/builders.c +1 -0
  27. data/src/analyze/missing_end.c +16 -0
  28. data/src/analyze/parse_errors.c +43 -1
  29. data/src/analyze/render_nodes.c +231 -35
  30. data/src/analyze/strict_locals.c +22 -324
  31. data/src/analyze/transform.c +23 -2
  32. data/src/ast/ast_nodes.c +114 -57
  33. data/src/ast/ast_pretty_print.c +109 -25
  34. data/src/include/analyze/action_view/tag_helper_handler.h +3 -0
  35. data/src/include/analyze/action_view/tag_helper_node_builders.h +7 -0
  36. data/src/include/analyze/analyze.h +6 -1
  37. data/src/include/analyze/helpers.h +18 -0
  38. data/src/include/ast/ast_nodes.h +27 -13
  39. data/src/include/version.h +1 -1
  40. data/src/parser/match_tags.c +37 -6
  41. data/src/parser.c +8 -0
  42. data/src/visitor.c +50 -7
  43. metadata +1 -1
data/lib/herb/project.rb CHANGED
@@ -71,9 +71,9 @@ module Herb
71
71
  attr_reader :successful, :failed, :timeout, :template_error, :unexpected_error,
72
72
  :strict_parse_error, :analyze_parse_error,
73
73
  :validation_error, :compilation_failed, :strict_compilation_failed,
74
- :invalid_ruby,
74
+ :invalid_ruby, :skipped,
75
75
  :error_outputs, :file_contents, :parse_errors, :compilation_errors,
76
- :file_diagnostics
76
+ :file_diagnostics, :skip_reasons
77
77
 
78
78
  def initialize
79
79
  @successful = []
@@ -87,11 +87,13 @@ module Herb
87
87
  @compilation_failed = []
88
88
  @strict_compilation_failed = []
89
89
  @invalid_ruby = []
90
+ @skipped = []
90
91
  @error_outputs = {}
91
92
  @file_contents = {}
92
93
  @parse_errors = {}
93
94
  @compilation_errors = {}
94
95
  @file_diagnostics = {}
96
+ @skip_reasons = {}
95
97
  end
96
98
 
97
99
  def problem_files
@@ -432,8 +434,7 @@ module Herb
432
434
  nil
433
435
  end
434
436
 
435
- { file_path: file_path, status: :timeout, file_content: file_content,
436
- log: "⏱️ Parsing #{file_path} timed out after 1 second" }
437
+ { file_path: file_path, status: :timeout, file_content: file_content, log: "⏱️ Parsing #{file_path} timed out after 1 second" }
437
438
  rescue StandardError => e
438
439
  file_content ||= begin
439
440
  File.read(file_path)
@@ -441,8 +442,7 @@ module Herb
441
442
  nil
442
443
  end
443
444
 
444
- { file_path: file_path, status: :failed, file_content: file_content,
445
- log: "⚠️ Error processing #{file_path}: #{e.message}" }
445
+ { file_path: file_path, status: :failed, file_content: file_content, log: "⚠️ Error processing #{file_path}: #{e.message}" }
446
446
  ensure
447
447
  [stdout_file, stderr_file].each do |tempfile|
448
448
  next unless tempfile
@@ -488,6 +488,9 @@ module Herb
488
488
  Herb::Engine.new(file_content, filename: file_path, escape: true, validate_ruby: validate_ruby)
489
489
 
490
490
  { status: :successful, log: "✅ Compiled #{file_path} successfully" }
491
+ rescue Herb::Engine::GeneratorTemplateError => e
492
+ { status: :skipped, skip_reason: e.message,
493
+ log: "⊘ Skipping #{file_path}: #{e.message}" }
491
494
  rescue Herb::Engine::InvalidRubyError => e
492
495
  { status: :invalid_ruby, file_content: file_content,
493
496
  compilation_error: { error: e.message, backtrace: e.backtrace&.first(10) || [] },
@@ -545,6 +548,7 @@ module Herb
545
548
  tracker.parse_errors[file_path] = result[:parse_error] if result[:parse_error]
546
549
  tracker.compilation_errors[file_path] = result[:compilation_error] if result[:compilation_error]
547
550
  tracker.file_diagnostics[file_path] = result[:diagnostics] if result[:diagnostics]&.any?
551
+ tracker.skip_reasons[file_path] = result[:skip_reason] if result[:skip_reason]
548
552
  end
549
553
 
550
554
  def print_summary(results, log, duration)
@@ -563,13 +567,18 @@ module Herb
563
567
  puts " #{label("Checked")} #{cyan("#{total} #{pluralize(total, "file")}")}"
564
568
 
565
569
  if total > 1
566
- files_line = if issues.positive?
567
- "#{bold(green("#{passed} clean"))} | #{bold(red("#{issues} with issues"))}"
568
- else
569
- bold(green("#{total} clean"))
570
- end
570
+ files_parts = []
571
571
 
572
- puts " #{label("Files")} #{files_line}"
572
+ if issues.positive?
573
+ files_parts << bold(green("#{passed} clean"))
574
+ files_parts << bold(red("#{issues} with issues"))
575
+ else
576
+ files_parts << bold(green("#{total - results.skipped.count} clean"))
577
+ end
578
+
579
+ files_parts << dimmed("#{results.skipped.count} skipped") if results.skipped.any?
580
+
581
+ puts " #{label("Files")} #{files_parts.join(" | ")}"
573
582
  end
574
583
 
575
584
  parser_parts = []
@@ -581,8 +590,9 @@ module Herb
581
590
  parser_parts << stat(results.analyze_parse_error.count, "analyze", :yellow) if results.analyze_parse_error.any?
582
591
  puts " #{label("Parser")} #{parser_parts.join(" | ")}"
583
592
 
584
- skipped = total - passed - results.validation_error.count - results.compilation_failed.count -
585
- results.strict_compilation_failed.count - results.invalid_ruby.count
593
+ not_compiled = total - passed - results.skipped.count - results.validation_error.count -
594
+ results.compilation_failed.count - results.strict_compilation_failed.count -
595
+ results.invalid_ruby.count
586
596
 
587
597
  engine_parts = []
588
598
  engine_parts << stat(passed, "compiled", :green)
@@ -590,13 +600,17 @@ module Herb
590
600
  engine_parts << stat(results.compilation_failed.count, "compilation", :red) if results.compilation_failed.any?
591
601
  engine_parts << stat(results.strict_compilation_failed.count, "strict", :yellow) if results.strict_compilation_failed.any?
592
602
  engine_parts << stat(results.invalid_ruby.count, "produced invalid Ruby", :red) if results.invalid_ruby.any?
593
- engine_parts << dimmed("#{skipped} skipped") if skipped.positive?
603
+ engine_parts << dimmed("#{not_compiled} not compiled") if not_compiled.positive?
594
604
  puts " #{label("Engine")} #{engine_parts.join(" | ")}"
595
605
 
596
606
  if results.timeout.any?
597
607
  puts " #{label("Timeout")} #{stat(results.timeout.count, "timed out", :yellow)}"
598
608
  end
599
609
 
610
+ if results.skipped.any?
611
+ puts " #{label("Skipped")} #{dimmed("#{results.skipped.count} #{pluralize(results.skipped.count, "file")}")}"
612
+ end
613
+
600
614
  if duration
601
615
  puts " #{label("Duration")} #{cyan(format_duration(duration))}"
602
616
  end
@@ -630,6 +644,7 @@ module Herb
630
644
  log.puts ""
631
645
  log.puts "--- Other ---"
632
646
  log.puts "⏱️ Timed out: #{results.timeout.count} (#{percentage(results.timeout.count, total)}%)"
647
+ log.puts "⊘ Skipped: #{results.skipped.count} (#{percentage(results.skipped.count, total)}%)"
633
648
 
634
649
  return unless duration
635
650
 
@@ -639,10 +654,27 @@ module Herb
639
654
  def print_file_lists(results, log)
640
655
  log_file_lists(results, log)
641
656
 
642
- return unless results.problem_files.any?
643
-
644
657
  printed_section = false
645
658
 
659
+ if results.skipped.any?
660
+ printed_section = true
661
+
662
+ puts "\n"
663
+ puts " #{bold("Skipped files:")}"
664
+ puts " #{dimmed("These files were parsed successfully but skipped for compilation by the engine.")}"
665
+
666
+ results.skipped.each do |file|
667
+ relative = relative_path(file)
668
+ reason = results.skip_reasons[file]
669
+
670
+ puts ""
671
+ puts " #{cyan(relative)}:"
672
+ puts " #{dimmed("⊘")} #{dimmed(reason)}"
673
+ end
674
+ end
675
+
676
+ return unless results.problem_files.any?
677
+
646
678
  ISSUE_TYPES.each do |type|
647
679
  file_list = results.send(type[:key])
648
680
  next unless file_list.any?
@@ -682,6 +714,15 @@ module Herb
682
714
  end
683
715
 
684
716
  def log_file_lists(results, log)
717
+ if results.skipped.any?
718
+ log.puts "\n#{heading("Files: Skipped")}"
719
+
720
+ results.skipped.each do |file|
721
+ reason = results.skip_reasons[file]
722
+ log.puts "#{file} - #{reason}"
723
+ end
724
+ end
725
+
685
726
  ISSUE_TYPES.each do |type|
686
727
  file_list = results.send(type[:key])
687
728
  next unless file_list.any?
data/lib/herb/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # typed: true
3
3
 
4
4
  module Herb
5
- VERSION = "0.9.3"
5
+ VERSION = "0.9.5"
6
6
  end
data/lib/herb/visitor.rb CHANGED
@@ -271,6 +271,12 @@ module Herb
271
271
  visit_child_nodes(node)
272
272
  end
273
273
 
274
+ #: (Herb::AST::RubyRenderKeywordsNode) -> void
275
+ def visit_ruby_render_keywords_node(node)
276
+ visit_node(node)
277
+ visit_child_nodes(node)
278
+ end
279
+
274
280
  #: (Herb::AST::ERBRenderNode) -> void
275
281
  def visit_erb_render_node(node)
276
282
  visit_node(node)
@@ -278,8 +284,8 @@ module Herb
278
284
  visit_child_nodes(node)
279
285
  end
280
286
 
281
- #: (Herb::AST::RubyStrictLocalNode) -> void
282
- def visit_ruby_strict_local_node(node)
287
+ #: (Herb::AST::RubyParameterNode) -> void
288
+ def visit_ruby_parameter_node(node)
283
289
  visit_node(node)
284
290
  visit_child_nodes(node)
285
291
  end
@@ -944,6 +944,7 @@ module Herb
944
944
  # | tag_closing: Herb::Token?,
945
945
  # | prism_node: String?,
946
946
  # | body: Array[Herb::AST::Node],
947
+ # | block_arguments: Array[Herb::AST::RubyParameterNode]?,
947
948
  # | rescue_clause: Herb::AST::ERBRescueNode?,
948
949
  # | else_clause: Herb::AST::ERBElseNode?,
949
950
  # | ensure_clause: Herb::AST::ERBEnsureNode?,
@@ -962,6 +963,8 @@ module Herb
962
963
 
963
964
  attr_reader body: Array[Herb::AST::Node]
964
965
 
966
+ attr_reader block_arguments: Array[Herb::AST::RubyParameterNode]?
967
+
965
968
  attr_reader rescue_clause: Herb::AST::ERBRescueNode?
966
969
 
967
970
  attr_reader else_clause: Herb::AST::ERBElseNode?
@@ -970,8 +973,8 @@ module Herb
970
973
 
971
974
  attr_reader end_node: Herb::AST::ERBEndNode?
972
975
 
973
- # : (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
974
- def initialize: (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
976
+ # : (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
977
+ def initialize: (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
975
978
 
976
979
  # : () -> Prism::node?
977
980
  def deserialized_prism_node: () -> Prism::node?
@@ -1514,12 +1517,7 @@ module Herb
1514
1517
  def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
1515
1518
  end
1516
1519
 
1517
- # : type serialized_erb_render_node = {
1518
- # | tag_opening: Herb::Token?,
1519
- # | content: Herb::Token?,
1520
- # | tag_closing: Herb::Token?,
1521
- # | analyzed_ruby: nil,
1522
- # | prism_node: String?,
1520
+ # : type serialized_ruby_render_keywords_node = {
1523
1521
  # | partial: Herb::Token?,
1524
1522
  # | template_path: Herb::Token?,
1525
1523
  # | layout: Herb::Token?,
@@ -1539,19 +1537,9 @@ module Herb
1539
1537
  # | content_type: Herb::Token?,
1540
1538
  # | locals: Array[Herb::AST::RubyRenderLocalNode]?,
1541
1539
  # | }
1542
- class ERBRenderNode < Node
1540
+ class RubyRenderKeywordsNode < Node
1543
1541
  include Colors
1544
1542
 
1545
- attr_reader tag_opening: Herb::Token?
1546
-
1547
- attr_reader content: Herb::Token?
1548
-
1549
- attr_reader tag_closing: Herb::Token?
1550
-
1551
- attr_reader analyzed_ruby: nil
1552
-
1553
- attr_reader prism_node: String?
1554
-
1555
1543
  attr_reader partial: Herb::Token?
1556
1544
 
1557
1545
  attr_reader template_path: Herb::Token?
@@ -1588,8 +1576,71 @@ module Herb
1588
1576
 
1589
1577
  attr_reader locals: Array[Herb::AST::RubyRenderLocalNode]?
1590
1578
 
1591
- # : (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, nil, String, 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
1592
- def initialize: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, nil, String, 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
1579
+ # : (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
1580
+ def initialize: (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
1581
+
1582
+ # : () -> serialized_ruby_render_keywords_node
1583
+ def to_hash: () -> serialized_ruby_render_keywords_node
1584
+
1585
+ # : (Visitor) -> void
1586
+ def accept: (Visitor) -> void
1587
+
1588
+ # : () -> Array[Herb::AST::Node?]
1589
+ def child_nodes: () -> Array[Herb::AST::Node?]
1590
+
1591
+ # : () -> Array[Herb::AST::Node]
1592
+ def compact_child_nodes: () -> Array[Herb::AST::Node]
1593
+
1594
+ # : () -> String
1595
+ def inspect: () -> String
1596
+
1597
+ # : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
1598
+ def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
1599
+ end
1600
+
1601
+ # : type serialized_erb_render_node = {
1602
+ # | tag_opening: Herb::Token?,
1603
+ # | content: Herb::Token?,
1604
+ # | tag_closing: Herb::Token?,
1605
+ # | analyzed_ruby: nil,
1606
+ # | prism_node: String?,
1607
+ # | keywords: Herb::AST::RubyRenderKeywordsNode?,
1608
+ # | body: Array[Herb::AST::Node],
1609
+ # | block_arguments: Array[Herb::AST::RubyParameterNode]?,
1610
+ # | rescue_clause: Herb::AST::ERBRescueNode?,
1611
+ # | else_clause: Herb::AST::ERBElseNode?,
1612
+ # | ensure_clause: Herb::AST::ERBEnsureNode?,
1613
+ # | end_node: Herb::AST::ERBEndNode?,
1614
+ # | }
1615
+ class ERBRenderNode < Node
1616
+ include Colors
1617
+
1618
+ attr_reader tag_opening: Herb::Token?
1619
+
1620
+ attr_reader content: Herb::Token?
1621
+
1622
+ attr_reader tag_closing: Herb::Token?
1623
+
1624
+ attr_reader analyzed_ruby: nil
1625
+
1626
+ attr_reader prism_node: String?
1627
+
1628
+ attr_reader keywords: Herb::AST::RubyRenderKeywordsNode?
1629
+
1630
+ attr_reader body: Array[Herb::AST::Node]
1631
+
1632
+ attr_reader block_arguments: Array[Herb::AST::RubyParameterNode]?
1633
+
1634
+ attr_reader rescue_clause: Herb::AST::ERBRescueNode?
1635
+
1636
+ attr_reader else_clause: Herb::AST::ERBElseNode?
1637
+
1638
+ attr_reader ensure_clause: Herb::AST::ERBEnsureNode?
1639
+
1640
+ attr_reader end_node: Herb::AST::ERBEndNode?
1641
+
1642
+ # : (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
1643
+ def initialize: (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
1593
1644
 
1594
1645
  # : () -> Prism::node?
1595
1646
  def deserialized_prism_node: () -> Prism::node?
@@ -1613,28 +1664,28 @@ module Herb
1613
1664
  def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
1614
1665
  end
1615
1666
 
1616
- # : type serialized_ruby_strict_local_node = {
1667
+ # : type serialized_ruby_parameter_node = {
1617
1668
  # | name: Herb::Token?,
1618
1669
  # | default_value: Herb::AST::RubyLiteralNode?,
1670
+ # | kind: String?,
1619
1671
  # | required: bool,
1620
- # | double_splat: bool,
1621
1672
  # | }
1622
- class RubyStrictLocalNode < Node
1673
+ class RubyParameterNode < Node
1623
1674
  include Colors
1624
1675
 
1625
1676
  attr_reader name: Herb::Token?
1626
1677
 
1627
1678
  attr_reader default_value: Herb::AST::RubyLiteralNode?
1628
1679
 
1629
- attr_reader required: bool
1680
+ attr_reader kind: String?
1630
1681
 
1631
- attr_reader double_splat: bool
1682
+ attr_reader required: bool
1632
1683
 
1633
- # : (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::AST::RubyLiteralNode, bool, bool) -> void
1634
- def initialize: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::AST::RubyLiteralNode, bool, bool) -> void
1684
+ # : (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::AST::RubyLiteralNode, String, bool) -> void
1685
+ def initialize: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::AST::RubyLiteralNode, String, bool) -> void
1635
1686
 
1636
- # : () -> serialized_ruby_strict_local_node
1637
- def to_hash: () -> serialized_ruby_strict_local_node
1687
+ # : () -> serialized_ruby_parameter_node
1688
+ def to_hash: () -> serialized_ruby_parameter_node
1638
1689
 
1639
1690
  # : (Visitor) -> void
1640
1691
  def accept: (Visitor) -> void
@@ -1658,7 +1709,7 @@ module Herb
1658
1709
  # | tag_closing: Herb::Token?,
1659
1710
  # | analyzed_ruby: nil,
1660
1711
  # | prism_node: String?,
1661
- # | locals: Array[Herb::AST::RubyStrictLocalNode]?,
1712
+ # | locals: Array[Herb::AST::RubyParameterNode]?,
1662
1713
  # | }
1663
1714
  class ERBStrictLocalsNode < Node
1664
1715
  include Colors
@@ -1673,10 +1724,10 @@ module Herb
1673
1724
 
1674
1725
  attr_reader prism_node: String?
1675
1726
 
1676
- attr_reader locals: Array[Herb::AST::RubyStrictLocalNode]?
1727
+ attr_reader locals: Array[Herb::AST::RubyParameterNode]?
1677
1728
 
1678
- # : (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, nil, String, Array[Herb::AST::RubyStrictLocalNode]) -> void
1679
- def initialize: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, nil, String, Array[Herb::AST::RubyStrictLocalNode]) -> void
1729
+ # : (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, nil, String, Array[Herb::AST::RubyParameterNode]) -> void
1730
+ def initialize: (String, Location, Array[Herb::Errors::Error], Herb::Token, Herb::Token, Herb::Token, nil, String, Array[Herb::AST::RubyParameterNode]) -> void
1680
1731
 
1681
1732
  # : () -> Prism::node?
1682
1733
  def deserialized_prism_node: () -> Prism::node?
@@ -5,6 +5,16 @@ module Herb
5
5
  class Compiler < ::Herb::Visitor
6
6
  EXPRESSION_TOKEN_TYPES: untyped
7
7
 
8
+ TRAILING_WHITESPACE: ::Regexp
9
+
10
+ TRAILING_INDENTATION: ::Regexp
11
+
12
+ TRAILING_INDENTATION_CAPTURE: ::Regexp
13
+
14
+ WHITESPACE_ONLY: ::Regexp
15
+
16
+ WHITESPACE_ONLY_CAPTURE: ::Regexp
17
+
8
18
  attr_reader tokens: untyped
9
19
 
10
20
  def initialize: (untyped engine, ?untyped options) -> untyped
@@ -85,6 +95,8 @@ module Herb
85
95
 
86
96
  private
87
97
 
98
+ def check_for_escaped_erb_tag!: (untyped opening) -> untyped
99
+
88
100
  def current_context: () -> untyped
89
101
 
90
102
  def push_context: (untyped context) -> untyped
@@ -134,6 +146,10 @@ module Herb
134
146
 
135
147
  def preceding_token_ends_with_newline?: () -> untyped
136
148
 
149
+ def left_trim?: (untyped node) -> untyped
150
+
151
+ def right_trim?: (untyped node) -> untyped
152
+
137
153
  def last_text_token: () -> untyped
138
154
 
139
155
  def extract_leading_space: () -> untyped
data/sig/herb/engine.rbs CHANGED
@@ -27,6 +27,9 @@ module Herb
27
27
  class CompilationError < StandardError
28
28
  end
29
29
 
30
+ class GeneratorTemplateError < CompilationError
31
+ end
32
+
30
33
  class InvalidRubyError < CompilationError
31
34
  attr_reader compiled_source: untyped
32
35
 
data/sig/herb/visitor.rbs CHANGED
@@ -130,11 +130,14 @@ module Herb
130
130
  # : (Herb::AST::RubyRenderLocalNode) -> void
131
131
  def visit_ruby_render_local_node: (Herb::AST::RubyRenderLocalNode) -> void
132
132
 
133
+ # : (Herb::AST::RubyRenderKeywordsNode) -> void
134
+ def visit_ruby_render_keywords_node: (Herb::AST::RubyRenderKeywordsNode) -> void
135
+
133
136
  # : (Herb::AST::ERBRenderNode) -> void
134
137
  def visit_erb_render_node: (Herb::AST::ERBRenderNode) -> void
135
138
 
136
- # : (Herb::AST::RubyStrictLocalNode) -> void
137
- def visit_ruby_strict_local_node: (Herb::AST::RubyStrictLocalNode) -> void
139
+ # : (Herb::AST::RubyParameterNode) -> void
140
+ def visit_ruby_parameter_node: (Herb::AST::RubyParameterNode) -> void
138
141
 
139
142
  # : (Herb::AST::ERBStrictLocalsNode) -> void
140
143
  def visit_erb_strict_locals_node: (Herb::AST::ERBStrictLocalsNode) -> void
@@ -170,6 +170,7 @@ module Herb
170
170
  tag_closing: Herb::Token,
171
171
  prism_node: String,
172
172
  body: Array[Herb::AST::Node],
173
+ block_arguments: Array[Herb::AST::RubyParameterNode],
173
174
  rescue_clause: Herb::AST::ERBRescueNode,
174
175
  else_clause: Herb::AST::ERBElseNode,
175
176
  ensure_clause: Herb::AST::ERBEnsureNode,
@@ -276,12 +277,7 @@ module Herb
276
277
  value: Herb::AST::RubyLiteralNode,
277
278
  }
278
279
 
279
- type serialized_erb_render_node = serialized_node & {
280
- tag_opening: Herb::Token,
281
- content: Herb::Token,
282
- tag_closing: Herb::Token,
283
- analyzed_ruby: nil,
284
- prism_node: String,
280
+ type serialized_ruby_render_keywords_node = serialized_node & {
285
281
  partial: Herb::Token,
286
282
  template_path: Herb::Token,
287
283
  layout: Herb::Token,
@@ -302,11 +298,26 @@ module Herb
302
298
  locals: Array[Herb::AST::RubyRenderLocalNode],
303
299
  }
304
300
 
305
- type serialized_ruby_strict_local_node = serialized_node & {
301
+ type serialized_erb_render_node = serialized_node & {
302
+ tag_opening: Herb::Token,
303
+ content: Herb::Token,
304
+ tag_closing: Herb::Token,
305
+ analyzed_ruby: nil,
306
+ prism_node: String,
307
+ keywords: Herb::AST::RubyRenderKeywordsNode,
308
+ body: Array[Herb::AST::Node],
309
+ block_arguments: Array[Herb::AST::RubyParameterNode],
310
+ rescue_clause: Herb::AST::ERBRescueNode,
311
+ else_clause: Herb::AST::ERBElseNode,
312
+ ensure_clause: Herb::AST::ERBEnsureNode,
313
+ end_node: Herb::AST::ERBEndNode,
314
+ }
315
+
316
+ type serialized_ruby_parameter_node = serialized_node & {
306
317
  name: Herb::Token,
307
318
  default_value: Herb::AST::RubyLiteralNode,
319
+ kind: String,
308
320
  required: bool,
309
- double_splat: bool,
310
321
  }
311
322
 
312
323
  type serialized_erb_strict_locals_node = serialized_node & {
@@ -315,7 +326,7 @@ module Herb
315
326
  tag_closing: Herb::Token,
316
327
  analyzed_ruby: nil,
317
328
  prism_node: String,
318
- locals: Array[Herb::AST::RubyStrictLocalNode],
329
+ locals: Array[Herb::AST::RubyParameterNode],
319
330
  }
320
331
 
321
332
  type serialized_erb_yield_node = serialized_node & {
@@ -1,4 +1,9 @@
1
1
  #include "../../include/analyze/action_view/tag_helper_handler.h"
2
+ #include "../../include/analyze/action_view/tag_helper_node_builders.h"
3
+ #include "../../include/ast/ast_nodes.h"
4
+ #include "../../include/lib/hb_array.h"
5
+ #include "../../include/lib/hb_string.h"
6
+ #include "../../include/visitor.h"
2
7
 
3
8
  #include <prism.h>
4
9
  #include <stdbool.h>
@@ -45,6 +50,39 @@ bool javascript_tag_supports_block(void) {
45
50
  return true;
46
51
  }
47
52
 
53
+ bool wrap_javascript_tag_body_visitor(const AST_NODE_T* node, void* data) {
54
+ hb_allocator_T* allocator = (hb_allocator_T*) data;
55
+
56
+ if (node == NULL || node->type != AST_HTML_ELEMENT_NODE) { return true; }
57
+
58
+ AST_HTML_ELEMENT_NODE_T* element = (AST_HTML_ELEMENT_NODE_T*) node;
59
+
60
+ if (!hb_string_equals(element->element_source, hb_string("ActionView::Helpers::JavaScriptHelper#javascript_tag"))) {
61
+ return true;
62
+ }
63
+
64
+ if (element->body == NULL || hb_array_size(element->body) == 0) { return false; }
65
+
66
+ for (size_t i = 0; i < hb_array_size(element->body); i++) {
67
+ AST_NODE_T* child = (AST_NODE_T*) hb_array_get(element->body, i);
68
+ if (child && child->type == AST_CDATA_NODE) { return false; }
69
+ }
70
+
71
+ hb_array_T* cdata_children = hb_array_init(hb_array_size(element->body), allocator);
72
+
73
+ for (size_t i = 0; i < hb_array_size(element->body); i++) {
74
+ hb_array_append(cdata_children, hb_array_get(element->body, i));
75
+ }
76
+
77
+ AST_CDATA_NODE_T* cdata_node =
78
+ create_javascript_cdata_node(cdata_children, element->base.location.start, element->base.location.end, allocator);
79
+
80
+ element->body->size = 0;
81
+ hb_array_append(element->body, (AST_NODE_T*) cdata_node);
82
+
83
+ return false;
84
+ }
85
+
48
86
  const tag_helper_handler_T javascript_tag_handler = {
49
87
  .name = "javascript_tag",
50
88
  .source = HB_STRING_LITERAL("ActionView::Helpers::JavaScriptHelper#javascript_tag"),
@@ -124,7 +124,7 @@ AST_HTML_ATTRIBUTE_NODE_T* create_html_attribute_node_precise(
124
124
  open_quote,
125
125
  value_children,
126
126
  close_quote,
127
- positions->quoted,
127
+ true,
128
128
  positions->value_start,
129
129
  positions->value_end,
130
130
  hb_array_init(0, allocator),
@@ -179,7 +179,7 @@ AST_HTML_ATTRIBUTE_NODE_T* create_html_attribute_with_ruby_literal_precise(
179
179
  NULL,
180
180
  value_children,
181
181
  NULL,
182
- false,
182
+ true,
183
183
  positions->content_start,
184
184
  positions->content_end,
185
185
  hb_array_init(0, allocator),
@@ -385,3 +385,24 @@ void append_body_content_node(
385
385
  if (text_node) { hb_array_append(body, (AST_NODE_T*) text_node); }
386
386
  }
387
387
  }
388
+
389
+ AST_CDATA_NODE_T* create_javascript_cdata_node(
390
+ hb_array_T* children,
391
+ position_T start,
392
+ position_T end,
393
+ hb_allocator_T* allocator
394
+ ) {
395
+ token_T* cdata_opening = create_synthetic_token(allocator, "\n//<![CDATA[\n", TOKEN_CDATA_START, start, end);
396
+
397
+ token_T* cdata_closing = create_synthetic_token(allocator, "\n//]]>\n", TOKEN_CDATA_END, start, end);
398
+
399
+ return ast_cdata_node_init(
400
+ cdata_opening,
401
+ children,
402
+ cdata_closing,
403
+ start,
404
+ end,
405
+ hb_array_init(0, allocator),
406
+ allocator
407
+ );
408
+ }