@herb-tools/node 0.8.8 → 0.8.10

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 (33) hide show
  1. package/dist/herb-node.esm.js +1 -1
  2. package/extension/error_helpers.cpp +27 -1
  3. package/extension/error_helpers.h +2 -1
  4. package/extension/libherb/analyze.c +28 -12
  5. package/extension/libherb/analyze_helpers.c +32 -9
  6. package/extension/libherb/analyze_helpers.h +18 -15
  7. package/extension/libherb/analyze_missing_end.c +1 -1
  8. package/extension/libherb/analyze_transform.c +1 -1
  9. package/extension/libherb/ast_nodes.c +1 -1
  10. package/extension/libherb/ast_nodes.h +1 -1
  11. package/extension/libherb/ast_pretty_print.c +1 -1
  12. package/extension/libherb/ast_pretty_print.h +1 -1
  13. package/extension/libherb/errors.c +38 -1
  14. package/extension/libherb/errors.h +9 -1
  15. package/extension/libherb/extract.c +6 -3
  16. package/extension/libherb/include/analyze_helpers.h +18 -15
  17. package/extension/libherb/include/ast_nodes.h +1 -1
  18. package/extension/libherb/include/ast_pretty_print.h +1 -1
  19. package/extension/libherb/include/errors.h +9 -1
  20. package/extension/libherb/include/util/string.h +11 -0
  21. package/extension/libherb/include/version.h +1 -1
  22. package/extension/libherb/main.c +32 -44
  23. package/extension/libherb/parser.c +6 -5
  24. package/extension/libherb/parser_match_tags.c +1 -1
  25. package/extension/libherb/util/string.h +11 -0
  26. package/extension/libherb/version.h +1 -1
  27. package/extension/libherb/visitor.c +1 -1
  28. package/extension/nodes.cpp +1 -1
  29. package/extension/nodes.h +1 -1
  30. package/extension/prism/include/prism/ast.h +4 -4
  31. package/extension/prism/include/prism/version.h +2 -2
  32. package/extension/prism/src/prism.c +1 -1
  33. package/package.json +2 -2
@@ -6,7 +6,7 @@ import { createRequire } from 'module';
6
6
  import { fileURLToPath } from 'url';
7
7
 
8
8
  var name = "@herb-tools/node";
9
- var version = "0.8.8";
9
+ var version = "0.8.10";
10
10
  var packageJSON = {
11
11
  name: name,
12
12
  version: version};
@@ -1,5 +1,5 @@
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.8/templates/javascript/packages/node/extension/error_helpers.cpp.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.10/templates/javascript/packages/node/extension/error_helpers.cpp.erb
3
3
 
4
4
  #include <node_api.h>
5
5
  #include "error_helpers.h"
@@ -354,6 +354,29 @@ napi_value ERBMultipleBlocksInTagErrorFromCStruct(napi_env env, ERB_MULTIPLE_BLO
354
354
  return result;
355
355
  }
356
356
 
357
+ napi_value ERBCaseWithConditionsErrorFromCStruct(napi_env env, ERB_CASE_WITH_CONDITIONS_ERROR_T* erb_case_with_conditions_error) {
358
+ if (!erb_case_with_conditions_error) {
359
+ napi_value null_value;
360
+ napi_get_null(env, &null_value);
361
+ return null_value;
362
+ }
363
+
364
+ napi_value result;
365
+ napi_create_object(env, &result);
366
+
367
+ napi_value type = CreateString(env, error_type_to_string(&erb_case_with_conditions_error->base));
368
+ napi_set_named_property(env, result, "type", type);
369
+
370
+ napi_value message = CreateString(env, erb_case_with_conditions_error->base.message);
371
+ napi_set_named_property(env, result, "message", message);
372
+
373
+ napi_value location = CreateLocation(env, erb_case_with_conditions_error->base.location);
374
+ napi_set_named_property(env, result, "location", location);
375
+
376
+
377
+ return result;
378
+ }
379
+
357
380
 
358
381
  napi_value ErrorsArrayFromCArray(napi_env env, hb_array_T* array) {
359
382
  napi_value result;
@@ -416,6 +439,9 @@ napi_value ErrorFromCStruct(napi_env env, ERROR_T* error) {
416
439
  case ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR:
417
440
  return ERBMultipleBlocksInTagErrorFromCStruct(env, (ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR_T*) error);
418
441
  break;
442
+ case ERB_CASE_WITH_CONDITIONS_ERROR:
443
+ return ERBCaseWithConditionsErrorFromCStruct(env, (ERB_CASE_WITH_CONDITIONS_ERROR_T*) error);
444
+ break;
419
445
  default:
420
446
  napi_value null_value;
421
447
  napi_get_null(env, &null_value);
@@ -1,5 +1,5 @@
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.8/templates/javascript/packages/node/extension/error_helpers.h.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.10/templates/javascript/packages/node/extension/error_helpers.h.erb
3
3
 
4
4
  #ifndef HERB_EXTENSION_ERRORS_H
5
5
  #define HERB_EXTENSION_ERRORS_H
@@ -25,5 +25,6 @@ napi_value RubyParseErrorFromCStruct(napi_env env, RUBY_PARSE_ERROR_T* ruby_pars
25
25
  napi_value ERBControlFlowScopeErrorFromCStruct(napi_env env, ERB_CONTROL_FLOW_SCOPE_ERROR_T* erb_control_flow_scope_error);
26
26
  napi_value MissingERBEndTagErrorFromCStruct(napi_env env, MISSINGERB_END_TAG_ERROR_T* missingerb_end_tag_error);
27
27
  napi_value ERBMultipleBlocksInTagErrorFromCStruct(napi_env env, ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR_T* erb_multiple_blocks_in_tag_error);
28
+ napi_value ERBCaseWithConditionsErrorFromCStruct(napi_env env, ERB_CASE_WITH_CONDITIONS_ERROR_T* erb_case_with_conditions_error);
28
29
 
29
30
  #endif
@@ -14,6 +14,7 @@
14
14
  #include "include/util.h"
15
15
  #include "include/util/hb_array.h"
16
16
  #include "include/util/hb_string.h"
17
+ #include "include/util/string.h"
17
18
  #include "include/visitor.h"
18
19
 
19
20
  #include <prism.h>
@@ -34,17 +35,20 @@ static analyzed_ruby_T* herb_analyze_ruby(hb_string_T source) {
34
35
  pm_visit_node(analyzed->root, search_until_nodes, analyzed);
35
36
  pm_visit_node(analyzed->root, search_begin_nodes, analyzed);
36
37
  pm_visit_node(analyzed->root, search_unless_nodes, analyzed);
38
+ pm_visit_node(analyzed->root, search_when_nodes, analyzed);
39
+ pm_visit_node(analyzed->root, search_in_nodes, analyzed);
37
40
 
38
- search_elsif_nodes(analyzed);
39
- search_else_nodes(analyzed);
40
- search_end_nodes(analyzed);
41
- search_when_nodes(analyzed);
42
- search_in_nodes(analyzed);
43
- search_rescue_nodes(analyzed);
44
- search_ensure_nodes(analyzed);
41
+ search_unexpected_elsif_nodes(analyzed);
42
+ search_unexpected_else_nodes(analyzed);
43
+ search_unexpected_end_nodes(analyzed);
44
+ search_unexpected_when_nodes(analyzed);
45
+ search_unexpected_in_nodes(analyzed);
46
+
47
+ search_unexpected_rescue_nodes(analyzed);
48
+ search_unexpected_ensure_nodes(analyzed);
45
49
  search_yield_nodes(analyzed->root, analyzed);
46
50
  search_then_keywords(analyzed->root, analyzed);
47
- search_block_closing_nodes(analyzed);
51
+ search_unexpected_block_closing_nodes(analyzed);
48
52
 
49
53
  if (!analyzed->valid) { pm_visit_node(analyzed->root, search_unclosed_control_flows, analyzed); }
50
54
 
@@ -57,8 +61,8 @@ static bool analyze_erb_content(const AST_NODE_T* node, void* data) {
57
61
 
58
62
  const char* opening = erb_content_node->tag_opening->value;
59
63
 
60
- if (strcmp(opening, "<%%") != 0 && strcmp(opening, "<%%=") != 0 && strcmp(opening, "<%#") != 0
61
- && strcmp(opening, "<%graphql") != 0) {
64
+ if (!string_equals(opening, "<%%") && !string_equals(opening, "<%%=") && !string_equals(opening, "<%#")
65
+ && !string_equals(opening, "<%graphql")) {
62
66
  analyzed_ruby_T* analyzed = herb_analyze_ruby(hb_string(erb_content_node->content->value));
63
67
 
64
68
  erb_content_node->parsed = true;
@@ -72,6 +76,16 @@ static bool analyze_erb_content(const AST_NODE_T* node, void* data) {
72
76
  erb_content_node->base.errors
73
77
  );
74
78
  }
79
+
80
+ if (!analyzed->valid
81
+ && ((analyzed->case_node_count > 0 && analyzed->when_node_count > 0)
82
+ || (analyzed->case_match_node_count > 0 && analyzed->in_node_count > 0))) {
83
+ append_erb_case_with_conditions_error(
84
+ erb_content_node->base.location.start,
85
+ erb_content_node->base.location.end,
86
+ erb_content_node->base.errors
87
+ );
88
+ }
75
89
  } else {
76
90
  erb_content_node->parsed = false;
77
91
  erb_content_node->valid = true;
@@ -274,12 +288,14 @@ static control_type_t detect_control_type(AST_ERB_CONTENT_NODE_T* erb_node) {
274
288
  if (has_elsif_node(ruby)) { return CONTROL_TYPE_ELSIF; }
275
289
  if (has_else_node(ruby)) { return CONTROL_TYPE_ELSE; }
276
290
  if (has_end(ruby)) { return CONTROL_TYPE_END; }
277
- if (has_when_node(ruby)) { return CONTROL_TYPE_WHEN; }
278
- if (has_in_node(ruby)) { return CONTROL_TYPE_IN; }
291
+ if (has_when_node(ruby) && !has_case_node(ruby)) { return CONTROL_TYPE_WHEN; }
292
+ if (has_in_node(ruby) && !has_case_match_node(ruby)) { return CONTROL_TYPE_IN; }
279
293
  if (has_rescue_node(ruby)) { return CONTROL_TYPE_RESCUE; }
280
294
  if (has_ensure_node(ruby)) { return CONTROL_TYPE_ENSURE; }
281
295
  if (has_block_closing(ruby)) { return CONTROL_TYPE_BLOCK_CLOSE; }
282
296
 
297
+ if (ruby->unclosed_control_flow_count == 0 && !has_yield_node(ruby)) { return CONTROL_TYPE_UNKNOWN; }
298
+
283
299
  return find_earliest_control_keyword(root, ruby->parser.start);
284
300
  }
285
301
 
@@ -3,6 +3,7 @@
3
3
  #include <string.h>
4
4
 
5
5
  #include "include/analyzed_ruby.h"
6
+ #include "include/util/string.h"
6
7
 
7
8
  bool has_if_node(analyzed_ruby_T* analyzed) {
8
9
  return analyzed->if_node_count > 0;
@@ -83,7 +84,7 @@ bool has_then_keyword(analyzed_ruby_T* analyzed) {
83
84
  bool has_error_message(analyzed_ruby_T* anlayzed, const char* message) {
84
85
  for (const pm_diagnostic_t* error = (const pm_diagnostic_t*) anlayzed->parser.error_list.head; error != NULL;
85
86
  error = (const pm_diagnostic_t*) error->node.next) {
86
- if (strcmp(error->message, message) == 0) { return true; }
87
+ if (string_equals(error->message, message)) { return true; }
87
88
  }
88
89
 
89
90
  return false;
@@ -242,7 +243,28 @@ bool search_unless_nodes(const pm_node_t* node, void* data) {
242
243
  return false;
243
244
  }
244
245
 
245
- bool search_elsif_nodes(analyzed_ruby_T* analyzed) {
246
+ bool search_when_nodes(const pm_node_t* node, void* data) {
247
+ analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
248
+
249
+ if (node->type == PM_WHEN_NODE) { analyzed->when_node_count++; }
250
+
251
+ pm_visit_child_nodes(node, search_when_nodes, analyzed);
252
+
253
+ return false;
254
+ }
255
+
256
+ bool search_in_nodes(const pm_node_t* node, void* data) {
257
+ analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
258
+
259
+ if (node->type == PM_IN_NODE) { analyzed->in_node_count++; }
260
+ if (node->type == PM_MATCH_PREDICATE_NODE) { analyzed->in_node_count++; }
261
+
262
+ pm_visit_child_nodes(node, search_in_nodes, analyzed);
263
+
264
+ return false;
265
+ }
266
+
267
+ bool search_unexpected_elsif_nodes(analyzed_ruby_T* analyzed) {
246
268
  if (has_error_message(analyzed, "unexpected 'elsif', ignoring it")) {
247
269
  analyzed->elsif_node_count++;
248
270
  return true;
@@ -251,7 +273,7 @@ bool search_elsif_nodes(analyzed_ruby_T* analyzed) {
251
273
  return false;
252
274
  }
253
275
 
254
- bool search_else_nodes(analyzed_ruby_T* analyzed) {
276
+ bool search_unexpected_else_nodes(analyzed_ruby_T* analyzed) {
255
277
  if (has_error_message(analyzed, "unexpected 'else', ignoring it")) {
256
278
  analyzed->else_node_count++;
257
279
  return true;
@@ -260,7 +282,7 @@ bool search_else_nodes(analyzed_ruby_T* analyzed) {
260
282
  return false;
261
283
  }
262
284
 
263
- bool search_end_nodes(analyzed_ruby_T* analyzed) {
285
+ bool search_unexpected_end_nodes(analyzed_ruby_T* analyzed) {
264
286
  if (has_error_message(analyzed, "unexpected 'end', ignoring it")) {
265
287
  if (has_error_message(analyzed, "unexpected '=', ignoring it")) {
266
288
  // `=end`
@@ -274,7 +296,7 @@ bool search_end_nodes(analyzed_ruby_T* analyzed) {
274
296
  return false;
275
297
  }
276
298
 
277
- bool search_block_closing_nodes(analyzed_ruby_T* analyzed) {
299
+ bool search_unexpected_block_closing_nodes(analyzed_ruby_T* analyzed) {
278
300
  if (has_error_message(analyzed, "unexpected '}', ignoring it")) {
279
301
  analyzed->block_closing_count++;
280
302
  return true;
@@ -283,7 +305,7 @@ bool search_block_closing_nodes(analyzed_ruby_T* analyzed) {
283
305
  return false;
284
306
  }
285
307
 
286
- bool search_when_nodes(analyzed_ruby_T* analyzed) {
308
+ bool search_unexpected_when_nodes(analyzed_ruby_T* analyzed) {
287
309
  if (has_error_message(analyzed, "unexpected 'when', ignoring it")) {
288
310
  analyzed->when_node_count++;
289
311
  return true;
@@ -292,7 +314,7 @@ bool search_when_nodes(analyzed_ruby_T* analyzed) {
292
314
  return false;
293
315
  }
294
316
 
295
- bool search_in_nodes(analyzed_ruby_T* analyzed) {
317
+ bool search_unexpected_in_nodes(analyzed_ruby_T* analyzed) {
296
318
  if (has_error_message(analyzed, "unexpected 'in', ignoring it")) {
297
319
  analyzed->in_node_count++;
298
320
  return true;
@@ -301,7 +323,7 @@ bool search_in_nodes(analyzed_ruby_T* analyzed) {
301
323
  return false;
302
324
  }
303
325
 
304
- bool search_rescue_nodes(analyzed_ruby_T* analyzed) {
326
+ bool search_unexpected_rescue_nodes(analyzed_ruby_T* analyzed) {
305
327
  if (has_error_message(analyzed, "unexpected 'rescue', ignoring it")) {
306
328
  analyzed->rescue_node_count++;
307
329
  return true;
@@ -310,7 +332,7 @@ bool search_rescue_nodes(analyzed_ruby_T* analyzed) {
310
332
  return false;
311
333
  }
312
334
 
313
- bool search_ensure_nodes(analyzed_ruby_T* analyzed) {
335
+ bool search_unexpected_ensure_nodes(analyzed_ruby_T* analyzed) {
314
336
  if (has_error_message(analyzed, "unexpected 'ensure', ignoring it")) {
315
337
  analyzed->ensure_node_count++;
316
338
  return true;
@@ -468,6 +490,7 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
468
490
  if (has_opening && !has_valid_block_closing(block_node->opening_loc, block_node->closing_loc)) {
469
491
  analyzed->unclosed_control_flow_count++;
470
492
  }
493
+
471
494
  break;
472
495
  }
473
496
 
@@ -34,26 +34,29 @@ bool is_brace_block(pm_location_t opening_location);
34
34
  bool is_closing_brace(pm_location_t location);
35
35
  bool has_valid_block_closing(pm_location_t opening_loc, pm_location_t closing_loc);
36
36
 
37
- bool search_if_nodes(const pm_node_t* node, void* data);
37
+ bool search_begin_nodes(const pm_node_t* node, void* data);
38
38
  bool search_block_nodes(const pm_node_t* node, void* data);
39
- bool search_case_nodes(const pm_node_t* node, void* data);
40
39
  bool search_case_match_nodes(const pm_node_t* node, void* data);
41
- bool search_while_nodes(const pm_node_t* node, void* data);
40
+ bool search_case_nodes(const pm_node_t* node, void* data);
42
41
  bool search_for_nodes(const pm_node_t* node, void* data);
43
- bool search_until_nodes(const pm_node_t* node, void* data);
44
- bool search_begin_nodes(const pm_node_t* node, void* data);
45
- bool search_unless_nodes(const pm_node_t* node, void* data);
46
- bool search_elsif_nodes(analyzed_ruby_T* analyzed);
47
- bool search_else_nodes(analyzed_ruby_T* analyzed);
48
- bool search_end_nodes(analyzed_ruby_T* analyzed);
49
- bool search_block_closing_nodes(analyzed_ruby_T* analyzed);
50
- bool search_when_nodes(analyzed_ruby_T* analyzed);
51
- bool search_in_nodes(analyzed_ruby_T* analyzed);
52
- bool search_rescue_nodes(analyzed_ruby_T* analyzed);
53
- bool search_ensure_nodes(analyzed_ruby_T* analyzed);
54
- bool search_yield_nodes(const pm_node_t* node, void* data);
42
+ bool search_if_nodes(const pm_node_t* node, void* data);
43
+ bool search_in_nodes(const pm_node_t* node, void* data);
55
44
  bool search_then_keywords(const pm_node_t* node, void* data);
56
45
  bool search_unclosed_control_flows(const pm_node_t* node, void* data);
46
+ bool search_unless_nodes(const pm_node_t* node, void* data);
47
+ bool search_until_nodes(const pm_node_t* node, void* data);
48
+ bool search_when_nodes(const pm_node_t* node, void* data);
49
+ bool search_while_nodes(const pm_node_t* node, void* data);
50
+ bool search_yield_nodes(const pm_node_t* node, void* data);
51
+
52
+ bool search_unexpected_block_closing_nodes(analyzed_ruby_T* analyzed);
53
+ bool search_unexpected_else_nodes(analyzed_ruby_T* analyzed);
54
+ bool search_unexpected_elsif_nodes(analyzed_ruby_T* analyzed);
55
+ bool search_unexpected_end_nodes(analyzed_ruby_T* analyzed);
56
+ bool search_unexpected_ensure_nodes(analyzed_ruby_T* analyzed);
57
+ bool search_unexpected_in_nodes(analyzed_ruby_T* analyzed);
58
+ bool search_unexpected_rescue_nodes(analyzed_ruby_T* analyzed);
59
+ bool search_unexpected_when_nodes(analyzed_ruby_T* analyzed);
57
60
 
58
61
  void check_erb_node_for_missing_end(const AST_NODE_T* node);
59
62
 
@@ -1,5 +1,5 @@
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.8/templates/src/analyze_missing_end.c.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.10/templates/src/analyze_missing_end.c.erb
3
3
 
4
4
  #include "include/analyze_helpers.h"
5
5
  #include "include/errors.h"
@@ -1,5 +1,5 @@
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.8/templates/src/analyze_transform.c.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.10/templates/src/analyze_transform.c.erb
3
3
 
4
4
  #include "include/analyze.h"
5
5
  #include "include/visitor.h"
@@ -1,5 +1,5 @@
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.8/templates/src/ast_nodes.c.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.10/templates/src/ast_nodes.c.erb
3
3
 
4
4
  #include <stdio.h>
5
5
  #include <stdbool.h>
@@ -1,5 +1,5 @@
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.8/templates/src/include/ast_nodes.h.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.10/templates/src/include/ast_nodes.h.erb
3
3
 
4
4
  #ifndef HERB_AST_NODES_H
5
5
  #define HERB_AST_NODES_H
@@ -1,5 +1,5 @@
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.8/templates/src/ast_pretty_print.c.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.10/templates/src/ast_pretty_print.c.erb
3
3
 
4
4
  #include "include/analyze_helpers.h"
5
5
  #include "include/ast_node.h"
@@ -1,5 +1,5 @@
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.8/templates/src/include/ast_pretty_print.h.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.10/templates/src/include/ast_pretty_print.h.erb
3
3
 
4
4
  #ifndef HERB_AST_PRETTY_PRINT_H
5
5
  #define HERB_AST_PRETTY_PRINT_H
@@ -1,5 +1,5 @@
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.8/templates/src/errors.c.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.10/templates/src/errors.c.erb
3
3
 
4
4
  #include "include/errors.h"
5
5
  #include "include/location.h"
@@ -511,6 +511,20 @@ void append_erb_multiple_blocks_in_tag_error(position_T start, position_T end, h
511
511
  hb_array_append(errors, erb_multiple_blocks_in_tag_error_init(start, end));
512
512
  }
513
513
 
514
+ ERB_CASE_WITH_CONDITIONS_ERROR_T* erb_case_with_conditions_error_init(position_T start, position_T end) {
515
+ ERB_CASE_WITH_CONDITIONS_ERROR_T* erb_case_with_conditions_error = malloc(sizeof(ERB_CASE_WITH_CONDITIONS_ERROR_T));
516
+
517
+ error_init(&erb_case_with_conditions_error->base, ERB_CASE_WITH_CONDITIONS_ERROR, start, end);
518
+
519
+ erb_case_with_conditions_error->base.message = herb_strdup("A `case` statement with `when`/`in` in a single ERB tag cannot be formatted. Use separate tags for `case` and its conditions.");
520
+
521
+ return erb_case_with_conditions_error;
522
+ }
523
+
524
+ void append_erb_case_with_conditions_error(position_T start, position_T end, hb_array_T* errors) {
525
+ hb_array_append(errors, erb_case_with_conditions_error_init(start, end));
526
+ }
527
+
514
528
  const char* error_type_to_string(ERROR_T* error) {
515
529
  switch (error->type) {
516
530
  case UNEXPECTED_ERROR: return "UNEXPECTED_ERROR";
@@ -525,6 +539,7 @@ const char* error_type_to_string(ERROR_T* error) {
525
539
  case ERB_CONTROL_FLOW_SCOPE_ERROR: return "ERB_CONTROL_FLOW_SCOPE_ERROR";
526
540
  case MISSINGERB_END_TAG_ERROR: return "MISSINGERB_END_TAG_ERROR";
527
541
  case ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR: return "ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR";
542
+ case ERB_CASE_WITH_CONDITIONS_ERROR: return "ERB_CASE_WITH_CONDITIONS_ERROR";
528
543
  }
529
544
 
530
545
  return "Unknown error_type_T";
@@ -544,6 +559,7 @@ const char* error_human_type(ERROR_T* error) {
544
559
  case ERB_CONTROL_FLOW_SCOPE_ERROR: return "ERBControlFlowScopeError";
545
560
  case MISSINGERB_END_TAG_ERROR: return "MissingERBEndTagError";
546
561
  case ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR: return "ERBMultipleBlocksInTagError";
562
+ case ERB_CASE_WITH_CONDITIONS_ERROR: return "ERBCaseWithConditionsError";
547
563
  }
548
564
 
549
565
  return "Unknown error_type_T";
@@ -638,6 +654,12 @@ static void error_free_erb_multiple_blocks_in_tag_error(ERB_MULTIPLE_BLOCKS_IN_T
638
654
  error_free_base_error(&erb_multiple_blocks_in_tag_error->base);
639
655
  }
640
656
 
657
+ static void error_free_erb_case_with_conditions_error(ERB_CASE_WITH_CONDITIONS_ERROR_T* erb_case_with_conditions_error) {
658
+ /* no ERB_CASE_WITH_CONDITIONS_ERROR_T specific fields to free up */
659
+
660
+ error_free_base_error(&erb_case_with_conditions_error->base);
661
+ }
662
+
641
663
  void error_free(ERROR_T* error) {
642
664
  if (!error) { return; }
643
665
 
@@ -654,6 +676,7 @@ void error_free(ERROR_T* error) {
654
676
  case ERB_CONTROL_FLOW_SCOPE_ERROR: error_free_erb_control_flow_scope_error((ERB_CONTROL_FLOW_SCOPE_ERROR_T*) error); break;
655
677
  case MISSINGERB_END_TAG_ERROR: error_free_missingerb_end_tag_error((MISSINGERB_END_TAG_ERROR_T*) error); break;
656
678
  case ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR: error_free_erb_multiple_blocks_in_tag_error((ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR_T*) error); break;
679
+ case ERB_CASE_WITH_CONDITIONS_ERROR: error_free_erb_case_with_conditions_error((ERB_CASE_WITH_CONDITIONS_ERROR_T*) error); break;
657
680
  }
658
681
  }
659
682
 
@@ -877,6 +900,19 @@ static void error_pretty_print_erb_multiple_blocks_in_tag_error(ERB_MULTIPLE_BLO
877
900
  pretty_print_quoted_property(hb_string("message"), hb_string(error->base.message), indent, relative_indent, true, buffer);
878
901
  }
879
902
 
903
+ static void error_pretty_print_erb_case_with_conditions_error(ERB_CASE_WITH_CONDITIONS_ERROR_T* error, const size_t indent, const size_t relative_indent, hb_buffer_T* buffer) {
904
+ if (!error) { return; }
905
+
906
+ hb_buffer_append(buffer, "@ ");
907
+ hb_buffer_append(buffer, error_human_type((ERROR_T*) error));
908
+ hb_buffer_append(buffer, " ");
909
+
910
+ pretty_print_location(error->base.location, buffer);
911
+ hb_buffer_append(buffer, "\n");
912
+
913
+ pretty_print_quoted_property(hb_string("message"), hb_string(error->base.message), indent, relative_indent, true, buffer);
914
+ }
915
+
880
916
  void error_pretty_print(ERROR_T* error, const size_t indent, const size_t relative_indent, hb_buffer_T* buffer) {
881
917
  if (!error) { return; }
882
918
 
@@ -893,5 +929,6 @@ void error_pretty_print(ERROR_T* error, const size_t indent, const size_t relati
893
929
  case ERB_CONTROL_FLOW_SCOPE_ERROR: error_pretty_print_erb_control_flow_scope_error((ERB_CONTROL_FLOW_SCOPE_ERROR_T*) error, indent, relative_indent, buffer); break;
894
930
  case MISSINGERB_END_TAG_ERROR: error_pretty_print_missingerb_end_tag_error((MISSINGERB_END_TAG_ERROR_T*) error, indent, relative_indent, buffer); break;
895
931
  case ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR: error_pretty_print_erb_multiple_blocks_in_tag_error((ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR_T*) error, indent, relative_indent, buffer); break;
932
+ case ERB_CASE_WITH_CONDITIONS_ERROR: error_pretty_print_erb_case_with_conditions_error((ERB_CASE_WITH_CONDITIONS_ERROR_T*) error, indent, relative_indent, buffer); break;
896
933
  }
897
934
  }
@@ -1,5 +1,5 @@
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.8/templates/src/include/errors.h.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.10/templates/src/include/errors.h.erb
3
3
 
4
4
  #ifndef HERB_ERRORS_H
5
5
  #define HERB_ERRORS_H
@@ -24,6 +24,7 @@ typedef enum {
24
24
  ERB_CONTROL_FLOW_SCOPE_ERROR,
25
25
  MISSINGERB_END_TAG_ERROR,
26
26
  ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR,
27
+ ERB_CASE_WITH_CONDITIONS_ERROR,
27
28
  } error_type_T;
28
29
 
29
30
  typedef struct ERROR_STRUCT {
@@ -102,6 +103,11 @@ typedef struct {
102
103
  /* no additional fields */
103
104
  } ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR_T;
104
105
 
106
+ typedef struct {
107
+ ERROR_T base;
108
+ /* no additional fields */
109
+ } ERB_CASE_WITH_CONDITIONS_ERROR_T;
110
+
105
111
  UNEXPECTED_ERROR_T* unexpected_error_init(const char* description, const char* expected, const char* found, position_T start, position_T end);
106
112
  void append_unexpected_error(const char* description, const char* expected, const char* found, position_T start, position_T end, hb_array_T* errors);
107
113
  UNEXPECTED_TOKEN_ERROR_T* unexpected_token_error_init(token_type_T expected_type, token_T* found, position_T start, position_T end);
@@ -126,6 +132,8 @@ MISSINGERB_END_TAG_ERROR_T* missingerb_end_tag_error_init(const char* keyword, p
126
132
  void append_missingerb_end_tag_error(const char* keyword, position_T start, position_T end, hb_array_T* errors);
127
133
  ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR_T* erb_multiple_blocks_in_tag_error_init(position_T start, position_T end);
128
134
  void append_erb_multiple_blocks_in_tag_error(position_T start, position_T end, hb_array_T* errors);
135
+ ERB_CASE_WITH_CONDITIONS_ERROR_T* erb_case_with_conditions_error_init(position_T start, position_T end);
136
+ void append_erb_case_with_conditions_error(position_T start, position_T end, hb_array_T* errors);
129
137
 
130
138
  void error_init(ERROR_T* error, error_type_T type, position_T start, position_T end);
131
139
 
@@ -3,7 +3,9 @@
3
3
  #include "include/lexer.h"
4
4
  #include "include/util/hb_array.h"
5
5
  #include "include/util/hb_buffer.h"
6
+ #include "include/util/string.h"
6
7
 
8
+ #include <assert.h>
7
9
  #include <stdlib.h>
8
10
  #include <string.h>
9
11
 
@@ -22,11 +24,11 @@ void herb_extract_ruby_to_buffer(const char* source, hb_buffer_T* output) {
22
24
  }
23
25
 
24
26
  case TOKEN_ERB_START: {
25
- if (strcmp(token->value, "<%#") == 0) {
27
+ if (string_equals(token->value, "<%#")) {
26
28
  skip_erb_content = true;
27
29
  is_comment_tag = true;
28
- } else if (strcmp(token->value, "<%%") == 0 || strcmp(token->value, "<%%=") == 0
29
- || strcmp(token->value, "<%graphql") == 0) {
30
+ } else if (string_equals(token->value, "<%%") || string_equals(token->value, "<%%=")
31
+ || string_equals(token->value, "<%graphql")) {
30
32
  skip_erb_content = true;
31
33
  is_comment_tag = false;
32
34
  } else {
@@ -129,6 +131,7 @@ char* herb_extract(const char* source, const herb_extract_language_T language) {
129
131
  switch (language) {
130
132
  case HERB_EXTRACT_LANGUAGE_RUBY: herb_extract_ruby_to_buffer(source, &output); break;
131
133
  case HERB_EXTRACT_LANGUAGE_HTML: herb_extract_html_to_buffer(source, &output); break;
134
+ default: assert(0 && "invalid extract language");
132
135
  }
133
136
 
134
137
  return output.value;
@@ -34,26 +34,29 @@ bool is_brace_block(pm_location_t opening_location);
34
34
  bool is_closing_brace(pm_location_t location);
35
35
  bool has_valid_block_closing(pm_location_t opening_loc, pm_location_t closing_loc);
36
36
 
37
- bool search_if_nodes(const pm_node_t* node, void* data);
37
+ bool search_begin_nodes(const pm_node_t* node, void* data);
38
38
  bool search_block_nodes(const pm_node_t* node, void* data);
39
- bool search_case_nodes(const pm_node_t* node, void* data);
40
39
  bool search_case_match_nodes(const pm_node_t* node, void* data);
41
- bool search_while_nodes(const pm_node_t* node, void* data);
40
+ bool search_case_nodes(const pm_node_t* node, void* data);
42
41
  bool search_for_nodes(const pm_node_t* node, void* data);
43
- bool search_until_nodes(const pm_node_t* node, void* data);
44
- bool search_begin_nodes(const pm_node_t* node, void* data);
45
- bool search_unless_nodes(const pm_node_t* node, void* data);
46
- bool search_elsif_nodes(analyzed_ruby_T* analyzed);
47
- bool search_else_nodes(analyzed_ruby_T* analyzed);
48
- bool search_end_nodes(analyzed_ruby_T* analyzed);
49
- bool search_block_closing_nodes(analyzed_ruby_T* analyzed);
50
- bool search_when_nodes(analyzed_ruby_T* analyzed);
51
- bool search_in_nodes(analyzed_ruby_T* analyzed);
52
- bool search_rescue_nodes(analyzed_ruby_T* analyzed);
53
- bool search_ensure_nodes(analyzed_ruby_T* analyzed);
54
- bool search_yield_nodes(const pm_node_t* node, void* data);
42
+ bool search_if_nodes(const pm_node_t* node, void* data);
43
+ bool search_in_nodes(const pm_node_t* node, void* data);
55
44
  bool search_then_keywords(const pm_node_t* node, void* data);
56
45
  bool search_unclosed_control_flows(const pm_node_t* node, void* data);
46
+ bool search_unless_nodes(const pm_node_t* node, void* data);
47
+ bool search_until_nodes(const pm_node_t* node, void* data);
48
+ bool search_when_nodes(const pm_node_t* node, void* data);
49
+ bool search_while_nodes(const pm_node_t* node, void* data);
50
+ bool search_yield_nodes(const pm_node_t* node, void* data);
51
+
52
+ bool search_unexpected_block_closing_nodes(analyzed_ruby_T* analyzed);
53
+ bool search_unexpected_else_nodes(analyzed_ruby_T* analyzed);
54
+ bool search_unexpected_elsif_nodes(analyzed_ruby_T* analyzed);
55
+ bool search_unexpected_end_nodes(analyzed_ruby_T* analyzed);
56
+ bool search_unexpected_ensure_nodes(analyzed_ruby_T* analyzed);
57
+ bool search_unexpected_in_nodes(analyzed_ruby_T* analyzed);
58
+ bool search_unexpected_rescue_nodes(analyzed_ruby_T* analyzed);
59
+ bool search_unexpected_when_nodes(analyzed_ruby_T* analyzed);
57
60
 
58
61
  void check_erb_node_for_missing_end(const AST_NODE_T* node);
59
62
 
@@ -1,5 +1,5 @@
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.8/templates/src/include/ast_nodes.h.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.10/templates/src/include/ast_nodes.h.erb
3
3
 
4
4
  #ifndef HERB_AST_NODES_H
5
5
  #define HERB_AST_NODES_H
@@ -1,5 +1,5 @@
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.8/templates/src/include/ast_pretty_print.h.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.10/templates/src/include/ast_pretty_print.h.erb
3
3
 
4
4
  #ifndef HERB_AST_PRETTY_PRINT_H
5
5
  #define HERB_AST_PRETTY_PRINT_H
@@ -1,5 +1,5 @@
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.8/templates/src/include/errors.h.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.10/templates/src/include/errors.h.erb
3
3
 
4
4
  #ifndef HERB_ERRORS_H
5
5
  #define HERB_ERRORS_H
@@ -24,6 +24,7 @@ typedef enum {
24
24
  ERB_CONTROL_FLOW_SCOPE_ERROR,
25
25
  MISSINGERB_END_TAG_ERROR,
26
26
  ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR,
27
+ ERB_CASE_WITH_CONDITIONS_ERROR,
27
28
  } error_type_T;
28
29
 
29
30
  typedef struct ERROR_STRUCT {
@@ -102,6 +103,11 @@ typedef struct {
102
103
  /* no additional fields */
103
104
  } ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR_T;
104
105
 
106
+ typedef struct {
107
+ ERROR_T base;
108
+ /* no additional fields */
109
+ } ERB_CASE_WITH_CONDITIONS_ERROR_T;
110
+
105
111
  UNEXPECTED_ERROR_T* unexpected_error_init(const char* description, const char* expected, const char* found, position_T start, position_T end);
106
112
  void append_unexpected_error(const char* description, const char* expected, const char* found, position_T start, position_T end, hb_array_T* errors);
107
113
  UNEXPECTED_TOKEN_ERROR_T* unexpected_token_error_init(token_type_T expected_type, token_T* found, position_T start, position_T end);
@@ -126,6 +132,8 @@ MISSINGERB_END_TAG_ERROR_T* missingerb_end_tag_error_init(const char* keyword, p
126
132
  void append_missingerb_end_tag_error(const char* keyword, position_T start, position_T end, hb_array_T* errors);
127
133
  ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR_T* erb_multiple_blocks_in_tag_error_init(position_T start, position_T end);
128
134
  void append_erb_multiple_blocks_in_tag_error(position_T start, position_T end, hb_array_T* errors);
135
+ ERB_CASE_WITH_CONDITIONS_ERROR_T* erb_case_with_conditions_error_init(position_T start, position_T end);
136
+ void append_erb_case_with_conditions_error(position_T start, position_T end, hb_array_T* errors);
129
137
 
130
138
  void error_init(ERROR_T* error, error_type_T type, position_T start, position_T end);
131
139
 
@@ -0,0 +1,11 @@
1
+ #ifndef HERB_UTILS_STRING_H
2
+ #define HERB_UTILS_STRING_H
3
+
4
+ #include <stdbool.h>
5
+ #include <string.h>
6
+
7
+ static inline bool string_equals(const char* a, const char* b) {
8
+ return strcmp(a, b) == 0;
9
+ }
10
+
11
+ #endif
@@ -1,6 +1,6 @@
1
1
  #ifndef HERB_VERSION_H
2
2
  #define HERB_VERSION_H
3
3
 
4
- #define HERB_VERSION "0.8.8"
4
+ #define HERB_VERSION "0.8.10"
5
5
 
6
6
  #endif
@@ -9,8 +9,10 @@
9
9
  #include "include/io.h"
10
10
  #include "include/ruby_parser.h"
11
11
  #include "include/util/hb_buffer.h"
12
+ #include "include/util/string.h"
12
13
 
13
14
  #include <stdio.h>
15
+ #include <stdlib.h>
14
16
  #include <string.h>
15
17
  #include <time.h>
16
18
 
@@ -34,22 +36,22 @@ void print_time_diff(const struct timespec start, const struct timespec end, con
34
36
 
35
37
  int main(const int argc, char* argv[]) {
36
38
  if (argc < 2) {
37
- printf("./herb [command] [options]\n\n");
39
+ puts("./herb [command] [options]\n");
38
40
 
39
- printf("Herb 🌿 Powerful and seamless HTML-aware ERB parsing and tooling.\n\n");
41
+ puts("Herb 🌿 Powerful and seamless HTML-aware ERB parsing and tooling.\n");
40
42
 
41
- printf("./herb lex [file] - Lex a file\n");
42
- printf("./herb parse [file] - Parse a file\n");
43
- printf("./herb ruby [file] - Extract Ruby from a file\n");
44
- printf("./herb html [file] - Extract HTML from a file\n");
45
- printf("./herb prism [file] - Extract Ruby from a file and parse the Ruby source with Prism\n");
43
+ puts("./herb lex [file] - Lex a file");
44
+ puts("./herb parse [file] - Parse a file");
45
+ puts("./herb ruby [file] - Extract Ruby from a file");
46
+ puts("./herb html [file] - Extract HTML from a file");
47
+ puts("./herb prism [file] - Extract Ruby from a file and parse the Ruby source with Prism");
46
48
 
47
- return 1;
49
+ return EXIT_FAILURE;
48
50
  }
49
51
 
50
52
  if (argc < 3) {
51
- printf("Please specify input file.\n");
52
- return 1;
53
+ puts("Please specify input file.");
54
+ return EXIT_FAILURE;
53
55
  }
54
56
 
55
57
  hb_buffer_T output;
@@ -61,38 +63,20 @@ int main(const int argc, char* argv[]) {
61
63
  struct timespec start, end;
62
64
  clock_gettime(CLOCK_MONOTONIC, &start);
63
65
 
64
- if (strcmp(argv[1], "visit") == 0) {
65
- AST_DOCUMENT_NODE_T* root = herb_parse(source, NULL);
66
- clock_gettime(CLOCK_MONOTONIC, &end);
67
-
68
- herb_analyze_parse_tree(root, source);
69
-
70
- ast_pretty_print_node((AST_NODE_T*) root, 0, 0, &output);
71
- printf("%s\n", output.value);
72
-
73
- print_time_diff(start, end, "visiting");
74
-
75
- ast_node_free((AST_NODE_T*) root);
76
- free(output.value);
77
- free(source);
78
-
79
- return 0;
80
- }
81
-
82
- if (strcmp(argv[1], "lex") == 0) {
66
+ if (string_equals(argv[1], "lex")) {
83
67
  herb_lex_to_buffer(source, &output);
84
68
  clock_gettime(CLOCK_MONOTONIC, &end);
85
69
 
86
- printf("%s\n", output.value);
70
+ puts(output.value);
87
71
  print_time_diff(start, end, "lexing");
88
72
 
89
73
  free(output.value);
90
74
  free(source);
91
75
 
92
- return 0;
76
+ return EXIT_SUCCESS;
93
77
  }
94
78
 
95
- if (strcmp(argv[1], "parse") == 0) {
79
+ if (string_equals(argv[1], "parse")) {
96
80
  AST_DOCUMENT_NODE_T* root = herb_parse(source, NULL);
97
81
 
98
82
  herb_analyze_parse_tree(root, source);
@@ -100,11 +84,11 @@ int main(const int argc, char* argv[]) {
100
84
  clock_gettime(CLOCK_MONOTONIC, &end);
101
85
 
102
86
  int silent = 0;
103
- if (argc > 3 && strcmp(argv[3], "--silent") == 0) { silent = 1; }
87
+ if (argc > 3 && string_equals(argv[3], "--silent")) { silent = 1; }
104
88
 
105
89
  if (!silent) {
106
90
  ast_pretty_print_node((AST_NODE_T*) root, 0, 0, &output);
107
- printf("%s\n", output.value);
91
+ puts(output.value);
108
92
 
109
93
  print_time_diff(start, end, "parsing");
110
94
  }
@@ -113,36 +97,36 @@ int main(const int argc, char* argv[]) {
113
97
  free(output.value);
114
98
  free(source);
115
99
 
116
- return 0;
100
+ return EXIT_SUCCESS;
117
101
  }
118
102
 
119
- if (strcmp(argv[1], "ruby") == 0) {
103
+ if (string_equals(argv[1], "ruby")) {
120
104
  herb_extract_ruby_to_buffer(source, &output);
121
105
  clock_gettime(CLOCK_MONOTONIC, &end);
122
106
 
123
- printf("%s\n", output.value);
107
+ puts(output.value);
124
108
  print_time_diff(start, end, "extracting Ruby");
125
109
 
126
110
  free(output.value);
127
111
  free(source);
128
112
 
129
- return 0;
113
+ return EXIT_SUCCESS;
130
114
  }
131
115
 
132
- if (strcmp(argv[1], "html") == 0) {
116
+ if (string_equals(argv[1], "html")) {
133
117
  herb_extract_html_to_buffer(source, &output);
134
118
  clock_gettime(CLOCK_MONOTONIC, &end);
135
119
 
136
- printf("%s\n", output.value);
120
+ puts(output.value);
137
121
  print_time_diff(start, end, "extracting HTML");
138
122
 
139
123
  free(output.value);
140
124
  free(source);
141
125
 
142
- return 0;
126
+ return EXIT_SUCCESS;
143
127
  }
144
128
 
145
- if (strcmp(argv[1], "prism") == 0) {
129
+ if (string_equals(argv[1], "prism")) {
146
130
  printf("HTML+ERB File: \n%s\n", source);
147
131
 
148
132
  char* ruby_source = herb_extract(source, HERB_EXTRACT_LANGUAGE_RUBY);
@@ -150,9 +134,13 @@ int main(const int argc, char* argv[]) {
150
134
 
151
135
  herb_parse_ruby_to_stdout(ruby_source);
152
136
 
153
- return 0;
137
+ free(ruby_source);
138
+ free(output.value);
139
+ free(source);
140
+
141
+ return EXIT_SUCCESS;
154
142
  }
155
143
 
156
144
  printf("Unknown Command: %s\n", argv[1]);
157
- return 1;
145
+ return EXIT_FAILURE;
158
146
  }
@@ -12,6 +12,7 @@
12
12
  #include "include/util/hb_array.h"
13
13
  #include "include/util/hb_buffer.h"
14
14
  #include "include/util/hb_string.h"
15
+ #include "include/util/string.h"
15
16
  #include "include/visitor.h"
16
17
 
17
18
  #include <stdio.h>
@@ -346,7 +347,7 @@ static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_quoted_html_attribute_value
346
347
  while (!token_is(parser, TOKEN_EOF)
347
348
  && !(
348
349
  token_is(parser, TOKEN_QUOTE) && opening_quote != NULL
349
- && strcmp(parser->current_token->value, opening_quote->value) == 0
350
+ && string_equals(parser->current_token->value, opening_quote->value)
350
351
  )) {
351
352
  if (token_is(parser, TOKEN_ERB_START)) {
352
353
  parser_append_literal_node_from_buffer(parser, &buffer, children, start);
@@ -364,7 +365,7 @@ static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_quoted_html_attribute_value
364
365
  token_T* next_token = lexer_next_token(parser->lexer);
365
366
 
366
367
  if (next_token && next_token->type == TOKEN_QUOTE && opening_quote != NULL
367
- && strcmp(next_token->value, opening_quote->value) == 0) {
368
+ && string_equals(next_token->value, opening_quote->value)) {
368
369
  hb_buffer_append(&buffer, parser->current_token->value);
369
370
  hb_buffer_append(&buffer, next_token->value);
370
371
 
@@ -387,7 +388,7 @@ static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_quoted_html_attribute_value
387
388
  }
388
389
 
389
390
  if (token_is(parser, TOKEN_QUOTE) && opening_quote != NULL
390
- && strcmp(parser->current_token->value, opening_quote->value) == 0) {
391
+ && string_equals(parser->current_token->value, opening_quote->value)) {
391
392
  lexer_state_snapshot_T saved_state = lexer_save_state(parser->lexer);
392
393
 
393
394
  token_T* potential_closing = parser->current_token;
@@ -415,7 +416,7 @@ static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_quoted_html_attribute_value
415
416
  while (!token_is(parser, TOKEN_EOF)
416
417
  && !(
417
418
  token_is(parser, TOKEN_QUOTE) && opening_quote != NULL
418
- && strcmp(parser->current_token->value, opening_quote->value) == 0
419
+ && string_equals(parser->current_token->value, opening_quote->value)
419
420
  )) {
420
421
  if (token_is(parser, TOKEN_ERB_START)) {
421
422
  parser_append_literal_node_from_buffer(parser, &buffer, children, start);
@@ -445,7 +446,7 @@ static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_quoted_html_attribute_value
445
446
 
446
447
  token_T* closing_quote = parser_consume_expected(parser, TOKEN_QUOTE, errors);
447
448
 
448
- if (opening_quote != NULL && closing_quote != NULL && strcmp(opening_quote->value, closing_quote->value) != 0) {
449
+ if (opening_quote != NULL && closing_quote != NULL && !string_equals(opening_quote->value, closing_quote->value)) {
449
450
  append_quotes_mismatch_error(
450
451
  opening_quote,
451
452
  closing_quote,
@@ -1,5 +1,5 @@
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.8/templates/src/parser_match_tags.c.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.10/templates/src/parser_match_tags.c.erb
3
3
 
4
4
  #include "include/parser.h"
5
5
  #include "include/ast_nodes.h"
@@ -0,0 +1,11 @@
1
+ #ifndef HERB_UTILS_STRING_H
2
+ #define HERB_UTILS_STRING_H
3
+
4
+ #include <stdbool.h>
5
+ #include <string.h>
6
+
7
+ static inline bool string_equals(const char* a, const char* b) {
8
+ return strcmp(a, b) == 0;
9
+ }
10
+
11
+ #endif
@@ -1,6 +1,6 @@
1
1
  #ifndef HERB_VERSION_H
2
2
  #define HERB_VERSION_H
3
3
 
4
- #define HERB_VERSION "0.8.8"
4
+ #define HERB_VERSION "0.8.10"
5
5
 
6
6
  #endif
@@ -1,5 +1,5 @@
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.8/templates/src/visitor.c.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.10/templates/src/visitor.c.erb
3
3
 
4
4
  #include <stdio.h>
5
5
 
@@ -1,5 +1,5 @@
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.8/templates/javascript/packages/node/extension/nodes.cpp.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.10/templates/javascript/packages/node/extension/nodes.cpp.erb
3
3
 
4
4
  #include <node_api.h>
5
5
  #include "error_helpers.h"
package/extension/nodes.h CHANGED
@@ -1,5 +1,5 @@
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.8/templates/javascript/packages/node/extension/nodes.h.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-0.8.10/templates/javascript/packages/node/extension/nodes.h.erb
3
3
 
4
4
  #ifndef HERB_EXTENSION_NODES_H
5
5
  #define HERB_EXTENSION_NODES_H
@@ -1826,20 +1826,20 @@ typedef struct pm_block_node {
1826
1826
  /**
1827
1827
  * BlockNode#opening_loc
1828
1828
  *
1829
- * Represents the location of the opening `|`.
1829
+ * Represents the location of the opening `{` or `do`.
1830
1830
  *
1831
1831
  * [1, 2, 3].each { |i| puts x }
1832
- * ^
1832
+ * ^
1833
1833
  */
1834
1834
  pm_location_t opening_loc;
1835
1835
 
1836
1836
  /**
1837
1837
  * BlockNode#closing_loc
1838
1838
  *
1839
- * Represents the location of the closing `|`.
1839
+ * Represents the location of the closing `}` or `end`.
1840
1840
  *
1841
1841
  * [1, 2, 3].each { |i| puts x }
1842
- * ^
1842
+ * ^
1843
1843
  */
1844
1844
  pm_location_t closing_loc;
1845
1845
  } pm_block_node_t;
@@ -14,7 +14,7 @@
14
14
  /**
15
15
  * The minor version of the Prism library as an int.
16
16
  */
17
- #define PRISM_VERSION_MINOR 8
17
+ #define PRISM_VERSION_MINOR 9
18
18
 
19
19
  /**
20
20
  * The patch version of the Prism library as an int.
@@ -24,6 +24,6 @@
24
24
  /**
25
25
  * The version of the Prism library as a constant string.
26
26
  */
27
- #define PRISM_VERSION "1.8.0"
27
+ #define PRISM_VERSION "1.9.0"
28
28
 
29
29
  #endif
@@ -12438,7 +12438,7 @@ expect1_opening(pm_parser_t *parser, pm_token_type_t type, pm_diagnostic_id_t di
12438
12438
 
12439
12439
  pm_parser_err(parser, opening->start, opening->end, diag_id);
12440
12440
 
12441
- parser->previous.start = opening->end;
12441
+ parser->previous.start = parser->previous.end;
12442
12442
  parser->previous.type = PM_TOKEN_MISSING;
12443
12443
  }
12444
12444
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@herb-tools/node",
3
- "version": "0.8.8",
3
+ "version": "0.8.10",
4
4
  "description": "Native Node.js addon for HTML-aware ERB parsing using Herb.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -48,7 +48,7 @@
48
48
  "host": "https://github.com/marcoroth/herb/releases/download/"
49
49
  },
50
50
  "dependencies": {
51
- "@herb-tools/core": "0.8.8",
51
+ "@herb-tools/core": "0.8.10",
52
52
  "@mapbox/node-pre-gyp": "^2.0.3",
53
53
  "node-addon-api": "^8.5.0",
54
54
  "node-pre-gyp-github": "^2.0.0"