herb 0.9.4-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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/config.yml +57 -21
  3. data/ext/herb/extension.c +8 -0
  4. data/ext/herb/extension_helpers.c +1 -0
  5. data/ext/herb/nodes.c +93 -55
  6. data/lib/herb/3.0/herb.so +0 -0
  7. data/lib/herb/3.1/herb.so +0 -0
  8. data/lib/herb/3.2/herb.so +0 -0
  9. data/lib/herb/3.3/herb.so +0 -0
  10. data/lib/herb/3.4/herb.so +0 -0
  11. data/lib/herb/4.0/herb.so +0 -0
  12. data/lib/herb/action_view/helper_registry.rb +8107 -0
  13. data/lib/herb/ast/nodes.rb +212 -78
  14. data/lib/herb/engine/compiler.rb +4 -6
  15. data/lib/herb/parser_options.rb +7 -2
  16. data/lib/herb/project.rb +2 -5
  17. data/lib/herb/version.rb +1 -1
  18. data/lib/herb/visitor.rb +8 -2
  19. data/sig/herb/action_view/helper_registry.rbs +1144 -0
  20. data/sig/herb/ast/nodes.rbs +85 -34
  21. data/sig/herb/parser_options.rbs +6 -2
  22. data/sig/herb/visitor.rbs +5 -2
  23. data/sig/serialized_ast_nodes.rbs +20 -9
  24. data/src/analyze/action_view/generated_handlers.c +355 -0
  25. data/src/analyze/action_view/generated_handlers.h +16 -0
  26. data/src/analyze/action_view/helper_registry.c +7244 -0
  27. data/src/analyze/action_view/image_tag.c +4 -31
  28. data/src/analyze/action_view/javascript_include_tag.c +1 -42
  29. data/src/analyze/action_view/javascript_tag.c +26 -40
  30. data/src/analyze/action_view/registry.c +2 -2
  31. data/src/analyze/action_view/tag_helper_node_builders.c +23 -2
  32. data/src/analyze/action_view/tag_helpers.c +61 -134
  33. data/src/analyze/action_view/turbo_frame_tag.c +1 -36
  34. data/src/analyze/analyze.c +28 -0
  35. data/src/analyze/analyze_helpers.c +406 -0
  36. data/src/analyze/builders.c +1 -0
  37. data/src/analyze/missing_end.c +16 -0
  38. data/src/analyze/parse_errors.c +3 -2
  39. data/src/analyze/postfix_conditionals.c +326 -0
  40. data/src/analyze/render_nodes.c +231 -35
  41. data/src/analyze/strict_locals.c +22 -338
  42. data/src/analyze/ternary_conditionals.c +265 -0
  43. data/src/analyze/transform.c +23 -2
  44. data/src/ast/ast_nodes.c +114 -57
  45. data/src/ast/ast_pretty_print.c +109 -25
  46. data/src/include/analyze/action_view/helper_registry.h +325 -0
  47. data/src/include/analyze/action_view/tag_helper_handler.h +3 -0
  48. data/src/include/analyze/action_view/tag_helper_node_builders.h +7 -0
  49. data/src/include/analyze/action_view/tag_helpers.h +0 -1
  50. data/src/include/analyze/helpers.h +18 -0
  51. data/src/include/analyze/postfix_conditionals.h +9 -0
  52. data/src/include/analyze/ternary_conditionals.h +15 -0
  53. data/src/include/ast/ast_nodes.h +27 -13
  54. data/src/include/parser/parser.h +1 -0
  55. data/src/include/version.h +1 -1
  56. data/src/parser/match_tags.c +37 -6
  57. data/src/parser.c +9 -0
  58. data/src/visitor.c +50 -7
  59. data/templates/java/org/herb/ast/HelperRegistry.java.erb +258 -0
  60. data/templates/javascript/packages/core/src/action-view-helpers.ts.erb +171 -0
  61. data/templates/javascript/packages/core/src/nodes.ts.erb +5 -1
  62. data/templates/lib/herb/action_view/helper_registry.rb.erb +288 -0
  63. data/templates/rust/src/action_view_helpers.rs.erb +154 -0
  64. data/templates/src/analyze/action_view/generated_handlers.c.erb +230 -0
  65. data/templates/src/analyze/action_view/generated_handlers.h.erb +12 -0
  66. data/templates/src/analyze/action_view/helper_registry.c.erb +114 -0
  67. data/templates/src/include/analyze/action_view/helper_registry.h.erb +82 -0
  68. data/templates/template.rb +338 -1
  69. metadata +19 -3
  70. data/src/analyze/action_view/content_tag.c +0 -78
  71. data/src/analyze/action_view/tag.c +0 -87
