antlers 0.8.1 → 0.8.2

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: 8d3bcf6e14ade37294793b87b3ab3ab152e519f8c081a130644b0d28d489b63b
4
- data.tar.gz: d9886a3044fb8654b37f111a9536ba7dfef4945c26fb08112e400ab14e76d8e7
3
+ metadata.gz: e0dbec268b4fe0b7966b5f7161c61b16c155695ae10ab9c16d66ea67462348f4
4
+ data.tar.gz: a5ef4b1479077100df98ebf33a16379cf934cecbb980184008b5ecb86c3bcbb0
5
5
  SHA512:
6
- metadata.gz: a4179e613ca96ea49fdbc7d991a627a45640182ae5aaa5f01dc935396586ba8b583df469113c26c7a139308956bc18980cdbd04877c73a9b7cd14617682dd2d3
7
- data.tar.gz: 698769c0d6bfd0e9872c5022f72555290acff3888615f44061ed10847af8f97af58477c35059678c2e02a2bdafc16d3f06ff514ab80aa539abc2de7cbfeda6bd
6
+ metadata.gz: e8e4537ad73ba6356a5ce6a4632da46113374c21e6449ba9f744f9166e47ec93fcb619cab17d536d0b6413145c11e91f726b0a48e6b628af35c3662ec55e2970
7
+ data.tar.gz: 34b6b683e8ca4d3b736efa8684d049064032abf7ca081d2791370e0135b8ff7adc02e67dcf22a3c32dbe616b84302882b5346cc28c0915145e5278252cab5048
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'plugs'
4
+
5
+ module Antlers
6
+ class Elements
7
+ include Plugs
8
+
9
+ plug(:root) do
10
+ plug(:node) do
11
+ lazy do
12
+ require_relative '../nodes/root_node'
13
+ RootNode
14
+ end
15
+ end
16
+ end
17
+
18
+ plug(:html) do
19
+ plug(:node) do
20
+ lazy do
21
+ require_relative '../nodes/html_node'
22
+ HTMLNode
23
+ end
24
+ end
25
+ end
26
+
27
+ plug(:form) do
28
+ plug(:lexeme) do
29
+ lazy do
30
+ require_relative '../lexemes/form_lexeme'
31
+ FormLexeme
32
+ end
33
+ end
34
+
35
+ plug(:node) do
36
+ lazy do
37
+ require_relative '../nodes/form_node'
38
+ FormNode
39
+ end
40
+ end
41
+ end
42
+
43
+ plug(:for) do
44
+ plug(:lexeme) do
45
+ lazy do
46
+ require_relative '../lexemes/for_lexeme'
47
+ ForLexeme
48
+ end
49
+ end
50
+
51
+ plug(:node) do
52
+ lazy do
53
+ require_relative '../nodes/for_node'
54
+ ForNode
55
+ end
56
+ end
57
+ end
58
+
59
+ plug(:if) do
60
+ plug(:lexeme) do
61
+ lazy do
62
+ require_relative '../lexemes/if_lexeme'
63
+ IfLexeme
64
+ end
65
+ end
66
+
67
+ plug(:node) do
68
+ lazy do
69
+ require_relative '../nodes/if_node'
70
+ IfNode
71
+ end
72
+ end
73
+ end
74
+
75
+ plug(:prop) do
76
+ plug(:lexeme) do
77
+ lazy do
78
+ require_relative '../lexemes/prop_lexeme'
79
+ PropLexeme
80
+ end
81
+ end
82
+
83
+ plug(:node) do
84
+ lazy do
85
+ require_relative '../nodes/prop_node'
86
+ PropNode
87
+ end
88
+ end
89
+ end
90
+
91
+ plug(:slot) do
92
+ plug(:lexeme) do
93
+ lazy do
94
+ require_relative '../lexemes/slot_lexeme'
95
+ SlotLexeme
96
+ end
97
+ end
98
+
99
+ plug(:node) do
100
+ lazy do
101
+ require_relative '../nodes/slot_node'
102
+ SlotNode
103
+ end
104
+ end
105
+ end
106
+
107
+ plug(:yield) do
108
+ plug(:lexeme) do
109
+ lazy do
110
+ require_relative '../lexemes/yield_lexeme'
111
+ YieldLexeme
112
+ end
113
+ end
114
+
115
+ plug(:node) do
116
+ lazy do
117
+ require_relative '../nodes/yield_node'
118
+ YieldNode
119
+ end
120
+ end
121
+ end
122
+
123
+ plug(:var) do
124
+ plug(:node) do
125
+ lazy do
126
+ require_relative '../nodes/var_node'
127
+ VarNode
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -1,36 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'lexemes/for_lexeme'
4
- require_relative 'lexemes/form_lexeme'
5
- require_relative 'lexemes/if_lexeme'
6
- require_relative 'lexemes/prop_lexeme'
7
- require_relative 'lexemes/slot_lexeme'
8
- require_relative 'lexemes/yield_lexeme'
9
- require_relative 'support/queries'
3
+ require_relative '../support/queries'
10
4
 
