phlexing 0.1.1 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36ca848b92899d1a6c218053bc730d321b550766aed6797467018e8a7bb10fa8
4
- data.tar.gz: 145d06606a772720817fc8bc30befb4c34cd5e5685f2bf1d8911b4e66d28b8ab
3
+ metadata.gz: 36dca58e17556b8b085edeb24dbe3fc5f8c8cb976056a6f739a655c5d94d7a36
4
+ data.tar.gz: 21f2b6dbec24a29a4dbfe52bb25d77887e52c72d29098e41c5a80a2173e8cc66
5
5
  SHA512:
6
- metadata.gz: 15d9ab5288501b69858b18e054ab254c6069adb66d6420d50371f1a008677a2dd62b9d219826d114bac054a16b887937dda370e5b50bfb339e5ab5b890a90f7e
7
- data.tar.gz: 800aa986cecaadbdca99aeadd44b2b2d3f4584b28864b5cab5aa6f40f4ee2e392efa7218f5327fefd92752494022af02237227cc4e6c1c30507797302b472afb
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)
@@ -45,13 +45,15 @@ GEM
45
45
  css_press
46
46
  multi_js (0.1.0)
47
47
  uglifier (~> 2)
48
- nokogiri (1.13.9-x86_64-darwin)
48
+ nokogiri (1.13.10-x86_64-darwin)
49
+ racc (~> 1.4)
50
+ nokogiri (1.13.10-x86_64-linux)
49
51
  racc (~> 1.4)
50
52
  parallel (1.22.1)
51
53
  parser (3.1.2.1)
52
54
  ast (~> 2.4.1)
53
55
  polyglot (0.3.5)
54
- racc (1.6.0)
56
+ racc (1.6.2)
55
57
  rainbow (3.1.1)
56
58
  rake (13.0.6)
57
59
  regexp_parser (2.6.0)
@@ -60,7 +62,7 @@ GEM
60
62
  parser (>= 3.1.1.0)
61
63
  ruby-progressbar (1.11.0)
62
64
  rufo (0.13.0)
63
- treetop (1.6.11)
65
+ treetop (1.6.12)
64
66
  polyglot (~> 0.3)
65
67
  uglifier (2.7.2)
66
68
  execjs (>= 0.3.0)
@@ -69,6 +71,7 @@ GEM
69
71
 
70
72
  PLATFORMS
71
73
  x86_64-darwin-19
74
+ x86_64-linux
72
75
 
73
76
  DEPENDENCIES
74
77
  minitest (~> 5.0)
data/README.md CHANGED
@@ -1,9 +1,5 @@
1
1
  # Phlexing
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/phlexing`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
6
-
7
3
  ## Installation
8
4
 
9
5
  Install the gem and add to the application's Gemfile by executing:
@@ -14,10 +10,6 @@ If bundler is not being used to manage dependencies, install the gem by executin
14
10
 
15
11
  $ gem install phlexing
16
12
 
17
- ## Usage
18
-
19
- TODO: Write usage instructions here
20
-
21
13
  ## Development
22
14
 
23
15
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -12,16 +12,22 @@ 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
- def self.convert(html)
18
- new(html).buffer
17
+ def self.convert(html, **options)
18
+ new(html, **options).output
19
19
  end
20
20
 
21
- def initialize(html)
21
+ def initialize(html, **options)
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
29
+ @options = options
30
+ analyze_ruby
25
31
  handle_node
26
32
  end
27
33
 
@@ -30,7 +36,7 @@ module Phlexing
30
36
 
31
37
  if text.squish.empty? && text.length.positive?
32
38
  @buffer << indent(level)
33
- @buffer << "whitespace\n"
39
+ @buffer << whitespace(@options)
34
40
 
35
41
  text.strip!
36
42
  end
@@ -42,16 +48,17 @@ module Phlexing
42
48
  @buffer << "text "
43
49
  end
44
50
 
45
- @buffer << double_quote(text)
51
+ @buffer << quote(text)
46
52
  @buffer << "\n" if newline
47
53
  end
48
54
  end
49
55
 
50
56
  def handle_erb_element(node, level, newline: true)
51
57
  if erb_safe_output?(node)
52
- @buffer << "raw "
58
+ @buffer << "unsafe_raw "
53
59
  @buffer << node.text.from(1)
54
60
  @buffer << "\n" if newline
61
+
55
62
  return
56
63
  end
57
64
 
@@ -99,7 +106,7 @@ module Phlexing
99
106
  def handle_comment_node(node, level)
100
107
  @buffer << indent(level)
101
108
  @buffer << "comment "
102
- @buffer << double_quote(node.text.strip)
109
+ @buffer << quote(node.text.strip)
103
110
  @buffer << "\n"
104
111
  end
105
112
 
@@ -161,6 +168,76 @@ module Phlexing
161
168
  @buffer.string.strip
162
169
  end
163
170
 
171
+ def output
172
+ out = StringIO.new
173
+
174
+ if @options.fetch(:phlex_class, false)
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
195
+
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"
211
+ end
212
+
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"
222
+ else
223
+ out << @buffer.string
224
+ end
225
+
226
+ Rufo::Formatter.format(out.string.strip)
227
+ rescue Rufo::SyntaxError
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
239
+ end
240
+
164
241
  def converted_erb
165
242
  ErbParser.transform_xml(html).gsub("\n", "").gsub("\r", "")
166
243
  rescue StandardError
@@ -1,13 +1,21 @@
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
 
8
12
  " " * level
9
13
  end
10
14
 
15
+ def whitespace(options)
16
+ options.fetch(:whitespace, true) ? "whitespace\n" : ""
17
+ end
18
+
11
19
  def double_quote(string)
12
20
  "\"#{string}\""
13
21
  end
@@ -16,12 +24,23 @@ module Phlexing
16
24
  "'#{string}'"
17
25
  end
18
26
 
27
+ def percent_literal_string(string)
28
+ "%(#{string})"
29
+ end
30
+
31
+ def quote(string)
32
+ return double_quote(string) unless string.include?('"')
33
+ return single_quote(string) unless string.include?("'")
34
+
35
+ percent_literal_string(string)
36
+ end
37
+
19
38
  def node_name(node)
20
39
  return "template_tag" if node.name == "template"
21
- return node.name unless node.name.include?("-")
22
40
 
23
41
  name = node.name.gsub("-", "_")
24
- @custom_elements << name
42
+
43
+ @custom_elements << name unless KNOWN_ELEMENTS.include?(name)
25
44
 
26
45
  name
27
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.1.1"
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.1.1
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: 2022-10-29 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: