node_query 1.6.1 → 1.8.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: 474136c42ade45282559b6e9700faffacdec002f75d8033f00d05639034a3245
4
- data.tar.gz: 1be2a9b18e54c36605468ce8ca5e9ad78c05c698b6f9994c0d6ea18f2270e25c
3
+ metadata.gz: 3638d51ca40eb891535cc2320377e3492023439946460a1c0a81af02f211c3ce
4
+ data.tar.gz: 4919be334676677f9ad144db4358be354ca81f8244294e3ea1fbf07d6d0a9845
5
5
  SHA512:
6
- metadata.gz: a0d40e1da75eb1a235398b5cddeae0e2378bbb2c92c03f8d7a9e5680b8a2512fa9f8230b713b70d3cc164497451157998520ee5d62e5637cef07e023a6033efb
7
- data.tar.gz: e587ebfd379a4ff909583109ba42d16c572aeaab69bf2303efa5bd92325750c8cddb3a20dd8712e668233691a1cb3eba25250fbbdb936651fd15a9722514a12d
6
+ metadata.gz: af54774545d5b284e3d6bd1977094f108553526fc9613ceebe0c96e46be9ac26c5c66db2e4301cef483cf66e4c02f04f19e1e8180e8025d360e5c2b0437c2efa
7
+ data.tar.gz: ca74ee091e6ec5d603ce4efaed4927e4d08a123563f95f7e09807e7c8433447ef53390ba727f7500037d60fc74ea5fb1601dfeba52e2cc569e54bd25eea14fc9
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 1.8.0 (2022-10-14)
4
+
5
+ * Support `:first-child` and `:last-child`
6
+
7
+ ## 1.7.0 (2022-10-01)
8
+
9
+ * Better regexp to match evaluated value
10
+ * Make `base_node` as the root matching node
11
+
3
12
  ## 1.6.1 (2022-09-28)
4
13
 
5
14
  * Do not handle `erange` and `irange` in `actual_value`
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- node_query (1.6.1)
4
+ node_query (1.8.0)
5
5
  activesupport (< 7.0.0)
6
6
 
7
7
  GEM
@@ -78,7 +78,7 @@ GEM
78
78
  thor (1.2.1)
79
79
  tzinfo (2.0.5)
80
80
  concurrent-ruby (~> 1.0)
81
- zeitwerk (2.6.0)
81
+ zeitwerk (2.6.1)
82
82
 
83
83
  PLATFORMS
84
84
  x86_64-darwin-21
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # NodeQuery
2
2
 
3
- NodeQuery defines an AST node query language, which is a css like syntax for matching nodes,
4
- it supports other ast parser if it implements `NodeQuery::Adapter`.
3
+ NodeQuery defines a NQL (node query language) and node rules to query AST nodes.
5
4
 
6
5
  ## Table of Contents
7
6
 
@@ -25,7 +24,8 @@ it supports other ast parser if it implements `NodeQuery::Adapter`.
25
24
  - [Adjacent sibling combinator](#adjacent-sibling-combinator)
26
25
  - [General sibling combinator](#general-sibling-combinator)
27
26
  - [nql matches goto scope](#nql-matches-goto-scope)
28
- - [nql matches pseudo selector](#nql-matches-pseudo-selector)
27
+ - [nql matches :has and :not_has pseudo selector](#nql-matches-has-and-not_has-pseudo-selector)
28
+ - [nql matches :first-child and :last-child pseudo selector](#nql-matches-first-child-and-last-child-pseudo-selector)
29
29
  - [nql matches multiple expressions](#nql-matches-multiple-expressions)
30
30
  - [Node Rules](#node-rules)
31
31
  - [rules matches node type](#rules-matches-node-type)
@@ -61,7 +61,7 @@ Or install it yourself as:
61
61
  It provides two apis: `query_nodes` and `match_node?`
62
62
 
63
63
  ```ruby
64
- node_query = NodeQuery.new(nqlOrRules: String | Hash) # Initialize NodeQuery
64
+ node_query = NodeQuery.new(nql_or_rules: String | Hash) # Initialize NodeQuery
65
65
  node_query.query_nodes(node: Node, options = { including_self: true, stop_at_first_match: false, recursive: true }): Node[] # Get the matching nodes.
66
66
  node_query.match_node?(node: Node): boolean # Check if the node matches nql or rules.
67
67
  ```
@@ -286,7 +286,7 @@ It matches send node only if it is follows the send node whose left value is @id
286
286
 
287
287
  It matches send node who is in the body of def node.
288
288
 
289
- ### nql matches pseudo selector
289
+ ### nql matches :has and :not_has pseudo selector
290
290
 
291
291
  ```
292
292
  .class:has(.def[name=initialize])
@@ -300,6 +300,20 @@ It matches class node who has an initialize def node.
300
300
 
301
301
  It matches class node who does not have an initialize def node.
302
302
 
303
+ ### nql matches :first-child and :last-child pseudo selector
304
+
305
+ ```
306
+ .def:first-child
307
+ ```
308
+
309
+ It matches the first def node.
310
+
311
+ ```
312
+ .def:last-child
313
+ ```
314
+
315
+ It matches the last def node.
316
+
303
317
  ### nql matches multiple expressions
304
318
 
305
319
  ```
@@ -15,10 +15,10 @@ module NodeQuery::Compiler
15
15
 
16
16
  # Get the expected value.
17
17
  # @return [Array]
18
- def expected_value
18
+ def expected_value(base_node)
19
19
  expected = []
20
20
  expected.push(@value) if @value
21
- expected += @rest.expected_value if @rest
21
+ expected += @rest.expected_value(base_node) if @rest
22
22
  expected
23
23
  end
24
24
 
@@ -15,10 +15,10 @@ module NodeQuery::Compiler
15
15
 
16
16
  # Check if the node matches the attribute.
17
17
  # @param node [Node] the node
18
+ # @param base_node [Node] the bae node for evaluated value
18
19
  # @return [Boolean]
19
- def match?(node)
20
- @value.base_node = node if @value.is_a?(String)
21
- node && @value.match?(NodeQuery::Helper.get_target_node(node, @key), @operator)
20
+ def match?(node, base_node)
21
+ node && @value.match?(NodeQuery::Helper.get_target_node(node, @key), base_node, @operator)
22
22
  end
23
23
 
24
24
  def to_s
@@ -13,9 +13,10 @@ module NodeQuery::Compiler
13
13
 
14
14
  # Check if the node matches the attribute list.
15
15
  # @param node [Node] the node
16
+ # @param base_node [Node] the base node for evaluated value
16
17
  # @return [Boolean]
17
- def match?(node)
18
- @attribute.match?(node) && (!@rest || @rest.match?(node))
18
+ def match?(node, base_node)
19
+ @attribute.match?(node, base_node) && (!@rest || @rest.match?(node, base_node))
19
20
  end
20
21
 
21
22
  def to_s
@@ -13,11 +13,12 @@ module NodeQuery::Compiler
13
13
 
14
14
  # Check if node matches the selector.
15
15
  # @param node [Node] the node
16
+ # @param base_node [Node] the base node for evaluated value
16
17
  # @return [Boolean]
17
- def match?(node, _operator = '==')
18
+ def match?(node, base_node, _operator = '==')
18
19
  return false unless node
19
20
 
20
- @node_type.to_sym == NodeQuery.adapter.get_node_type(node) && (!@attribute_list || @attribute_list.match?(node))
21
+ @node_type.to_sym == NodeQuery.adapter.get_node_type(node) && (!@attribute_list || @attribute_list.match?(node, base_node))
21
22
  end
22
23
 
23
24
  def to_s
@@ -12,69 +12,71 @@ module NodeQuery::Compiler
12
12
  # Check if the actual value matches the expected value.
13
13
  #
14
14
  # @param node [Node] node to calculate actual value
15
+ # @param base_node [Node] the base node for evaluated value
15
16
  # @param operator [String] operator to compare with expected value, operator can be <code>'=='</code>, <code>'!='</code>, <code>'>'</code>, <code>'>='</code>, <code>'<'</code>, <code>'<='</code>, <code>'includes'</code>, <code>'in'</code>, <code>'not_in'</code>, <code>'=~'</code>, <code>'!~'</code>
16
17
  # @return [Boolean] true if actual value matches the expected value
17
18
  # @raise [NodeQuery::Compiler::InvalidOperatorError] if operator is invalid
18
- def match?(node, operator)
19
+ def match?(node, base_node, operator)
19
20
  raise InvalidOperatorError, "invalid operator #{operator}" unless valid_operator?(operator)
20
21
 
22
+ actual = actual_value(node)
23
+ expected = expected_value(base_node)
21
24
  case operator
22
25
  when '!='
23
- if expected_value.is_a?(::Array)
24
- actual = actual_value(node)
25
- !actual.is_a?(::Array) || actual.size != expected_value.size ||
26
- actual.zip(expected_value).any? { |actual_node, expected_node| expected_node.match?(actual_node, '!=') }
26
+ if expected.is_a?(::Array)
27
+ !actual.is_a?(::Array) || actual.size != expected.size ||
28
+ actual.zip(expected).any? { |actual_child, expected_child| expected_child.match?(actual_child, base_node, '!=') }
27
29
  else
28
- !is_equal?(node)
30
+ !is_equal?(actual, expected)
29
31
  end
30
32
  when '=~'
31
- actual_value(node) =~ expected_value
33
+ actual =~ expected
32
34
  when '!~'
33
- actual_value(node) !~ expected_value
35
+ actual !~ expected
34
36
  when '^='
35
- actual_value(node).start_with?(expected_value)
37
+ actual.start_with?(expected)
36
38
  when '$='
37
- actual_value(node).end_with?(expected_value)
39
+ actual.end_with?(expected)
38
40
  when '*='
39
- actual_value(node).include?(expected_value)
41
+ actual.include?(expected)
40
42
  when '>'
41
- actual_value(node) > expected_value
43
+ actual > expected
42
44
  when '>='
43
- actual_value(node) >= expected_value
45
+ actual >= expected
44
46
  when '<'
45
- actual_value(node) < expected_value
47
+ actual < expected
46
48
  when '<='
47
- actual_value(node) <= expected_value
49
+ actual <= expected
48
50
  when 'in'
49
51
  if node.is_a?(Array)
50
- node.all? { |child| expected_value.any? { |expected| expected.match?(child, '==') } }
52
+ node.all? { |child| expected.any? { |expected_child| expected_child.match?(child, base_node, '==') } }
51
53
  else
52
- expected_value.any? { |expected| expected.match?(node, '==') }
54
+ expected.any? { |expected_child| expected_child.match?(node, base_node, '==') }
53
55
  end
54
56
  when 'not_in'
55
57
  if node.is_a?(Array)
56
- node.all? { |child| expected_value.all? { |expected| expected.match?(child, '!=') } }
58
+ node.all? { |child| expected.all? { |expected_child| expected_child.match?(child, base_node, '!=') } }
57
59
  else
58
- expected_value.all? { |expected| expected.match?(node, '!=') }
60
+ expected.all? { |expected_child| expected_child.match?(node, base_node, '!=') }
59
61
  end
60
62
  when 'includes'
61
- actual_value(node).any? { |actual| actual == expected_value }
63
+ actual.any? { |actual_child| actual_child == expected }
62
64
  else
63
- if expected_value.is_a?(::Array)
64
- actual = actual_value(node)
65
- actual.is_a?(::Array) && actual.size == expected_value.size &&
66
- actual.zip(expected_value).all? { |actual_node, expected_node| expected_node.match?(actual_node, '==') }
65
+ if expected.is_a?(::Array)
66
+ actual.is_a?(::Array) && actual.size == expected.size &&
67
+ actual.zip(expected).all? { |actual_child, expected_child| expected_child.match?(actual_child, base_node, '==') }
67
68
  else
68
- is_equal?(node)
69
+ is_equal?(actual, expected)
69
70
  end
70
71
  end
71
72
  end
72
73
 
73
- # Check if the actual value equals the node value.
74
- # @param node [Node] the node
75
- # @return [Boolean] true if the actual value equals the node value.
76
- def is_equal?(node)
77
- actual_value(node) == expected_value
74
+ # Check if the actual value equals the expected value.
75
+ # @param acutal
76
+ # @param expected
77
+ # @return [Boolean] true if the actual value equals the expected value.
78
+ def is_equal?(actual, expected)
79
+ actual == expected
78
80
  end
79
81
 
80
82
  # Get the actual value from ast node.
@@ -104,8 +106,9 @@ module NodeQuery::Compiler
104
106
  end
105
107
 
106
108
  # Get the expected value
109
+ # @param base_node [Node] the base node for evaluated value
107
110
  # @return expected value, could be integer, float, string, boolean, nil, range, and etc.
108
- def expected_value
111
+ def expected_value(base_node)
109
112
  @value
110
113
  end
111
114
 
@@ -13,9 +13,10 @@ module NodeQuery::Compiler
13
13
 
14
14
  # Check if the regexp value matches the node value.
15
15
  # @param node [Node] the node
16
+ # @param _base_node [Node] the base node for evaluated value
16
17
  # @param operator [String] the operator
17
18
  # @return [Boolean] true if the regexp value matches the node value, otherwise, false.
18
- def match?(node, operator = '=~')
19
+ def match?(node, _base_node, operator = '=~')
19
20
  match =
20
21
  if NodeQuery.adapter.is_node?(node)
21
22
  @value.match(NodeQuery.adapter.get_source(node))
@@ -8,22 +8,25 @@ module NodeQuery::Compiler
8
8
  # @param relationship [String] the relationship between the selectors, it can be descendant <code>nil</code>, child <code>></code>, next sibling <code>+</code> or subsequent sibing <code>~</code>.
9
9
  # @param rest [NodeQuery::Compiler::Selector] the rest selector
10
10
  # @param basic_selector [NodeQuery::Compiler::BasicSelector] the simple selector
11
+ # @param position [String] the position of the node
11
12
  # @param attribute_list [NodeQuery::Compiler::AttributeList] the attribute list
12
13
  # @param pseudo_class [String] the pseudo class, can be <code>has</code> or <code>not_has</code>
13
14
  # @param pseudo_selector [NodeQuery::Compiler::Expression] the pseudo selector
14
- def initialize(goto_scope: nil, relationship: nil, rest: nil, basic_selector: nil, pseudo_class: nil, pseudo_selector: nil)
15
+ def initialize(goto_scope: nil, relationship: nil, rest: nil, basic_selector: nil, position: nil, pseudo_class: nil, pseudo_selector: nil)
15
16
  @goto_scope = goto_scope
16
17
  @relationship = relationship
17
18
  @rest = rest
18
19
  @basic_selector = basic_selector
20
+ @position = position
19
21
  @pseudo_class = pseudo_class
20
22
  @pseudo_selector = pseudo_selector
21
23
  end
22
24
 
23
25
  # Check if node matches the selector.
24
26
  # @param node [Parser::AST::Node] the node
25
- def match?(node)
26
- NodeQuery.adapter.is_node?(node) && (!@basic_selector || @basic_selector.match?(node)) && match_pseudo_class?(node)
27
+ # @param base_node [Parser::AST::Node] the base node for evaluated node
28
+ def match?(node, base_node)
29
+ NodeQuery.adapter.is_node?(node) && (!@basic_selector || @basic_selector.match?(node, base_node)) && match_pseudo_class?(node)
27
30
  end
28
31
 
29
32
  # Query nodes by the selector.
@@ -49,32 +52,32 @@ module NodeQuery::Compiler
49
52
  return find_nodes_by_goto_scope(node) if @goto_scope
50
53
 
51
54
  if options[:including_self] && !options[:recursive]
52
- return match?(node) ? [node] : []
55
+ return match?(node, node) ? [node] : []
53
56
  end
54
57
 
55
58
  nodes = []
56
- if options[:including_self] && match?(node)
59
+ if options[:including_self] && match?(node, node)
57
60
  nodes << node
58
61
  return nodes if options[:stop_at_first_match]
59
62
  end
60
63
  if @basic_selector
61
64
  if options[:recursive]
62
65
  NodeQuery::Helper.handle_recursive_child(node) do |child_node|
63
- if match?(child_node)
66
+ if match?(child_node, child_node)
64
67
  nodes << child_node
65
68
  break if options[:stop_at_first_match]
66
69
  end
67
70
  end
68
71
  else
69
72
  NodeQuery.adapter.get_children(node).each do |child_node|
70
- if match?(child_node)
73
+ if match?(child_node, child_node)
71
74
  nodes << child_node
72
75
  break if options[:stop_at_first_match]
73
76
  end
74
77
  end
75
78
  end
76
79
  end
77
- nodes
80
+ filter_by_position(nodes)
78
81
  end
79
82
 
80
83
  def to_s
@@ -83,10 +86,29 @@ module NodeQuery::Compiler
83
86
  result << "#{@relationship} " if @relationship
84
87
  result << @rest.to_s if @rest
85
88
  result << @basic_selector.to_s if @basic_selector
89
+ result << ":#{@position}" if @position
86
90
  result << ":#{@pseudo_class}(#{@pseudo_selector})" if @pseudo_class
87
91
  result.join('')
88
92
  end
89
93
 
94
+ protected
95
+
96
+ # Filter nodes by position.
97
+ # @param nodes [Array<Node>] nodes to filter
98
+ # @return [Array<Node>|Node] first node or last node or nodes
99
+ def filter_by_position(nodes)
100
+ return nodes unless @position
101
+
102
+ case @position
103
+ when 'first-child'
104
+ [nodes.first]
105
+ when 'last-child'
106
+ [nodes.last]
107
+ else
108
+ nodes
109
+ end
110
+ end
111
+
90
112
  private
91
113
 
92
114
  # Find nodes by @goto_scope
@@ -106,28 +128,28 @@ module NodeQuery::Compiler
106
128
  when '>'
107
129
  if node.is_a?(::Array)
108
130
  node.each do |child_node|
109
- nodes << child_node if @rest.match?(child_node)
131
+ nodes << child_node if @rest.match?(child_node, child_node)
110
132
  end
111
133
  else
112
134
  node.children.each do |child_node|
113
135
  if NodeQuery.adapter.is_node?(child_node) && :begin == NodeQuery.adapter.get_node_type(child_node)
114
136
  child_node.children.each do |child_child_node|
115
- nodes << child_child_node if @rest.match?(child_child_node)
137
+ nodes << child_child_node if @rest.match?(child_child_node, child_child_node)
116
138
  end
117
- elsif @rest.match?(child_node)
139
+ elsif @rest.match?(child_node, child_node)
118
140
  nodes << child_node
119
141
  end
120
142
  end
121
143
  end
122
144
  when '+'
123
145
  next_sibling = node.siblings.first
124
- nodes << next_sibling if @rest.match?(next_sibling)
146
+ nodes << next_sibling if @rest.match?(next_sibling, next_sibling)
125
147
  when '~'
126
148
  node.siblings.each do |sibling_node|
127
- nodes << sibling_node if @rest.match?(sibling_node)
149
+ nodes << sibling_node if @rest.match?(sibling_node, sibling_node)
128
150
  end
129
151
  end
130
- nodes
152
+ @rest.filter_by_position(nodes)
131
153
  end
132
154
 
133
155
  # Check if it matches pseudo class.
@@ -5,8 +5,6 @@ module NodeQuery::Compiler
5
5
  class String
6
6
  include Comparable
7
7
 
8
- attr_accessor :base_node
9
-
10
8
  # Initialize a String.
11
9
  # @param value [String] the string value
12
10
  def initialize(value:)
@@ -18,16 +16,18 @@ module NodeQuery::Compiler
18
16
  # if the source code of the node is @id = id,
19
17
  # and the @value is "@{{right_vaue}}",
20
18
  # then it returns "@id".
19
+ # @param base_node [Node] the base node for evaluated value
21
20
  # @return [String] the expected string, if it contains evaluated value, evaluate the node value.
22
- def expected_value
21
+ def expected_value(base_node)
23
22
  NodeQuery::Helper.evaluate_node_value(base_node, @value)
24
23
  end
25
24
 
26
25
  # Check if the actual value equals the node value.
27
26
  # @param node [Node] the node
27
+ # @param base_node [Node] the base node for evaluated value
28
28
  # @return [Boolean] true if the actual value equals the node value.
29
- def is_equal?(node)
30
- NodeQuery::Helper.to_string(actual_value(node)) == expected_value
29
+ def is_equal?(actual, expected)
30
+ NodeQuery::Helper.to_string(actual) == expected
31
31
  end
32
32
 
33
33
  # Get valid operators.
@@ -48,7 +48,7 @@ class NodeQuery::Helper
48
48
  # @param str [String] string to be evaluated
49
49
  # @return [String] evaluated string
50
50
  def evaluate_node_value(node, str)
51
- str.scan(/{{(.*?)}}/).each do |match_data|
51
+ str.scan(/{{(.+?)}}/).each do |match_data|
52
52
  target_node = NodeQuery::Helper.get_target_node(node, match_data.first)
53
53
  str = str.sub("{{#{match_data.first}}}", to_string(target_node))
54
54
  end
@@ -144,8 +144,8 @@ class NodeQuery::NodeRules
144
144
  # Convert a hash to flat one.
145
145
  #
146
146
  # @example
147
- # flat_hash(type: 'block', caller: {type: 'send', receiver: 'RSpec'})
148
- # # {[:type] => 'block', [:caller, :type] => 'send', [:caller, :receiver] => 'RSpec'}
147
+ # flat_hash(node_type: 'block', caller: { node_type: 'send', receiver: 'RSpec' })
148
+ # # {[:node_type] => 'block', [:caller, :node_type] => 'send', [:caller, :receiver] => 'RSpec'}
149
149
  # @param h [Hash] original hash.
150
150
  # @return flatten hash.
151
151
  def flat_hash(h, k = [])
@@ -190,4 +190,4 @@ class NodeQuery::NodeRules
190
190
  string
191
191
  end
192
192
  end
193
- end
193
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class NodeQuery
4
- VERSION = "1.6.1"
4
+ VERSION = "1.8.0"
5
5
  end
data/lib/node_query.rb CHANGED
@@ -27,12 +27,12 @@ class NodeQuery
27
27
  end
28
28
 
29
29
  # Initialize a NodeQuery.
30
- # @param nqlOrRules [String | Hash] node query language or node rules
31
- def initialize(nqlOrRules)
32
- if nqlOrRules.is_a?(String)
33
- @expression = NodeQueryParser.new.parse(nqlOrRules)
30
+ # @param nql_or_ruls [String | Hash] node query language or node rules
31
+ def initialize(nql_or_ruls)
32
+ if nql_or_ruls.is_a?(String)
33
+ @expression = NodeQueryParser.new.parse(nql_or_ruls)
34
34
  else
35
- @rules = NodeRules.new(nqlOrRules)
35
+ @rules = NodeRules.new(nql_or_ruls)
36
36
  end
37
37
  end
38
38
 
@@ -26,6 +26,8 @@ rules
26
26
  # [:state] pattern [actions]
27
27
  /\s+/
28
28
  /,/ { [:tCOMMA, text] }
29
+ /:first-child/ { [:tPOSITION, text[1..-1]] }
30
+ /:last-child/ { [:tPOSITION, text[1..-1]] }
29
31
  /:has/ { [:tPSEUDO_CLASS, text[1..-1]] }
30
32
  /:not_has/ { [:tPSEUDO_CLASS, text[1..-1]] }
31
33
  /#{NODE_TYPE}/ { [:tNODE_TYPE, text[1..]] }
@@ -125,6 +125,10 @@ class NodeQueryLexer
125
125
  # do nothing
126
126
  when text = ss.scan(/,/) then
127
127
  action { [:tCOMMA, text] }
128
+ when text = ss.scan(/:first-child/) then
129
+ action { [:tPOSITION, text[1..-1]] }
130
+ when text = ss.scan(/:last-child/) then
131
+ action { [:tPOSITION, text[1..-1]] }
128
132
  when text = ss.scan(/:has/) then
129
133
  action { [:tPSEUDO_CLASS, text[1..-1]] }
130
134
  when text = ss.scan(/:not_has/) then
@@ -22,85 +22,86 @@ class NodeQueryParser < Racc::Parser
22
22
  ##### State transition tables begin ###
23
23
 
24
24
  racc_action_table = [
25
- 8, 8, 7, 9, 10, 36, 12, 5, 6, 16,
26
- 27, 17, 21, 22, 23, 24, 29, 30, 31, 32,
27
- 33, 34, 35, 8, 16, 8, 7, 40, 36, nil,
28
- 8, 5, 6, nil, 37, 36, nil, nil, nil, 29,
29
- 30, 31, 32, 33, 34, 35, 29, 30, 31, 32,
30
- 33, 34, 35, 8, 7, 8, 7, 8, 7, 5,
31
- 6, 5, 6, 5, 6, 8, 7, nil, nil, nil,
32
- nil, 5, 6 ]
25
+ 8, 8, 7, 9, 10, 37, 12, 5, 6, 13,
26
+ 28, 17, 18, 22, 23, 24, 25, 30, 31, 32,
27
+ 33, 34, 35, 36, 8, 17, 8, 7, 41, 37,
28
+ nil, 8, 5, 6, nil, 38, 37, nil, nil, nil,
29
+ nil, 30, 31, 32, 33, 34, 35, 36, 30, 31,
30
+ 32, 33, 34, 35, 36, 8, 7, 8, 7, 8,
31
+ 7, 5, 6, 5, 6, 5, 6, 8, 7, nil,
32
+ nil, nil, nil, 5, 6 ]
33
33
 
34
34
  racc_action_check = [
35
- 24, 0, 0, 1, 2, 24, 5, 0, 0, 8,
36
- 24, 9, 16, 19, 20, 21, 24, 24, 24, 24,
37
- 24, 24, 24, 27, 23, 3, 3, 38, 27, nil,
38
- 39, 3, 3, nil, 27, 39, nil, nil, nil, 27,
39
- 27, 27, 27, 27, 27, 27, 39, 39, 39, 39,
40
- 39, 39, 39, 6, 6, 7, 7, 10, 10, 6,
41
- 6, 7, 7, 10, 10, 12, 12, nil, nil, nil,
42
- nil, 12, 12 ]
35
+ 25, 0, 0, 1, 2, 25, 4, 0, 0, 5,
36
+ 25, 8, 9, 17, 20, 21, 22, 25, 25, 25,
37
+ 25, 25, 25, 25, 28, 24, 3, 3, 39, 28,
38
+ nil, 40, 3, 3, nil, 28, 40, nil, nil, nil,
39
+ nil, 28, 28, 28, 28, 28, 28, 28, 40, 40,
40
+ 40, 40, 40, 40, 40, 6, 6, 7, 7, 10,
41
+ 10, 6, 6, 7, 7, 10, 10, 13, 13, nil,
42
+ nil, nil, nil, 13, 13 ]
43
43
 
44
44
  racc_action_pointer = [
45
- -2, 3, 2, 22, nil, -9, 50, 52, -2, 11,
46
- 54, nil, 62, nil, nil, nil, 6, nil, nil, -3,
47
- 2, -2, nil, 13, -3, nil, nil, 20, nil, nil,
48
- nil, nil, nil, nil, nil, nil, nil, nil, 13, 27,
49
- nil, nil ]
45
+ -2, 3, 2, 23, -11, -6, 52, 54, 0, 12,
46
+ 56, nil, nil, 64, nil, nil, nil, 7, nil, nil,
47
+ -2, 3, -2, nil, 14, -3, nil, nil, 21, nil,
48
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, 14,
49
+ 28, nil, nil ]
50
50
 
51
51
  racc_action_default = [
52
- -27, -27, -2, -4, -5, -27, -27, -27, -9, -27,
53
- -27, -3, -27, -7, -8, -10, -27, 42, -1, -27,
54
- -27, -27, -6, -12, -27, -11, -13, -27, -18, -19,
55
- -20, -21, -22, -23, -24, -25, -26, -14, -27, -17,
56
- -15, -16 ]
52
+ -28, -28, -2, -4, -6, -28, -28, -28, -10, -28,
53
+ -28, -3, -5, -28, -8, -9, -11, -28, 43, -1,
54
+ -28, -28, -28, -7, -13, -28, -12, -14, -28, -19,
55
+ -20, -21, -22, -23, -24, -25, -26, -27, -15, -28,
56
+ -18, -16, -17 ]
57
57
 
58
58
  racc_goto_table = [
59
- 28, 15, 38, 28, 13, 14, 11, 1, 20, 26,
60
- 19, nil, nil, nil, 41, 28, 25, 18 ]
59
+ 16, 39, 29, 11, 1, 29, 21, 27, 14, 15,
60
+ nil, nil, nil, 42, 19, 20, 26, 29 ]
61
61
 
62
62
  racc_goto_check = [
63
- 4, 5, 8, 4, 3, 3, 2, 1, 6, 7,
64
- 3, nil, nil, nil, 8, 4, 5, 1 ]
63
+ 5, 8, 4, 2, 1, 4, 6, 7, 3, 3,
64
+ nil, nil, nil, 8, 1, 3, 5, 4 ]
65
65
 
66
66
  racc_goto_pointer = [
67
- nil, 7, 3, -2, -24, -7, -8, -15, -25 ]
67
+ nil, 4, 0, 2, -23, -8, -11, -18, -27 ]
68
68
 
69
69
  racc_goto_default = [
70
- nil, nil, 2, 3, 4, nil, nil, 39, nil ]
70
+ nil, nil, 2, 3, 4, nil, nil, 40, nil ]
71
71
 
72
72
  racc_reduce_table = [
73
73
  0, 0, :racc_error,
74
- 3, 27, :_reduce_1,
75
- 1, 27, :_reduce_2,
76
- 2, 28, :_reduce_3,
77
- 1, 28, :_reduce_4,
78
- 1, 29, :_reduce_5,
79
- 4, 29, :_reduce_6,
80
- 2, 29, :_reduce_7,
81
- 2, 29, :_reduce_8,
82
- 1, 30, :_reduce_9,
83
- 2, 30, :_reduce_10,
84
- 4, 31, :_reduce_11,
85
- 3, 31, :_reduce_12,
74
+ 3, 28, :_reduce_1,
75
+ 1, 28, :_reduce_2,
76
+ 2, 29, :_reduce_3,
77
+ 1, 29, :_reduce_4,
78
+ 2, 30, :_reduce_5,
79
+ 1, 30, :_reduce_6,
80
+ 4, 30, :_reduce_7,
81
+ 2, 30, :_reduce_8,
82
+ 2, 30, :_reduce_9,
83
+ 1, 31, :_reduce_10,
84
+ 2, 31, :_reduce_11,
85
+ 4, 32, :_reduce_12,
86
86
  3, 32, :_reduce_13,
87
- 4, 32, :_reduce_14,
88
- 5, 32, :_reduce_15,
89
- 2, 34, :_reduce_16,
90
- 1, 34, :_reduce_17,
91
- 1, 33, :_reduce_none,
92
- 1, 33, :_reduce_19,
93
- 1, 33, :_reduce_20,
94
- 1, 33, :_reduce_21,
95
- 1, 33, :_reduce_22,
96
- 1, 33, :_reduce_23,
97
- 1, 33, :_reduce_24,
98
- 1, 33, :_reduce_25,
99
- 1, 33, :_reduce_26 ]
100
-
101
- racc_reduce_n = 27
102
-
103
- racc_shift_n = 42
87
+ 3, 33, :_reduce_14,
88
+ 4, 33, :_reduce_15,
89
+ 5, 33, :_reduce_16,
90
+ 2, 35, :_reduce_17,
91
+ 1, 35, :_reduce_18,
92
+ 1, 34, :_reduce_none,
93
+ 1, 34, :_reduce_20,
94
+ 1, 34, :_reduce_21,
95
+ 1, 34, :_reduce_22,
96
+ 1, 34, :_reduce_23,
97
+ 1, 34, :_reduce_24,
98
+ 1, 34, :_reduce_25,
99
+ 1, 34, :_reduce_26,
100
+ 1, 34, :_reduce_27 ]
101
+
102
+ racc_reduce_n = 28
103
+
104
+ racc_shift_n = 43
104
105
 