11
5
  module Antlers
12
6
  extend Queries
13
7
 
14
- class LexerParseError < StandardError; end
15
-
16
- LEXEMES = [
17
- # FormLexeme must be ordered before ForLexeme for regex to work.
18
- Antlers::FormLexeme,
19
- Antlers::ForLexeme,
20
- Antlers::IfLexeme,
21
- Antlers::PropLexeme,
22
- Antlers::SlotLexeme,
23
- Antlers::YieldLexeme,
24
- ]
8
+ class LexerError < StandardError; end
25
9
 
26
10
  class Lexer
27
- def initialize
11
+ def initialize(lexeme_types:)
28
12
  @delimiters = ['<{', '}>', '{', '}']
29
- @keywords = LEXEMES.flat_map { |lexeme| lexeme.const_get(:KEYWORDS) }
13
+ @lexeme_types = lexeme_types
14
+ @keywords = @lexeme_types.flat_map { |lexeme| lexeme.const_get(:KEYWORDS) }
30
15
  @cursor = 0
31
16
  end
32
17
 
33
- def parse(template)
18
+ def parse(template:)
34
19
  @cursor = 0
35
20
  sequence = []
36
21
 
@@ -67,11 +52,11 @@ module Antlers
67
52
 
68
53
  name, props, keywords = parse_segment(antlers_segment:)
69
54
 
70
- lexeme = LEXEMES.find { it.match?(name:, keywords:) }
55
+ lexeme = @lexeme_types.find { it.match?(name:, keywords:) }
71
56
  return lexeme.lexeme(name:, props:, keywords:) if lexeme
72
57
  return var(antlers_segment:, raw: true) if deerheads?(segments:)
73
58
 
74
- raise LexerParseError, "Unrecognised syntax: '#{antlers_segment}'"
59
+ raise LexerError, "Unrecognised syntax: '#{antlers_segment}'"
75
60
  end
76
61
 
77
62
  def parse_segment(antlers_segment:)
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Antlers
4
+ class Parser
5
+ class ParserError < StandardError; end
6
+
7
+ def initialize(namespace: nil, node_types:)
8
+ @namespace = namespace
9
+ @node_types = node_types
10
+ end
11
+
12
+ def parse(sequence:, id: :root_node)
13
+ branch(node: RootNode.new(name: id), sequence:)
14
+ end
15
+
16
+ def branch(node:, sequence:)
17
+ until sequence.empty?
18
+ segment = sequence.shift
19
+
20
+ child_class = @node_types.find { |n| n.match?(segment:) }
21
+ raise(ParserError, "No node matches #{segment}") unless child_class
22
+
23
+ child = child_class.build(segment:, namespace: @namespace)
24
+ node.children << child
25
+
26
+ if (end_key = child_class::END_KEY)
27
+ sub_branch(node: child, sequence:, end_key:, end_name: child.end_name)
28
+ end
29
+ end
30
+
31
+ node
32
+ end
33
+
34
+ def sub_branch(node:, sequence:, end_key:, end_name: nil)
35
+ sub_sequence = []
36
+ sub_sequence << sequence.shift until sequence.first.is_a?(Hash) && sequence.first[end_key] == end_name
37
+ # Remove the end tag we just stopped before.
38
+ sequence.shift
39
+
40
+ branch(node:, sequence: sub_sequence)
41
+ end
42
+ end
43
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Antlers
4
- VERSION = '0.8.1'
4
+ VERSION = '0.8.2'
5
5
  end
data/lib/antlers.rb CHANGED
@@ -1,15 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'lexer'
4
- require_relative 'parser'
3
+ require_relative 'antlers/elements'
4
+ require_relative 'antlers/lexer'
5
+ require_relative 'antlers/parser'
6
+
7
+ # These requires allow downstream libraries to build their own antlers nodes.
8
+ require_relative 'interfaces/branch_node'
9
+ require_relative 'interfaces/leaf_node'
5
10
 
6
11
  module Antlers
12
+ DEFAULT_ELEMENTS = [:root, :html, :form, :for, :if, :prop, :slot, :yield, :var]
13
+
7
14
  class << self
8
- def ast(template:, namespace: nil)
15
+ def ast(template:, namespace: nil, elements: Elements[*DEFAULT_ELEMENTS])
9
16
  return template unless template.include?('<{') || template.include?('{')
10
17
 
11
- sequence = Lexer.new.parse(template)
12
- Parser.new(namespace:).parse(sequence:)
18
+ sequence = Lexer.new(lexeme_types: elements[:lexeme].to_a).parse(template:)
19
+ Parser.new(namespace:, node_types: elements[:node].to_a).parse(sequence:)
13
20
  end
14
21
 
15
22
  def render(ast:, current_binding:, parent_binding: nil, slot_node: nil)
@@ -4,6 +4,9 @@ module Antlers
4
4
  class AntlerNode
5
5
  attr_reader :name
6
6
 
7
+ DEF_KEY = nil
8
+ END_KEY = nil
9
+
7
10
  def initialize(name:)
8
11
  @name = name
9
12
  end
@@ -12,7 +15,21 @@ module Antlers
12
15
  raise NotImplementedError
13
16
  end
14
17
 
15
- # Consider instance a value object on comparison.
18
+ def end_name
19
+ 'level_1'
20
+ end
21
+
22
+ class << self
23
+ def match?(segment:)
24
+ raise NotImplementedError
25
+ end
26
+
27
+ def build(segment:, namespace:)
28
+ raise NotImplementedError
29
+ end
30
+ end
31
+
32
+ # Compare instance as a value object.
16
33
  def ==(other) = other.class == self.class
17
34
  def eql?(other) = self == other
18
35
  def hash = [self.class].hash
@@ -16,8 +16,7 @@ module Antlers
16
16
  output = ''
17
17
 
18
18
  @children.each do |child|
19
- # Antlers nodes respond to "render", whereas HTML is stored as a string and output as is.
20
- output += (child.respond_to?(:render) ? child.render(current_binding:, parent_binding:, slot_node:) : child) || ''
19
+ output += child.render(current_binding:, parent_binding:, slot_node:) || ''
21
20
  end
22
21
 
23
22
  output
@@ -6,7 +6,7 @@ module Antlers
6
6
  module Variables
7
7
  extend Queries
8
8
 
9
- # Evaluation limited to the following for security and to prevent a templating language becoming a programming language.
9
+ # Evaluation limited to the following for security and to stop a templating language becoming a programming language.
10
10
  # 1. An instance variable
11
11
  # 2. A method call/local variable
12
12
  # 3. A method chain
@@ -9,6 +9,9 @@ module Antlers
9
9
  include Props
10
10
  include Variables
11
11
 
12
+ DEF_KEY = :for_def
13
+ END_KEY = :for_end
14
+
12
15
  def initialize(name:, items:, value:, key: nil, props: [], children: [])
13
16
  super(name:, props:, children:)
14
17
 
@@ -28,12 +31,22 @@ module Antlers
28
31
  current_binding.local_variable_set(@key, key) if @key
29
32
 
30
33
  @children.each do |child|
31
- # Antlers nodes respond to "render", whereas HTML is stored as a string and output as is.
32
- output += (child.respond_to?(:render) ? child.render(current_binding:, parent_binding:, slot_node:) : child) || ''
34
+ output += child.render(current_binding:, parent_binding:, slot_node:) || ''
33
35
  end
34
36
  end
35
37
 
36
38
  output
37
39
  end
40
+
41
+ class << self
42
+ def match?(segment:)
43
+ segment[DEF_KEY]
44
+ end
45
+
46
+ def build(segment:, **)
47
+ value, key, items = segment.values_at(DEF_KEY, :key, :in)
48
+ new(name: value, key:, value:, items:)
49
+ end
50
+ end
38
51
  end
39
52
  end
@@ -9,6 +9,9 @@ module Antlers
9
9
  include Props
10
10
  include Variables
11
11
 
12
+ DEF_KEY = :form_def
13
+ END_KEY = :form_end
14
+
12
15
  def initialize(name:, action: nil, method: 'POST', props: [], children: [])
13
16
  super(name:, props:, children:)
14
17
 
@@ -20,12 +23,24 @@ module Antlers
20
23
  output = "<form action='#{@action}' method='#{@method}'>"
21
24
 
22
25
  @children.each do |child|
23
- # Antlers nodes respond to "render", whereas HTML is stored as a string and output as is.
24
- output += (child.respond_to?(:render) ? child.render(current_binding:, parent_binding:, slot_node:) : child) || ''
26
+ output += child.render(current_binding:, parent_binding:, slot_node:) || ''
25
27
  end
26
28
 
27
29
  output += '</form>'
28
30
  output
29
31
  end
32
+
33
+ class << self
34
+ def match?(segment:)
35
+ segment[DEF_KEY]
36
+ end
37
+
38
+ def build(segment:, **)
39
+ action, method = segment.values_at(DEF_KEY, :method)
40
+ return new(name: action, action:, method:) if method
41
+
42
+ new(name: action, action:)
43
+ end
44
+ end
30
45
  end
31
46
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../interfaces/leaf_node'
4
+
5
+ module Antlers
6
+ class HTMLNode < LeafNode
7
+ def initialize(html:)
8
+ super(name: nil)
9
+
10
+ @html = html
11
+ end
12
+
13
+ def render(**)
14
+ @html
15
+ end
16
+
17
+ class << self
18
+ def match?(segment:)
19
+ segment.is_a?(String)
20
+ end
21
+
22
+ def build(segment:, **)
23
+ new(html: segment)
24
+ end
25
+ end
26
+ end
27
+ end
data/lib/nodes/if_node.rb CHANGED
@@ -9,6 +9,9 @@ module Antlers
9
9
  include Props
10
10
  include Variables
11
11
 
12
+ DEF_KEY = :if_def
13
+ END_KEY = :if_end
14
+
12
15
  def initialize(name:, value:, props: [], children: [])
13
16
  super(name:, props:, children:)
14
17
 
@@ -20,12 +23,21 @@ module Antlers
20
23
 
21
24
  if evaluate(name: @value, current_binding:)
22
25
  @children.each do |child|
23
- # Antlers nodes respond to "render", whereas HTML is stored as a string and output as is.
24
- output += (child.respond_to?(:render) ? child.render(current_binding:, parent_binding:, slot_node:) : child) || ''
26
+ output += child.render(current_binding:, parent_binding:, slot_node:) || ''
25
27
  end
26
28
  end
27
29
 
28
30
  output
29
31
  end
32
+
33
+ class << self
34
+ def match?(segment:)
35
+ segment[DEF_KEY]
36
+ end
37
+
38
+ def build(segment:, **)
39
+ new(name: segment[DEF_KEY], value: segment[DEF_KEY])
40
+ end
41
+ end
30
42
  end
31
43
  end
@@ -30,6 +30,16 @@ module Antlers
30
30
  render_args(class_proxy:, instance:, event:, props:)
31
31
  end
32
32
 
33
+ class << self
34
+ def match?(segment:)
35
+ segment[:prop]
36
+ end
37
+
38
+ def build(segment:, namespace:)
39
+ new(name: segment[:prop], props: segment[:props], namespace:)
40
+ end
41
+ end
42
+
33
43
  private
34
44
 
35
45
  def create_instance(class_proxy:, klass:, event:, props:)
@@ -7,5 +7,15 @@ module Antlers
7
7
  def initialize(name: :root_node, children: [])
8
8
  super(name:, children:)
9
9
  end
10
+
11
+ class << self
12
+ def match?(**)
13
+ false
14
+ end
15
+
16
+ def build(**)
17
+ new()
18
+ end
19
+ end
10
20
  end
11
21
  end
@@ -7,7 +7,10 @@ require_relative '../modules/props'
7
7
  module Antlers
8
8
  class SlotNode < BranchNode
9
9
  include Namespace
10
- include Props # Immediate parent ancestor which props are passed to.
10
+ include Props # The immediate ancestor which props are passed to.
11
+
12
+ DEF_KEY = :slot_def
13
+ END_KEY = :slot_end
11
14
 
12
15
  attr_accessor :children
13
16
 
@@ -30,5 +33,19 @@ module Antlers
30
33
 
31
34
  props.empty? ? instance.render(event:) : instance.render(event:, **props)
32
35
  end
36
+
37
+ def end_name
38
+ @name
39
+ end
40
+
41
+ class << self
42
+ def match?(segment:)
43
+ segment[DEF_KEY]
44
+ end
45
+
46
+ def build(segment:, namespace:)
47
+ new(name: segment[DEF_KEY], props: segment[:props], namespace:)
48
+ end
49
+ end
33
50
  end
34
51
  end
@@ -25,5 +25,15 @@ module Antlers
25
25
 
26
26
  ERB::Util.html_escape(result)
27
27
  end
28
+
29
+ class << self
30
+ def match?(segment:)
31
+ segment[:var] || segment[:raw_var]
32
+ end
33
+
34
+ def build(segment:, **)
35
+ new(value: segment[:var] || segment[:raw_var], raw: !!segment[:raw_var])
36
+ end
37
+ end
28
38
  end
29
39
  end
@@ -8,20 +8,25 @@ module Antlers
8
8
  super(name:)
9
9
  end
10
10
 
11
- # Renders the children of the parent node in the binding of the parent.
12
- def render(current_binding: nil, parent_binding: nil, slot_node: nil)
11
+ # Render the children in the binding of the parent.
12
+ def render(current_binding: nil, parent_binding:, slot_node:)
13
13
  output = ''
14
14
 
15
15
  slot_node.children.each do |child|
16
- # Antlers nodes respond to "render", whereas HTML is stored as a string and output as is.
17
- if child.respond_to?(:render) # rubocop:disable Style/ConditionalAssignment
18
- output += child.render(current_binding: parent_binding, parent_binding: nil, slot_node: nil)
19
- else
20
- output += child || ''
21
- end
16
+ output += child.render(current_binding: parent_binding, parent_binding:, slot_node:) || ''
22
17
  end
23
18
 
24
19
  output
25
20
  end
21
+
22
+ class << self
23
+ def match?(segment:)
24
+ segment[:slot]
25
+ end
26
+
27
+ def build(segment:, **)
28
+ new(name: segment[:slot])
29
+ end
30
+ end
26
31
  end
27
32
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: antlers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - maedi
@@ -51,6 +51,20 @@ dependencies:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
53
  version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: plugs
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
54
68
  description: A templating language embedded within HTML that is itself embedded within
55
69
  Ruby/RBX
56
70
  email:
@@ -60,7 +74,10 @@ extensions: []
60
74
  extra_rdoc_files: []
61
75
  files:
62
76
  - lib/antlers.rb
63
- - lib/factories/node_factory.rb
77
+ - lib/antlers/elements.rb
78
+ - lib/antlers/lexer.rb
79
+ - lib/antlers/parser.rb
80
+ - lib/antlers/version.rb
64
81
  - lib/interfaces/antler_node.rb
65
82
  - lib/interfaces/branch_node.rb
66
83
  - lib/interfaces/leaf_node.rb
@@ -71,21 +88,19 @@ files:
71
88
  - lib/lexemes/prop_lexeme.rb
72
89
  - lib/lexemes/slot_lexeme.rb
73
90
  - lib/lexemes/yield_lexeme.rb
74
- - lib/lexer.rb
75
91
  - lib/modules/namespace.rb
76
92
  - lib/modules/props.rb
77
93
  - lib/modules/variables.rb
78
94
  - lib/nodes/for_node.rb
79
95
  - lib/nodes/form_node.rb
96
+ - lib/nodes/html_node.rb
80
97
  - lib/nodes/if_node.rb
81
98
  - lib/nodes/prop_node.rb
82
99
  - lib/nodes/root_node.rb
83
100
  - lib/nodes/slot_node.rb
84
101
  - lib/nodes/var_node.rb
85
102
  - lib/nodes/yield_node.rb
