node_query 1.6.1 → 1.8.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: 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