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
data/sig/herb/errors.rbs
CHANGED
|
@@ -458,5 +458,119 @@ module Herb
|
|
|
458
458
|
# : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
459
459
|
def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
460
460
|
end
|
|
461
|
+
|
|
462
|
+
class RenderAmbiguousLocalsError < Error
|
|
463
|
+
include Colors
|
|
464
|
+
|
|
465
|
+
attr_reader partial: String?
|
|
466
|
+
|
|
467
|
+
# : (String, Location?, String, String) -> void
|
|
468
|
+
def initialize: (String, Location?, String, String) -> void
|
|
469
|
+
|
|
470
|
+
# : () -> String
|
|
471
|
+
def inspect: () -> String
|
|
472
|
+
|
|
473
|
+
# : () -> serialized_render_ambiguous_locals_error
|
|
474
|
+
def to_hash: () -> serialized_render_ambiguous_locals_error
|
|
475
|
+
|
|
476
|
+
# : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
477
|
+
def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
class RenderMissingLocalsError < Error
|
|
481
|
+
include Colors
|
|
482
|
+
|
|
483
|
+
attr_reader partial: String?
|
|
484
|
+
|
|
485
|
+
attr_reader keywords: String?
|
|
486
|
+
|
|
487
|
+
# : (String, Location?, String, String, String) -> void
|
|
488
|
+
def initialize: (String, Location?, String, String, String) -> void
|
|
489
|
+
|
|
490
|
+
# : () -> String
|
|
491
|
+
def inspect: () -> String
|
|
492
|
+
|
|
493
|
+
# : () -> serialized_render_missing_locals_error
|
|
494
|
+
def to_hash: () -> serialized_render_missing_locals_error
|
|
495
|
+
|
|
496
|
+
# : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
497
|
+
def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
class RenderNoArgumentsError < Error
|
|
501
|
+
include Colors
|
|
502
|
+
|
|
503
|
+
# : () -> String
|
|
504
|
+
def inspect: () -> String
|
|
505
|
+
|
|
506
|
+
# : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
507
|
+
def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
class RenderConflictingPartialError < Error
|
|
511
|
+
include Colors
|
|
512
|
+
|
|
513
|
+
attr_reader positional_partial: String?
|
|
514
|
+
|
|
515
|
+
attr_reader keyword_partial: String?
|
|
516
|
+
|
|
517
|
+
# : (String, Location?, String, String, String) -> void
|
|
518
|
+
def initialize: (String, Location?, String, String, String) -> void
|
|
519
|
+
|
|
520
|
+
# : () -> String
|
|
521
|
+
def inspect: () -> String
|
|
522
|
+
|
|
523
|
+
# : () -> serialized_render_conflicting_partial_error
|
|
524
|
+
def to_hash: () -> serialized_render_conflicting_partial_error
|
|
525
|
+
|
|
526
|
+
# : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
527
|
+
def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
class RenderInvalidAsOptionError < Error
|
|
531
|
+
include Colors
|
|
532
|
+
|
|
533
|
+
attr_reader as_value: String?
|
|
534
|
+
|
|
535
|
+
# : (String, Location?, String, String) -> void
|
|
536
|
+
def initialize: (String, Location?, String, String) -> void
|
|
537
|
+
|
|
538
|
+
# : () -> String
|
|
539
|
+
def inspect: () -> String
|
|
540
|
+
|
|
541
|
+
# : () -> serialized_render_invalid_as_option_error
|
|
542
|
+
def to_hash: () -> serialized_render_invalid_as_option_error
|
|
543
|
+
|
|
544
|
+
# : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
545
|
+
def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
class RenderObjectAndCollectionError < Error
|
|
549
|
+
include Colors
|
|
550
|
+
|
|
551
|
+
# : () -> String
|
|
552
|
+
def inspect: () -> String
|
|
553
|
+
|
|
554
|
+
# : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
555
|
+
def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
class RenderLayoutWithoutBlockError < Error
|
|
559
|
+
include Colors
|
|
560
|
+
|
|
561
|
+
attr_reader layout: String?
|
|
562
|
+
|
|
563
|
+
# : (String, Location?, String, String) -> void
|
|
564
|
+
def initialize: (String, Location?, String, String) -> void
|
|
565
|
+
|
|
566
|
+
# : () -> String
|
|
567
|
+
def inspect: () -> String
|
|
568
|
+
|
|
569
|
+
# : () -> serialized_render_layout_without_block_error
|
|
570
|
+
def to_hash: () -> serialized_render_layout_without_block_error
|
|
571
|
+
|
|
572
|
+
# : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
573
|
+
def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
574
|
+
end
|
|
461
575
|
end
|
|
462
576
|
end
|
data/sig/herb/parser_options.rbs
CHANGED
|
@@ -10,6 +10,8 @@ module Herb
|
|
|
10
10
|
|
|
11
11
|
attr_reader action_view_helpers: bool
|
|
12
12
|
|
|
13
|
+
attr_reader render_nodes: bool
|
|
14
|
+
|
|
13
15
|
attr_reader prism_program: bool
|
|
14
16
|
|
|
15
17
|
attr_reader prism_nodes: bool
|
|
@@ -24,6 +26,8 @@ module Herb
|
|
|
24
26
|
|
|
25
27
|
DEFAULT_ACTION_VIEW_HELPERS: bool
|
|
26
28
|
|
|
29
|
+
DEFAULT_RENDER_NODES: bool
|
|
30
|
+
|
|
27
31
|
DEFAULT_PRISM_PROGRAM: bool
|
|
28
32
|
|
|
29
33
|
DEFAULT_PRISM_NODES: bool
|
data/sig/herb/visitor.rbs
CHANGED
|
@@ -121,6 +121,12 @@ module Herb
|
|
|
121
121
|
# : (Herb::AST::ERBUnlessNode) -> void
|
|
122
122
|
def visit_erb_unless_node: (Herb::AST::ERBUnlessNode) -> void
|
|
123
123
|
|
|
124
|
+
# : (Herb::AST::RubyRenderLocalNode) -> void
|
|
125
|
+
def visit_ruby_render_local_node: (Herb::AST::RubyRenderLocalNode) -> void
|
|
126
|
+
|
|
127
|
+
# : (Herb::AST::ERBRenderNode) -> void
|
|
128
|
+
def visit_erb_render_node: (Herb::AST::ERBRenderNode) -> void
|
|
129
|
+
|
|
124
130
|
# : (Herb::AST::ERBYieldNode) -> void
|
|
125
131
|
def visit_erb_yield_node: (Herb::AST::ERBYieldNode) -> void
|
|
126
132
|
|
data/sig/rubyvm.rbs
ADDED
|
@@ -112,4 +112,32 @@ module Herb
|
|
|
112
112
|
nested_tag_column: Integer,
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
type serialized_render_ambiguous_locals_error = serialized_error & {
|
|
116
|
+
partial: String,
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
type serialized_render_missing_locals_error = serialized_error & {
|
|
120
|
+
partial: String,
|
|
121
|
+
keywords: String,
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
type serialized_render_no_arguments_error = serialized_error & {
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
type serialized_render_conflicting_partial_error = serialized_error & {
|
|
128
|
+
positional_partial: String,
|
|
129
|
+
keyword_partial: String,
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
type serialized_render_invalid_as_option_error = serialized_error & {
|
|
133
|
+
as_value: String,
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
type serialized_render_object_and_collection_error = serialized_error & {
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
type serialized_render_layout_without_block_error = serialized_error & {
|
|
140
|
+
layout: String,
|
|
141
|
+
}
|
|
142
|
+
|
|
115
143
|
end
|
|
@@ -268,6 +268,37 @@ module Herb
|
|
|
268
268
|
end_node: Herb::AST::ERBEndNode,
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
+
type serialized_ruby_render_local_node = serialized_node & {
|
|
272
|
+
name: Herb::Token,
|
|
273
|
+
value: Herb::AST::RubyLiteralNode,
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
type serialized_erb_render_node = serialized_node & {
|
|
277
|
+
tag_opening: Herb::Token,
|
|
278
|
+
content: Herb::Token,
|
|
279
|
+
tag_closing: Herb::Token,
|
|
280
|
+
analyzed_ruby: nil,
|
|
281
|
+
prism_node: String,
|
|
282
|
+
partial: Herb::Token,
|
|
283
|
+
template_path: Herb::Token,
|
|
284
|
+
layout: Herb::Token,
|
|
285
|
+
file: Herb::Token,
|
|
286
|
+
inline_template: Herb::Token,
|
|
287
|
+
body: Herb::Token,
|
|
288
|
+
plain: Herb::Token,
|
|
289
|
+
html: Herb::Token,
|
|
290
|
+
renderable: Herb::Token,
|
|
291
|
+
collection: Herb::Token,
|
|
292
|
+
object: Herb::Token,
|
|
293
|
+
as_name: Herb::Token,
|
|
294
|
+
spacer_template: Herb::Token,
|
|
295
|
+
formats: Herb::Token,
|
|
296
|
+
variants: Herb::Token,
|
|
297
|
+
handlers: Herb::Token,
|
|
298
|
+
content_type: Herb::Token,
|
|
299
|
+
locals: Array[Herb::AST::RubyRenderLocalNode],
|
|
300
|
+
}
|
|
301
|
+
|
|
271
302
|
type serialized_erb_yield_node = serialized_node & {
|
|
272
303
|
tag_opening: Herb::Token,
|
|
273
304
|
content: Herb::Token,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include "../../include/analyze/action_view/attribute_extraction_helpers.h"
|
|
2
2
|
#include "../../include/analyze/action_view/tag_helper_node_builders.h"
|
|
3
|
+
#include "../../include/html_util.h"
|
|
3
4
|
#include "../../include/util.h"
|
|
4
5
|
#include "../../include/util/hb_allocator.h"
|
|
5
6
|
#include "../../include/util/hb_array.h"
|
|
@@ -58,6 +59,14 @@ static AST_HTML_ATTRIBUTE_NODE_T* create_attribute_from_value(
|
|
|
58
59
|
hb_allocator_dealloc(allocator, value_string);
|
|
59
60
|
|
|
60
61
|
return attribute;
|
|
62
|
+
} else if (value_node->type == PM_TRUE_NODE) {
|
|
63
|
+
if (is_boolean_attribute(hb_string((char*) name_string))) {
|
|
64
|
+
return create_html_attribute_node(name_string, NULL, start_position, end_position, allocator);
|
|
65
|
+
}
|
|
66
|
+
return create_html_attribute_node(name_string, "true", start_position, end_position, allocator);
|
|
67
|
+
} else if (value_node->type == PM_FALSE_NODE) {
|
|
68
|
+
if (is_boolean_attribute(hb_string((char*) name_string))) { return NULL; }
|
|
69
|
+
return create_html_attribute_node(name_string, "false", start_position, end_position, allocator);
|
|
61
70
|
} else if (value_node->type == PM_INTERPOLATED_STRING_NODE) {
|
|
62
71
|
return create_html_attribute_with_interpolated_value(
|
|
63
72
|
name_string,
|
|
@@ -265,7 +274,7 @@ bool has_html_attributes_in_call(pm_call_node_t* call_node) {
|
|
|
265
274
|
|
|
266
275
|
pm_node_t* last_argument = arguments->arguments.nodes[arguments->arguments.size - 1];
|
|
267
276
|
|
|
268
|
-
return last_argument && last_argument->type == PM_KEYWORD_HASH_NODE;
|
|
277
|
+
return last_argument && (last_argument->type == PM_KEYWORD_HASH_NODE || last_argument->type == PM_HASH_NODE);
|
|
269
278
|
}
|
|
270
279
|
|
|
271
280
|
hb_array_T* extract_html_attributes_from_call_node(
|
|
@@ -280,6 +289,19 @@ hb_array_T* extract_html_attributes_from_call_node(
|
|
|
280
289
|
pm_arguments_node_t* arguments = call_node->arguments;
|
|
281
290
|
pm_node_t* last_argument = arguments->arguments.nodes[arguments->arguments.size - 1];
|
|
282
291
|
|
|
292
|
+
if (last_argument->type == PM_HASH_NODE) {
|
|
293
|
+
pm_hash_node_t* hash_node = (pm_hash_node_t*) last_argument;
|
|
294
|
+
pm_keyword_hash_node_t synthetic = { .base = hash_node->base, .elements = hash_node->elements };
|
|
295
|
+
|
|
296
|
+
return extract_html_attributes_from_keyword_hash(
|
|
297
|
+
&synthetic,
|
|
298
|
+
source,
|
|
299
|
+
original_source,
|
|
300
|
+
erb_content_offset,
|
|
301
|
+
allocator
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
283
305
|
return extract_html_attributes_from_keyword_hash(
|
|
284
306
|
(pm_keyword_hash_node_t*) last_argument,
|
|
285
307
|
source,
|
|
@@ -38,23 +38,31 @@ char* extract_content_tag_name(pm_call_node_t* call_node, pm_parser_t* parser, h
|
|
|
38
38
|
char* extract_content_tag_content(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
|
|
39
39
|
(void) parser;
|
|
40
40
|
|
|
41
|
-
if (!call_node
|
|
41
|
+
if (!call_node) { return NULL; }
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
if (
|
|
43
|
+
char* block_content = extract_inline_block_content(call_node, allocator);
|
|
44
|
+
if (block_content) { return block_content; }
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
if (call_node->arguments) {
|
|
47
|
+
pm_arguments_node_t* arguments = call_node->arguments;
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
if (arguments->arguments.size >= 2) {
|
|
50
|
+
pm_node_t* second_argument = arguments->arguments.nodes[1];
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
if (second_argument->type != PM_KEYWORD_HASH_NODE) {
|
|
53
|
+
if (second_argument->type == PM_STRING_NODE) {
|
|
54
|
+
pm_string_node_t* string_node = (pm_string_node_t*) second_argument;
|
|
55
|
+
size_t length = pm_string_length(&string_node->unescaped);
|
|
56
|
+
return hb_allocator_strndup(allocator, (const char*) pm_string_source(&string_node->unescaped), length);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
size_t source_length = second_argument->location.end - second_argument->location.start;
|
|
60
|
+
return hb_allocator_strndup(allocator, (const char*) second_argument->location.start, source_length);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
54
63
|
}
|
|
55
64
|
|
|
56
|
-
|
|
57
|
-
return hb_allocator_strndup(allocator, (const char*) second_argument->location.start, source_length);
|
|
65
|
+
return NULL;
|
|
58
66
|
}
|
|
59
67
|
|
|
60
68
|
bool content_tag_supports_block(void) {
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#include "../../include/analyze/action_view/tag_helper_handler.h"
|
|
2
|
+
|
|
3
|
+
#include <prism.h>
|
|
4
|
+
#include <stdbool.h>
|
|
5
|
+
#include <stdlib.h>
|
|
6
|
+
#include <string.h>
|
|
7
|
+
|
|
8
|
+
bool detect_javascript_include_tag(pm_call_node_t* call_node, pm_parser_t* parser) {
|
|
9
|
+
if (!call_node || !call_node->name) { return false; }
|
|
10
|
+
|
|
11
|
+
pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, call_node->name);
|
|
12
|
+
return constant && constant->length == 22
|
|
13
|
+
&& strncmp((const char*) constant->start, "javascript_include_tag", 22) == 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
char* extract_javascript_include_tag_name(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
|
|
17
|
+
(void) call_node;
|
|
18
|
+
(void) parser;
|
|
19
|
+
|
|
20
|
+
return hb_allocator_strdup(allocator, "script");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
char* extract_javascript_include_tag_content(
|
|
24
|
+
pm_call_node_t* call_node,
|
|
25
|
+
pm_parser_t* parser,
|
|
26
|
+
hb_allocator_T* allocator
|
|
27
|
+
) {
|
|
28
|
+
(void) call_node;
|
|
29
|
+
(void) parser;
|
|
30
|
+
(void) allocator;
|
|
31
|
+
|
|
32
|
+
return NULL;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
char* extract_javascript_include_tag_src(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
|
|
36
|
+
(void) parser;
|
|
37
|
+
|
|
38
|
+
if (!call_node || !call_node->arguments) { return NULL; }
|
|
39
|
+
|
|
40
|
+
pm_arguments_node_t* arguments = call_node->arguments;
|
|
41
|
+
if (!arguments->arguments.size) { return NULL; }
|
|
42
|
+
|
|
43
|
+
pm_node_t* first_argument = arguments->arguments.nodes[0];
|
|
44
|
+
|
|
45
|
+
if (first_argument->type == PM_STRING_NODE) {
|
|
46
|
+
pm_string_node_t* string_node = (pm_string_node_t*) first_argument;
|
|
47
|
+
size_t length = pm_string_length(&string_node->unescaped);
|
|
48
|
+
|
|
49
|
+
return hb_allocator_strndup(allocator, (const char*) pm_string_source(&string_node->unescaped), length);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
size_t source_length = first_argument->location.end - first_argument->location.start;
|
|
53
|
+
return hb_allocator_strndup(allocator, (const char*) first_argument->location.start, source_length);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
bool javascript_include_tag_source_is_url(const char* source, size_t length) {
|
|
57
|
+
if (!source || length == 0) { return false; }
|
|
58
|
+
|
|
59
|
+
if (length >= 2 && source[0] == '/' && source[1] == '/') { return true; }
|
|
60
|
+
if (strstr(source, "://") != NULL) { return true; }
|
|
61
|
+
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
char* wrap_in_javascript_path(const char* source, size_t source_length, hb_allocator_T* allocator) {
|
|
66
|
+
const char* prefix = "javascript_path(";
|
|
67
|
+
const char* suffix = ")";
|
|
68
|
+
size_t prefix_length = strlen(prefix);
|
|
69
|
+
size_t suffix_length = strlen(suffix);
|
|
70
|
+
size_t total_length = prefix_length + source_length + suffix_length;
|
|
71
|
+
char* result = hb_allocator_alloc(allocator, total_length + 1);
|
|
72
|
+
|
|
73
|
+
memcpy(result, prefix, prefix_length);
|
|
74
|
+
memcpy(result + prefix_length, source, source_length);
|
|
75
|
+
memcpy(result + prefix_length + source_length, suffix, suffix_length);
|
|
76
|
+
result[total_length] = '\0';
|
|
77
|
+
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
bool javascript_include_tag_supports_block(void) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const tag_helper_handler_T javascript_include_tag_handler = {
|
|
86
|
+
.name = "javascript_include_tag",
|
|
87
|
+
.source = HB_STRING_LITERAL("ActionView::Helpers::AssetTagHelper#javascript_include_tag"),
|
|
88
|
+
.detect = detect_javascript_include_tag,
|
|
89
|
+
.extract_tag_name = extract_javascript_include_tag_name,
|
|
90
|
+
.extract_content = extract_javascript_include_tag_content,
|
|
91
|
+
.supports_block = javascript_include_tag_supports_block
|
|
92
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#include "../../include/analyze/action_view/tag_helper_handler.h"
|
|
2
|
+
|
|
3
|
+
#include <prism.h>
|
|
4
|
+
#include <stdbool.h>
|
|
5
|
+
#include <stdlib.h>
|
|
6
|
+
#include <string.h>
|
|
7
|
+
|
|
8
|
+
bool detect_javascript_tag(pm_call_node_t* call_node, pm_parser_t* parser) {
|
|
9
|
+
if (!call_node || !call_node->name) { return false; }
|
|
10
|
+
|
|
11
|
+
pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, call_node->name);
|
|
12
|
+
return constant && constant->length == 14 && strncmp((const char*) constant->start, "javascript_tag", 14) == 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
char* extract_javascript_tag_name(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
|
|
16
|
+
(void) call_node;
|
|
17
|
+
(void) parser;
|
|
18
|
+
|
|
19
|
+
return hb_allocator_strdup(allocator, "script");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
char* extract_javascript_tag_content(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
|
|
23
|
+
(void) parser;
|
|
24
|
+
|
|
25
|
+
if (!call_node || !call_node->arguments) { return NULL; }
|
|
26
|
+
|
|
27
|
+
pm_arguments_node_t* arguments = call_node->arguments;
|
|
28
|
+
if (!arguments->arguments.size) { return NULL; }
|
|
29
|
+
|
|
30
|
+
pm_node_t* first_argument = arguments->arguments.nodes[0];
|
|
31
|
+
|
|
32
|
+
if (first_argument->type == PM_KEYWORD_HASH_NODE) { return NULL; }
|
|
33
|
+
|
|
34
|
+
if (first_argument->type == PM_STRING_NODE) {
|
|
35
|
+
pm_string_node_t* string_node = (pm_string_node_t*) first_argument;
|
|
36
|
+
size_t length = pm_string_length(&string_node->unescaped);
|
|
37
|
+
return hb_allocator_strndup(allocator, (const char*) pm_string_source(&string_node->unescaped), length);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
size_t source_length = first_argument->location.end - first_argument->location.start;
|
|
41
|
+
return hb_allocator_strndup(allocator, (const char*) first_argument->location.start, source_length);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
bool javascript_tag_supports_block(void) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const tag_helper_handler_T javascript_tag_handler = {
|
|
49
|
+
.name = "javascript_tag",
|
|
50
|
+
.source = HB_STRING_LITERAL("ActionView::Helpers::JavaScriptHelper#javascript_tag"),
|
|
51
|
+
.detect = detect_javascript_tag,
|
|
52
|
+
.extract_tag_name = extract_javascript_tag_name,
|
|
53
|
+
.extract_content = extract_javascript_tag_content,
|
|
54
|
+
.supports_block = javascript_tag_supports_block
|
|
55
|
+
};
|
|
@@ -56,7 +56,12 @@ char* extract_link_to_tag_name(pm_call_node_t* call_node, pm_parser_t* parser, h
|
|
|
56
56
|
char* extract_link_to_content(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
|
|
57
57
|
(void) parser;
|
|
58
58
|
|
|
59
|
-
if (!call_node
|
|
59
|
+
if (!call_node) { return NULL; }
|
|
60
|
+
|
|
61
|
+
char* block_content = extract_inline_block_content(call_node, allocator);
|
|
62
|
+
if (block_content) { return block_content; }
|
|
63
|
+
|
|
64
|
+
if (!call_node->arguments) { return NULL; }
|
|
60
65
|
|
|
61
66
|
pm_arguments_node_t* arguments = call_node->arguments;
|
|
62
67
|
if (!arguments->arguments.size) { return NULL; }
|
|
@@ -96,6 +101,25 @@ char* extract_link_to_href(pm_call_node_t* call_node, pm_parser_t* parser, hb_al
|
|
|
96
101
|
if (!call_node || !call_node->arguments) { return NULL; }
|
|
97
102
|
|
|
98
103
|
pm_arguments_node_t* arguments = call_node->arguments;
|
|
104
|
+
bool has_inline_block = call_node->block && call_node->block->type == PM_BLOCK_NODE;
|
|
105
|
+
|
|
106
|
+
if (has_inline_block && arguments->arguments.size >= 1) {
|
|
107
|
+
pm_node_t* first_argument = arguments->arguments.nodes[0];
|
|
108
|
+
|
|
109
|
+
if (first_argument->type == PM_STRING_NODE) {
|
|
110
|
+
pm_string_node_t* string_node = (pm_string_node_t*) first_argument;
|
|
111
|
+
size_t length = pm_string_length(&string_node->unescaped);
|
|
112
|
+
return hb_allocator_strndup(allocator, (const char*) pm_string_source(&string_node->unescaped), length);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
size_t source_length = first_argument->location.end - first_argument->location.start;
|
|
116
|
+
|
|
117
|
+
if (is_route_helper_node(first_argument, parser)) {
|
|
118
|
+
return hb_allocator_strndup(allocator, (const char*) first_argument->location.start, source_length);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return wrap_in_url_for((const char*) first_argument->location.start, source_length, allocator);
|
|
122
|
+
}
|
|
99
123
|
|
|
100
124
|
// Format: "url_for(<expression>)"
|
|
101
125
|
if (arguments->arguments.size == 1) {
|
|
@@ -8,8 +8,10 @@ extern const tag_helper_handler_T content_tag_handler;
|
|
|
8
8
|
extern const tag_helper_handler_T tag_dot_handler;
|
|
9
9
|
extern const tag_helper_handler_T link_to_handler;
|
|
10
10
|
extern const tag_helper_handler_T turbo_frame_tag_handler;
|
|
11
|
+
extern const tag_helper_handler_T javascript_tag_handler;
|
|
12
|
+
extern const tag_helper_handler_T javascript_include_tag_handler;
|
|
11
13
|
|
|
12
|
-
static size_t handlers_count =
|
|
14
|
+
static size_t handlers_count = 6;
|
|
13
15
|
|
|
14
16
|
tag_helper_info_T* tag_helper_info_init(hb_allocator_T* allocator) {
|
|
15
17
|
tag_helper_info_T* info = hb_allocator_alloc(allocator, sizeof(tag_helper_info_T));
|
|
@@ -41,7 +43,7 @@ void tag_helper_info_free(tag_helper_info_T** info) {
|
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
tag_helper_handler_T* get_tag_helper_handlers(void) {
|
|
44
|
-
static tag_helper_handler_T static_handlers[
|
|
46
|
+
static tag_helper_handler_T static_handlers[6];
|
|
45
47
|
static bool initialized = false;
|
|
46
48
|
|
|
47
49
|
if (!initialized) {
|
|
@@ -49,6 +51,8 @@ tag_helper_handler_T* get_tag_helper_handlers(void) {
|
|
|
49
51
|
static_handlers[1] = tag_dot_handler;
|
|
50
52
|
static_handlers[2] = link_to_handler;
|
|
51
53
|
static_handlers[3] = turbo_frame_tag_handler;
|
|
54
|
+
static_handlers[4] = javascript_tag_handler;
|
|
55
|
+
static_handlers[5] = javascript_include_tag_handler;
|
|
52
56
|
initialized = true;
|
|
53
57
|
}
|
|
54
58
|
|
|
@@ -58,3 +62,26 @@ tag_helper_handler_T* get_tag_helper_handlers(void) {
|
|
|
58
62
|
size_t get_tag_helper_handlers_count(void) {
|
|
59
63
|
return handlers_count;
|
|
60
64
|
}
|
|
65
|
+
|
|
66
|
+
char* extract_inline_block_content(pm_call_node_t* call_node, hb_allocator_T* allocator) {
|
|
67
|
+
if (!call_node || !call_node->block || call_node->block->type != PM_BLOCK_NODE) { return NULL; }
|
|
68
|
+
|
|
69
|
+
pm_block_node_t* block_node = (pm_block_node_t*) call_node->block;
|
|
70
|
+
|
|
71
|
+
if (!block_node->body || block_node->body->type != PM_STATEMENTS_NODE) { return NULL; }
|
|
72
|
+
|
|
73
|
+
pm_statements_node_t* statements = (pm_statements_node_t*) block_node->body;
|
|
74
|
+
|
|
75
|
+
if (statements->body.size != 1) { return NULL; }
|
|
76
|
+
|
|
77
|
+
pm_node_t* statement = statements->body.nodes[0];
|
|
78
|
+
|
|
79
|
+
if (statement->type == PM_STRING_NODE) {
|
|
80
|
+
pm_string_node_t* string_node = (pm_string_node_t*) statement;
|
|
81
|
+
size_t length = pm_string_length(&string_node->unescaped);
|
|
82
|
+
return hb_allocator_strndup(allocator, (const char*) pm_string_source(&string_node->unescaped), length);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
size_t source_length = statement->location.end - statement->location.start;
|
|
86
|
+
return hb_allocator_strndup(allocator, (const char*) statement->location.start, source_length);
|
|
87
|
+
}
|
|
@@ -36,17 +36,23 @@ char* extract_tag_dot_name(pm_call_node_t* call_node, pm_parser_t* parser, hb_al
|
|
|
36
36
|
char* extract_tag_dot_content(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
|
|
37
37
|
(void) parser;
|
|
38
38
|
|
|
39
|
-
if (!call_node
|
|
39
|
+
if (!call_node) { return NULL; }
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
if (
|
|
41
|
+
char* block_content = extract_inline_block_content(call_node, allocator);
|
|
42
|
+
if (block_content) { return block_content; }
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
if (call_node->arguments) {
|
|
45
|
+
pm_arguments_node_t* arguments = call_node->arguments;
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
if (arguments->arguments.size) {
|
|
48
|
+
pm_node_t* first_argument = arguments->arguments.nodes[0];
|
|
49
|
+
|
|
50
|
+
if (first_argument->type == PM_STRING_NODE) {
|
|
51
|
+
pm_string_node_t* string_node = (pm_string_node_t*) first_argument;
|
|
52
|
+
size_t length = pm_string_length(&string_node->unescaped);
|
|
53
|
+
return hb_allocator_strndup(allocator, (const char*) pm_string_source(&string_node->unescaped), length);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
50
56
|
}
|
|
51
57
|
|
|
52
58
|
return NULL;
|
|
@@ -88,7 +88,8 @@ AST_HTML_ATTRIBUTE_NODE_T* create_html_attribute_node(
|
|
|
88
88
|
AST_HTML_ATTRIBUTE_NAME_NODE_T* name_node =
|
|
89
89
|
create_attribute_name_node(name_string, start_position, end_position, allocator);
|
|
90
90
|
|
|
91
|
-
token_T* equals_token =
|
|
91
|
+
token_T* equals_token =
|
|
92
|
+
value_string ? create_synthetic_token(allocator, "=", TOKEN_EQUALS, start_position, end_position) : NULL;
|
|
92
93
|
AST_HTML_ATTRIBUTE_VALUE_NODE_T* value_node = NULL;
|
|
93
94
|
|
|
94
95
|
if (value_string) {
|
|
@@ -210,8 +211,20 @@ static AST_HTML_ATTRIBUTE_VALUE_NODE_T* create_interpolated_attribute_value(
|
|
|
210
211
|
}
|
|
211
212
|
}
|
|
212
213
|
} else if (part->type == PM_EMBEDDED_STATEMENTS_NODE) {
|
|
213
|
-
|
|
214
|
-
|
|
214
|
+
pm_embedded_statements_node_t* embedded = (pm_embedded_statements_node_t*) part;
|
|
215
|
+
const uint8_t* content_start;
|
|
216
|
+
const uint8_t* content_end;
|
|
217
|
+
|
|
218
|
+
if (embedded->statements) {
|
|
219
|
+
content_start = embedded->statements->base.location.start;
|
|
220
|
+
content_end = embedded->statements->base.location.end;
|
|
221
|
+
} else {
|
|
222
|
+
content_start = part->location.start;
|
|
223
|
+
content_end = part->location.end;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
size_t ruby_length = content_end - content_start;
|
|
227
|
+
char* ruby_content = hb_allocator_strndup(allocator, (const char*) content_start, ruby_length);
|
|
215
228
|
|
|
216
229
|
if (ruby_content) {
|
|
217
230
|
AST_RUBY_LITERAL_NODE_T* ruby_node = ast_ruby_literal_node_init(
|