phlexing 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ffc28265f871c2d98adcd231e5c97677d186261c1f7770fa809b26bfc72490de
4
- data.tar.gz: 9a1aad812fab3bd2c355a5a768a68feae857b38af09075225ee0be4da5764c35
3
+ metadata.gz: 36dca58e17556b8b085edeb24dbe3fc5f8c8cb976056a6f739a655c5d94d7a36
4
+ data.tar.gz: 21f2b6dbec24a29a4dbfe52bb25d77887e52c72d29098e41c5a80a2173e8cc66
5
5
  SHA512:
6
- metadata.gz: bd78f6266b1fc40d5d61631b261867141b3cdfbc876f20ec0b78605f583e8969aff2d540010842c76e9376531daa6cd51ed7b35990aabd78209001104368cf6b
7
- data.tar.gz: f2dbaddeab5395082db642e60e8d95983af5e5a39f0687aeb2d9e1ec07761a7a4a6edac6d86fff18e206f9fe68c5bb6bb999428371b5a7e4a856501640fc6bee
6
+ metadata.gz: e52e0c6836f3e701c24f6ccf2338f823b5507497863e3af93d089712a2503213d2e86d5f3516f1f9d3e60bffd907de7ffbfc3661610141dd0f917f43a7cc2008
7
+ data.tar.gz: 00730543e38df6d87c1f5a1263ea964bfc27024de00dea885df86a5d60626afd665485899aad1d8cf350fba3df7e914879fda76040953125a4e9842e387c4b7b
data/Gemfile.lock CHANGED
@@ -17,7 +17,7 @@ GIT
17
17
  PATH
18
18
  remote: .
19
19
  specs:
20
- phlexing (0.1.0)
20
+ phlexing (0.2.0)
21
21
  erb_parser (~> 0.0.2)
22
22
  html_press (~> 0.8.2)
23
23
  nokogiri (~> 1.0)
@@ -62,7 +62,7 @@ GEM
62
62
  parser (>= 3.1.1.0)
63
63
  ruby-progressbar (1.11.0)
64
64
  rufo (0.13.0)
65
- treetop (1.6.11)
65
+ treetop (1.6.12)
66
66
  polyglot (~> 0.3)
67
67
  uglifier (2.7.2)
68
68
  execjs (>= 0.3.0)
@@ -12,7 +12,7 @@ module Phlexing
12
12
 
13
13
  using ::Phlexing::Refinements::StringRefinements
14
14
 
15
- attr_accessor :html, :custom_elements
15
+ attr_accessor :html, :custom_elements, :ivars, :locals, :idents
16
16
 
17
17
  def self.convert(html, **options)
18
18
  new(html, **options).output
@@ -22,7 +22,12 @@ module Phlexing
22
22
  @html = html
23
23
  @buffer = StringIO.new
24
24
  @custom_elements = Set.new
25
+ @ivars = Set.new
26
+ @locals = Set.new
27
+ @includes = Set.new
28
+ @idents = Set.new
25
29
  @options = options
30
+ analyze_ruby
26
31
  handle_node
27
32
  end
28
33
 
@@ -50,9 +55,10 @@ module Phlexing
50
55
 
51
56
  def handle_erb_element(node, level, newline: true)
52
57
  if erb_safe_output?(node)
53
- @buffer << "raw "
58
+ @buffer << "unsafe_raw "
54
59
  @buffer << node.text.from(1)
55
60
  @buffer << "\n" if newline
61
+
56
62
  return
57
63
  end
58
64
 
@@ -163,27 +169,73 @@ module Phlexing
163
169
  end
164
170
 
165
171
  def output
166
- buffer = StringIO.new
172
+ out = StringIO.new
167
173
 
168
174
  if @options.fetch(:phlex_class, false)