105
106
  racc_token_table = {
106
107
  false => 0,
@@ -120,17 +121,18 @@ racc_token_table = {
120
121
  :tCLOSE_ARRAY => 14,
121
122
  :tOPEN_SELECTOR => 15,
122
123
  :tCLOSE_SELECTOR => 16,
123
- :tOPERATOR => 17,
124
- :tARRAY_VALUE => 18,
125
- :tBOOLEAN => 19,
126
- :tFLOAT => 20,
127
- :tINTEGER => 21,
128
- :tNIL => 22,
129
- :tREGEXP => 23,
130
- :tSTRING => 24,
131
- :tSYMBOL => 25 }
132
-
133
- racc_nt_base = 26
124
+ :tPOSITION => 17,
125
+ :tOPERATOR => 18,
126
+ :tARRAY_VALUE => 19,
127
+ :tBOOLEAN => 20,
128
+ :tFLOAT => 21,
129
+ :tINTEGER => 22,
130
+ :tNIL => 23,
131
+ :tREGEXP => 24,
132
+ :tSTRING => 25,
133
+ :tSYMBOL => 26 }
134
+
135
+ racc_nt_base = 27
134
136
 
135
137
  racc_use_result_var = false
136
138
 
@@ -168,6 +170,7 @@ Racc_token_to_s_table = [
168
170
  "tCLOSE_ARRAY",
169
171
  "tOPEN_SELECTOR",
170
172
  "tCLOSE_SELECTOR",
173
+ "tPOSITION",
171
174
  "tOPERATOR",
172
175
  "tARRAY_VALUE",
173
176
  "tBOOLEAN",
@@ -210,88 +213,92 @@ def _reduce_4(val, _values)
210
213
  end
211
214
 
212
215
  def _reduce_5(val, _values)
213
- NodeQuery::Compiler::Selector.new(basic_selector: val[0])
216
+ NodeQuery::Compiler::Selector.new(basic_selector: val[0], position: val[1] )
214
217
  end
215
218
 
216
219
  def _reduce_6(val, _values)
217
- NodeQuery::Compiler::Selector.new(pseudo_class: val[0], pseudo_selector: val[2])
220
+ NodeQuery::Compiler::Selector.new(basic_selector: val[0])
218
221
  end
219
222
 
220
223
  def _reduce_7(val, _values)
221
- NodeQuery::Compiler::Selector.new(relationship: val[0], rest: val[1])
224
+ NodeQuery::Compiler::Selector.new(pseudo_class: val[0], pseudo_selector: val[2])
222
225
  end
223
226
 
224
227
  def _reduce_8(val, _values)
225
- NodeQuery::Compiler::Selector.new(goto_scope: val[0], rest: val[1])
228
+ NodeQuery::Compiler::Selector.new(relationship: val[0], rest: val[1])
226
229
  end
227
230
 
228
231
  def _reduce_9(val, _values)
229
- NodeQuery::Compiler::BasicSelector.new(node_type: val[0])
232
+ NodeQuery::Compiler::Selector.new(goto_scope: val[0], rest: val[1])
230
233
  end
231
234
 
232
235
  def _reduce_10(val, _values)
233
- NodeQuery::Compiler::BasicSelector.new(node_type: val[0], attribute_list: val[1])
236
+ NodeQuery::Compiler::BasicSelector.new(node_type: val[0])
234
237
  end
235
238
 
236
239
  def _reduce_11(val, _values)
237
- NodeQuery::Compiler::AttributeList.new(attribute: val[1], rest: val[3])
240
+ NodeQuery::Compiler::BasicSelector.new(node_type: val[0], attribute_list: val[1])
238
241
  end
239
242
 
240
243
  def _reduce_12(val, _values)
241
- NodeQuery::Compiler::AttributeList.new(attribute: val[1])
244
+ NodeQuery::Compiler::AttributeList.new(attribute: val[1], rest: val[3])
242
245
  end
243
246
 
244
247
  def _reduce_13(val, _values)
245
- NodeQuery::Compiler::Attribute.new(key: val[0], value: val[2], operator: val[1])
248
+ NodeQuery::Compiler::AttributeList.new(attribute: val[1])
246
249
  end
247
250
 
248
251
  def _reduce_14(val, _values)
249
- NodeQuery::Compiler::Attribute.new(key: val[0], value: NodeQuery::Compiler::ArrayValue.new, operator: val[1])
252
+ NodeQuery::Compiler::Attribute.new(key: val[0], value: val[2], operator: val[1])
250
253
  end
251
254
 
252
255
  def _reduce_15(val, _values)
253
- NodeQuery::Compiler::Attribute.new(key: val[0], value: val[3], operator: val[1])
256
+ NodeQuery::Compiler::Attribute.new(key: val[0], value: NodeQuery::Compiler::ArrayValue.new, operator: val[1])
254
257
  end
255
258
 
256
259
  def _reduce_16(val, _values)
257
- NodeQuery::Compiler::ArrayValue.new(value: val[0], rest: val[1])
260
+ NodeQuery::Compiler::Attribute.new(key: val[0], value: val[3], operator: val[1])
258
261
  end
259
262
 
260
263
  def _reduce_17(val, _values)
264
+ NodeQuery::Compiler::ArrayValue.new(value: val[0], rest: val[1])
265
+ end
266
+
267
+ def _reduce_18(val, _values)
261
268
  NodeQuery::Compiler::ArrayValue.new(value: val[0])
262
269
  end
263
270
 
264
- # reduce 18 omitted
271
+ # reduce 19 omitted
265
272
 
266
- def _reduce_19(val, _values)
273
+ def _reduce_20(val, _values)
267
274
  NodeQuery::Compiler::Boolean.new(value: val[0])
268
275
  end
269
276
 
270
- def _reduce_20(val, _values)
277
+ def _reduce_21(val, _values)
271
278
  NodeQuery::Compiler::Float.new(value: val[0])
272
279
  end
273
280
 
274
- def _reduce_21(val, _values)
281
+ def _reduce_22(val, _values)
275
282
  NodeQuery::Compiler::Integer.new(value: val[0])
276
283
  end
277
284
 
278
- def _reduce_22(val, _values)
285
+ def _reduce_23(val, _values)
279
286
  NodeQuery::Compiler::Nil.new(value: val[0])
280
287
  end
281
288
 
282
- def _reduce_23(val, _values)
289
+ def _reduce_24(val, _values)
283
290
  NodeQuery::Compiler::Regexp.new(value: val[0])
284
291
  end
285
292
 
286
- def _reduce_24(val, _values)
293
+ def _reduce_25(val, _values)
287
294
  NodeQuery::Compiler::String.new(value: val[0])
288
295
  end
289
296
 
290
- def _reduce_25(val, _values)
297
+ def _reduce_26(val, _values)
291
298
  NodeQuery::Compiler::Symbol.new(value: val[0])
292
299
  end
293
300
 
294
- def _reduce_26(val, _values)
301
+ def _reduce_27(val, _values)
295
302
  NodeQuery::Compiler::Identifier.new(value: val[0])
296
303
  end
297
304
 
@@ -1,7 +1,7 @@
1
1
  class NodeQueryParser
2
2
  options no_result_var
3
3
  token tCOMMA tNODE_TYPE tGOTO_SCOPE tATTRIBUTE tKEY tIDENTIFIER tIDENTIFIER_VALUE tPSEUDO_CLASS tRELATIONSHIP
4
- tOPEN_ATTRIBUTE tCLOSE_ATTRIBUTE tOPEN_ARRAY tCLOSE_ARRAY tOPEN_SELECTOR tCLOSE_SELECTOR
4
+ tOPEN_ATTRIBUTE tCLOSE_ATTRIBUTE tOPEN_ARRAY tCLOSE_ARRAY tOPEN_SELECTOR tCLOSE_SELECTOR tPOSITION
5
5
  tOPERATOR tARRAY_VALUE tBOOLEAN tFLOAT tINTEGER tNIL tREGEXP tSTRING tSYMBOL
6
6
  rule
7
7
  expression_list
@@ -13,7 +13,8 @@ rule
13
13
  | selector { NodeQuery::Compiler::Expression.new(selector: val[0]) }
14
14
 
15
15
  selector
16
- : basic_selector { NodeQuery::Compiler::Selector.new(basic_selector: val[0]) }
16
+ : basic_selector tPOSITION { NodeQuery::Compiler::Selector.new(basic_selector: val[0], position: val[1] ) }
17
+ | basic_selector { NodeQuery::Compiler::Selector.new(basic_selector: val[0]) }
17
18
  | tPSEUDO_CLASS tOPEN_SELECTOR selector tCLOSE_SELECTOR { NodeQuery::Compiler::Selector.new(pseudo_class: val[0], pseudo_selector: val[2]) }
18
19
  | tRELATIONSHIP selector { NodeQuery::Compiler::Selector.new(relationship: val[0], rest: val[1]) }
19
20
  | tGOTO_SCOPE selector { NodeQuery::Compiler::Selector.new(goto_scope: val[0], rest: val[1]) }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: node_query
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.1
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Huang
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-09-28 00:00:00.000000000 Z
11
+ date: 2022-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -91,7 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
91
  - !ruby/object:Gem::Version
92
92
  version: '0'
93
93
  requirements: []
94
- rubygems_version: 3.3.7
94
+ rubygems_version: 3.3.22
95
95
  signing_key:
96
96
  specification_version: 4
97
97
  summary: ast node query language