herb 0.9.5-arm-linux-gnu → 0.9.6-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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/ext/herb/extension.c +8 -0
  3. data/ext/herb/extension_helpers.c +1 -0
  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/action_view/helper_registry.rb +8107 -0
  11. data/lib/herb/parser_options.rb +7 -2
  12. data/lib/herb/project.rb +2 -5
  13. data/lib/herb/version.rb +1 -1
  14. data/sig/herb/action_view/helper_registry.rbs +1144 -0
  15. data/sig/herb/parser_options.rbs +6 -2
  16. data/src/analyze/action_view/generated_handlers.c +355 -0
  17. data/src/analyze/action_view/generated_handlers.h +16 -0
  18. data/src/analyze/action_view/helper_registry.c +7244 -0
  19. data/src/analyze/action_view/image_tag.c +4 -31
  20. data/src/analyze/action_view/javascript_include_tag.c +1 -42
  21. data/src/analyze/action_view/javascript_tag.c +0 -52
  22. data/src/analyze/action_view/registry.c +2 -2
  23. data/src/analyze/action_view/tag_helpers.c +8 -120
  24. data/src/analyze/action_view/turbo_frame_tag.c +1 -36
  25. data/src/analyze/analyze.c +7 -0
  26. data/src/analyze/postfix_conditionals.c +326 -0
  27. data/src/analyze/ternary_conditionals.c +265 -0
  28. data/src/include/analyze/action_view/helper_registry.h +325 -0
  29. data/src/include/analyze/action_view/tag_helpers.h +0 -1
  30. data/src/include/analyze/postfix_conditionals.h +9 -0
  31. data/src/include/analyze/ternary_conditionals.h +15 -0
  32. data/src/include/parser/parser.h +1 -0
  33. data/src/include/version.h +1 -1
  34. data/src/parser.c +1 -0
  35. data/templates/java/org/herb/ast/HelperRegistry.java.erb +258 -0
  36. data/templates/javascript/packages/core/src/action-view-helpers.ts.erb +171 -0
  37. data/templates/javascript/packages/core/src/nodes.ts.erb +5 -1
  38. data/templates/lib/herb/action_view/helper_registry.rb.erb +288 -0
  39. data/templates/rust/src/action_view_helpers.rs.erb +154 -0
  40. data/templates/src/analyze/action_view/generated_handlers.c.erb +230 -0
  41. data/templates/src/analyze/action_view/generated_handlers.h.erb +12 -0
  42. data/templates/src/analyze/action_view/helper_registry.c.erb +114 -0
  43. data/templates/src/include/analyze/action_view/helper_registry.h.erb +82 -0
  44. data/templates/template.rb +338 -1
  45. metadata +19 -3
  46. data/src/analyze/action_view/content_tag.c +0 -78
  47. data/src/analyze/action_view/tag.c +0 -87
@@ -449,6 +449,337 @@ module Herb
449
449
  end
450
450
  end
451
451
 