86
- - lib/parser.rb
87
103
  - lib/support/queries.rb
88
- - lib/version.rb
89
104
  homepage: https://github.com/raindeer-rb/antlers
90
105
  licenses: []
91
106
  metadata:
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../nodes/if_node'
4
- require_relative '../nodes/for_node'
5
- require_relative '../nodes/form_node'
6
- require_relative '../nodes/prop_node'
7
- require_relative '../nodes/slot_node'
8
- require_relative '../nodes/var_node'
9
- require_relative '../nodes/yield_node'
10
-
11
- module Antlers
12
- class NodeFactory
13
- def initialize(namespace:)
14
- @namespace = namespace
15
- end
16
-
17
- def if_node(segment:)
18
- IfNode.new(name: segment[:if_def], value: segment[:if_def])
19
- end
20
-
21
- def for_node(segment:)
22
- value, key, items = segment.values_at(:for_def, :key, :in)
23
- ForNode.new(name: value, key:, value:, items:)
24
- end
25
-
26
- def form_node(segment:)
27
- action, method = segment.values_at(:form_def, :method)
28
- return FormNode.new(name: action, action:, method:) if method
29
-
30
- FormNode.new(name: action, action:)
31
- end
32
-
33
- def prop_node(segment:)
34
- PropNode.new(name: segment[:prop], props: segment[:props], namespace:)
35
- end
36
-
37
- def slot_node(segment:)
38
- SlotNode.new(name: segment[:slot_def], props: segment[:props], namespace:)
39
- end
40
-
41
- def var_node(segment:)
42
- VarNode.new(value: segment[:var])
43
- end
44
-
45
- def raw_var_node(segment:)
46
- VarNode.new(value: segment[:raw_var], raw: true)
47
- end
48
-
49
- def yield_node(segment:)
50
- YieldNode.new(name: segment[:slot])
51
- end
52
-
53
- private
54
-
55
- attr_reader :namespace
56
- end
57
- end
data/lib/parser.rb DELETED
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'factories/node_factory'
4
- require_relative 'nodes/root_node'
5
-
6
- module Antlers
7
- class Parser
8
- def initialize(namespace: nil)
9
- @factory = NodeFactory.new(namespace:)
10
- end
11
-
12
- def parse(sequence:, id: :root_node)
13
- branch(node: RootNode.new(name: id), sequence:)
14
- end
15
-
16
- def branch(node:, sequence:) # rubocop:disable Metrics/AbcSize
17
- until sequence.empty?
18
- segment = sequence.shift
19
-
20
- if segment.is_a?(String)
21
- node.children << segment
22
- elsif segment[:var]
23
- node.children << @factory.var_node(segment:)
24
- elsif segment[:raw_var]
25
- node.children << @factory.raw_var_node(segment:)
26
- elsif segment[:prop]
27
- node.children << @factory.prop_node(segment:)
28
- elsif segment[:slot]
29
- node.children << @factory.yield_node(segment:)
30
- elsif segment[:slot_def]
31
- slot_node = @factory.slot_node(segment:)
32
- node.children << slot_node
33
- sub_branch(node: slot_node, sequence:, end_key: :slot_end, end_name: slot_node.name)
34
- elsif segment[:if_def]
35
- if_node = @factory.if_node(segment:)
36
- node.children << if_node
37
- sub_branch(node: if_node, sequence:, end_key: :if_end, end_name: 'level_1')
38
- elsif segment[:for_def]
39
- for_node = @factory.for_node(segment:)
40
- node.children << for_node
41
- sub_branch(node: for_node, sequence:, end_key: :for_end, end_name: 'level_1')
42
- elsif segment[:form_def]
43
- form_node = @factory.form_node(segment:)
44
- node.children << form_node
45
- sub_branch(node: form_node, sequence:, end_key: :form_end, end_name: 'level_1')
46
- end
47
- end
48
-
49
- node
50
- end
51
-
52
- def sub_branch(node:, sequence:, end_key:, end_name: nil)
53
- sub_sequence = []
54
- sub_sequence << sequence.shift until sequence.first.is_a?(Hash) && sequence.first[end_key] == end_name
55
-
56
- branch(node:, sequence: sub_sequence)
57
- end
58
- end
59
- end