@@ -1,26 +1,10 @@
1
+ #include "../../include/lib/hb_allocator.h"
2
+ #include "../../include/lib/hb_buffer.h"
3
+
1
4
  #include <prism.h>
2
5
  #include <stdbool.h>
3
- #include <stdlib.h>
4
6
  #include <string.h>
5
7
 
6
- #include "../../include/analyze/action_view/tag_helper_handler.h"
7
- #include "../../include/lib/hb_buffer.h"
8
-
9
- bool detect_image_tag(pm_call_node_t* call_node, pm_parser_t* parser) {
10
- if (!call_node || !call_node->name) { return false; }
11
-
12
- pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, call_node->name);
13
- return constant && constant->length == 9 && strncmp((const char*) constant->start, "image_tag", 9) == 0;
14
- }
15
-
16
- char* extract_image_tag_name(pm_call_node_t* _call_node, pm_parser_t* _parser, hb_allocator_T* allocator) {
17
- return hb_allocator_strdup(allocator, "img");
18
- }
19
-
20
- char* extract_image_tag_content(pm_call_node_t* _call_node, pm_parser_t* _parser, hb_allocator_T* _allocator) {
21
- return NULL;
22
- }
23
-
24
8
  char* extract_image_tag_src(pm_call_node_t* call_node, pm_parser_t* _parser, hb_allocator_T* allocator) {
25
9
  if (!call_node || !call_node->arguments) { return NULL; }
26
10
 
@@ -37,6 +21,7 @@ char* extract_image_tag_src(pm_call_node_t* call_node, pm_parser_t* _parser, hb_
37
21
  }
38
22
 
39
23
  size_t source_length = first_argument->location.end - first_argument->location.start;
24
+
40
25
  return hb_allocator_strndup(allocator, (const char*) first_argument->location.start, source_length);
41
26
  }
42
27
 
@@ -73,15 +58,3 @@ char* wrap_in_image_path(
73
58
 
74
59
  return result;
75
60
  }
76
-
77
- bool image_tag_supports_block(void) {
78
- return false;
79
- }
80
-
81
- const tag_helper_handler_T image_tag_handler = { .name = "image_tag",
82
- .source =
83
- HB_STRING_LITERAL("ActionView::Helpers::AssetTagHelper#image_tag"),
84
- .detect = detect_image_tag,
85
- .extract_tag_name = extract_image_tag_name,
86
- .extract_content = extract_image_tag_content,
87
- .supports_block = image_tag_supports_block };
@@ -1,38 +1,10 @@
1
- #include "../../include/analyze/action_view/tag_helper_handler.h"
1
+ #include "../../include/lib/hb_allocator.h"
2
2
  #include "../../include/lib/hb_buffer.h"
3
3
 
4
4
  #include <prism.h>
5
5
  #include <stdbool.h>
6
- #include <stdlib.h>
7
6
  #include <string.h>
8
7
 
