phlexing 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Phlexing
4
- VERSION = "0.2.0"
4
+ VERSION = "0.4.0"
5
5
  end
@@ -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.2.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-01-11 00:00:00.000000000 Z
11
+ date: 2023-03-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: erb_parser
14
+ name: deface
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.0.2
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: 0.0.2
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: rufo
56
+ name: phlex
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.13.0
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: 0.13.0
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: