-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdsl_compiler.rb
More file actions
148 lines (124 loc) · 3.02 KB
/
Copy pathdsl_compiler.rb
File metadata and controls
148 lines (124 loc) · 3.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# frozen_string_literal: true
require 'cgi'
# An example HTML template DSL rewriter
class DSLRewriter < Sirop::Sourcifier
def initialize
super
@html_buffer = +''
end
def to_source(node)
@buffer.clear
@html_buffer.clear
visit(node)
@buffer
end
def emit(str)
if @embed_mode
@embed_buffer << str
else
@buffer << str
end
end
def embed_visit(node, pre = '', post = '')
@embed_mode = true
@embed_buffer = +''
visit(node)
@embed_mode = false
@html_buffer << "#{pre}#{@embed_buffer}#{post}"
end
def html_embed_visit(node)
embed_visit(node, '#{CGI.escapeHTML(', ')}')
end
def tag_attr_embed_visit(node)
embed_visit(node, '#{', '}')
end
def adjust_whitespace(loc)
super(loc) if !@embed_mode
end
def emit_code(loc, semicolon: false)
flush_html_buffer if !@embed_mode
super
end
def emit_html(str)
@html_buffer << str
end
def flush_html_buffer
return if @html_buffer.empty?
if @last_loc_start
adjust_whitespace(@html_location_start) if @html_location_start
end
@buffer << "__buffer__ << \"#{@html_buffer}\""
@html_buffer.clear
@last_loc_end = loc_end(@html_location_end) if @html_location_end
@html_location_start = nil
@html_location_end = nil
end
def visit_call_node(node)
return super if node.receiver
@html_location_start ||= node.location
inner_text, attrs = tag_args(node)
block = node.block
if inner_text
emit_tag_open(node, attrs)
emit_tag_inner_text(inner_text)
emit_tag_close(node)
elsif block
emit_tag_open(node, attrs)
visit(block.body)
@html_location_start ||= node.block.closing_loc
emit_tag_close(node)
else
emit_tag_open_close(node, attrs)
end
@html_location_end = node.location
end
def tag_args(node)
args = node.arguments&.arguments
return nil if !args
if args[0]&.is_a?(Prism::KeywordHashNode)
[nil, args[0]]
elsif args[1]&.is_a?(Prism::KeywordHashNode)
args
else
[args && args[0], nil]
end
end
def emit_tag_open(node, attrs)
emit_html("<#{node.name}")
emit_tag_attributes(node, attrs) if attrs
emit_html(">")
end
def emit_tag_close(node)
emit_html("</#{node.name}>")
end
def emit_tag_open_close(node, attrs)
emit_html("<#{node.name}")
emit_tag_attributes(node, attrs) if attrs
emit_html("/>")
end
def emit_tag_inner_text(node)
case node
when Prism::StringNode, Prism::SymbolNode
@html_buffer << CGI.escapeHTML(node.unescaped)
else
html_embed_visit(node)
end
end
def emit_tag_attributes(node, attrs)
attrs.elements.each do |e|
emit_html(" ")
emit_tag_attribute_node(e.key)
emit_html('=\"')
emit_tag_attribute_node(e.value)
emit_html('\"')
end
end
def emit_tag_attribute_node(node)
case node
when Prism::StringNode, Prism::SymbolNode
@html_buffer << node.unescaped
else
tag_attr_embed_visit(node)
end
end
end