herb 0.9.0-arm-linux-gnu → 0.9.2-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.
- checksums.yaml +4 -4
- data/config.yml +156 -0
- data/ext/herb/error_helpers.c +168 -0
- data/ext/herb/extension.c +4 -0
- data/ext/herb/extension_helpers.c +1 -0
- data/ext/herb/nodes.c +110 -0
- data/lib/herb/3.0/herb.so +0 -0
- data/lib/herb/3.1/herb.so +0 -0
- data/lib/herb/3.2/herb.so +0 -0
- data/lib/herb/3.3/herb.so +0 -0
- data/lib/herb/3.4/herb.so +0 -0
- data/lib/herb/4.0/herb.so +0 -0
- data/lib/herb/ast/nodes.rb +393 -17
- data/lib/herb/engine/compiler.rb +17 -41
- data/lib/herb/engine.rb +76 -26
- data/lib/herb/errors.rb +245 -0
- data/lib/herb/parser_options.rb +6 -1
- data/lib/herb/prism_inspect.rb +5 -1
- data/lib/herb/version.rb +1 -1
- data/lib/herb/visitor.rb +10 -0
- data/sig/herb/ast/nodes.rbs +132 -0
- data/sig/herb/engine/compiler.rbs +4 -2
- data/sig/herb/engine.rbs +8 -0
- data/sig/herb/errors.rbs +114 -0
- data/sig/herb/parser_options.rbs +4 -0
- data/sig/herb/visitor.rbs +6 -0
- data/sig/rubyvm.rbs +5 -0
- data/sig/serialized_ast_errors.rbs +28 -0
- data/sig/serialized_ast_nodes.rbs +31 -0
- data/src/analyze/action_view/attribute_extraction_helpers.c +23 -1
- data/src/analyze/action_view/content_tag.c +19 -11
- data/src/analyze/action_view/javascript_include_tag.c +92 -0
- data/src/analyze/action_view/javascript_tag.c +55 -0
- data/src/analyze/action_view/link_to.c +25 -1
- data/src/analyze/action_view/registry.c +29 -2
- data/src/analyze/action_view/tag.c +14 -8
- data/src/analyze/action_view/tag_helper_node_builders.c +16 -3
- data/src/analyze/action_view/tag_helpers.c +332 -12
- data/src/analyze/analyze.c +3 -0
- data/src/analyze/prism_annotate.c +4 -2
- data/src/analyze/render_nodes.c +761 -0
- data/src/analyze/transform.c +7 -0
- data/src/ast_nodes.c +97 -0
- data/src/ast_pretty_print.c +74 -0
- data/src/errors.c +379 -0
- data/src/html_util.c +50 -0
- data/src/include/analyze/action_view/tag_helper_handler.h +2 -0
- data/src/include/analyze/render_nodes.h +11 -0
- data/src/include/ast_nodes.h +37 -0
- data/src/include/errors.h +58 -0
- data/src/include/html_util.h +1 -0
- data/src/include/parser.h +1 -0
- data/src/include/version.h +1 -1
- data/src/parser.c +1 -0
- data/src/parser_match_tags.c +20 -0
- data/src/util/hb_arena.c +3 -7
- data/src/visitor.c +20 -0
- data/templates/lib/herb/ast/nodes.rb.erb +8 -2
- data/templates/rust/src/ast/nodes.rs.erb +1 -1
- data/templates/rust/src/nodes.rs.erb +1 -1
- metadata +6 -1
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#include "../../include/analyze/analyze.h"
|
|
6
6
|
#include "../../include/ast_nodes.h"
|
|
7
7
|
#include "../../include/html_util.h"
|
|
8
|
+
#include "../../include/parser_helpers.h"
|
|
8
9
|
#include "../../include/position.h"
|
|
9
10
|
#include "../../include/util/hb_allocator.h"
|
|
10
11
|
#include "../../include/util/hb_array.h"
|
|
@@ -22,6 +23,10 @@ extern char* wrap_in_url_for(const char*, size_t, hb_allocator_T*);
|
|
|
22
23
|
extern char* extract_link_to_href(pm_call_node_t*, pm_parser_t*, hb_allocator_T*);
|
|
23
24
|
extern bool detect_turbo_frame_tag(pm_call_node_t*, pm_parser_t*);
|
|
24
25
|
extern char* extract_turbo_frame_tag_id(pm_call_node_t*, pm_parser_t*, hb_allocator_T*);
|
|
26
|
+
extern bool detect_javascript_include_tag(pm_call_node_t*, pm_parser_t*);
|
|
27
|
+
extern char* extract_javascript_include_tag_src(pm_call_node_t*, pm_parser_t*, hb_allocator_T*);
|
|
28
|
+
extern char* wrap_in_javascript_path(const char*, size_t, hb_allocator_T*);
|
|
29
|
+
extern bool javascript_include_tag_source_is_url(const char*, size_t);
|
|
25
30
|
|
|
26
31
|
typedef struct {
|
|
27
32
|
pm_parser_t parser;
|
|
@@ -262,13 +267,29 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
|
|
|
262
267
|
if (parse_context->info->call_node && handler->extract_content) {
|
|
263
268
|
helper_content = handler->extract_content(parse_context->info->call_node, &parse_context->parser, allocator);
|
|
264
269
|
|
|
265
|
-
if (helper_content
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
(
|
|
270
|
+
if (helper_content) {
|
|
271
|
+
pm_call_node_t* call = parse_context->info->call_node;
|
|
272
|
+
|
|
273
|
+
if (call->arguments) {
|
|
274
|
+
if (strcmp(handler->name, "content_tag") == 0 && call->arguments->arguments.size >= 2
|
|
275
|
+
&& call->arguments->arguments.nodes[1]->type != PM_KEYWORD_HASH_NODE) {
|
|
276
|
+
content_is_ruby_expression = (call->arguments->arguments.nodes[1]->type != PM_STRING_NODE);
|
|
277
|
+
} else if (strcmp(handler->name, "content_tag") != 0 && call->arguments->arguments.size >= 1
|
|
278
|
+
&& call->arguments->arguments.nodes[0]->type != PM_KEYWORD_HASH_NODE) {
|
|
279
|
+
content_is_ruby_expression = (call->arguments->arguments.nodes[0]->type != PM_STRING_NODE);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (!content_is_ruby_expression && call->block && call->block->type == PM_BLOCK_NODE) {
|
|
284
|
+
pm_block_node_t* block_node = (pm_block_node_t*) call->block;
|
|
285
|
+
|
|
286
|
+
if (block_node->body && block_node->body->type == PM_STATEMENTS_NODE) {
|
|
287
|
+
pm_statements_node_t* statements = (pm_statements_node_t*) block_node->body;
|
|
288
|
+
|
|
289
|
+
if (statements->body.size == 1) {
|
|
290
|
+
content_is_ruby_expression = (statements->body.nodes[0]->type != PM_STRING_NODE);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
272
293
|
}
|
|
273
294
|
}
|
|
274
295
|
}
|
|
@@ -294,6 +315,47 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
|
|
|
294
315
|
}
|
|
295
316
|
}
|
|
296
317
|
|
|
318
|
+
if (detect_javascript_include_tag(parse_context->info->call_node, &parse_context->parser)
|
|
319
|
+
&& parse_context->info->call_node->arguments && parse_context->info->call_node->arguments->arguments.size >= 1) {
|
|
320
|
+
char* source_value =
|
|
321
|
+
extract_javascript_include_tag_src(parse_context->info->call_node, &parse_context->parser, allocator);
|
|
322
|
+
|
|
323
|
+
if (source_value) {
|
|
324
|
+
if (!attributes) { attributes = hb_array_init(4, allocator); }
|
|
325
|
+
|
|
326
|
+
pm_node_t* first_argument = parse_context->info->call_node->arguments->arguments.nodes[0];
|
|
327
|
+
position_T source_start, source_end;
|
|
328
|
+
prism_node_location_to_positions(&first_argument->location, parse_context, &source_start, &source_end);
|
|
329
|
+
bool source_is_string = (first_argument->type == PM_STRING_NODE);
|
|
330
|
+
|
|
331
|
+
size_t source_length = strlen(source_value);
|
|
332
|
+
bool is_url = javascript_include_tag_source_is_url(source_value, source_length);
|
|
333
|
+
|
|
334
|
+
char* source_attribute_value = source_value;
|
|
335
|
+
if (source_is_string && !is_url) {
|
|
336
|
+
size_t quoted_length = source_length + 2;
|
|
337
|
+
char* quoted_source = hb_allocator_alloc(allocator, quoted_length + 1);
|
|
338
|
+
quoted_source[0] = '"';
|
|
339
|
+
memcpy(quoted_source + 1, source_value, source_length);
|
|
340
|
+
quoted_source[quoted_length - 1] = '"';
|
|
341
|
+
quoted_source[quoted_length] = '\0';
|
|
342
|
+
|
|
343
|
+
source_attribute_value = wrap_in_javascript_path(quoted_source, quoted_length, allocator);
|
|
344
|
+
hb_allocator_dealloc(allocator, quoted_source);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
AST_HTML_ATTRIBUTE_NODE_T* source_attribute =
|
|
348
|
+
is_url
|
|
349
|
+
? create_html_attribute_node("src", source_attribute_value, source_start, source_end, allocator)
|
|
350
|
+
: create_html_attribute_with_ruby_literal("src", source_attribute_value, source_start, source_end, allocator);
|
|
351
|
+
|
|
352
|
+
if (source_attribute) { attributes = prepend_attribute(attributes, (AST_NODE_T*) source_attribute, allocator); }
|
|
353
|
+
|
|
354
|
+
if (source_attribute_value != source_value) { hb_allocator_dealloc(allocator, source_attribute_value); }
|
|
355
|
+
hb_allocator_dealloc(allocator, source_value);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
297
359
|
token_T* tag_name_token =
|
|
298
360
|
tag_name ? create_synthetic_token(allocator, tag_name, TOKEN_IDENTIFIER, tag_name_start, tag_name_end) : NULL;
|
|
299
361
|
|
|
@@ -356,6 +418,166 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
|
|
|
356
418
|
return (AST_NODE_T*) element;
|
|
357
419
|
}
|
|
358
420
|
|
|
421
|
+
static size_t count_javascript_include_tag_sources(pm_call_node_t* call_node) {
|
|
422
|
+
if (!call_node || !call_node->arguments) { return 0; }
|
|
423
|
+
|
|
424
|
+
size_t count = 0;
|
|
425
|
+
pm_arguments_node_t* arguments = call_node->arguments;
|
|
426
|
+
|
|
427
|
+
for (size_t i = 0; i < arguments->arguments.size; i++) {
|
|
428
|
+
pm_node_t* arg = arguments->arguments.nodes[i];
|
|
429
|
+
if (arg->type == PM_KEYWORD_HASH_NODE) { break; }
|
|
430
|
+
count++;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return count;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
static AST_NODE_T* create_javascript_include_tag_element(
|
|
437
|
+
AST_ERB_CONTENT_NODE_T* erb_node,
|
|
438
|
+
tag_helper_parse_context_T* parse_context,
|
|
439
|
+
pm_node_t* source_argument,
|
|
440
|
+
hb_array_T* shared_attributes,
|
|
441
|
+
hb_allocator_T* allocator
|
|
442
|
+
) {
|
|
443
|
+
position_T tag_name_start, tag_name_end;
|
|
444
|
+
calculate_tag_name_positions(
|
|
445
|
+
parse_context,
|
|
446
|
+
erb_node->base.location.start,
|
|
447
|
+
erb_node->base.location.end,
|
|
448
|
+
&tag_name_start,
|
|
449
|
+
&tag_name_end
|
|
450
|
+
);
|
|
451
|
+
|
|
452
|
+
token_T* tag_name_token = create_synthetic_token(allocator, "script", TOKEN_IDENTIFIER, tag_name_start, tag_name_end);
|
|
453
|
+
|
|
454
|
+
char* source_value = NULL;
|
|
455
|
+
bool source_is_string = (source_argument->type == PM_STRING_NODE);
|
|
456
|
+
|
|
457
|
+
if (source_is_string) {
|
|
458
|
+
pm_string_node_t* string_node = (pm_string_node_t*) source_argument;
|
|
459
|
+
size_t length = pm_string_length(&string_node->unescaped);
|
|
460
|
+
source_value = hb_allocator_strndup(allocator, (const char*) pm_string_source(&string_node->unescaped), length);
|
|
461
|
+
} else {
|
|
462
|
+
size_t source_length = source_argument->location.end - source_argument->location.start;
|
|
463
|
+
source_value = hb_allocator_strndup(allocator, (const char*) source_argument->location.start, source_length);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
position_T source_start, source_end;
|
|
467
|
+
prism_node_location_to_positions(&source_argument->location, parse_context, &source_start, &source_end);
|
|
468
|
+
|
|
469
|
+
size_t source_length = strlen(source_value);
|
|
470
|
+
bool is_url = javascript_include_tag_source_is_url(source_value, source_length);
|
|
471
|
+
|
|
472
|
+
char* source_attribute_value = source_value;
|
|
473
|
+
if (source_is_string && !is_url) {
|
|
474
|
+
size_t quoted_length = source_length + 2;
|
|
475
|
+
char* quoted_source = hb_allocator_alloc(allocator, quoted_length + 1);
|
|
476
|
+
quoted_source[0] = '"';
|
|
477
|
+
memcpy(quoted_source + 1, source_value, source_length);
|
|
478
|
+
quoted_source[quoted_length - 1] = '"';
|
|
479
|
+
quoted_source[quoted_length] = '\0';
|
|
480
|
+
|
|
481
|
+
source_attribute_value = wrap_in_javascript_path(quoted_source, quoted_length, allocator);
|
|
482
|
+
hb_allocator_dealloc(allocator, quoted_source);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
hb_array_T* attributes = hb_array_init(hb_array_size(shared_attributes) + 1, allocator);
|
|
486
|
+
|
|
487
|
+
AST_HTML_ATTRIBUTE_NODE_T* source_attribute =
|
|
488
|
+
is_url
|
|
489
|
+
? create_html_attribute_node("src", source_attribute_value, source_start, source_end, allocator)
|
|
490
|
+
: create_html_attribute_with_ruby_literal("src", source_attribute_value, source_start, source_end, allocator);
|
|
491
|
+
if (source_attribute) { hb_array_append(attributes, source_attribute); }
|
|
492
|
+
|
|
493
|
+
for (size_t i = 0; i < hb_array_size(shared_attributes); i++) {
|
|
494
|
+
hb_array_append(attributes, hb_array_get(shared_attributes, i));
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (source_attribute_value != source_value) { hb_allocator_dealloc(allocator, source_attribute_value); }
|
|
498
|
+
hb_allocator_dealloc(allocator, source_value);
|
|
499
|
+
|
|
500
|
+
AST_ERB_OPEN_TAG_NODE_T* open_tag_node = ast_erb_open_tag_node_init(
|
|
501
|
+
erb_node->tag_opening,
|
|
502
|
+
erb_node->content,
|
|
503
|
+
erb_node->tag_closing,
|
|
504
|
+
tag_name_token,
|
|
505
|
+
attributes,
|
|
506
|
+
erb_node->base.location.start,
|
|
507
|
+
erb_node->base.location.end,
|
|
508
|
+
hb_array_init(0, allocator),
|
|
509
|
+
allocator
|
|
510
|
+
);
|
|
511
|
+
|
|
512
|
+
AST_HTML_VIRTUAL_CLOSE_TAG_NODE_T* virtual_close = ast_html_virtual_close_tag_node_init(
|
|
513
|
+
tag_name_token,
|
|
514
|
+
erb_node->base.location.end,
|
|
515
|
+
erb_node->base.location.end,
|
|
516
|
+
hb_array_init(0, allocator),
|
|
517
|
+
allocator
|
|
518
|
+
);
|
|
519
|
+
|
|
520
|
+
return (AST_NODE_T*) ast_html_element_node_init(
|
|
521
|
+
(AST_NODE_T*) open_tag_node,
|
|
522
|
+
tag_name_token,
|
|
523
|
+
hb_array_init(0, allocator),
|
|
524
|
+
(AST_NODE_T*) virtual_close,
|
|
525
|
+
false,
|
|
526
|
+
parse_context->matched_handler->source,
|
|
527
|
+
erb_node->base.location.start,
|
|
528
|
+
erb_node->base.location.end,
|
|
529
|
+
hb_array_init(0, allocator),
|
|
530
|
+
allocator
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
static hb_array_T* transform_javascript_include_tag_multi_source(
|
|
535
|
+
AST_ERB_CONTENT_NODE_T* erb_node,
|
|
536
|
+
analyze_ruby_context_T* context,
|
|
537
|
+
tag_helper_parse_context_T* parse_context
|
|
538
|
+
) {
|
|
539
|
+
hb_allocator_T* allocator = context->allocator;
|
|
540
|
+
pm_call_node_t* call_node = parse_context->info->call_node;
|
|
541
|
+
size_t source_count = count_javascript_include_tag_sources(call_node);
|
|
542
|
+
|
|
543
|
+
if (source_count == 0) { return NULL; }
|
|
544
|
+
|
|
545
|
+
hb_array_T* shared_attributes = extract_html_attributes_from_call_node(
|
|
546
|
+
call_node,
|
|
547
|
+
parse_context->prism_source,
|
|
548
|
+
parse_context->original_source,
|
|
549
|
+
parse_context->erb_content_offset,
|
|
550
|
+
allocator
|
|
551
|
+
);
|
|
552
|
+
if (!shared_attributes) { shared_attributes = hb_array_init(0, allocator); }
|
|
553
|
+
|
|
554
|
+
hb_array_T* elements = hb_array_init(source_count * 2, allocator);
|
|
555
|
+
|
|
556
|
+
for (size_t i = 0; i < source_count; i++) {
|
|
557
|
+
pm_node_t* source_arg = call_node->arguments->arguments.nodes[i];
|
|
558
|
+
AST_NODE_T* element =
|
|
559
|
+
create_javascript_include_tag_element(erb_node, parse_context, source_arg, shared_attributes, allocator);
|
|
560
|
+
|
|
561
|
+
if (element) {
|
|
562
|
+
if (hb_array_size(elements) > 0) {
|
|
563
|
+
position_T position = erb_node->base.location.start;
|
|
564
|
+
AST_HTML_TEXT_NODE_T* newline = ast_html_text_node_init(
|
|
565
|
+
hb_string_from_c_string("\n"),
|
|
566
|
+
position,
|
|
567
|
+
position,
|
|
568
|
+
hb_array_init(0, allocator),
|
|
569
|
+
allocator
|
|
570
|
+
);
|
|
571
|
+
if (newline) { hb_array_append(elements, (AST_NODE_T*) newline); }
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
hb_array_append(elements, element);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
return elements;
|
|
579
|
+
}
|
|
580
|
+
|
|
359
581
|
static AST_NODE_T* transform_erb_block_to_tag_helper(
|
|
360
582
|
AST_ERB_BLOCK_NODE_T* block_node,
|
|
361
583
|
analyze_ruby_context_T* context,
|
|
@@ -462,6 +684,27 @@ static AST_NODE_T* transform_erb_block_to_tag_helper(
|
|
|
462
684
|
hb_array_T* body = block_node->body ? block_node->body : hb_array_init(0, allocator);
|
|
463
685
|
AST_NODE_T* close_tag = (AST_NODE_T*) block_node->end_node;
|
|
464
686
|
|
|
687
|
+
if (tag_name && parser_is_foreign_content_tag(hb_string_from_c_string(tag_name)) && context->source
|
|
688
|
+
&& block_node->body && hb_array_size(block_node->body) > 0) {
|
|
689
|
+
size_t start_offset = block_node->tag_closing->range.to;
|
|
690
|
+
size_t end_offset = block_node->end_node->tag_opening->range.from;
|
|
691
|
+
|
|
692
|
+
if (end_offset > start_offset) {
|
|
693
|
+
position_T body_start = block_node->tag_closing->location.end;
|
|
694
|
+
position_T body_end = block_node->end_node->tag_opening->location.start;
|
|
695
|
+
|
|
696
|
+
size_t content_length = end_offset - start_offset;
|
|
697
|
+
char* raw_copy = hb_allocator_strndup(allocator, context->source + start_offset, content_length);
|
|
698
|
+
hb_string_T raw_content = { .data = raw_copy, .length = content_length };
|
|
699
|
+
|
|
700
|
+
AST_LITERAL_NODE_T* literal_node =
|
|
701
|
+
ast_literal_node_init(raw_content, body_start, body_end, hb_array_init(0, allocator), allocator);
|
|
702
|
+
|
|
703
|
+
body = hb_array_init(1, allocator);
|
|
704
|
+
hb_array_append(body, literal_node);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
465
708
|
AST_HTML_ELEMENT_NODE_T* element = ast_html_element_node_init(
|
|
466
709
|
(AST_NODE_T*) open_tag_node,
|
|
467
710
|
tag_name_token,
|
|
@@ -492,8 +735,12 @@ static AST_NODE_T* transform_link_to_helper(
|
|
|
492
735
|
|
|
493
736
|
hb_array_T* attributes = NULL;
|
|
494
737
|
pm_arguments_node_t* link_arguments = info->call_node->arguments;
|
|
495
|
-
bool
|
|
496
|
-
|
|
738
|
+
bool has_inline_block = info->call_node->block && info->call_node->block->type == PM_BLOCK_NODE;
|
|
739
|
+
|
|
740
|
+
bool second_arg_is_hash = link_arguments && link_arguments->arguments.size == 2
|
|
741
|
+
&& (link_arguments->arguments.nodes[1]->type == PM_KEYWORD_HASH_NODE
|
|
742
|
+
|| link_arguments->arguments.nodes[1]->type == PM_HASH_NODE);
|
|
743
|
+
bool keyword_hash_is_url = !has_inline_block && second_arg_is_hash;
|
|
497
744
|
|
|
498
745
|
if (!keyword_hash_is_url) {
|
|
499
746
|
attributes = extract_html_attributes_from_call_node(
|
|
@@ -507,6 +754,38 @@ static AST_NODE_T* transform_link_to_helper(
|
|
|
507
754
|
|
|
508
755
|
if (!attributes) { attributes = hb_array_init(4, allocator); }
|
|
509
756
|
|
|
757
|
+
if (has_inline_block && link_arguments && link_arguments->arguments.size >= 2) {
|
|
758
|
+
pm_node_t* second_arg = link_arguments->arguments.nodes[1];
|
|
759
|
+
|
|
760
|
+
if (second_arg->type != PM_KEYWORD_HASH_NODE && second_arg->type != PM_HASH_NODE
|
|
761
|
+
&& second_arg->type != PM_STRING_NODE && second_arg->type != PM_SYMBOL_NODE) {
|
|
762
|
+
size_t source_length = second_arg->location.end - second_arg->location.start;
|
|
763
|
+
char* content = hb_allocator_strndup(allocator, (const char*) second_arg->location.start, source_length);
|
|
764
|
+
|
|
765
|
+
if (content) {
|
|
766
|
+
position_T position = prism_location_to_position_with_offset(
|
|
767
|
+
&second_arg->location,
|
|
768
|
+
parse_context->original_source,
|
|
769
|
+
parse_context->erb_content_offset,
|
|
770
|
+
parse_context->prism_source
|
|
771
|
+
);
|
|
772
|
+
|
|
773
|
+
AST_RUBY_HTML_ATTRIBUTES_SPLAT_NODE_T* splat_node = ast_ruby_html_attributes_splat_node_init(
|
|
774
|
+
hb_string_from_c_string(content),
|
|
775
|
+
HB_STRING_EMPTY,
|
|
776
|
+
position,
|
|
777
|
+
position,
|
|
778
|
+
hb_array_init(0, allocator),
|
|
779
|
+
allocator
|
|
780
|
+
);
|
|
781
|
+
|
|
782
|
+
if (splat_node) { hb_array_append(attributes, (AST_NODE_T*) splat_node); }
|
|
783
|
+
|
|
784
|
+
hb_allocator_dealloc(allocator, content);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
510
789
|
// `method:` implies `rel="nofollow"`
|
|
511
790
|
bool has_data_method = false;
|
|
512
791
|
hb_string_T data_method_string = hb_string("data-method");
|
|
@@ -549,7 +828,12 @@ static AST_NODE_T* transform_link_to_helper(
|
|
|
549
828
|
pm_arguments_node_t* arguments = info->call_node->arguments;
|
|
550
829
|
pm_node_t* href_argument = NULL;
|
|
551
830
|
|
|
552
|
-
if (
|
|
831
|
+
if (has_inline_block) {
|
|
832
|
+
if (arguments->arguments.size >= 1) {
|
|
833
|
+
href_argument = arguments->arguments.nodes[0];
|
|
834
|
+
href_is_ruby_expression = (href_argument->type != PM_STRING_NODE);
|
|
835
|
+
}
|
|
836
|
+
} else if (arguments->arguments.size >= 2) {
|
|
553
837
|
href_argument = arguments->arguments.nodes[1];
|
|
554
838
|
href_is_ruby_expression = (href_argument->type != PM_STRING_NODE);
|
|
555
839
|
} else if (arguments->arguments.size == 1) {
|
|
@@ -602,7 +886,17 @@ static AST_NODE_T* transform_link_to_helper(
|
|
|
602
886
|
if (info->content) {
|
|
603
887
|
bool content_is_ruby_expression = false;
|
|
604
888
|
|
|
605
|
-
if (
|
|
889
|
+
if (has_inline_block && info->call_node->block && info->call_node->block->type == PM_BLOCK_NODE) {
|
|
890
|
+
pm_block_node_t* block_node = (pm_block_node_t*) info->call_node->block;
|
|
891
|
+
|
|
892
|
+
if (block_node->body && block_node->body->type == PM_STATEMENTS_NODE) {
|
|
893
|
+
pm_statements_node_t* statements = (pm_statements_node_t*) block_node->body;
|
|
894
|
+
|
|
895
|
+
if (statements->body.size == 1) {
|
|
896
|
+
content_is_ruby_expression = (statements->body.nodes[0]->type != PM_STRING_NODE);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
} else if (info->call_node && info->call_node->arguments && info->call_node->arguments->arguments.size >= 1) {
|
|
606
900
|
pm_node_t* first_argument = info->call_node->arguments->arguments.nodes[0];
|
|
607
901
|
content_is_ruby_expression = (first_argument->type != PM_STRING_NODE);
|
|
608
902
|
}
|
|
@@ -720,7 +1014,33 @@ void transform_tag_helper_blocks(const AST_NODE_T* node, analyze_ruby_context_T*
|
|
|
720
1014
|
parse_tag_helper_content(erb_string, context->source, erb_content_offset, context->allocator);
|
|
721
1015
|
|
|
722
1016
|
if (parse_context) {
|
|
723
|
-
if (strcmp(parse_context->matched_handler->name, "
|
|
1017
|
+
if (strcmp(parse_context->matched_handler->name, "javascript_include_tag") == 0
|
|
1018
|
+
&& parse_context->info->call_node
|
|
1019
|
+
&& count_javascript_include_tag_sources(parse_context->info->call_node) > 1) {
|
|
1020
|
+
hb_array_T* multi = transform_javascript_include_tag_multi_source(erb_node, context, parse_context);
|
|
1021
|
+
|
|
1022
|
+
if (multi && hb_array_size(multi) > 0) {
|
|
1023
|
+
size_t old_size = hb_array_size(array);
|
|
1024
|
+
size_t multi_size = hb_array_size(multi);
|
|
1025
|
+
hb_array_T* new_array = hb_array_init(old_size - 1 + multi_size, context->allocator);
|
|
1026
|
+
|
|
1027
|
+
for (size_t j = 0; j < old_size; j++) {
|
|
1028
|
+
if (j == i) {
|
|
1029
|
+
for (size_t k = 0; k < multi_size; k++) {
|
|
1030
|
+
hb_array_append(new_array, hb_array_get(multi, k));
|
|
1031
|
+
}
|
|
1032
|
+
} else {
|
|
1033
|
+
hb_array_append(new_array, hb_array_get(array, j));
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
array->items = new_array->items;
|
|
1038
|
+
array->size = new_array->size;
|
|
1039
|
+
array->capacity = new_array->capacity;
|
|
1040
|
+
|
|
1041
|
+
i += multi_size - 1;
|
|
1042
|
+
}
|
|
1043
|
+
} else if (strcmp(parse_context->matched_handler->name, "link_to") == 0) {
|
|
724
1044
|
replacement = transform_link_to_helper(erb_node, context, parse_context);
|
|
725
1045
|
} else {
|
|
726
1046
|
replacement = transform_tag_helper_with_attributes(erb_node, context, parse_context);
|
data/src/analyze/analyze.c
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
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/render_nodes.h"
|
|
11
12
|
#include "../include/ast_node.h"
|
|
12
13
|
#include "../include/ast_nodes.h"
|
|
13
14
|
#include "../include/errors.h"
|
|
@@ -859,6 +860,8 @@ void herb_analyze_parse_tree(
|
|
|
859
860
|
|
|
860
861
|
herb_visit_node((AST_NODE_T*) document, transform_erb_nodes, &context);
|
|
861
862
|
|
|
863
|
+
if (options && options->render_nodes) { herb_visit_node((AST_NODE_T*) document, transform_render_nodes, &context); }
|
|
864
|
+
|
|
862
865
|
if (options && options->action_view_helpers) {
|
|
863
866
|
herb_visit_node((AST_NODE_T*) document, transform_tag_helper_nodes, &context);
|
|
864
867
|
}
|
|
@@ -168,6 +168,7 @@ static void collect_prism_nodes(pm_node_t* node, hb_narray_T* list) {
|
|
|
168
168
|
static token_T* get_content_token(const AST_NODE_T* node) {
|
|
169
169
|
switch (node->type) {
|
|
170
170
|
case AST_ERB_CONTENT_NODE: return ((AST_ERB_CONTENT_NODE_T*) node)->content;
|
|
171
|
+
case AST_ERB_RENDER_NODE: return ((AST_ERB_RENDER_NODE_T*) node)->content;
|
|
171
172
|
case AST_ERB_IF_NODE: return ((AST_ERB_IF_NODE_T*) node)->content;
|
|
172
173
|
case AST_ERB_BLOCK_NODE: return ((AST_ERB_BLOCK_NODE_T*) node)->content;
|
|
173
174
|
case AST_ERB_CASE_NODE: return ((AST_ERB_CASE_NODE_T*) node)->content;
|
|
@@ -184,6 +185,7 @@ static token_T* get_content_token(const AST_NODE_T* node) {
|
|
|
184
185
|
static void set_prism_node(AST_NODE_T* node, herb_prism_node_T prism_ref) {
|
|
185
186
|
switch (node->type) {
|
|
186
187
|
case AST_ERB_CONTENT_NODE: ((AST_ERB_CONTENT_NODE_T*) node)->prism_node = prism_ref; break;
|
|
188
|
+
case AST_ERB_RENDER_NODE: ((AST_ERB_RENDER_NODE_T*) node)->prism_node = prism_ref; break;
|
|
187
189
|
case AST_ERB_IF_NODE: ((AST_ERB_IF_NODE_T*) node)->prism_node = prism_ref; break;
|
|
188
190
|
case AST_ERB_BLOCK_NODE: ((AST_ERB_BLOCK_NODE_T*) node)->prism_node = prism_ref; break;
|
|
189
191
|
case AST_ERB_CASE_NODE: ((AST_ERB_CASE_NODE_T*) node)->prism_node = prism_ref; break;
|
|
@@ -232,7 +234,7 @@ static bool annotate_visitor(const AST_NODE_T* node, void* data) {
|
|
|
232
234
|
pm_parser_t* parser;
|
|
233
235
|
hb_narray_T* node_list;
|
|
234
236
|
|
|
235
|
-
if (node->type == AST_ERB_CONTENT_NODE || context->prism_nodes_deep) {
|
|
237
|
+
if (node->type == AST_ERB_CONTENT_NODE || node->type == AST_ERB_RENDER_NODE || context->prism_nodes_deep) {
|
|
236
238
|
parser = context->parser;
|
|
237
239
|
node_list = context->node_list;
|
|
238
240
|
} else {
|
|
@@ -248,7 +250,7 @@ static bool annotate_visitor(const AST_NODE_T* node, void* data) {
|
|
|
248
250
|
}
|
|
249
251
|
|
|
250
252
|
static bool collect_content_ranges_visitor(const AST_NODE_T* node, void* data) {
|
|
251
|
-
if (node->type != AST_ERB_CONTENT_NODE) { return true; }
|
|
253
|
+
if (node->type != AST_ERB_CONTENT_NODE && node->type != AST_ERB_RENDER_NODE) { return true; }
|
|
252
254
|
|
|
253
255
|
hb_narray_T* ranges = (hb_narray_T*) data;
|
|
254
256
|
token_T* content = get_content_token(node);
|