169
- buffer << "class #{@options.fetch(:component_name, 'MyComponent')}"
170
- buffer << "< #{@options.fetch(:parent_component, 'Phlex::HTML')}\n"
175
+ component_name = @options.fetch(:component_name, "Component")
176
+ component_name = "A#{component_name}" if component_name[0] == "0" || component_name[0].to_i != 0
177
+
178
+ parent_component = @options.fetch(:parent_component, "Phlex::HTML")
179
+ parent_component = "A#{parent_component}" if parent_component[0] == "0" || parent_component[0].to_i != 0
180
+
181
+ out << "class #{component_name}"
182
+ out << "< #{parent_component}\n"
183
+
184
+ if locals.any?
185
+ out << indent(1)
186
+ out << "attr_accessor "
187
+ out << locals.sort.map { |local| ":#{local}" }.join(", ")
188
+ out << "\n\n"
189
+ end
190
+
191
+ @custom_elements.sort.each do |element|
192
+ out << indent(1)
193
+ out << "register_element :#{element}\n"
194
+ end
171
195
 
172
- @custom_elements.each do |element|
173
- buffer << (indent(1) + "register_element :#{element}\n")
196
+ kwargs = Set.new(ivars + locals).sort
197
+
198
+ if kwargs.any?
199
+ out << indent(1)
200
+ out << "def initialize("
201
+ out << kwargs.map { |kwarg| "#{kwarg}: " }.join(", ")
202
+ out << ")\n"
203
+
204
+ kwargs.each do |dep|
205
+ out << indent(2)
206
+ out << "@#{dep} = #{dep}\n"
207
+ end
208
+
209
+ out << indent(1)
210
+ out << "end\n"
174
211
  end
175
212
 
176
- buffer << ("#{indent(1)}def template\n")
177
- buffer << (indent(2) + @buffer.string)
178
- buffer << ("#{indent(1)}end\n")
179
- buffer << "end\n"
213
+ out << indent(1)
214
+ out << "def template\n"
215
+
216
+ out << indent(2)
217
+ out << @buffer.string
218
+
219
+ out << indent(1)
220
+ out << "end\n"
221
+ out << "end\n"
180
222
  else
181
- buffer << @buffer.string
223
+ out << @buffer.string
182
224
  end
183
225
 
184
- Rufo::Formatter.format(buffer.string.strip)
226
+ Rufo::Formatter.format(out.string.strip)
185
227
  rescue Rufo::SyntaxError
186
- buffer.string.strip
228
+ out.string.strip
229
+ end
230
+
231
+ def analyze_ruby
232
+ ruby_code = ErbParser.parse(html).tokens.map { |tag| tag.is_a?(ErbParser::ErbTag) && !tag.to_s.start_with?("<%#") ? tag.ruby_code.delete_prefix("=") : nil }.join("\n")
233
+ visitor = Phlexing::Visitor.new(self)
234
+ program = SyntaxTree.parse(ruby_code)
235
+ # puts program.construct_keys
236
+ visitor.visit(program)
237
+ rescue StandardError => e
238
+ puts e.inspect
187
239
  end
188
240
 
189
241
  def converted_erb
@@ -1,7 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "phlex"
4
+
3
5
  module Phlexing
4
6
  module Helpers
7
+ KNOWN_ELEMENTS = Phlex::HTML::VOID_ELEMENTS.values + Phlex::HTML::STANDARD_ELEMENTS.values
8
+
5
9
  def indent(level)
6
10
  return "" if level == 1
7
11
 
@@ -33,10 +37,10 @@ module Phlexing
33
37
 
34
38
  def node_name(node)
35
39
  return "template_tag" if node.name == "template"
36
- return node.name unless node.name.include?("-")
37
40
 
38
41
  name = node.name.gsub("-", "_")
39
- @custom_elements << name
42
+
43
+ @custom_elements << name unless KNOWN_ELEMENTS.include?(name)
40
44
 
41
45
  name
42
46
  end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phlexing
