phlex 0.3.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of phlex might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.editorconfig +8 -0
- data/.rubocop.yml +21 -5
- data/Gemfile +26 -12
- data/Procfile.dev +3 -0
- data/README.md +1 -1
- data/Rakefile +3 -5
- data/SECURITY.md +1 -1
- data/bench.rb +7 -0
- data/config/sus.rb +15 -0
- data/docs/assets/application.css +6 -0
- data/docs/build.rb +17 -10
- data/docs/components/callout.rb +1 -1
- data/docs/components/code_block.rb +2 -2
- data/docs/components/code_span.rb +9 -0
- data/docs/components/example.rb +5 -5
- data/docs/components/heading.rb +2 -2
- data/docs/components/layout.rb +62 -17
- data/docs/components/markdown.rb +14 -15
- data/docs/components/nav/item.rb +33 -0
- data/docs/components/nav.rb +6 -0
- data/docs/components/tabs/tab.rb +4 -2
- data/docs/components/tabs.rb +1 -1
- data/docs/components/title.rb +2 -2
- data/docs/page_builder.rb +3 -0
- data/docs/pages/application_page.rb +1 -1
- data/docs/pages/helpers.rb +97 -0
- data/docs/pages/index.rb +6 -17
- data/docs/pages/library/collections.rb +83 -0
- data/docs/pages/rails/getting_started.rb +53 -0
- data/docs/pages/rails/helpers.rb +55 -0
- data/docs/pages/rails/layouts.rb +61 -0
- data/docs/pages/rails/migrating.rb +37 -0
- data/docs/pages/rails/rendering_views.rb +35 -0
- data/docs/pages/templates.rb +53 -151
- data/docs/pages/testing/capybara.rb +48 -0
- data/docs/pages/testing/getting_started.rb +44 -0
- data/docs/pages/testing/nokogiri.rb +83 -0
- data/docs/pages/testing/rails.rb +17 -0
- data/docs/pages/translations.rb +81 -0
- data/docs/pages/views.rb +87 -78
- data/fixtures/compiler_test_helpers.rb +19 -0
- data/fixtures/content.rb +60 -0
- data/fixtures/dummy/app/components/comment_component.html.erb +14 -0
- data/fixtures/dummy/app/components/comment_component.rb +8 -0
- data/fixtures/dummy/app/components/reaction_component.html.erb +3 -0
- data/fixtures/dummy/app/components/reaction_component.rb +7 -0
- data/fixtures/dummy/app/controllers/comments_controller.rb +4 -0
- data/fixtures/dummy/app/views/application_view.rb +8 -0
- data/fixtures/dummy/app/views/articles/form.rb +3 -1
- data/fixtures/dummy/app/views/card.rb +4 -2
- data/fixtures/dummy/app/views/comments/comment.rb +25 -0
- data/fixtures/dummy/app/views/comments/index.html.erb +3 -0
- data/fixtures/dummy/app/views/comments/reaction.rb +17 -0
- data/fixtures/dummy/app/views/comments/show.html.erb +3 -0
- data/fixtures/dummy/app/views/heading.rb +1 -1
- data/fixtures/layout.rb +5 -5
- data/fixtures/page.rb +18 -24
- data/fixtures/{test_helper.rb → rails_helper.rb} +3 -7
- data/fixtures/standard_element.rb +87 -0
- data/fixtures/view_helper.rb +1 -1
- data/fixtures/void_element.rb +31 -0
- data/lib/generators/phlex/collection/USAGE +8 -0
- data/lib/generators/phlex/collection/collection_generator.rb +13 -0
- data/lib/generators/phlex/collection/templates/collection.rb.erb +16 -0
- data/lib/generators/phlex/controller/USAGE +10 -0
- data/lib/generators/phlex/controller/controller_generator.rb +54 -0
- data/lib/generators/phlex/controller/templates/controller.rb.erb +10 -0
- data/lib/generators/phlex/controller/templates/view.rb.erb +14 -0
- data/lib/generators/phlex/layout/USAGE +8 -0
- data/lib/generators/phlex/layout/layout_generator.rb +13 -0
- data/lib/generators/phlex/layout/templates/layout.rb.erb +31 -0
- data/lib/generators/phlex/page/USAGE +8 -0
- data/lib/generators/phlex/page/page_generator.rb +13 -0
- data/lib/generators/phlex/page/templates/page.rb.erb +13 -0
- data/lib/generators/phlex/table/USAGE +8 -0
- data/lib/generators/phlex/table/table_generator.rb +14 -0
- data/lib/generators/phlex/table/templates/table.rb.erb +11 -0
- data/lib/generators/phlex/view/templates/view.rb.erb +7 -1
- data/lib/generators/phlex/view/view_generator.rb +9 -1
- data/lib/install/phlex.rb +10 -1
- data/lib/phlex/block.rb +2 -4
- data/lib/phlex/buffered.rb +6 -8
- data/lib/phlex/callable.rb +9 -0
- data/lib/phlex/collection.rb +33 -0
- data/lib/phlex/compiler/elements.rb +49 -0
- data/lib/phlex/compiler/generators/content.rb +103 -0
- data/lib/phlex/compiler/generators/element.rb +61 -0
- data/lib/phlex/compiler/nodes/base.rb +19 -0
- data/lib/phlex/compiler/nodes/call.rb +9 -0
- data/lib/phlex/compiler/nodes/command.rb +13 -0
- data/lib/phlex/compiler/nodes/fcall.rb +18 -0
- data/lib/phlex/compiler/nodes/method_add_block.rb +33 -0
- data/lib/phlex/compiler/nodes/vcall.rb +9 -0
- data/lib/phlex/compiler/optimizer.rb +66 -0
- data/lib/phlex/compiler/visitors/base.rb +15 -0
- data/lib/phlex/compiler/visitors/file.rb +23 -11
- data/lib/phlex/compiler/visitors/stable_scope.rb +28 -0
- data/lib/phlex/compiler/visitors/statements.rb +36 -0
- data/lib/phlex/compiler/visitors/view.rb +19 -0
- data/lib/phlex/compiler/visitors/view_method.rb +59 -0
- data/lib/phlex/compiler.rb +23 -3
- data/lib/phlex/elements.rb +57 -0
- data/lib/phlex/engine.rb +0 -3
- data/lib/phlex/helpers.rb +59 -0
- data/lib/phlex/html/callbacks.rb +11 -0
- data/lib/phlex/html.rb +209 -54
- data/lib/phlex/markdown.rb +76 -0
- data/lib/phlex/rails/form.rb +67 -0
- data/lib/phlex/rails/helpers.rb +118 -0
- data/lib/phlex/rails/layout.rb +15 -0
- data/lib/phlex/rails.rb +10 -0
- data/lib/phlex/renderable.rb +9 -3
- data/lib/phlex/table.rb +104 -0
- data/lib/phlex/testing/capybara.rb +25 -0
- data/lib/phlex/testing/nokogiri.rb +24 -0
- data/lib/phlex/testing/rails.rb +19 -0
- data/lib/phlex/testing/view_helper.rb +15 -0
- data/lib/phlex/translation.rb +23 -0
- data/lib/phlex/turbo/frame.rb +21 -0
- data/lib/phlex/turbo/stream.rb +18 -0
- data/lib/phlex/version.rb +1 -1
- data/lib/phlex.rb +22 -24
- metadata +112 -15
- data/.rspec +0 -1
- data/fixtures/compilation/vcall.rb +0 -38
- data/lib/phlex/compiler/generators/standard_element.rb +0 -30
- data/lib/phlex/compiler/generators/void_element.rb +0 -29
- data/lib/phlex/compiler/optimizers/base_optimizer.rb +0 -34
- data/lib/phlex/compiler/optimizers/vcall.rb +0 -29
- data/lib/phlex/compiler/visitors/base_visitor.rb +0 -19
- data/lib/phlex/compiler/visitors/component.rb +0 -28
- data/lib/phlex/compiler/visitors/component_method.rb +0 -28
- data/lib/phlex/rails/tag_helpers.rb +0 -29
- data/lib/phlex/view.rb +0 -223
data/lib/phlex/buffered.rb
CHANGED
@@ -1,19 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Phlex
|
4
|
-
class Buffered
|
4
|
+
class Buffered < SimpleDelegator
|
5
5
|
def initialize(object, buffer:)
|
6
|
-
|
6
|
+
super(object)
|
7
|
+
@buffer = buffer
|
7
8
|
end
|
8
9
|
|
9
|
-
|
10
|
-
|
10
|
+
# Alias output methods to this
|
11
|
+
def __output_method__(*args, **kwargs, &block)
|
12
|
+
output = __getobj__.public_send(__callee__, *args, **kwargs, &block)
|
11
13
|
@buffer << output if output.is_a? String
|
12
14
|
nil
|
13
15
|
end
|
14
|
-
|
15
|
-
def respond_to_missing?(name)
|
16
|
-
@object.respond_to?(name)
|
17
|
-
end
|
18
16
|
end
|
19
17
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlex
|
4
|
+
module Collection
|
5
|
+
def initialize(collection: nil, item: nil)
|
6
|
+
unless collection || item
|
7
|
+
raise ArgumentError, "You must pass a collection or an item as a keyword argument."
|
8
|
+
end
|
9
|
+
|
10
|
+
@collection = collection
|
11
|
+
@item = item
|
12
|
+
end
|
13
|
+
|
14
|
+
def template
|
15
|
+
@item ? item_template : collection_template { yield_items }
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def yield_items
|
21
|
+
if @item
|
22
|
+
raise ArgumentError, "You can only yield_items when rendering a collection. You are currently rendering an item."
|
23
|
+
end
|
24
|
+
|
25
|
+
@collection.each do |item|
|
26
|
+
@item = item
|
27
|
+
item_template
|
28
|
+
end
|
29
|
+
|
30
|
+
@item = nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlex::Compiler::Elements
|
4
|
+
module VCall
|
5
|
+
def format(formatter)
|
6
|
+
Phlex::Compiler::Generators::Element.new(
|
7
|
+
Phlex::Compiler::Nodes::VCall.new(self),
|
8
|
+
formatter: formatter
|
9
|
+
).call
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module FCall
|
14
|
+
def format(formatter)
|
15
|
+
Phlex::Compiler::Generators::Element.new(
|
16
|
+
Phlex::Compiler::Nodes::FCall.new(self),
|
17
|
+
formatter: formatter
|
18
|
+
).call
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module Command
|
23
|
+
def format(formatter)
|
24
|
+
Phlex::Compiler::Generators::Element.new(
|
25
|
+
Phlex::Compiler::Nodes::Command.new(self),
|
26
|
+
formatter: formatter
|
27
|
+
).call
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module MutatingMethodAddBlock
|
32
|
+
def format(formatter)
|
33
|
+
Phlex::Compiler::Generators::Element.new(
|
34
|
+
Phlex::Compiler::Nodes::MethodAddBlock.new(self),
|
35
|
+
formatter: formatter,
|
36
|
+
mutating: true
|
37
|
+
).call
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module MethodAddBlock
|
42
|
+
def format(formatter)
|
43
|
+
Phlex::Compiler::Generators::Element.new(
|
44
|
+
Phlex::Compiler::Nodes::MethodAddBlock.new(self),
|
45
|
+
formatter: formatter
|
46
|
+
).call
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlex
|
4
|
+
class Compiler
|
5
|
+
module Generators
|
6
|
+
class Content
|
7
|
+
def initialize(formatter, content:, mutating: false)
|
8
|
+
@formatter = formatter
|
9
|
+
@content = content
|
10
|
+
@mutating = mutating
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
return if nil_value?
|
15
|
+
return bare_string_value if bare_string_value?
|
16
|
+
return symbol_value if symbol_value?
|
17
|
+
return numeric_value if numeric_value?
|
18
|
+
return variable_value if variable_value?
|
19
|
+
|
20
|
+
unknown_value
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def nil_value?
|
26
|
+
case @content
|
27
|
+
in SyntaxTree::VarRef[value: SyntaxTree::Kw[value: "nil"]]
|
28
|
+
true
|
29
|
+
else
|
30
|
+
false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def bare_string_value?
|
35
|
+
case @content
|
36
|
+
in SyntaxTree::StringLiteral[parts: [SyntaxTree::TStringContent]]
|
37
|
+
true
|
38
|
+
else
|
39
|
+
false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def symbol_value?
|
44
|
+
@content.is_a?(SyntaxTree::SymbolLiteral)
|
45
|
+
end
|
46
|
+
|
47
|
+
def numeric_value?
|
48
|
+
@content.is_a?(SyntaxTree::Int) || @content.is_a?(SyntaxTree::FloatLiteral)
|
49
|
+
end
|
50
|
+
|
51
|
+
def variable_value?
|
52
|
+
@content.is_a?(SyntaxTree::VarRef)
|
53
|
+
end
|
54
|
+
|
55
|
+
def bare_string_value
|
56
|
+
@formatter.append do |f|
|
57
|
+
f.text Hescape.escape_html(
|
58
|
+
@content.parts.first.value
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def symbol_value
|
64
|
+
@formatter.append do |f|
|
65
|
+
f.text Hescape.escape_html(
|
66
|
+
@content.value.value
|
67
|
+
)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def numeric_value
|
72
|
+
@formatter.append do |f|
|
73
|
+
f.text Hescape.escape_html(
|
74
|
+
@content.value
|
75
|
+
)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def variable_value
|
80
|
+
@formatter.chain_append do |f|
|
81
|
+
f.text "Hescape.escape_html("
|
82
|
+
@content.format(f)
|
83
|
+
f.text ")"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def unknown_value
|
88
|
+
@formatter.breakable(force: true)
|
89
|
+
if @mutating
|
90
|
+
@content.format(@formatter)
|
91
|
+
else
|
92
|
+
@formatter.text "yield_content {"
|
93
|
+
@formatter.breakable(force: true)
|
94
|
+
@content.format(@formatter)
|
95
|
+
@formatter.breakable(force: true)
|
96
|
+
@formatter.text "}"
|
97
|
+
end
|
98
|
+
@formatter.breakable(force: true)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlex
|
4
|
+
class Compiler
|
5
|
+
module Generators
|
6
|
+
class Element
|
7
|
+
def initialize(node, formatter:, mutating: false)
|
8
|
+
@node = node
|
9
|
+
@formatter = formatter
|
10
|
+
@mutating = mutating
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
@formatter.append do |f|
|
15
|
+
f.text "<"
|
16
|
+
f.text tag
|
17
|
+
end
|
18
|
+
|
19
|
+
if @node.arguments&.parts&.any?
|
20
|
+
@formatter.chain_append do |f|
|
21
|
+
f.text "_attributes("
|
22
|
+
@node.arguments.format(@formatter)
|
23
|
+
f.text ")"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
@formatter.append do |f|
|
28
|
+
f.text ">"
|
29
|
+
end
|
30
|
+
|
31
|
+
return if void?
|
32
|
+
|
33
|
+
case @node.content
|
34
|
+
in SyntaxTree::Statements[body: [c]]
|
35
|
+
Content.new(@formatter, content: c, mutating: @mutating).call
|
36
|
+
in nil
|
37
|
+
nil
|
38
|
+
else
|
39
|
+
@node.content.format(@formatter)
|
40
|
+
end
|
41
|
+
|
42
|
+
@formatter.append do |f|
|
43
|
+
f.text "</"
|
44
|
+
f.text tag
|
45
|
+
f.text ">"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def tag
|
52
|
+
HTML::STANDARD_ELEMENTS[@node.name] || HTML::VOID_ELEMENTS[@node.name]
|
53
|
+
end
|
54
|
+
|
55
|
+
def void?
|
56
|
+
HTML::VOID_ELEMENTS.key?(@node.name)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlex::Compiler::Nodes
|
4
|
+
class FCall < Base
|
5
|
+
def name
|
6
|
+
@node.value.value.to_sym
|
7
|
+
end
|
8
|
+
|
9
|
+
def arguments
|
10
|
+
case @node.arguments
|
11
|
+
in SyntaxTree::Args
|
12
|
+
@node.arguments
|
13
|
+
in SyntaxTree::ArgParen
|
14
|
+
@node.arguments.arguments
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlex::Compiler::Nodes
|
4
|
+
class MethodAddBlock < Base
|
5
|
+
def name
|
6
|
+
method_call.name
|
7
|
+
end
|
8
|
+
|
9
|
+
def arguments
|
10
|
+
method_call.arguments
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_call
|
14
|
+
@method_call ||= case @node.call
|
15
|
+
in SyntaxTree::FCall
|
16
|
+
Phlex::Compiler::Nodes::FCall.new(@node.call)
|
17
|
+
in SyntaxTree::Command
|
18
|
+
Phlex::Compiler::Nodes::Command.new(@node.call)
|
19
|
+
in SyntaxTree::Call
|
20
|
+
Phlex::Compiler::Nodes::Call.new(@node.call)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def content
|
25
|
+
case @node.block
|
26
|
+
in SyntaxTree::BraceBlock
|
27
|
+
@node.block.statements
|
28
|
+
in SyntaxTree::DoBlock
|
29
|
+
@node.block.bodystmt.statements
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Phlex::Compiler
|
4
|
+
class Optimizer
|
5
|
+
def initialize(node, compiler:)
|
6
|
+
@node = node
|
7
|
+
@compiler = compiler
|
8
|
+
end
|
9
|
+
|
10
|
+
def call
|
11
|
+
return optimize_element if optimize_element?
|
12
|
+
|
13
|
+
false
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def optimize_element
|
19
|
+
case @node
|
20
|
+
in Nodes::VCall
|
21
|
+
@node.node.extend(Phlex::Compiler::Elements::VCall)
|
22
|
+
in Nodes::FCall
|
23
|
+
@node.node.extend(Phlex::Compiler::Elements::FCall)
|
24
|
+
in Nodes::Command
|
25
|
+
@node.node.extend(Phlex::Compiler::Elements::Command)
|
26
|
+
in Nodes::MethodAddBlock
|
27
|
+
optimize_add_method_block_element
|
28
|
+
end
|
29
|
+
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
def optimize_add_method_block_element
|
34
|
+
visitor = Phlex::Compiler::Visitors::Statements.new(@compiler)
|
35
|
+
visitor.visit(@node.content)
|
36
|
+
|
37
|
+
if visitor.mutating?
|
38
|
+
@node.node.extend(Phlex::Compiler::Elements::MutatingMethodAddBlock)
|
39
|
+
else
|
40
|
+
@node.node.extend(Phlex::Compiler::Elements::MethodAddBlock)
|
41
|
+
end
|
42
|
+
|
43
|
+
Phlex::Compiler::Visitors::ViewMethod.new(@compiler).visit(@node.content)
|
44
|
+
end
|
45
|
+
|
46
|
+
def optimize_element?
|
47
|
+
element? && !redefined?
|
48
|
+
end
|
49
|
+
|
50
|
+
def element?
|
51
|
+
standard_element? || void_element?
|
52
|
+
end
|
53
|
+
|
54
|
+
def redefined?
|
55
|
+
@compiler.redefined?(@node.name)
|
56
|
+
end
|
57
|
+
|
58
|
+
def standard_element?
|
59
|
+
Phlex::HTML::STANDARD_ELEMENTS.key?(@node.name)
|
60
|
+
end
|
61
|
+
|
62
|
+
def void_element?
|
63
|
+
Phlex::HTML::VOID_ELEMENTS.key?(@node.name)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlex::Compiler::Visitors
|
4
|
+
class Base < SyntaxTree::Visitor
|
5
|
+
def initialize(compiler = nil)
|
6
|
+
@compiler = compiler
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def format(node)
|
12
|
+
Phlex::Compiler::Formatter.format("", node)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,17 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Phlex
|
4
|
-
class
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
3
|
+
module Phlex::Compiler::Visitors
|
4
|
+
class File < Base
|
5
|
+
def initialize(compiler)
|
6
|
+
@scope = []
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
visit_method def visit_class(node)
|
11
|
+
@scope.push(node)
|
12
|
+
|
13
|
+
if node.location.start_line == @compiler.line
|
14
|
+
@compiler.scope = @scope
|
15
|
+
View.new(@compiler).visit_all(node.child_nodes)
|
16
|
+
else
|
17
|
+
super
|
14
18
|
end
|
19
|
+
|
20
|
+
@scope.pop
|
21
|
+
end
|
22
|
+
|
23
|
+
visit_method def visit_module(node)
|
24
|
+
@scope.push(node)
|
25
|
+
super
|
26
|
+
@scope.pop
|
15
27
|
end
|
16
28
|
end
|
17
29
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# A mixin for visitors that stops them from visiting other scopes.
|
4
|
+
|
5
|
+
module Phlex::Compiler::Visitors::StableScope
|
6
|
+
def visit_class(node)
|
7
|
+
nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def visit_module(node)
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def visit_brace_block(node)
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def visit_do_block(node)
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def visit_method_add_block(node)
|
23
|
+
node = Phlex::Compiler::Nodes::MethodAddBlock.new(node)
|
24
|
+
if node.method_call.name == :render
|
25
|
+
visit(node.content)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlex::Compiler::Visitors
|
4
|
+
class Statements < Base
|
5
|
+
MUTATING_METHODS = [:raw, :whitespace, :comment, :text, :doctype]
|
6
|
+
|
7
|
+
include StableScope
|
8
|
+
|
9
|
+
def mutating?
|
10
|
+
!!@mutating
|
11
|
+
end
|
12
|
+
|
13
|
+
visit_method def visit_vcall(node)
|
14
|
+
check Phlex::Compiler::Nodes::VCall.new(node)
|
15
|
+
end
|
16
|
+
|
17
|
+
visit_method def visit_fcall(node)
|
18
|
+
check Phlex::Compiler::Nodes::FCall.new(node)
|
19
|
+
end
|
20
|
+
|
21
|
+
visit_method def visit_command(node)
|
22
|
+
check Phlex::Compiler::Nodes::Command.new(node)
|
23
|
+
end
|
24
|
+
|
25
|
+
visit_method def visit_method_add_block(node)
|
26
|
+
check Phlex::Compiler::Nodes::MethodAddBlock.new(node)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def check(node)
|
32
|
+
@mutating = true if @compiler.tag_method?(node.name)
|
33
|
+
@mutating = true if MUTATING_METHODS.include?(node.name) && !@compiler.redefined?(node.name)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlex::Compiler::Visitors
|
4
|
+
class View < Base
|
5
|
+
include StableScope
|
6
|
+
|
7
|
+
visit_method def visit_def(node)
|
8
|
+
visitor = ViewMethod.new(@compiler)
|
9
|
+
visitor.visit_all(node.child_nodes)
|
10
|
+
|
11
|
+
if visitor.optimized_something?
|
12
|
+
@compiler.redefine(
|
13
|
+
format(node),
|
14
|
+
line: node.location.start_line
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlex::Compiler::Visitors
|
4
|
+
class ViewMethod < Base
|
5
|
+
include StableScope
|
6
|
+
|
7
|
+
def optimized_something?
|
8
|
+
!!@optimized_something
|
9
|
+
end
|
10
|
+
|
11
|
+
visit_method def visit_method_add_block(node)
|
12
|
+
return super if node.call.is_a?(SyntaxTree::Call)
|
13
|
+
|
14
|
+
optimizer = Phlex::Compiler::Optimizer.new(
|
15
|
+
Phlex::Compiler::Nodes::MethodAddBlock.new(node),
|
16
|
+
compiler: @compiler
|
17
|
+
)
|
18
|
+
|
19
|
+
if optimizer.call
|
20
|
+
@optimized_something = true
|
21
|
+
end
|
22
|
+
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
visit_method def visit_vcall(node)
|
27
|
+
optimizer = Phlex::Compiler::Optimizer.new(
|
28
|
+
Phlex::Compiler::Nodes::VCall.new(node),
|
29
|
+
compiler: @compiler
|
30
|
+
)
|
31
|
+
|
32
|
+
if optimizer.call
|
33
|
+
@optimized_something = true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
visit_method def visit_fcall(node)
|
38
|
+
optimizer = Phlex::Compiler::Optimizer.new(
|
39
|
+
Phlex::Compiler::Nodes::FCall.new(node),
|
40
|
+
compiler: @compiler
|
41
|
+
)
|
42
|
+
|
43
|
+
if optimizer.call
|
44
|
+
@optimized_something = true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
visit_method def visit_command(node)
|
49
|
+
optimizer = Phlex::Compiler::Optimizer.new(
|
50
|
+
Phlex::Compiler::Nodes::Command.new(node),
|
51
|
+
compiler: @compiler
|
52
|
+
)
|
53
|
+
|
54
|
+
if optimizer.call
|
55
|
+
@optimized_something = true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|