9
- bool detect_javascript_include_tag(pm_call_node_t* call_node, pm_parser_t* parser) {
10
- if (!call_node || !call_node->name) { return false; }
11
-
12
- pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, call_node->name);
13
- return constant && constant->length == 22
14
- && strncmp((const char*) constant->start, "javascript_include_tag", 22) == 0;
15
- }
16
-
17
- char* extract_javascript_include_tag_name(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
18
- (void) call_node;
19
- (void) parser;
20
-
21
- return hb_allocator_strdup(allocator, "script");
22
- }
23
-
24
- char* extract_javascript_include_tag_content(
25
- pm_call_node_t* call_node,
26
- pm_parser_t* parser,
27
- hb_allocator_T* allocator
28
- ) {
29
- (void) call_node;
30
- (void) parser;
31
- (void) allocator;
32
-
33
- return NULL;
34
- }
35
-
36
8
  char* extract_javascript_include_tag_src(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
37
9
  (void) parser;
38
10
 
@@ -87,16 +59,3 @@ char* wrap_in_javascript_path(
87
59
 
88
60
  return result;
89
61
  }
90
-
91
- bool javascript_include_tag_supports_block(void) {
92
- return false;
93
- }
94
-
95
- const tag_helper_handler_T javascript_include_tag_handler = {
96
- .name = "javascript_include_tag",
97
- .source = HB_STRING_LITERAL("ActionView::Helpers::AssetTagHelper#javascript_include_tag"),
98
- .detect = detect_javascript_include_tag,
99
- .extract_tag_name = extract_javascript_include_tag_name,
100
- .extract_content = extract_javascript_include_tag_content,
101
- .supports_block = javascript_include_tag_supports_block
102
- };
@@ -1,55 +1,41 @@
1
- #include "../../include/analyze/action_view/tag_helper_handler.h"
1
+ #include "../../include/analyze/action_view/tag_helper_node_builders.h"
2
+ #include "../../include/ast/ast_nodes.h"
3
+ #include "../../include/lib/hb_array.h"
4
+ #include "../../include/lib/hb_string.h"
5
+ #include "../../include/visitor.h"
2
6
 
3
- #include <prism.h>
4
7
  #include <stdbool.h>
5
8
  #include <stdlib.h>
6
- #include <string.h>
7
9
 
8
- bool detect_javascript_tag(pm_call_node_t* call_node, pm_parser_t* parser) {
9
- if (!call_node || !call_node->name) { return false; }
10
+ bool wrap_javascript_tag_body_visitor(const AST_NODE_T* node, void* data) {
11
+ hb_allocator_T* allocator = (hb_allocator_T*) data;
10
12
 
11
- pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, call_node->name);
12
- return constant && constant->length == 14 && strncmp((const char*) constant->start, "javascript_tag", 14) == 0;
13
- }
14
-
15
- char* extract_javascript_tag_name(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
16
- (void) call_node;
17
- (void) parser;
13
+ if (node == NULL || node->type != AST_HTML_ELEMENT_NODE) { return true; }
18
14
 
19
- return hb_allocator_strdup(allocator, "script");
20
- }
15
+ AST_HTML_ELEMENT_NODE_T* element = (AST_HTML_ELEMENT_NODE_T*) node;
21
16
 
22
- char* extract_javascript_tag_content(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
23
- (void) parser;
24
-
25
- if (!call_node || !call_node->arguments) { return NULL; }
17
+ if (!hb_string_equals(element->element_source, hb_string("ActionView::Helpers::JavaScriptHelper#javascript_tag"))) {
18
+ return true;
19
+ }
26
20
 
27
- pm_arguments_node_t* arguments = call_node->arguments;
28
- if (!arguments->arguments.size) { return NULL; }
21
+ if (element->body == NULL || hb_array_size(element->body) == 0) { return false; }
29
22
 
30
- pm_node_t* first_argument = arguments->arguments.nodes[0];
23
+ for (size_t i = 0; i < hb_array_size(element->body); i++) {
24
+ AST_NODE_T* child = (AST_NODE_T*) hb_array_get(element->body, i);
25
+ if (child && child->type == AST_CDATA_NODE) { return false; }
26
+ }
31
27
 
32
- if (first_argument->type == PM_KEYWORD_HASH_NODE) { return NULL; }
28
+ hb_array_T* cdata_children = hb_array_init(hb_array_size(element->body), allocator);
33
29
 
34
- if (first_argument->type == PM_STRING_NODE) {
35
- pm_string_node_t* string_node = (pm_string_node_t*) first_argument;
36
- size_t length = pm_string_length(&string_node->unescaped);
37
- return hb_allocator_strndup(allocator, (const char*) pm_string_source(&string_node->unescaped), length);
30
+ for (size_t i = 0; i < hb_array_size(element->body); i++) {
31
+ hb_array_append(cdata_children, hb_array_get(element->body, i));
38
32
  }
39
33
 
40
- size_t source_length = first_argument->location.end - first_argument->location.start;
41
- return hb_allocator_strndup(allocator, (const char*) first_argument->location.start, source_length);
42
- }
34
+ AST_CDATA_NODE_T* cdata_node =
35
+ create_javascript_cdata_node(cdata_children, element->base.location.start, element->base.location.end, allocator);
43
36
 
44
- bool javascript_tag_supports_block(void) {
45
- return true;
46
- }
37
+ element->body->size = 0;
38
+ hb_array_append(element->body, (AST_NODE_T*) cdata_node);
47
39
 
48
- const tag_helper_handler_T javascript_tag_handler = {
49
- .name = "javascript_tag",
50
- .source = HB_STRING_LITERAL("ActionView::Helpers::JavaScriptHelper#javascript_tag"),
51
- .detect = detect_javascript_tag,
52
- .extract_tag_name = extract_javascript_tag_name,
53
- .extract_content = extract_javascript_tag_content,
54
- .supports_block = javascript_tag_supports_block
55
- };
40
+ return false;
41
+ }
@@ -5,7 +5,7 @@
5
5
  #include <stdlib.h>
6
6
 
7
7
  extern const tag_helper_handler_T content_tag_handler;
8
- extern const tag_helper_handler_T tag_dot_handler;
8
+ extern const tag_helper_handler_T tag_handler;
9
9
  extern const tag_helper_handler_T link_to_handler;
10
10
  extern const tag_helper_handler_T turbo_frame_tag_handler;
11
11
  extern const tag_helper_handler_T javascript_tag_handler;
@@ -49,7 +49,7 @@ tag_helper_handler_T* get_tag_helper_handlers(void) {
49
49
 
50
50
  if (!initialized) {
51
51
  static_handlers[0] = content_tag_handler;
52
- static_handlers[1] = tag_dot_handler;
52
+ static_handlers[1] = tag_handler;
53
53
  static_handlers[2] = link_to_handler;
54
54
  static_handlers[3] = turbo_frame_tag_handler;
55
55
  static_handlers[4] = javascript_tag_handler;
@@ -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
+ }
@@ -45,8 +45,6 @@ typedef struct {
45
45
  const tag_helper_handler_T* matched_handler;
46
46
  const char* original_source;
47
47
  size_t erb_content_offset;
48
- char* condition_source;
49
- char* condition_type;
50
48
  } tag_helper_parse_context_T;
51
49
 
52
50
  static tag_helper_parse_context_T* parse_tag_helper_content(
@@ -76,15 +74,12 @@ static tag_helper_parse_context_T* parse_tag_helper_content(
76
74
  }
77
75
 
78
76
  parse_context->info = tag_helper_info_init(allocator);
79
- parse_context->condition_source = NULL;
80
- parse_context->condition_type = NULL;
81
77
 
82
78
  tag_helper_search_data_T search = { .tag_helper_node = NULL,
83
79
  .source = parse_context->prism_source,
84
80
  .parser = &parse_context->parser,
85
81
  .info = parse_context->info,
86
- .found = false,
87
- .postfix_conditional_node = NULL };
82
+ .found = false };
88
83
  pm_visit_node(parse_context->root, search_tag_helper_node, &search);
89
84
 
90
85
  if (!search.found) {
@@ -96,22 +91,6 @@ static tag_helper_parse_context_T* parse_tag_helper_content(
96
91
  return NULL;
97
92
  }
98
93
 
99
- if (search.postfix_conditional_node) {
100
- if (search.postfix_conditional_node->type == PM_IF_NODE) {
101
- pm_if_node_t* if_node = (pm_if_node_t*) search.postfix_conditional_node;
102
- size_t predicate_length = if_node->predicate->location.end - if_node->predicate->location.start;
103
- parse_context->condition_source =
104
- hb_allocator_strndup(allocator, (const char*) if_node->predicate->location.start, predicate_length);
105
- parse_context->condition_type = hb_allocator_strdup(allocator, "if");
106
- } else if (search.postfix_conditional_node->type == PM_UNLESS_NODE) {
107
- pm_unless_node_t* unless_node = (pm_unless_node_t*) search.postfix_conditional_node;
108
- size_t predicate_length = unless_node->predicate->location.end - unless_node->predicate->location.start;
109
- parse_context->condition_source =
110
- hb_allocator_strndup(allocator, (const char*) unless_node->predicate->location.start, predicate_length);
111
- parse_context->condition_type = hb_allocator_strdup(allocator, "unless");
112
- }
113
- }
114
-
115
94
  parse_context->matched_handler = search.matched_handler;
116
95
  return parse_context;
117
96
  }
@@ -131,92 +110,6 @@ static void free_tag_helper_parse_context(tag_helper_parse_context_T* parse_cont
131
110
  }
132
111
  }
133
112
 
134
- static AST_NODE_T* wrap_in_conditional_if_needed(
135
- AST_NODE_T* element,
136
- tag_helper_parse_context_T* parse_context,
137
- hb_allocator_T* allocator
138
- ) {
139
- if (!element || !parse_context || !parse_context->condition_source || !parse_context->condition_type) {
140
- return element;
141
- }
142
-
143
- position_T start = element->location.start;
144
- position_T end = element->location.end;
145
-
146
- hb_buffer_T content_buffer;
147
- hb_buffer_init(&content_buffer, 64, allocator);
148
- hb_buffer_append(&content_buffer, " ");
149
- hb_buffer_append(&content_buffer, parse_context->condition_type);
150
- hb_buffer_append(&content_buffer, " ");
151
- hb_buffer_append(&content_buffer, parse_context->condition_source);
152
- hb_buffer_append(&content_buffer, " ");
153
- const char* content_string = hb_buffer_value(&content_buffer);
154
-
155
- token_T* tag_opening = create_synthetic_token(allocator, "<%", TOKEN_ERB_START, start, start);
156
- token_T* content_token = create_synthetic_token(allocator, content_string, TOKEN_ERB_CONTENT, start, end);
157
- token_T* tag_closing = create_synthetic_token(allocator, "%>", TOKEN_ERB_END, end, end);
158
-
159
- hb_array_T* statements = hb_array_init(1, allocator);
160
- hb_array_append(statements, element);
161
-
162
- token_T* end_opening = create_synthetic_token(allocator, "<%", TOKEN_ERB_START, end, end);
163
- token_T* end_content = create_synthetic_token(allocator, " end ", TOKEN_ERB_CONTENT, end, end);
164
- token_T* end_closing = create_synthetic_token(allocator, "%>", TOKEN_ERB_END, end, end);
165
-
166
- AST_ERB_END_NODE_T* end_node =
167
- ast_erb_end_node_init(end_opening, end_content, end_closing, end, end, hb_array_init(0, allocator), allocator);
168
-
169
- herb_prism_node_T empty_prism_node = HERB_PRISM_NODE_EMPTY;
170
-
171
- if (strcmp(parse_context->condition_type, "if") == 0) {
172
- AST_ERB_IF_NODE_T* if_node = ast_erb_if_node_init(
173
- tag_opening,
174
- content_token,
175
- tag_closing,
176
- NULL,
177
- empty_prism_node,
178
- statements,
179
- NULL,
180
- end_node,
181
- start,
182
- end,
183
- hb_array_init(0, allocator),
184
- allocator
185
- );
186
-
187
- return (AST_NODE_T*) if_node;
188
- } else {
189
- AST_ERB_UNLESS_NODE_T* unless_node = ast_erb_unless_node_init(
190
- tag_opening,
191
- content_token,
192
- tag_closing,
193
- NULL,
194
- empty_prism_node,
195
- statements,
196
- NULL,
197
- end_node,
198
- start,
199
- end,
200
- hb_array_init(0, allocator),
201
- allocator
202
- );
203
-
204
- return (AST_NODE_T*) unless_node;
205
- }
206
- }
207
-
208
- static bool is_postfix_if_node(const pm_node_t* node) {
209
- if (node->type != PM_IF_NODE) { return false; }
210
- pm_if_node_t* if_node = (pm_if_node_t*) node;
211
- return if_node->if_keyword_loc.start != NULL && if_node->end_keyword_loc.start == NULL;
212
- }
213
-
214
- static bool is_postfix_unless_node(const pm_node_t* node) {
215
- if (node->type != PM_UNLESS_NODE) { return false; }
216
- pm_unless_node_t* unless_node = (pm_unless_node_t*) node;
217
- return unless_node->keyword_loc.start != NULL && unless_node->end_keyword_loc.start == NULL;
218
- }
219
-
220
113
  bool search_tag_helper_node(const pm_node_t* node, void* data) {
221
114
  tag_helper_search_data_T* search_data = (tag_helper_search_data_T*) data;
222
115
 
@@ -247,16 +140,6 @@ bool search_tag_helper_node(const pm_node_t* node, void* data) {
247
140
  return false;
248
141
  }
249
142
 
250
- if (is_postfix_if_node(node) || is_postfix_unless_node(node)) {
251
- const pm_node_t* saved = search_data->postfix_conditional_node;
252
- search_data->postfix_conditional_node = node;
253
- pm_visit_child_nodes(node, search_tag_helper_node, search_data);
254
-
255
- if (!search_data->found) { search_data->postfix_conditional_node = saved; }
256
-
257
- return search_data->found;
258
- }
259
-
260
143
  pm_visit_child_nodes(node, search_tag_helper_node, search_data);
261
144
 
262
145
  return search_data->found;
@@ -639,7 +522,15 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
639
522
  id_is_ruby_expression ? create_html_attribute_with_ruby_literal("id", id_value, id_start, id_end, allocator)
640
523
  : create_html_attribute_node("id", id_value, id_start, id_end, allocator);
641
524
 
642
- if (id_attribute) { attributes = prepend_attribute(attributes, (AST_NODE_T*) id_attribute, allocator); }
525
+ if (id_attribute) {
526
+ AST_NODE_T* src_node = remove_attribute_by_name(attributes, "src");
527
+ AST_NODE_T* target_node = remove_attribute_by_name(attributes, "target");
528
+
529
+ hb_array_append(attributes, (AST_NODE_T*) id_attribute);
530
+
531
+ if (src_node) { hb_array_append(attributes, src_node); }
532
+ if (target_node) { hb_array_append(attributes, target_node); }
533
+ }
643
534
 
644
535
  hb_allocator_dealloc(allocator, id_value);
645
536
  }
@@ -679,7 +570,7 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
679
570
  ? create_html_attribute_node("src", source_attribute_value, source_start, source_end, allocator)
680
571
  : create_html_attribute_with_ruby_literal("src", source_attribute_value, source_start, source_end, allocator);
681
572
 
682
- if (source_attribute) { attributes = prepend_attribute(attributes, (AST_NODE_T*) source_attribute, allocator); }
573
+ if (source_attribute) { hb_array_append(attributes, (AST_NODE_T*) source_attribute); }
683
574
 
684
575
  if (source_attribute_value != source_value) { hb_allocator_dealloc(allocator, source_attribute_value); }
685
576
  hb_allocator_dealloc(allocator, source_value);
@@ -723,7 +614,7 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
723
614
  ? create_html_attribute_node("src", source_attribute_value, source_start, source_end, allocator)
724
615
  : create_html_attribute_with_ruby_literal("src", source_attribute_value, source_start, source_end, allocator);
725
616
 
726
- if (source_attribute) { attributes = prepend_attribute(attributes, (AST_NODE_T*) source_attribute, allocator); }
617
+ if (source_attribute) { hb_array_append(attributes, (AST_NODE_T*) source_attribute); }
727
618
  if (source_attribute_value != source_value) { hb_allocator_dealloc(allocator, source_attribute_value); }
728
619
 
729
620
  hb_allocator_dealloc(allocator, source_value);
@@ -798,14 +689,37 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
798
689
  );