452
+ def self.escape_string(string)
453
+ string.to_s.gsub(/["\\]/) do |char|
454
+ case char
455
+ when "\\" then "\\\\"
456
+ when '"' then '\\"'
457
+ else char
458
+ end
459
+ end
460
+ end
461
+
462
+ class HelperArgument
463
+ attr_reader :name, :position, :type, :optional, :default, :splat, :description
464
+
465
+ def initialize(config)
466
+ @name = config.fetch("name")
467
+ @position = config.fetch("position")
468
+ @type = Array(config.fetch("type"))
469
+ @optional = config.fetch("optional", false)
470
+ @default = config.fetch("default", nil)
471
+ @splat = config.fetch("splat", false)
472
+ @description = config.fetch("description", "")
473
+ end
474
+
475
+ def type_display
476
+ @type.join(" | ")
477
+ end
478
+
479
+ def escaped_description
480
+ Template.escape_string(@description)
481
+ end
482
+
483
+ def escaped_default
484
+ @default ? Template.escape_string(@default) : nil
485
+ end
486
+ end
487
+
488
+ class HelperOption
489
+ attr_reader :name, :type, :maps_to, :description
490
+
491
+ def initialize(config)
492
+ @name = config.fetch("name")
493
+ @type = Array(config.fetch("type"))
494
+ @maps_to = config.fetch("maps_to", nil)
495
+ @description = config.fetch("description", "")
496
+ end
497
+
498
+ def type_display
499
+ @type.join(" | ")
500
+ end
501
+
502
+ def escaped_description
503
+ Template.escape_string(@description)
504
+ end
505
+ end
506
+
507
+ class HelperImplicitAttribute
508
+ attr_reader :name, :source, :source_with_block, :wrapper, :skip_wrapping_for,
509
+ :wrapper_quotes_arg
510
+
511
+ def initialize(config)
512
+ @name = config.fetch("name")
513
+ @source = config.fetch("source")
514
+ @source_with_block = config.fetch("source_with_block", nil)
515
+ @wrapper = config.fetch("wrapper")
516
+ @wrapper_quotes_arg = config.fetch("wrapper_quotes_arg", false)
517
+ @skip_wrapping_for = config.fetch("skip_wrapping_for", [])
518
+ end
519
+ end
520
+
521
+ class HelperContent
522
+ attr_reader :source, :arg_position, :skip_if_hash, :to_s_suffix_when_single
523
+
524
+ def initialize(config)
525
+ @source = config.fetch("source")
526
+ @arg_position = config.fetch("arg_position", nil)
527
+ @skip_if_hash = config.fetch("skip_if_hash", false)
528
+ @to_s_suffix_when_single = config.fetch("to_s_suffix_when_single", false)
529
+ end
530
+
531
+ def null?
532
+ false
533
+ end
534
+
535
+ def first_arg?
536
+ @source == "first_arg"
537
+ end
538
+
539
+ def block_or_arg?
540
+ @source == "block_or_arg"
541
+ end
542
+ end
543
+
544
+ class HelperSpecialBehavior
545
+ attr_reader :type, :config
546
+
547
+ def initialize(config)
548
+ if config.is_a?(String)
549
+ @type = config
550
+ @config = {}
551
+ else
552
+ @type = config.fetch("type")
553
+ @config = config
554
+ end
555
+ end
556
+
557
+ def implied_attribute?
558
+ @type == "implied_attribute"
559
+ end
560
+
561
+ def wrap_body?
562
+ @type == "wrap_body"
563
+ end
564
+
565
+ def multiple_elements?
566
+ @type == "multiple_elements"
567
+ end
568
+
569
+ def size_to_dimensions?
570
+ @type == "size_to_dimensions"
571
+ end
572
+
573
+ def remove_non_html_options?
574
+ @type == "remove_non_html_options"
575
+ end
576
+
577
+ def [](key)
578
+ @config[key.to_s]
579
+ end
580
+
581
+ def to_s
582
+ @type
583
+ end
584
+ end
585
+
586
+ class HelperTagInfo
587
+ attr_reader :name, :is_void, :preferred, :detect_style, :implicit_attribute
588
+
589
+ def initialize(config)
590
+ @name = config.fetch("name")
591
+ @is_void = config.fetch("is_void", false)
592
+ @preferred = config.fetch("preferred", false)
593
+ @detect_style = config.fetch("detect_style", nil)
594
+
595
+ implicit_config = config.fetch("implicit_attribute", nil)
596
+ @implicit_attribute = implicit_config ? HelperImplicitAttribute.new(implicit_config) : nil
597
+ end
598
+
599
+ def preferred?
600
+ @preferred
601
+ end
602
+
603
+ def implicit_attribute?
604
+ !@implicit_attribute.nil?
605
+ end
606
+
607
+ def call_name_detect?
608
+ @detect_style == "call_name"
609
+ end
610
+
611
+ def receiver_call_detect?
612
+ @detect_style == "receiver_call"
613
+ end
614
+ end
615
+
616
+ class HelperType
617
+ attr_reader :name, :source, :gem, :output, :visibility, :supports_block,
618
+ :supported, :description, :signature, :documentation_url, :tag,
619
+ :content, :attributes_arg, :attributes_arg_with_block,
620
+ :transform_style, :custom_transform,
621
+ :arguments, :options, :special_behaviors, :aliases
622
+
623
+ def initialize(config)
624
+ @name = config.fetch("name")
625
+ @source = config.fetch("source")
626
+ @gem = config.fetch("gem")
627
+ @output = config.fetch("output", "html")
628
+ @visibility = config.fetch("visibility", "public")
629
+ @supports_block = config.fetch("supports_block", false)
630
+ @supported = config.fetch("supported", false)
631
+ @description = config.fetch("description", "").strip
632
+ @signature = config.fetch("signature")
633
+ @documentation_url = config.fetch("documentation_url")
634
+
635
+ tag_config = config.fetch("tag", nil)
636
+ @tag = tag_config ? HelperTagInfo.new(tag_config) : nil
637
+
638
+ content_config = config.fetch("content", nil)
639
+ @content = content_config ? HelperContent.new(content_config) : nil
640
+
641
+ @attributes_arg = config.fetch("attributes_arg", nil)
642
+ @attributes_arg_with_block = config.fetch("attributes_arg_with_block", nil)
643
+ @transform_style = config.fetch("transform_style", "generic")
644
+ @custom_transform = config.fetch("custom_transform", nil)
645
+
646
+ @arguments = (config.fetch("arguments", []) || []).map { |arg| HelperArgument.new(arg) }
647
+ @options = (config.fetch("options", []) || []).map { |opt| HelperOption.new(opt) }
648
+
649
+ raw_behaviors = config.fetch("special_behaviors", []) || []
650
+ @special_behaviors = raw_behaviors.map { |b| HelperSpecialBehavior.new(b) }
651
+ @aliases = config.fetch("aliases", []) || []
652
+ end
653
+
654
+ def tag_name
655
+ @tag&.name
656
+ end
657
+
658
+ def void?
659
+ @tag&.is_void || false
660
+ end
661
+
662
+ def preferred_for_tag
663
+ @tag&.preferred || false
664
+ end
665
+
666
+ def detect_style
667
+ @tag&.detect_style
668
+ end
669
+
670
+ def implicit_attribute
671
+ @tag&.implicit_attribute
672
+ end
673
+
674
+ # "ActionView::Helpers::UrlHelper#link_to" => "UrlHelper"
675
+ def module_name
676
+ source.split("#").first.split("::").last
677
+ end
678
+
679
+ # "ActionView::Helpers::UrlHelper#link_to" => "url_helper"
680
+ def module_key
681
+ module_name.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
682
+ end
683
+
684
+ # "link_to" => "link_to", "current_page?" => "current_page_p", "uncacheable!" => "uncacheable_bang"
685
+ def safe_name
686
+ name.gsub("?", "_p").gsub("!", "_bang")
687
+ end
688
+
689
+ # "link_to" => "LINK_TO", "current_page?" => "CURRENT_PAGE_P", "content_for?" => "CONTENT_FOR_P"
690
+ def constant_name
691
+ safe_name.upcase
692
+ end
693
+
694
+ # "link_to" => "LinkTo", "current_page?" => "CurrentPage"
695
+ def camel_case_name
696
+ safe_name.split("_").map(&:capitalize).join
697
+ end
698
+
699
+ # "link_to" => "linkTo", "current_page?" => "currentPage"
700
+ def lower_camel_case_name
701
+ parts = safe_name.split("_")
702
+
703
+ parts.first + parts[1..].map(&:capitalize).join
704
+ end
705
+
706
+ def escaped_description
707
+ Template.escape_string(@description)
708
+ end
709
+
710
+ def escaped_signature
711
+ Template.escape_string(@signature)
712
+ end
713
+
714
+ def public?
715
+ @visibility == "public"
716
+ end
717
+
718
+ def internal?
719
+ @visibility == "internal"
720
+ end
721
+
722
+ def tag?
723
+ !@tag.nil?
724
+ end
725
+
726
+ def preferred_for_tag?
727
+ @tag&.preferred || false
728
+ end
729
+
730
+ def supported?
731
+ @supported
732
+ end
733
+
734
+ def static_tag_name?
735
+ !tag_name.nil?
736
+ end
737
+
738
+ def implicit_attribute?
739
+ !implicit_attribute.nil?
740
+ end
741
+
742
+ def call_name_detect?
743
+ @tag&.call_name_detect? || false
744
+ end
745
+
746
+ def receiver_call_detect?
747
+ @tag&.receiver_call_detect? || false
748
+ end
749
+
750
+ def html_output?
751
+ @output == "html"
752
+ end
753
+
754
+ def text_output?
755
+ @output == "text"
756
+ end
757
+
758
+ def url_output?
759
+ @output == "url"
760
+ end
761
+
762
+ def boolean_output?
763
+ @output == "boolean"
764
+ end
765
+
766
+ def void_output?
767
+ @output == "void"
768
+ end
769
+
770
+ def content?
771
+ !@content.nil?
772
+ end
773
+
774
+ def generic_transform?
775
+ @transform_style == "generic"
776
+ end
777
+
778
+ def custom_transform?
779
+ @transform_style == "custom"
780
+ end
781
+ end
782
+
452
783
  class PrintfMessageTemplate
453
784
  MAX_STRING_SIZE = 128
454
785
 
@@ -541,7 +872,7 @@ module Herb
541
872
  )
542
873
  end
543
874
 
544
- rendered_template = read_template(template_path.to_s).result_with_hash({ nodes: nodes, errors: errors, union_kinds: union_kinds })
875
+ rendered_template = read_template(template_path.to_s).result_with_hash({ nodes: nodes, errors: errors, union_kinds: union_kinds, helpers: helpers })
545
876
  content = heading_for(name, template_file) + rendered_template
546
877
 
547
878
  check_gitignore(name)
@@ -604,6 +935,12 @@ module Herb
604
935
  (config.dig("errors", "types") || []).map { |node| ErrorType.new(node) }
605
936
  end
606
937
 
938
+ def self.helpers
939
+ Dir.glob("config/action_view_helpers/**/*.yml").map do |file|
940
+ HelperType.new(YAML.load_file(file))
941
+ end
942
+ end
943
+
607
944
  def self.config
608
945
  YAML.load_file("config.yml")
609
946
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: herb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.5
4
+ version: 0.9.6
5
5
  platform: arm-linux-gnu
6
6
  authors:
7
7
  - Marco Roth
@@ -40,6 +40,7 @@ files:
40
40
  - lib/herb/3.3/herb.so
41
41
  - lib/herb/3.4/herb.so
42
42
  - lib/herb/4.0/herb.so
43
+ - lib/herb/action_view/helper_registry.rb
43
44
  - lib/herb/ast.rb
44
45
  - lib/herb/ast/erb_content_node.rb
45
46
  - lib/herb/ast/helpers.rb
@@ -77,6 +78,7 @@ files:
77
78
  - lib/herb/visitor.rb
78
79
  - lib/herb/warnings.rb
79
80
  - sig/herb.rbs
81
+ - sig/herb/action_view/helper_registry.rbs
80
82
  - sig/herb/ast.rbs
81
83
  - sig/herb/ast/erb_content_node.rbs
82
84
  - sig/herb/ast/helpers.rbs
@@ -117,13 +119,14 @@ files:
117
119
  - sig/serialized_ast_errors.rbs
118
120
  - sig/serialized_ast_nodes.rbs
119
121
  - src/analyze/action_view/attribute_extraction_helpers.c
120
- - src/analyze/action_view/content_tag.c
122
+ - src/analyze/action_view/generated_handlers.c
123
+ - src/analyze/action_view/generated_handlers.h
124
+ - src/analyze/action_view/helper_registry.c
121
125
  - src/analyze/action_view/image_tag.c
122
126
  - src/analyze/action_view/javascript_include_tag.c
123
127
  - src/analyze/action_view/javascript_tag.c
124
128
  - src/analyze/action_view/link_to.c
125
129
  - src/analyze/action_view/registry.c
126
- - src/analyze/action_view/tag.c
127
130
  - src/analyze/action_view/tag_helper_node_builders.c
128
131
  - src/analyze/action_view/tag_helpers.c
129
132
  - src/analyze/action_view/turbo_frame_tag.c
@@ -137,9 +140,11 @@ files:
137
140
  - src/analyze/invalid_structures.c
138
141
  - src/analyze/missing_end.c
139
142
  - src/analyze/parse_errors.c
143
+ - src/analyze/postfix_conditionals.c
140
144
  - src/analyze/prism_annotate.c
141
145
  - src/analyze/render_nodes.c
142
146
  - src/analyze/strict_locals.c
147
+ - src/analyze/ternary_conditionals.c
143
148
  - src/analyze/transform.c
144
149
  - src/ast/ast_node.c
145
150
  - src/ast/ast_nodes.c
@@ -149,6 +154,7 @@ files:
149
154
  - src/extract.c
150
155
  - src/herb.c
151
156
  - src/include/analyze/action_view/attribute_extraction_helpers.h
157
+ - src/include/analyze/action_view/helper_registry.h
152
158
  - src/include/analyze/action_view/tag_helper_handler.h
153
159
  - src/include/analyze/action_view/tag_helper_node_builders.h
154
160
  - src/include/analyze/action_view/tag_helpers.h
@@ -160,9 +166,11 @@ files:
160
166
  - src/include/analyze/control_type.h
161
167
  - src/include/analyze/helpers.h
162
168
  - src/include/analyze/invalid_structures.h
169
+ - src/include/analyze/postfix_conditionals.h
163
170
  - src/include/analyze/prism_annotate.h
164
171
  - src/include/analyze/render_nodes.h
165
172
  - src/include/analyze/strict_locals.h
173
+ - src/include/analyze/ternary_conditionals.h
166
174
  - src/include/ast/ast_node.h
167
175
  - src/include/ast/ast_nodes.h
168
176
  - src/include/ast/ast_pretty_print.h
@@ -241,9 +249,11 @@ files:
241
249
  - templates/java/nodes.c.erb
242
250
  - templates/java/nodes.h.erb
243
251
  - templates/java/org/herb/ast/Errors.java.erb
252
+ - templates/java/org/herb/ast/HelperRegistry.java.erb
244
253
  - templates/java/org/herb/ast/NodeVisitor.java.erb
245
254
  - templates/java/org/herb/ast/Nodes.java.erb
246
255
  - templates/java/org/herb/ast/Visitor.java.erb
256
+ - templates/javascript/packages/core/src/action-view-helpers.ts.erb
247
257
  - templates/javascript/packages/core/src/errors.ts.erb
248
258
  - templates/javascript/packages/core/src/node-type-guards.ts.erb
249
259
  - templates/javascript/packages/core/src/nodes.ts.erb
@@ -252,9 +262,11 @@ files:
252
262
  - templates/javascript/packages/node/extension/error_helpers.h.erb
253
263
  - templates/javascript/packages/node/extension/nodes.cpp.erb
254
264
  - templates/javascript/packages/node/extension/nodes.h.erb
265
+ - templates/lib/herb/action_view/helper_registry.rb.erb
255
266
  - templates/lib/herb/ast/nodes.rb.erb
256
267
  - templates/lib/herb/errors.rb.erb
257
268
  - templates/lib/herb/visitor.rb.erb
269
+ - templates/rust/src/action_view_helpers.rs.erb
258
270
  - templates/rust/src/ast/nodes.rs.erb
259
271
  - templates/rust/src/errors.rs.erb
260
272
  - templates/rust/src/nodes.rs.erb
@@ -262,11 +274,15 @@ files:
262
274
  - templates/rust/src/visitor.rs.erb
263
275
  - templates/sig/serialized_ast_errors.rbs.erb
264
276
  - templates/sig/serialized_ast_nodes.rbs.erb
277
+ - templates/src/analyze/action_view/generated_handlers.c.erb
278
+ - templates/src/analyze/action_view/generated_handlers.h.erb
279
+ - templates/src/analyze/action_view/helper_registry.c.erb
265
280
  - templates/src/analyze/missing_end.c.erb
266
281
  - templates/src/analyze/transform.c.erb
267
282
  - templates/src/ast/ast_nodes.c.erb
268
283
  - templates/src/ast/ast_pretty_print.c.erb
269
284
  - templates/src/errors.c.erb
285
+ - templates/src/include/analyze/action_view/helper_registry.h.erb
270
286
  - templates/src/include/ast/ast_nodes.h.erb
271
287
  - templates/src/include/ast/ast_pretty_print.h.erb
272
288
  - templates/src/include/errors.h.erb
@@ -1,78 +0,0 @@
1
- #include "../../include/analyze/action_view/tag_helper_handler.h"
2
-
3
- #include <prism.h>
4
- #include <stdbool.h>
5
- #include <stdlib.h>
6
- #include <string.h>
7
-
8
- bool detect_content_tag(pm_call_node_t* call_node, pm_parser_t* parser) {
9
- if (!call_node || !call_node->name) { return false; }
10
-
11
- pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, call_node->name);
12
- return constant && constant->length == 11 && strncmp((const char*) constant->start, "content_tag", 11) == 0;
13
- }
14
-
15
- char* extract_content_tag_name(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
16
- (void) parser;
17
-
18
- if (!call_node || !call_node->arguments) { return NULL; }
19
-
20
- pm_arguments_node_t* arguments = call_node->arguments;
21
- if (!arguments->arguments.size) { return NULL; }
22
-
23
- pm_node_t* first_argument = arguments->arguments.nodes[0];
24
-
25
- if (first_argument->type == PM_STRING_NODE) {
26
- pm_string_node_t* string_node = (pm_string_node_t*) first_argument;
27
- size_t length = pm_string_length(&string_node->unescaped);
28
- return hb_allocator_strndup(allocator, (const char*) pm_string_source(&string_node->unescaped), length);
29
- } else if (first_argument->type == PM_SYMBOL_NODE) {
30
- pm_symbol_node_t* symbol_node = (pm_symbol_node_t*) first_argument;
31
- size_t length = pm_string_length(&symbol_node->unescaped);
32
- return hb_allocator_strndup(allocator, (const char*) pm_string_source(&symbol_node->unescaped), length);
33
- }
34
-
35
- return NULL;
36
- }
37
-
38
- char* extract_content_tag_content(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
39
- (void) parser;
40
-
41
- if (!call_node) { return NULL; }
42
-
43
- char* block_content = extract_inline_block_content(call_node, allocator);
44
- if (block_content) { return block_content; }
45
-
46
- if (call_node->arguments) {
47
- pm_arguments_node_t* arguments = call_node->arguments;
48
-
49
- if (arguments->arguments.size >= 2) {
50
- pm_node_t* second_argument = arguments->arguments.nodes[1];
51
-
52
- if (second_argument->type != PM_KEYWORD_HASH_NODE) {
53
- if (second_argument->type == PM_STRING_NODE) {
54
- pm_string_node_t* string_node = (pm_string_node_t*) second_argument;
55
- size_t length = pm_string_length(&string_node->unescaped);
56
- return hb_allocator_strndup(allocator, (const char*) pm_string_source(&string_node->unescaped), length);
57
- }
58
-
59
- size_t source_length = second_argument->location.end - second_argument->location.start;
60
- return hb_allocator_strndup(allocator, (const char*) second_argument->location.start, source_length);
61
- }
62
- }
63
- }
64
-
65
- return NULL;
66
- }
67
-
68
- bool content_tag_supports_block(void) {
69
- return true;
70
- }
71
-
72
- const tag_helper_handler_T content_tag_handler = { .name = "content_tag",
73
- .source =
74
- HB_STRING_LITERAL("ActionView::Helpers::TagHelper#content_tag"),
75
- .detect = detect_content_tag,
76
- .extract_tag_name = extract_content_tag_name,
77
- .extract_content = extract_content_tag_content,
78
- .supports_block = content_tag_supports_block };
@@ -1,87 +0,0 @@
1
- #include "../../include/analyze/action_view/tag_helper_handler.h"
2
- #include "../../include/util/ruby_util.h"
3
-
4
- #include <prism.h>
5
- #include <stdbool.h>
6
- #include <stdlib.h>
7
- #include <string.h>
8
-
9
- bool detect_tag_dot(pm_call_node_t* call_node, pm_parser_t* parser) {
10
- if (!call_node || !call_node->receiver) { return false; }
11
- if (call_node->receiver->type != PM_CALL_NODE) { return false; }
12
-
13
- pm_call_node_t* receiver_node = (pm_call_node_t*) call_node->receiver;
14
- if (!receiver_node->name) { return false; }
15
-
16
- pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, receiver_node->name);
17
-
18
- return constant && constant->length == 3 && strncmp((const char*) constant->start, "tag", 3) == 0;
19
- }
20
-
21
- char* extract_tag_dot_name(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
22
- if (!call_node || !call_node->name) { return NULL; }
23
-
24
- pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, call_node->name);
25
- if (!constant) { return NULL; }
26
-
27
- if (is_ruby_introspection_method(hb_string_from_data((const char*) constant->start, constant->length))) {
28
- return NULL;
29
- }
30
-
31
- char* name = hb_allocator_strndup(allocator, (const char*) constant->start, constant->length);
32
-
33
- for (size_t i = 0; i < constant->length && name[i] != '\0'; i++) {
34
- if (name[i] == '_') { name[i] = '-'; }
35
- }
36
-
37
- return name;
38
- }
39
-
40
- // TODO: this should probably be an array of nodes
41
- char* extract_tag_dot_content(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
42
- if (!call_node) { return NULL; }
43
-
44
- if (call_node->name) {
45
- pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, call_node->name);
46
-
47
- if (constant
48
- && is_ruby_introspection_method(hb_string_from_data((const char*) constant->start, constant->length))) {
49
- return NULL;
50
- }
51
- }
52
-
53
- char* block_content = extract_inline_block_content(call_node, allocator);
54
- if (block_content) { return block_content; }
55
-
56
- if (call_node->arguments) {
57
- pm_arguments_node_t* arguments = call_node->arguments;
58
-
59
- if (arguments->arguments.size) {
60
- pm_node_t* first_argument = arguments->arguments.nodes[0];
61
-
62
- if (first_argument->type == PM_KEYWORD_HASH_NODE) { return NULL; }
63
-
64
- if (first_argument->type == PM_STRING_NODE) {
65
- pm_string_node_t* string_node = (pm_string_node_t*) first_argument;
66
- size_t length = pm_string_length(&string_node->unescaped);
67
- return hb_allocator_strndup(allocator, (const char*) pm_string_source(&string_node->unescaped), length);
68
- }
69
-
70
- size_t source_length = first_argument->location.end - first_argument->location.start;
71
- return hb_allocator_strndup(allocator, (const char*) first_argument->location.start, source_length);
72
- }
73
- }
74
-
75
- return NULL;
76
- }
77
-
78
- bool tag_dot_supports_block(void) {
79
- return true;
80
- }
81
-
82
- const tag_helper_handler_T tag_dot_handler = { .name = "tag",
83
- .source = HB_STRING_LITERAL("ActionView::Helpers::TagHelper#tag"),
84
- .detect = detect_tag_dot,
85
- .extract_tag_name = extract_tag_dot_name,
86
- .extract_content = extract_tag_dot_content,
87
- .supports_block = tag_dot_supports_block };