phlexing 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +167 -15
- data/Rakefile +1 -6
- data/lib/phlexing/component_generator.rb +121 -0
- data/lib/phlexing/converter.rb +19 -178
- data/lib/phlexing/erb_transformer.rb +46 -0
- data/lib/phlexing/formatter.rb +22 -0
- data/lib/phlexing/helpers.rb +85 -55
- data/lib/phlexing/minifier.rb +41 -0
- data/lib/phlexing/name_suggestor.rb +76 -0
- data/lib/phlexing/options.rb +27 -0
- data/lib/phlexing/parser.rb +32 -0
- data/lib/phlexing/patches/html_press.rb +28 -0
- data/lib/phlexing/refinements/string_refinements.rb +26 -0
- data/lib/phlexing/ruby_analyzer.rb +83 -0
- data/lib/phlexing/template_generator.rb +209 -0
- data/lib/phlexing/version.rb +1 -1
- data/lib/phlexing/visitor.rb +105 -0
- data/lib/phlexing.rb +14 -1
- metadata +47 -8
@@ -0,0 +1,209 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "nokogiri"
|
4
|
+
|
5
|
+
module Phlexing
|
6
|
+
class TemplateGenerator
|
7
|
+
using Refinements::StringRefinements
|
8
|
+
|
9
|
+
include Helpers
|
10
|
+
|
11
|
+
attr_accessor :converter, :out, :options
|
12
|
+
|
13
|
+
def self.call(converter, source)
|
14
|
+
new(converter).call(source)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(converter)
|
18
|
+
@converter = converter
|
19
|
+
@options = @converter.options
|
20
|
+
@out = StringIO.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(source)
|
24
|
+
document = Parser.call(source)
|
25
|
+
handle_node(document)
|
26
|
+
|
27
|
+
Formatter.call(out.string.strip)
|
28
|
+
rescue StandardError
|
29
|
+
out.string.strip
|
30
|
+
end
|
31
|
+
|
32
|
+
def handle_text_output(text)
|
33
|
+
output("text", text)
|
34
|
+
end
|
35
|
+
|
36
|
+
def handle_html_comment_output(text)
|
37
|
+
output("comment", braces(quote(text)))
|
38
|
+
end
|
39
|
+
|
40
|
+
def handle_erb_comment_output(text)
|
41
|
+
output("#", text)
|
42
|
+
end
|
43
|
+
|
44
|
+
def handle_erb_unsafe_output(text)
|
45
|
+
output("unsafe_raw", text)
|
46
|
+
end
|
47
|
+
|
48
|
+
def handle_output(text)
|
49
|
+
output("", unescape(text).strip)
|
50
|
+
end
|
51
|
+
|
52
|
+
def handle_attributes(node)
|
53
|
+
return "" if node.attributes.keys.none?
|
54
|
+
|
55
|
+
attributes = []
|
56
|
+
|
57
|
+
node.attributes.each_value do |attribute|
|
58
|
+
attributes << handle_attribute(attribute)
|
59
|
+
end
|
60
|
+
|
61
|
+
parens(attributes.join(", "))
|
62
|
+
end
|
63
|
+
|
64
|
+
def handle_attribute(attribute)
|
65
|
+
if attribute.name.start_with?(/data-erb-(\d+)+/)
|
66
|
+
handle_erb_interpolation_in_tag(attribute)
|
67
|
+
elsif attribute.name.start_with?("data-erb-")
|
68
|
+
handle_erb_attribute_output(attribute)
|
69
|
+
else
|
70
|
+
handle_html_attribute_output(attribute)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def handle_html_attribute_output(attribute)
|
75
|
+
String.new.tap { |s|
|
76
|
+
s << arg(attribute.name.underscore)
|
77
|
+
s << quote(attribute.value)
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
def handle_erb_attribute_output(attribute)
|
82
|
+
String.new.tap { |s|
|
83
|
+
s << arg(attribute.name.delete_prefix("data-erb-").underscore)
|
84
|
+
|
85
|
+
s << if attribute.value.start_with?("<%=") && attribute.value.scan("<%").one? && attribute.value.end_with?("%>")
|
86
|
+
value = unwrap_erb(attribute.value)
|
87
|
+
value.include?(" ") ? parens(value) : value
|
88
|
+
else
|
89
|
+
transformed = Parser.call(attribute.value)
|
90
|
+
attribute = StringIO.new
|
91
|
+
|
92
|
+
transformed.children.each do |node|
|
93
|
+
case node
|
94
|
+
when Nokogiri::XML::Text
|
95
|
+
attribute << node.text
|
96
|
+
when Nokogiri::XML::Node
|
97
|
+
if node.attributes["loud"]
|
98
|
+
attribute << interpolate(node.text.strip)
|
99
|
+
else
|
100
|
+
attribute << interpolate("#{node.text.strip} && nil")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
quote(attribute.string)
|
106
|
+
end
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
def handle_erb_interpolation_in_tag(attribute)
|
111
|
+
"**#{parens("#{unwrap_erb(unescape(attribute.value))}: true")}"
|
112
|
+
end
|
113
|
+
|
114
|
+
def handle_erb_safe_node(node)
|
115
|
+
if siblings?(node) && string_output?(node)
|
116
|
+
handle_text_output(node.text.strip)
|
117
|
+
else
|
118
|
+
handle_output(node.text.strip)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def handle_text_node(node)
|
123
|
+
text = node.text
|
124
|
+
|
125
|
+
if text.squish.empty? && text.length.positive?
|
126
|
+
out << whitespace
|
127
|
+
|
128
|
+
text.strip!
|
129
|
+
end
|
130
|
+
|
131
|
+
return if text.length.zero?
|
132
|
+
|
133
|
+
if siblings?(node)
|
134
|
+
handle_text_output(quote(node.text))
|
135
|
+
else
|
136
|
+
handle_output(quote(text))
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def handle_html_element_node(node, level)
|
141
|
+
out << tag_name(node)
|
142
|
+
out << handle_attributes(node)
|
143
|
+
|
144
|
+
if node.children.any?
|
145
|
+
block { handle_children(node, level) }
|
146
|
+
end
|
147
|
+
|
148
|
+
out << newline
|
149
|
+
end
|
150
|
+
|
151
|
+
def handle_loud_erb_node(node)
|
152
|
+
if node.text.start_with?("=")
|
153
|
+
handle_erb_unsafe_output(node.text.from(1).strip)
|
154
|
+
else
|
155
|
+
handle_erb_safe_node(node)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def handle_silent_erb_node(node)
|
160
|
+
if node.text.start_with?("#")
|
161
|
+
handle_erb_comment_output(node.text.from(1).strip)
|
162
|
+
elsif node.text.start_with?("-")
|
163
|
+
handle_output(node.text.from(1).to(-2).strip)
|
164
|
+
else
|
165
|
+
handle_output(node.text.strip)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def handle_html_comment_node(node)
|
170
|
+
handle_html_comment_output(node.text.strip)
|
171
|
+
end
|
172
|
+
|
173
|
+
def handle_element_node(node, level)
|
174
|
+
case node
|
175
|
+
in name: "erb", attributes: [{ name: "loud", value: "" }]
|
176
|
+
handle_loud_erb_node(node)
|
177
|
+
in name: "erb", attributes: [{ name: "silent", value: "" }]
|
178
|
+
handle_silent_erb_node(node)
|
179
|
+
else
|
180
|
+
handle_html_element_node(node, level)
|
181
|
+
end
|
182
|
+
|
183
|
+
out << newline if level == 1
|
184
|
+
end
|
185
|
+
|
186
|
+
def handle_document_node(node, level)
|
187
|
+
handle_children(node, level)
|
188
|
+
end
|
189
|
+
|
190
|
+
def handle_children(node, level)
|
191
|
+
node.children.each do |child|
|
192
|
+
handle_node(child, level + 1)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def handle_node(node, level = 0)
|
197
|
+
case node
|
198
|
+
in Nokogiri::XML::Text
|
199
|
+
handle_text_node(node)
|
200
|
+
in Nokogiri::XML::Element
|
201
|
+
handle_element_node(node, level)
|
202
|
+
in Nokogiri::HTML4::Document | Nokogiri::HTML4::DocumentFragment | Nokogiri::XML::DTD
|
203
|
+
handle_document_node(node, level)
|
204
|
+
in Nokogiri::XML::Comment
|
205
|
+
handle_html_comment_node(node)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
data/lib/phlexing/version.rb
CHANGED
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "syntax_tree"
|
4
|
+
|
5
|
+
module Phlexing
|
6
|
+
class Visitor < SyntaxTree::Visitor
|
7
|
+
using Refinements::StringRefinements
|
8
|
+
include Helpers
|
9
|
+
|
10
|
+
def initialize(analyzer)
|
11
|
+
@analyzer = analyzer
|
12
|
+
end
|
13
|
+
|
14
|
+
def visit_ivar(node)
|
15
|
+
@analyzer.ivars << node.value.from(1)
|
16
|
+
end
|
17
|
+
|
18
|
+
def visit_const(node)
|
19
|
+
@analyzer.consts << node.value
|
20
|
+
end
|
21
|
+
|
22
|
+
def visit_command(node)
|
23
|
+
unless rails_helper?(node.message.value)
|
24
|
+
@analyzer.instance_methods << node.message.value
|
25
|
+
end
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
def visit_call(node)
|
30
|
+
if node.receiver
|
31
|
+
case node.receiver
|
32
|
+
when SyntaxTree::VarRef
|
33
|
+
value = node.receiver.value.value
|
34
|
+
|
35
|
+
case node.receiver.value
|
36
|
+
when SyntaxTree::IVar
|
37
|
+
@analyzer.ivars << value.from(1)
|
38
|
+
when SyntaxTree::Ident
|
39
|
+
@analyzer.idents << value
|
40
|
+
end
|
41
|
+
|
42
|
+
@analyzer.calls << value
|
43
|
+
|
44
|
+
when SyntaxTree::VCall
|
45
|
+
case node.receiver.value
|
46
|
+
when SyntaxTree::Ident
|
47
|
+
@analyzer.calls << node.receiver.value.value
|
48
|
+
end
|
49
|
+
|
50
|
+
when SyntaxTree::Ident
|
51
|
+
value = node.receiver.value.value.value
|
52
|
+
|
53
|
+
@analyzer.idents << value unless value.ends_with?("?")
|
54
|
+
@analyzer.calls << value
|
55
|
+
|
56
|
+
when SyntaxTree::Const
|
57
|
+
@analyzer.calls << node.receiver.value
|
58
|
+
end
|
59
|
+
|
60
|
+
elsif node.receiver.nil? && node.operator.nil?
|
61
|
+
case node.message
|
62
|
+
when SyntaxTree::Ident
|
63
|
+
if node.message.value.end_with?("?") || node.child_nodes[3].is_a?(SyntaxTree::ArgParen)
|
64
|
+
unless rails_helper?(node.message.value)
|
65
|
+
@analyzer.instance_methods << node.message.value
|
66
|
+
end
|
67
|
+
@analyzer.calls << node.message.value
|
68
|
+
else
|
69
|
+
@analyzer.idents << node.message.value
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
super
|
75
|
+
end
|
76
|
+
|
77
|
+
def visit_vcall(node)
|
78
|
+
unless rails_helper?(node.value.value)
|
79
|
+
@analyzer.locals << node.value.value
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def visit_ident(node)
|
84
|
+
unless rails_helper?(node.value)
|
85
|
+
@analyzer.idents << node.value
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def rails_helper?(name)
|
92
|
+
if known_rails_helpers.keys.include?(name)
|
93
|
+
@analyzer.includes << known_rails_helpers[name]
|
94
|
+
return true
|
95
|
+
end
|
96
|
+
|
97
|
+
if routes_helpers.map { |regex| name.scan(regex).any? }.reduce(:|)
|
98
|
+
@analyzer.includes << "Phlex::Rails::Helpers::Routes"
|
99
|
+
return true
|
100
|
+
end
|
101
|
+
|
102
|
+
false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/lib/phlexing.rb
CHANGED
@@ -1,8 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "phlexing/version"
|
4
|
-
require_relative "phlexing/helpers"
|
5
4
|
require_relative "phlexing/refinements/string_refinements"
|
5
|
+
require_relative "phlexing/patches/html_press"
|
6
|
+
|
7
|
+
require_relative "phlexing/erb_transformer"
|
8
|
+
require_relative "phlexing/formatter"
|
9
|
+
require_relative "phlexing/helpers"
|
10
|
+
require_relative "phlexing/minifier"
|
11
|
+
require_relative "phlexing/options"
|
12
|
+
require_relative "phlexing/parser"
|
13
|
+
require_relative "phlexing/ruby_analyzer"
|
14
|
+
require_relative "phlexing/visitor"
|
15
|
+
|
16
|
+
require_relative "phlexing/name_suggestor"
|
17
|
+
require_relative "phlexing/component_generator"
|
18
|
+
require_relative "phlexing/template_generator"
|
6
19
|
require_relative "phlexing/converter"
|
7
20
|
|
8
21
|
module Phlexing
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phlexing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marco Roth
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-03-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: deface
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: '1.9'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: '1.9'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: html_press
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -53,19 +53,47 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: phlex
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: '1.6'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: '1.6'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: phlex-rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.9'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.9'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: syntax_tree
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '6.0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '6.0'
|
69
97
|
description: Simple ERB to Phlex converter
|
70
98
|
email:
|
71
99
|
- marco.roth@hey.com
|
@@ -81,10 +109,21 @@ files:
|
|
81
109
|
- README.md
|
82
110
|
- Rakefile
|
83
111
|
- lib/phlexing.rb
|
112
|
+
- lib/phlexing/component_generator.rb
|
84
113
|
- lib/phlexing/converter.rb
|
114
|
+
- lib/phlexing/erb_transformer.rb
|
115
|
+
- lib/phlexing/formatter.rb
|
85
116
|
- lib/phlexing/helpers.rb
|
117
|
+
- lib/phlexing/minifier.rb
|
118
|
+
- lib/phlexing/name_suggestor.rb
|
119
|
+
- lib/phlexing/options.rb
|
120
|
+
- lib/phlexing/parser.rb
|
121
|
+
- lib/phlexing/patches/html_press.rb
|
86
122
|
- lib/phlexing/refinements/string_refinements.rb
|
123
|
+
- lib/phlexing/ruby_analyzer.rb
|
124
|
+
- lib/phlexing/template_generator.rb
|
87
125
|
- lib/phlexing/version.rb
|
126
|
+
- lib/phlexing/visitor.rb
|
88
127
|
- sig/phlexing.rbs
|
89
128
|
homepage: https://github.com/marcoroth/phlexing
|
90
129
|
licenses:
|