799
690
  }
800
691
 
801
- append_body_content_node(
802
- body,
803
- helper_content,
804
- content_is_ruby_expression,
805
- erb_node->base.location.start,
806
- erb_node->base.location.end,
807
- allocator
808
- );
692
+ if (string_equals(handler->name, "javascript_tag")) {
693
+ hb_array_T* cdata_children = hb_array_init(1, allocator);
694
+
695
+ append_body_content_node(
696
+ cdata_children,
697
+ helper_content,
698
+ content_is_ruby_expression,
699
+ erb_node->base.location.start,
700
+ erb_node->base.location.end,
701
+ allocator
702
+ );
703
+
704
+ AST_CDATA_NODE_T* cdata_node = create_javascript_cdata_node(
705
+ cdata_children,
706
+ erb_node->base.location.start,
707
+ erb_node->base.location.end,
708
+ allocator
709
+ );
710
+
711
+ if (cdata_node) { hb_array_append(body, (AST_NODE_T*) cdata_node); }
712
+ } else {
713
+ append_body_content_node(
714
+ body,
715
+ helper_content,
716
+ content_is_ruby_expression,
717
+ erb_node->base.location.start,
718
+ erb_node->base.location.end,
719
+ allocator
720
+ );
721
+ }
722
+
809
723
  hb_allocator_dealloc(allocator, helper_content);
810
724
  }
811
725
 
@@ -1117,7 +1031,7 @@ static AST_NODE_T* transform_erb_block_to_tag_helper(
1117
1031
  AST_HTML_ATTRIBUTE_NODE_T* href_attribute =
1118
1032
  create_href_attribute(href, href_is_ruby_expression, href_start, href_end, allocator);
1119
1033
 
1120
- if (href_attribute) { attributes = prepend_attribute(attributes, (AST_NODE_T*) href_attribute, allocator); }
1034
+ if (href_attribute) { hb_array_append(attributes, (AST_NODE_T*) href_attribute); }
1121
1035
 
1122
1036
  hb_allocator_dealloc(allocator, href);
1123
1037
  }
@@ -1138,7 +1052,15 @@ static AST_NODE_T* transform_erb_block_to_tag_helper(
1138
1052
  id_is_ruby_expression ? create_html_attribute_with_ruby_literal("id", id_value, id_start, id_end, allocator)
1139
1053
  : create_html_attribute_node("id", id_value, id_start, id_end, allocator);
1140
1054
 
1141
- if (id_attribute) { attributes = prepend_attribute(attributes, (AST_NODE_T*) id_attribute, allocator); }
1055
+ if (id_attribute) {
1056
+ AST_NODE_T* src_node = remove_attribute_by_name(attributes, "src");
1057
+ AST_NODE_T* target_node = remove_attribute_by_name(attributes, "target");
1058
+
1059
+ hb_array_append(attributes, (AST_NODE_T*) id_attribute);
1060
+
1061
+ if (src_node) { hb_array_append(attributes, src_node); }
1062
+ if (target_node) { hb_array_append(attributes, target_node); }
1063
+ }
1142
1064
 
1143
1065
  hb_allocator_dealloc(allocator, id_value);
1144
1066
  }
@@ -1395,7 +1317,7 @@ static AST_NODE_T* transform_link_to_helper(
1395
1317
  AST_HTML_ATTRIBUTE_NODE_T* href_attribute =
1396
1318
  create_href_attribute(href, href_is_ruby_expression, href_start, href_end, allocator);
1397
1319
 
1398
- if (href_attribute) { attributes = prepend_attribute(attributes, (AST_NODE_T*) href_attribute, allocator); }
1320
+ if (href_attribute) { hb_array_append(attributes, (AST_NODE_T*) href_attribute); }
1399
1321
  if (!info->content) {
1400
1322
  href_for_body = hb_allocator_strdup(allocator, href);
1401
1323
  href_for_body_is_ruby_expression = href_is_ruby_expression;
@@ -1503,6 +1425,12 @@ void transform_tag_helper_array(hb_array_T* array, analyze_ruby_context_T* conte
1503
1425
 
1504
1426
  if (child->type == AST_ERB_BLOCK_NODE) {
1505
1427
  AST_ERB_BLOCK_NODE_T* block_node = (AST_ERB_BLOCK_NODE_T*) child;
1428
+
1429
+ if (block_node->tag_opening && !hb_string_is_empty(block_node->tag_opening->value)) {
1430
+ const char* opening_string = block_node->tag_opening->value.data;
1431
+ if (opening_string && strstr(opening_string, "=") == NULL) { continue; }
1432
+ }
1433
+
1506
1434
  token_T* block_content = block_node->content;
1507
1435
 
1508
1436
  if (block_content && !hb_string_is_empty(block_content->value)) {
@@ -1518,7 +1446,6 @@ void transform_tag_helper_array(hb_array_T* array, analyze_ruby_context_T* conte
1518
1446
 
1519
1447
  if (parse_context) {
1520
1448
  replacement = transform_erb_block_to_tag_helper(block_node, context, parse_context);
1521
- replacement = wrap_in_conditional_if_needed(replacement, parse_context, context->allocator);
1522
1449
  free_tag_helper_parse_context(parse_context);
1523
1450
  }
1524
1451
 
@@ -1532,6 +1459,7 @@ void transform_tag_helper_array(hb_array_T* array, analyze_ruby_context_T* conte
1532
1459
  const char* opening_string = tag_opening->value.data;
1533
1460
 
1534
1461
  if (opening_string && strstr(opening_string, "#") != NULL) { continue; }
1462
+ if (opening_string && strstr(opening_string, "=") == NULL) { continue; }
1535
1463
  }
1536
1464
 
1537
1465
  token_T* erb_content = erb_node->content;
@@ -1615,7 +1543,6 @@ void transform_tag_helper_array(hb_array_T* array, analyze_ruby_context_T* conte
1615
1543
  replacement = transform_tag_helper_with_attributes(erb_node, context, parse_context);
1616
1544
  }
1617
1545
 
1618
- replacement = wrap_in_conditional_if_needed(replacement, parse_context, context->allocator);
1619
1546
  free_tag_helper_parse_context(parse_context);
1620
1547
  }
1621
1548
 
@@ -1,32 +1,9 @@
1
- #include "../../include/analyze/action_view/tag_helper_handler.h"
1
+ #include "../../include/lib/hb_allocator.h"
2
2
 
3
3
  #include <prism.h>
4
4
  #include <stdbool.h>
5
- #include <stdlib.h>
6
5
  #include <string.h>
7
6
 
8
- bool detect_turbo_frame_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 == 15 && strncmp((const char*) constant->start, "turbo_frame_tag", 15) == 0;
13
- }
14
-
15
- char* extract_turbo_frame_tag_name(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
16
- (void) call_node;
17
- (void) parser;
18
-
19
- return hb_allocator_strdup(allocator, "turbo-frame");
20
- }
21
-
22
- char* extract_turbo_frame_tag_content(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
23
- (void) call_node;
24
- (void) parser;
25
- (void) allocator;
26
-
27
- return NULL;
28
- }
29
-
30
7
  char* extract_turbo_frame_tag_id(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
31
8
  if (!call_node || !call_node->arguments) { return NULL; }
32
9
 
@@ -74,15 +51,3 @@ char* extract_turbo_frame_tag_id(pm_call_node_t* call_node, pm_parser_t* parser,
74
51
 
75
52
  return result;
76
53
  }
77
-
78
- bool turbo_frame_tag_supports_block(void) {
79
- return true;
80
- }
81
-
82
- const tag_helper_handler_T turbo_frame_tag_handler = { .name = "turbo_frame_tag",
83
- .source =
84
- HB_STRING_LITERAL("Turbo::FramesHelper#turbo_frame_tag"),
85
- .detect = detect_turbo_frame_tag,
86
- .extract_tag_name = extract_turbo_frame_tag_name,
87
- .extract_content = extract_turbo_frame_tag_content,
88
- .supports_block = turbo_frame_tag_supports_block };
@@ -8,8 +8,10 @@
8
8
  #include "../include/analyze/control_type.h"
9
9
  #include "../include/analyze/helpers.h"
10
10
  #include "../include/analyze/invalid_structures.h"
11
+ #include "../include/analyze/postfix_conditionals.h"
11
12
  #include "../include/analyze/render_nodes.h"
12
13
  #include "../include/analyze/strict_locals.h"
14
+ #include "../include/analyze/ternary_conditionals.h"
13
15
  #include "../include/ast/ast_node.h"
14
16
  #include "../include/ast/ast_nodes.h"
15
17
  #include "../include/errors.h"
@@ -736,12 +738,32 @@ static size_t process_block_structure(
736
738
  hb_array_T* block_errors = erb_node->base.errors;
737
739
  erb_node->base.errors = NULL;
738
740
 
741
+ // Filter out "incomplete block" Prism errors since we've matched the block with its end tag.
742
+ if (block_errors) {
743
+ for (size_t error_index = hb_array_size(block_errors); error_index > 0; error_index--) {
744
+ ERROR_T* error = hb_array_get(block_errors, error_index - 1);
745
+ if (!error || error->type != RUBY_PARSE_ERROR) { continue; }
746
+
747
+ RUBY_PARSE_ERROR_T* parse_error = (RUBY_PARSE_ERROR_T*) error;
748
+
749
+ if (string_equals(parse_error->diagnostic_id.data, "block_term_end")
750
+ || string_equals(parse_error->diagnostic_id.data, "block_term_brace")
751
+ || string_equals(parse_error->diagnostic_id.data, "unexpected_token_close_context")) {
752
+ hb_array_remove(block_errors, error_index - 1);
753
+ }
754
+ }
755
+ }
756
+
757
+ hb_array_T* block_arguments =
758
+ extract_block_arguments_from_erb_node(erb_node, context->source, block_errors, allocator);
759
+
739
760
  AST_ERB_BLOCK_NODE_T* block_node = ast_erb_block_node_init(
740
761
  erb_node->tag_opening,
741
762
  erb_node->content,
742
763
  erb_node->tag_closing,
743
764
  HERB_PRISM_NODE_EMPTY,
744
765
  children,
766
+ block_arguments,
745
767
  rescue_clause,
746
768
  else_clause,
747
769
  ensure_clause,
@@ -942,6 +964,7 @@ hb_array_T* get_node_children_array(const AST_NODE_T* node) {
942
964
  case AST_ERB_ENSURE_NODE: return ((AST_ERB_ENSURE_NODE_T*) node)->statements;
943
965
  case AST_ERB_CASE_NODE: return ((AST_ERB_CASE_NODE_T*) node)->children;
944
966
  case AST_ERB_WHEN_NODE: return ((AST_ERB_WHEN_NODE_T*) node)->statements;
967
+ case AST_ERB_RENDER_NODE: return ((AST_ERB_RENDER_NODE_T*) node)->body;
945
968
  default: return NULL;
946
969
  }
947
970
  }
@@ -1008,6 +1031,11 @@ void herb_analyze_parse_tree(
1008
1031
  .source = source,
1009
1032
  };
1010
1033
 
1034
+ if (options && (options->transform_conditionals || options->action_view_helpers)) {
1035
+ herb_visit_node((AST_NODE_T*) document, transform_conditional_nodes, &context);
1036
+ herb_visit_node((AST_NODE_T*) document, transform_ternary_conditional_nodes, &context);
1037
+ }
1038
+
1011
1039
  herb_visit_node((AST_NODE_T*) document, transform_erb_nodes, &context);
1012
1040
 
1013
1041
  if (options && options->render_nodes) { herb_visit_node((AST_NODE_T*) document, transform_render_nodes, &context); }