4
+ class NameSuggestor
5
+ def self.suggest(html)
6
+ converter = Phlexing::Converter.new(html)
7
+
8
+ ivars = converter.ivars
9
+ locals = converter.locals
10
+
11
+ ids = extract(converter, :extract_id_from_element)
12
+ classes = extract(converter, :extract_class_from_element)
13
+ tags = extract(converter, :extract_tag_name_from_element)
14
+
15
+ return wrap(ivars.first) if ivars.one? && locals.none?
16
+ return wrap(locals.first) if locals.one? && ivars.none?
17
+ return wrap(ids.first) if ids.any?
18
+ return wrap(ivars.first) if ivars.any?
19
+ return wrap(locals.first) if locals.any?
20
+ return wrap(classes.first) if classes.any?
21
+ return wrap(tags.first) if tags.any?
22
+
23
+ "Component"
24
+ end
25
+
26
+ def self.wrap(name)
27
+ "#{name}_component".gsub("-", "_").gsub(" ", "_").camelize
28
+ end
29
+
30
+ def self.extract(converter, method)
31
+ return [] unless converter.parsed
32
+
33
+ converter.parsed.children.map { |element| send(method, element) }.compact
34
+ end
35
+
36
+ def self.extract_id_from_element(element)
37
+ return if element.nil?
38
+ return if element.is_a?(Nokogiri::XML::Text)
39
+
40
+ id_attribute = element.attributes.try(:[], "id")
41
+ return if id_attribute.nil?
42
+
43
+ id = id_attribute.value.to_s.strip
44
+ return if id.include?("<erb")
45
+
46
+ id
47
+ end
48
+
49
+ def self.extract_class_from_element(element)
50
+ return if element.nil?
51
+ return if element.is_a?(Nokogiri::XML::Text)
52
+
53
+ class_attribute = element.attributes.try(:[], "class")
54
+
55
+ return if class_attribute.nil?
56
+
57
+ classes = class_attribute.value.strip.split
58
+
59
+ return if classes.empty?
60
+
61
+ classes[0]
62
+ end
63
+
64
+ def self.extract_tag_name_from_element(element)
65
+ return if element.nil?
66
+ return if element.is_a?(Nokogiri::XML::Text)
67
+
68
+ return if ["div", "span", "p", "erb"].include?(element.name)
69
+
70
+ element.name
71
+ end
72
+ end
73
+ 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.3.0"
5
5
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "syntax_tree"
4
+
5
+ module Phlexing
6
+ class Visitor < SyntaxTree::Visitor
7
+ def initialize(converter)
8
+ @converter = converter
9
+ end
10
+
11
+ def visit_ivar(node)
12
+ @converter.ivars << node.value.from(1)
13
+ end
14
+
15
+ def visit_vcall(node)
16
+ @converter.locals << node.value.value
17
+ end
18
+
19
+ def visit_ident(node)
20
+ @converter.idents << node.value
21
+ end
22
+ end
23
+ end
data/lib/phlexing.rb CHANGED
@@ -3,6 +3,8 @@
3
3
  require_relative "phlexing/version"
4
4
  require_relative "phlexing/helpers"
5
5
  require_relative "phlexing/refinements/string_refinements"
6
+ require_relative "phlexing/visitor"
7
+ require_relative "phlexing/name_suggestor"
6
8
  require_relative "phlexing/converter"
7
9
 
8
10
  module Phlexing
metadata CHANGED
@@ -1,14 +1,14 @@
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.3.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-01-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: erb_parser
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.13.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: syntax_tree
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  description: Simple ERB to Phlex converter
70
84
  email:
71
85
  - marco.roth@hey.com
@@ -83,8 +97,10 @@ files:
83
97
  - lib/phlexing.rb
84
98
  - lib/phlexing/converter.rb
85
99
  - lib/phlexing/helpers.rb
100
+ - lib/phlexing/name_suggestor.rb
86
101
  - lib/phlexing/refinements/string_refinements.rb
87
102
  - lib/phlexing/version.rb
103
+ - lib/phlexing/visitor.rb
88
104
  - sig/phlexing.rbs
89
105
  homepage: https://github.com/marcoroth/phlexing
90
106
  licenses: