@herb-tools/node 0.8.9 → 0.9.0

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 (174) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/binding.gyp +26 -8
  3. package/dist/herb-node.cjs +41 -12
  4. package/dist/herb-node.cjs.map +1 -1
  5. package/dist/herb-node.esm.js +8 -1
  6. package/dist/herb-node.esm.js.map +1 -1
  7. package/dist/types/node-backend.d.ts +3 -1
  8. package/extension/error_helpers.cpp +419 -71
  9. package/extension/error_helpers.h +14 -3
  10. package/extension/extension_helpers.cpp +38 -35
  11. package/extension/extension_helpers.h +2 -2
  12. package/extension/herb.cpp +183 -64
  13. package/extension/libherb/analyze/action_view/attribute_extraction_helpers.c +290 -0
  14. package/extension/libherb/analyze/action_view/attribute_extraction_helpers.h +36 -0
  15. package/extension/libherb/analyze/action_view/content_tag.c +70 -0
  16. package/extension/libherb/analyze/action_view/link_to.c +143 -0
  17. package/extension/libherb/analyze/action_view/registry.c +60 -0
  18. package/extension/libherb/analyze/action_view/tag.c +64 -0
  19. package/extension/libherb/analyze/action_view/tag_helper_handler.h +41 -0
  20. package/extension/libherb/analyze/action_view/tag_helper_node_builders.c +305 -0
  21. package/extension/libherb/analyze/action_view/tag_helper_node_builders.h +70 -0
  22. package/extension/libherb/analyze/action_view/tag_helpers.c +748 -0
  23. package/extension/libherb/analyze/action_view/tag_helpers.h +38 -0
  24. package/extension/libherb/analyze/action_view/turbo_frame_tag.c +88 -0
  25. package/extension/libherb/analyze/analyze.c +882 -0
  26. package/extension/libherb/{include → analyze}/analyze.h +14 -4
  27. package/extension/libherb/{analyzed_ruby.c → analyze/analyzed_ruby.c} +13 -11
  28. package/extension/libherb/{analyzed_ruby.h → analyze/analyzed_ruby.h} +3 -3
  29. package/extension/libherb/analyze/builders.c +343 -0
  30. package/extension/libherb/analyze/builders.h +27 -0
  31. package/extension/libherb/analyze/conditional_elements.c +594 -0
  32. package/extension/libherb/analyze/conditional_elements.h +9 -0
  33. package/extension/libherb/analyze/conditional_open_tags.c +640 -0
  34. package/extension/libherb/analyze/conditional_open_tags.h +9 -0
  35. package/extension/libherb/analyze/control_type.c +250 -0
  36. package/extension/libherb/analyze/control_type.h +14 -0
  37. package/extension/libherb/{analyze_helpers.c → analyze/helpers.c} +79 -31
  38. package/extension/libherb/{analyze_helpers.h → analyze/helpers.h} +22 -17
  39. package/extension/libherb/analyze/invalid_structures.c +193 -0
  40. package/extension/libherb/analyze/invalid_structures.h +11 -0
  41. package/extension/libherb/{analyze_missing_end.c → analyze/missing_end.c} +33 -22
  42. package/extension/libherb/analyze/parse_errors.c +84 -0
  43. package/extension/libherb/analyze/prism_annotate.c +397 -0
  44. package/extension/libherb/analyze/prism_annotate.h +16 -0
  45. package/extension/libherb/{analyze_transform.c → analyze/transform.c} +17 -3
  46. package/extension/libherb/ast_node.c +17 -7
  47. package/extension/libherb/ast_node.h +11 -5
  48. package/extension/libherb/ast_nodes.c +663 -388
  49. package/extension/libherb/ast_nodes.h +118 -39
  50. package/extension/libherb/ast_pretty_print.c +191 -7
  51. package/extension/libherb/ast_pretty_print.h +6 -1
  52. package/extension/libherb/element_source.h +3 -8
  53. package/extension/libherb/errors.c +1100 -507
  54. package/extension/libherb/errors.h +155 -54
  55. package/extension/libherb/extract.c +148 -49
  56. package/extension/libherb/extract.h +21 -5
  57. package/extension/libherb/herb.c +52 -34
  58. package/extension/libherb/herb.h +18 -6
  59. package/extension/libherb/herb_prism_node.h +13 -0
  60. package/extension/libherb/html_util.c +241 -12
  61. package/extension/libherb/html_util.h +7 -2
  62. package/extension/libherb/include/analyze/action_view/attribute_extraction_helpers.h +36 -0
  63. package/extension/libherb/include/analyze/action_view/tag_helper_handler.h +41 -0
  64. package/extension/libherb/include/analyze/action_view/tag_helper_node_builders.h +70 -0
  65. package/extension/libherb/include/analyze/action_view/tag_helpers.h +38 -0
  66. package/extension/libherb/{analyze.h → include/analyze/analyze.h} +14 -4
  67. package/extension/libherb/include/{analyzed_ruby.h → analyze/analyzed_ruby.h} +3 -3
  68. package/extension/libherb/include/analyze/builders.h +27 -0
  69. package/extension/libherb/include/analyze/conditional_elements.h +9 -0
  70. package/extension/libherb/include/analyze/conditional_open_tags.h +9 -0
  71. package/extension/libherb/include/analyze/control_type.h +14 -0
  72. package/extension/libherb/include/{analyze_helpers.h → analyze/helpers.h} +22 -17
  73. package/extension/libherb/include/analyze/invalid_structures.h +11 -0
  74. package/extension/libherb/include/analyze/prism_annotate.h +16 -0
  75. package/extension/libherb/include/ast_node.h +11 -5
  76. package/extension/libherb/include/ast_nodes.h +118 -39
  77. package/extension/libherb/include/ast_pretty_print.h +6 -1
  78. package/extension/libherb/include/element_source.h +3 -8
  79. package/extension/libherb/include/errors.h +155 -54
  80. package/extension/libherb/include/extract.h +21 -5
  81. package/extension/libherb/include/herb.h +18 -6
  82. package/extension/libherb/include/herb_prism_node.h +13 -0
  83. package/extension/libherb/include/html_util.h +7 -2
  84. package/extension/libherb/include/io.h +3 -1
  85. package/extension/libherb/include/lex_helpers.h +29 -0
  86. package/extension/libherb/include/lexer.h +1 -1
  87. package/extension/libherb/include/lexer_peek_helpers.h +87 -13
  88. package/extension/libherb/include/lexer_struct.h +2 -0
  89. package/extension/libherb/include/location.h +2 -1
  90. package/extension/libherb/include/parser.h +27 -2
  91. package/extension/libherb/include/parser_helpers.h +19 -3
  92. package/extension/libherb/include/pretty_print.h +10 -5
  93. package/extension/libherb/include/prism_context.h +45 -0
  94. package/extension/libherb/include/prism_helpers.h +10 -7
  95. package/extension/libherb/include/prism_serialized.h +12 -0
  96. package/extension/libherb/include/token.h +16 -4
  97. package/extension/libherb/include/token_struct.h +10 -3
  98. package/extension/libherb/include/utf8.h +2 -1
  99. package/extension/libherb/include/util/hb_allocator.h +78 -0
  100. package/extension/libherb/include/util/hb_arena.h +6 -1
  101. package/extension/libherb/include/util/hb_arena_debug.h +12 -1
  102. package/extension/libherb/include/util/hb_array.h +7 -3
  103. package/extension/libherb/include/util/hb_buffer.h +6 -4
  104. package/extension/libherb/include/util/hb_foreach.h +79 -0
  105. package/extension/libherb/include/util/hb_narray.h +8 -4
  106. package/extension/libherb/include/util/hb_string.h +56 -9
  107. package/extension/libherb/include/util/string.h +11 -0
  108. package/extension/libherb/include/util.h +6 -3
  109. package/extension/libherb/include/version.h +1 -1
  110. package/extension/libherb/io.c +3 -2
  111. package/extension/libherb/io.h +3 -1
  112. package/extension/libherb/lex_helpers.h +29 -0
  113. package/extension/libherb/lexer.c +42 -30
  114. package/extension/libherb/lexer.h +1 -1
  115. package/extension/libherb/lexer_peek_helpers.c +12 -74
  116. package/extension/libherb/lexer_peek_helpers.h +87 -13
  117. package/extension/libherb/lexer_struct.h +2 -0
  118. package/extension/libherb/location.c +2 -2
  119. package/extension/libherb/location.h +2 -1
  120. package/extension/libherb/main.c +79 -66
  121. package/extension/libherb/parser.c +784 -247
  122. package/extension/libherb/parser.h +27 -2
  123. package/extension/libherb/parser_helpers.c +110 -23
  124. package/extension/libherb/parser_helpers.h +19 -3
  125. package/extension/libherb/parser_match_tags.c +110 -49
  126. package/extension/libherb/pretty_print.c +29 -24
  127. package/extension/libherb/pretty_print.h +10 -5
  128. package/extension/libherb/prism_context.h +45 -0
  129. package/extension/libherb/prism_helpers.c +30 -27
  130. package/extension/libherb/prism_helpers.h +10 -7
  131. package/extension/libherb/prism_serialized.h +12 -0
  132. package/extension/libherb/ruby_parser.c +2 -0
  133. package/extension/libherb/token.c +151 -66
  134. package/extension/libherb/token.h +16 -4
  135. package/extension/libherb/token_matchers.c +0 -1
  136. package/extension/libherb/token_struct.h +10 -3
  137. package/extension/libherb/utf8.c +7 -6
  138. package/extension/libherb/utf8.h +2 -1
  139. package/extension/libherb/util/hb_allocator.c +341 -0
  140. package/extension/libherb/util/hb_allocator.h +78 -0
  141. package/extension/libherb/util/hb_arena.c +81 -56
  142. package/extension/libherb/util/hb_arena.h +6 -1
  143. package/extension/libherb/util/hb_arena_debug.c +32 -17
  144. package/extension/libherb/util/hb_arena_debug.h +12 -1
  145. package/extension/libherb/util/hb_array.c +30 -15
  146. package/extension/libherb/util/hb_array.h +7 -3
  147. package/extension/libherb/util/hb_buffer.c +17 -21
  148. package/extension/libherb/util/hb_buffer.h +6 -4
  149. package/extension/libherb/util/hb_foreach.h +79 -0
  150. package/extension/libherb/util/hb_narray.c +22 -7
  151. package/extension/libherb/util/hb_narray.h +8 -4
  152. package/extension/libherb/util/hb_string.c +49 -35
  153. package/extension/libherb/util/hb_string.h +56 -9
  154. package/extension/libherb/util/string.h +11 -0
  155. package/extension/libherb/util.c +21 -11
  156. package/extension/libherb/util.h +6 -3
  157. package/extension/libherb/version.h +1 -1
  158. package/extension/libherb/visitor.c +48 -1
  159. package/extension/nodes.cpp +451 -6
  160. package/extension/nodes.h +8 -1
  161. package/extension/prism/include/prism/ast.h +4 -4
  162. package/extension/prism/include/prism/version.h +2 -2
  163. package/extension/prism/src/prism.c +1 -1
  164. package/package.json +12 -8
  165. package/src/node-backend.ts +11 -1
  166. package/dist/types/index-cjs.d.cts +0 -1
  167. package/extension/libherb/analyze.c +0 -1594
  168. package/extension/libherb/element_source.c +0 -12
  169. package/extension/libherb/include/util/hb_system.h +0 -9
  170. package/extension/libherb/util/hb_system.c +0 -30
  171. package/extension/libherb/util/hb_system.h +0 -9
  172. package/src/index-cjs.cts +0 -22
  173. /package/dist/types/{index-esm.d.mts → index.d.ts} +0 -0
  174. /package/src/{index-esm.mts → index.ts} +0 -0
@@ -0,0 +1,193 @@
1
+ #include "../include/analyze/invalid_structures.h"
2
+ #include "../include/analyze/analyze.h"
3
+ #include "../include/analyze/analyzed_ruby.h"
4
+ #include "../include/analyze/helpers.h"
5
+ #include "../include/ast_node.h"
6
+ #include "../include/ast_nodes.h"
7
+ #include "../include/errors.h"
8
+ #include "../include/token_struct.h"
9
+ #include "../include/util/hb_array.h"
10
+ #include "../include/util/hb_string.h"
11
+ #include "../include/visitor.h"
12
+
13
+ #include <stdbool.h>
14
+ #include <stddef.h>
15
+
16
+ bool detect_invalid_erb_structures(const AST_NODE_T* node, void* data) {
17
+ invalid_erb_context_T* context = (invalid_erb_context_T*) data;
18
+
19
+ if (node->type == AST_HTML_ATTRIBUTE_NAME_NODE) { return false; }
20
+
21
+ bool is_begin_node = (node->type == AST_ERB_BEGIN_NODE);
22
+ bool is_loop_node =
23
+ (node->type == AST_ERB_WHILE_NODE || node->type == AST_ERB_UNTIL_NODE || node->type == AST_ERB_FOR_NODE
24
+ || node->type == AST_ERB_BLOCK_NODE);
25
+
26
+ if (is_loop_node) { context->loop_depth++; }
27
+ if (is_begin_node) { context->rescue_depth++; }
28
+
29
+ if (node->type == AST_ERB_CONTENT_NODE) {
30
+ const AST_ERB_CONTENT_NODE_T* content_node = (const AST_ERB_CONTENT_NODE_T*) node;
31
+
32
+ if (content_node->parsed && !content_node->valid && content_node->analyzed_ruby != NULL) {
33
+ analyzed_ruby_T* analyzed = content_node->analyzed_ruby;
34
+
35
+ // =begin
36
+ if (has_error_message(analyzed, "embedded document meets end of file")) {
37
+ if (is_loop_node) { context->loop_depth--; }
38
+ if (is_begin_node) { context->rescue_depth--; }
39
+
40
+ return true;
41
+ }
42
+
43
+ // =end
44
+ if (has_error_message(analyzed, "unexpected '=', ignoring it")
45
+ && has_error_message(analyzed, "unexpected 'end', ignoring it")) {
46
+ if (is_loop_node) { context->loop_depth--; }
47
+ if (is_begin_node) { context->rescue_depth--; }
48
+
49
+ return true;
50
+ }
51
+
52
+ hb_string_T keyword = HB_STRING_NULL;
53
+
54
+ if (context->loop_depth == 0) {
55
+ if (has_error_message(analyzed, "Invalid break")) {
56
+ keyword = hb_string("`<% break %>`");
57
+ } else if (has_error_message(analyzed, "Invalid next")) {
58
+ keyword = hb_string("`<% next %>`");
59
+ } else if (has_error_message(analyzed, "Invalid redo")) {
60
+ keyword = hb_string("`<% redo %>`");
61
+ }
62
+ } else {
63
+ if (has_error_message(analyzed, "Invalid redo") || has_error_message(analyzed, "Invalid break")
64
+ || has_error_message(analyzed, "Invalid next")) {
65
+
66
+ if (is_loop_node) { context->loop_depth--; }
67
+ if (is_begin_node) { context->rescue_depth--; }
68
+
69
+ return true;
70
+ }
71
+ }
72
+
73
+ if (context->rescue_depth == 0) {
74
+ if (has_error_message(analyzed, "Invalid retry without rescue")) { keyword = hb_string("`<% retry %>`"); }
75
+ } else {
76
+ if (has_error_message(analyzed, "Invalid retry without rescue")) {
77
+ if (is_loop_node) { context->loop_depth--; }
78
+ if (is_begin_node) { context->rescue_depth--; }
79
+
80
+ return true;
81
+ }
82
+ }
83
+
84
+ if (hb_string_is_null(keyword)) { keyword = erb_keyword_from_analyzed_ruby(analyzed); }
85
+
86
+ if (!hb_string_is_null(keyword) && !token_value_empty(content_node->tag_closing)) {
87
+ append_erb_control_flow_scope_error(
88
+ keyword,
89
+ node->location.start,
90
+ node->location.end,
91
+ context->allocator,
92
+ node->errors
93
+ );
94
+ }
95
+ }
96
+ }
97
+
98
+ if (node->type == AST_ERB_IF_NODE) {
99
+ const AST_ERB_IF_NODE_T* if_node = (const AST_ERB_IF_NODE_T*) node;
100
+
101
+ if (if_node->end_node == NULL) { check_erb_node_for_missing_end(node, context->allocator); }
102
+
103
+ if (if_node->statements != NULL) {
104
+ for (size_t i = 0; i < hb_array_size(if_node->statements); i++) {
105
+ AST_NODE_T* statement = (AST_NODE_T*) hb_array_get(if_node->statements, i);
106
+
107
+ if (statement != NULL) { herb_visit_node(statement, detect_invalid_erb_structures, context); }
108
+ }
109
+ }
110
+
111
+ AST_NODE_T* subsequent = if_node->subsequent;
112
+
113
+ while (subsequent != NULL) {
114
+ if (subsequent->type == AST_ERB_CONTENT_NODE) {
115
+ const AST_ERB_CONTENT_NODE_T* content_node = (const AST_ERB_CONTENT_NODE_T*) subsequent;
116
+
117
+ if (content_node->parsed && !content_node->valid && content_node->analyzed_ruby != NULL) {
118
+ analyzed_ruby_T* analyzed = content_node->analyzed_ruby;
119
+ hb_string_T keyword = erb_keyword_from_analyzed_ruby(analyzed);
120
+
121
+ if (!token_value_empty(content_node->tag_closing)) {
122
+ append_erb_control_flow_scope_error(
123
+ keyword,
124
+ subsequent->location.start,
125
+ subsequent->location.end,
126
+ context->allocator,
127
+ subsequent->errors
128
+ );
129
+ }
130
+ }
131
+ }
132
+
133
+ if (subsequent->type == AST_ERB_IF_NODE) {
134
+ const AST_ERB_IF_NODE_T* elsif_node = (const AST_ERB_IF_NODE_T*) subsequent;
135
+
136
+ if (elsif_node->statements != NULL) {
137
+ for (size_t i = 0; i < hb_array_size(elsif_node->statements); i++) {
138
+ AST_NODE_T* statement = (AST_NODE_T*) hb_array_get(elsif_node->statements, i);
139
+
140
+ if (statement != NULL) { herb_visit_node(statement, detect_invalid_erb_structures, context); }
141
+ }
142
+ }
143
+
144
+ subsequent = elsif_node->subsequent;
145
+ } else if (subsequent->type == AST_ERB_ELSE_NODE) {
146
+ const AST_ERB_ELSE_NODE_T* else_node = (const AST_ERB_ELSE_NODE_T*) subsequent;
147
+
148
+ if (else_node->statements != NULL) {
149
+ for (size_t i = 0; i < hb_array_size(else_node->statements); i++) {
150
+ AST_NODE_T* statement = (AST_NODE_T*) hb_array_get(else_node->statements, i);
151
+
152
+ if (statement != NULL) { herb_visit_node(statement, detect_invalid_erb_structures, context); }
153
+ }
154
+ }
155
+
156
+ break;
157
+ } else {
158
+ break;
159
+ }
160
+ }
161
+ }
162
+
163
+ if (node->type == AST_ERB_UNLESS_NODE || node->type == AST_ERB_WHILE_NODE || node->type == AST_ERB_UNTIL_NODE
164
+ || node->type == AST_ERB_FOR_NODE || node->type == AST_ERB_CASE_NODE || node->type == AST_ERB_CASE_MATCH_NODE
165
+ || node->type == AST_ERB_BEGIN_NODE || node->type == AST_ERB_BLOCK_NODE || node->type == AST_ERB_ELSE_NODE) {
166
+ herb_visit_child_nodes(node, detect_invalid_erb_structures, context);
167
+ }
168
+
169
+ if (node->type == AST_ERB_UNLESS_NODE || node->type == AST_ERB_WHILE_NODE || node->type == AST_ERB_UNTIL_NODE
170
+ || node->type == AST_ERB_FOR_NODE || node->type == AST_ERB_CASE_NODE || node->type == AST_ERB_CASE_MATCH_NODE
171
+ || node->type == AST_ERB_BEGIN_NODE || node->type == AST_ERB_BLOCK_NODE || node->type == AST_ERB_ELSE_NODE) {
172
+ check_erb_node_for_missing_end(node, context->allocator);
173
+
174
+ if (is_loop_node) { context->loop_depth--; }
175
+ if (is_begin_node) { context->rescue_depth--; }
176
+
177
+ return false;
178
+ }
179
+
180
+ if (node->type == AST_ERB_IF_NODE) {
181
+ if (is_loop_node) { context->loop_depth--; }
182
+ if (is_begin_node) { context->rescue_depth--; }
183
+
184
+ return false;
185
+ }
186
+
187
+ bool result = true;
188
+
189
+ if (is_loop_node) { context->loop_depth--; }
190
+ if (is_begin_node) { context->rescue_depth--; }
191
+
192
+ return result;
193
+ }
@@ -0,0 +1,11 @@
1
+ #ifndef HERB_ANALYZE_INVALID_STRUCTURES_H
2
+ #define HERB_ANALYZE_INVALID_STRUCTURES_H
3
+
4
+ #include "../ast_node.h"
5
+ #include "analyze.h"
6
+
7
+ #include <stdbool.h>
8
+
9
+ bool detect_invalid_erb_structures(const AST_NODE_T* node, void* data);
10
+
11
+ #endif
@@ -1,20 +1,23 @@
1
1
  // NOTE: This file is generated by the templates/template.rb script and should not
2
- // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.9/templates/src/analyze_missing_end.c.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.9.0/templates/src/analyze/missing_end.c.erb
3
3
 
4
- #include "include/analyze_helpers.h"
5
- #include "include/errors.h"
4
+ #include "../include/analyze/helpers.h"
5
+ #include "../include/errors.h"
6
+ #include "../include/util/hb_allocator.h"
7
+ #include "../include/util/hb_string.h"
6
8
 
7
9
 
8
- void check_erb_node_for_missing_end(const AST_NODE_T* node) {
10
+ void check_erb_node_for_missing_end(const AST_NODE_T* node, hb_allocator_T* allocator) {
9
11
  switch (node->type) {
10
12
  case AST_ERB_IF_NODE: {
11
13
  const AST_ERB_IF_NODE_T* erb_if_node = (const AST_ERB_IF_NODE_T*) node;
12
14
 
13
15
  if (erb_if_node->end_node == NULL) {
14
- append_missingerb_end_tag_error(
15
- "`<" "%" " if " "%" ">`",
16
+ append_missing_erb_end_tag_error(
17
+ hb_string("`<" "%" " if " "%" ">`"),
16
18
  erb_if_node->tag_opening->location.start,
17
19
  erb_if_node->tag_closing->location.end,
20
+ allocator,
18
21
  node->errors
19
22
  );
20
23
  }
@@ -26,10 +29,11 @@ void check_erb_node_for_missing_end(const AST_NODE_T* node) {
26
29
  const AST_ERB_BLOCK_NODE_T* erb_block_node = (const AST_ERB_BLOCK_NODE_T*) node;
27
30
 
28
31
  if (erb_block_node->end_node == NULL) {
29
- append_missingerb_end_tag_error(
30
- "ERB block",
32
+ append_missing_erb_end_tag_error(
33
+ hb_string("ERB block"),
31
34
  erb_block_node->tag_opening->location.start,
32
35
  erb_block_node->tag_closing->location.end,
36
+ allocator,
33
37
  node->errors
34
38
  );
35
39
  }
@@ -41,10 +45,11 @@ void check_erb_node_for_missing_end(const AST_NODE_T* node) {
41
45
  const AST_ERB_CASE_NODE_T* erb_case_node = (const AST_ERB_CASE_NODE_T*) node;
42
46
 
43
47
  if (erb_case_node->end_node == NULL) {
44
- append_missingerb_end_tag_error(
45
- "`<" "%" " case " "%" ">`",
48
+ append_missing_erb_end_tag_error(
49
+ hb_string("`<" "%" " case " "%" ">`"),
46
50
  erb_case_node->tag_opening->location.start,
47
51
  erb_case_node->tag_closing->location.end,
52
+ allocator,
48
53
  node->errors
49
54
  );
50
55
  }
@@ -56,10 +61,11 @@ void check_erb_node_for_missing_end(const AST_NODE_T* node) {
56
61
  const AST_ERB_CASE_MATCH_NODE_T* erb_case_match_node = (const AST_ERB_CASE_MATCH_NODE_T*) node;
57
62
 
58
63
  if (erb_case_match_node->end_node == NULL) {
59
- append_missingerb_end_tag_error(
60
- "`<" "%" " case " "%" ">`",
64
+ append_missing_erb_end_tag_error(
65
+ hb_string("`<" "%" " case " "%" ">`"),
61
66
  erb_case_match_node->tag_opening->location.start,
62
67
  erb_case_match_node->tag_closing->location.end,
68
+ allocator,
63
69
  node->errors
64
70
  );
65
71
  }
@@ -71,10 +77,11 @@ void check_erb_node_for_missing_end(const AST_NODE_T* node) {
71
77
  const AST_ERB_WHILE_NODE_T* erb_while_node = (const AST_ERB_WHILE_NODE_T*) node;
72
78
 
73
79
  if (erb_while_node->end_node == NULL) {
74
- append_missingerb_end_tag_error(
75
- "`<" "%" " while " "%" ">`",
80
+ append_missing_erb_end_tag_error(
81
+ hb_string("`<" "%" " while " "%" ">`"),
76
82
  erb_while_node->tag_opening->location.start,
77
83
  erb_while_node->tag_closing->location.end,
84
+ allocator,
78
85
  node->errors
79
86
  );
80
87
  }
@@ -86,10 +93,11 @@ void check_erb_node_for_missing_end(const AST_NODE_T* node) {
86
93
  const AST_ERB_UNTIL_NODE_T* erb_until_node = (const AST_ERB_UNTIL_NODE_T*) node;
87
94
 
88
95
  if (erb_until_node->end_node == NULL) {
89
- append_missingerb_end_tag_error(
90
- "`<" "%" " until " "%" ">`",
96
+ append_missing_erb_end_tag_error(
97
+ hb_string("`<" "%" " until " "%" ">`"),
91
98
  erb_until_node->tag_opening->location.start,
92
99
  erb_until_node->tag_closing->location.end,
100
+ allocator,
93
101
  node->errors
94
102
  );
95
103
  }
@@ -101,10 +109,11 @@ void check_erb_node_for_missing_end(const AST_NODE_T* node) {
101
109
  const AST_ERB_FOR_NODE_T* erb_for_node = (const AST_ERB_FOR_NODE_T*) node;
102
110
 
103
111
  if (erb_for_node->end_node == NULL) {
104
- append_missingerb_end_tag_error(
105
- "`<" "%" " for " "%" ">`",
112
+ append_missing_erb_end_tag_error(
113
+ hb_string("`<" "%" " for " "%" ">`"),
106
114
  erb_for_node->tag_opening->location.start,
107
115
  erb_for_node->tag_closing->location.end,
116
+ allocator,
108
117
  node->errors
109
118
  );
110
119
  }
@@ -116,10 +125,11 @@ void check_erb_node_for_missing_end(const AST_NODE_T* node) {
116
125
  const AST_ERB_BEGIN_NODE_T* erb_begin_node = (const AST_ERB_BEGIN_NODE_T*) node;
117
126
 
118
127
  if (erb_begin_node->end_node == NULL) {
119
- append_missingerb_end_tag_error(
120
- "`<" "%" " begin " "%" ">`",
128
+ append_missing_erb_end_tag_error(
129
+ hb_string("`<" "%" " begin " "%" ">`"),
121
130
  erb_begin_node->tag_opening->location.start,
122
131
  erb_begin_node->tag_closing->location.end,
132
+ allocator,
123
133
  node->errors
124
134
  );
125
135
  }
@@ -131,10 +141,11 @@ void check_erb_node_for_missing_end(const AST_NODE_T* node) {
131
141
  const AST_ERB_UNLESS_NODE_T* erb_unless_node = (const AST_ERB_UNLESS_NODE_T*) node;
132
142
 
133
143
  if (erb_unless_node->end_node == NULL) {
134
- append_missingerb_end_tag_error(
135
- "`<" "%" " unless " "%" ">`",
144
+ append_missing_erb_end_tag_error(
145
+ hb_string("`<" "%" " unless " "%" ">`"),
136
146
  erb_unless_node->tag_opening->location.start,
137
147
  erb_unless_node->tag_closing->location.end,
148
+ allocator,
138
149
  node->errors
139
150
  );
140
151
  }
@@ -0,0 +1,84 @@
1
+ #include "../include/analyze/analyze.h"
2
+ #include "../include/ast_node.h"
3
+ #include "../include/ast_nodes.h"
4
+ #include "../include/errors.h"
5
+ #include "../include/extract.h"
6
+ #include "../include/prism_helpers.h"
7
+ #include "../include/util/hb_allocator.h"
8
+ #include "../include/util/hb_string.h"
9
+
10
+ #include <prism.h>
11
+ #include <stdlib.h>
12
+ #include <string.h>
13
+
14
+ static void parse_erb_content_errors(AST_NODE_T* erb_node, const char* source, hb_allocator_T* allocator) {
15
+ if (!erb_node || erb_node->type != AST_ERB_CONTENT_NODE) { return; }
16
+ AST_ERB_CONTENT_NODE_T* content_node = (AST_ERB_CONTENT_NODE_T*) erb_node;
17
+
18
+ if (!content_node->content || hb_string_is_empty(content_node->content->value)) { return; }
19
+
20
+ char* content = hb_string_to_c_string_using_malloc(content_node->content->value);
21
+ if (!content) { return; }
22
+
23
+ pm_parser_t parser;
24
+ pm_options_t options = { 0, .partial_script = true };
25
+ pm_parser_init(&parser, (const uint8_t*) content, strlen(content), &options);
26
+
27
+ pm_node_t* root = pm_parse(&parser);
28
+
29
+ const pm_diagnostic_t* error = (const pm_diagnostic_t*) parser.error_list.head;
30
+
31
+ if (error != NULL) {
32
+ RUBY_PARSE_ERROR_T* parse_error = ruby_parse_error_from_prism_error_with_positions(
33
+ error,
34
+ erb_node->location.start,
35
+ erb_node->location.end,
36
+ allocator
37
+ );
38
+
39
+ hb_array_append(erb_node->errors, parse_error);
40
+ }
41
+
42
+ pm_node_destroy(&parser, root);
43
+ pm_parser_free(&parser);
44
+ pm_options_free(&options);
45
+ free(content);
46
+ }
47
+
48
+ void herb_analyze_parse_errors(AST_DOCUMENT_NODE_T* document, const char* source, hb_allocator_T* allocator) {
49
+ char* extracted_ruby = herb_extract_ruby_with_semicolons(source, allocator);
50
+
51
+ if (!extracted_ruby) { return; }
52
+
53
+ pm_parser_t parser;
54
+ pm_options_t options = { 0, .partial_script = true };
55
+ pm_parser_init(&parser, (const uint8_t*) extracted_ruby, strlen(extracted_ruby), &options);
56
+
57
+ pm_node_t* root = pm_parse(&parser);
58
+
59
+ for (const pm_diagnostic_t* error = (const pm_diagnostic_t*) parser.error_list.head; error != NULL;
60
+ error = (const pm_diagnostic_t*) error->node.next) {
61
+ size_t error_offset = (size_t) (error->location.start - parser.start);
62
+
63
+ if (strstr(error->message, "unexpected ';'") != NULL) {
64
+ if (error_offset < strlen(extracted_ruby) && extracted_ruby[error_offset] == ';') {
65
+ if (error_offset >= strlen(source) || source[error_offset] != ';') {
66
+ AST_NODE_T* erb_node = find_erb_content_at_offset(document, source, error_offset);
67
+
68
+ if (erb_node) { parse_erb_content_errors(erb_node, source, allocator); }
69
+
70
+ continue;
71
+ }
72
+ }
73
+ }
74
+
75
+ RUBY_PARSE_ERROR_T* parse_error =
76
+ ruby_parse_error_from_prism_error(error, (AST_NODE_T*) document, source, &parser, allocator);
77
+ hb_array_append(document->base.errors, parse_error);
78
+ }
79
+
80
+ pm_node_destroy(&parser, root);
81
+ pm_parser_free(&parser);
82
+ pm_options_free(&options);
83
+ hb_allocator_dealloc(allocator, extracted_ruby);
84
+ }