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.
@@ -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: