node_query 1.13.12 → 1.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +4 -3
- data/README.md +3 -7
- data/lib/node_query/compiler/array_value.rb +3 -1
- data/lib/node_query/compiler/attribute.rb +4 -2
- data/lib/node_query/compiler/basic_selector.rb +4 -2
- data/lib/node_query/compiler/boolean.rb +3 -1
- data/lib/node_query/compiler/comparable.rb +2 -1
- data/lib/node_query/compiler/float.rb +3 -1
- data/lib/node_query/compiler/identifier.rb +5 -3
- data/lib/node_query/compiler/integer.rb +3 -1
- data/lib/node_query/compiler/nil.rb +3 -1
- data/lib/node_query/compiler/regexp.rb +5 -3
- data/lib/node_query/compiler/selector.rb +9 -6
- data/lib/node_query/compiler/string.rb +5 -3
- data/lib/node_query/compiler/symbol.rb +3 -1
- data/lib/node_query/helper.rb +20 -17
- data/lib/node_query/node_rules.rb +16 -14
- data/lib/node_query/version.rb +1 -1
- data/lib/node_query.rb +19 -16
- data/lib/node_query_parser.racc.rb +33 -32
- data/lib/node_query_parser.y +22 -21
- data/sig/node_query.rbs +1 -5
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3dfe6e9207a883cc7d7240f46bac3d4628443f9eb40bcd5af36802311ebad8ae
|
4
|
+
data.tar.gz: 1d4dbd34cb794d95fc594f020fd07706e5babc85a38ea303a2c9ce4a31ed2f0a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70dc0235743a5191905c18633a633f620bdff6ffcd8bd4704b31d84ff724239e2e604e9999be9532022fa4d6b590bf3d2b886f468f0e4add83c4c1594f45ad58
|
7
|
+
data.tar.gz: 3831937eb116d7e49812631488cc12bbbcf1c923212e810e35ca98a15590b6241c3659ed24909d36206a28176d2d7a721f1ec9e2d10556c6fea62f2889e0d104
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
node_query (1.
|
4
|
+
node_query (1.14.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -38,9 +38,10 @@ GEM
|
|
38
38
|
nenv (~> 0.1)
|
39
39
|
shellany (~> 0.0)
|
40
40
|
oedipus_lex (2.6.0)
|
41
|
-
parser (3.2.2.
|
41
|
+
parser (3.2.2.3)
|
42
42
|
ast (~> 2.4.1)
|
43
|
-
|
43
|
+
racc
|
44
|
+
parser_node_ext (1.2.1)
|
44
45
|
parser
|
45
46
|
prettier_print (1.2.1)
|
46
47
|
pry (0.14.1)
|
data/README.md
CHANGED
@@ -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(nql_or_rules: String | Hash) # Initialize NodeQuery
|
64
|
+
node_query = NodeQuery.new(nql_or_rules: String | Hash, adapter: Symbol) # 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
|
```
|
@@ -82,8 +82,8 @@ source = `
|
|
82
82
|
node = Parser::CurrentRuby.parse(source)
|
83
83
|
|
84
84
|
# It will get the node of initialize.
|
85
|
-
NodeQuery.new('.def[name=initialize]').query_nodes(node)
|
86
|
-
NodeQuery.new({ node_type: 'def', name: 'initialize' }).query_nodes(node)
|
85
|
+
NodeQuery.new('.def[name=initialize]', adapter: :parser).query_nodes(node)
|
86
|
+
NodeQuery.new({ node_type: 'def', name: 'initialize' }, adapter: :parser).query_nodes(node)
|
87
87
|
```
|
88
88
|
|
89
89
|
## Node Query Language
|
@@ -483,10 +483,6 @@ It provides 2 adapters
|
|
483
483
|
1. `ParserAdapter`
|
484
484
|
2. `SyntaxTreeAdapter`
|
485
485
|
|
486
|
-
```ruby
|
487
|
-
NodeQuery.configure(adapter: SyntaxTreeAdapter.new) # default is ParserAdapter
|
488
|
-
```
|
489
|
-
|
490
486
|
## Development
|
491
487
|
|
492
488
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -8,9 +8,11 @@ module NodeQuery::Compiler
|
|
8
8
|
# Initialize an Array.
|
9
9
|
# @param value the first value of the array
|
10
10
|
# @param rest the rest value of the array
|
11
|
-
|
11
|
+
# @param adapter [NodeQuery::Adapter]
|
12
|
+
def initialize(value: nil, rest: nil, adapter:)
|
12
13
|
@value = value
|
13
14
|
@rest = rest
|
15
|
+
@adapter = adapter
|
14
16
|
end
|
15
17
|
|
16
18
|
# Get the expected value.
|
@@ -7,10 +7,12 @@ module NodeQuery::Compiler
|
|
7
7
|
# @param key [String] the key
|
8
8
|
# @param value the value can be any class implement {NodeQuery::Compiler::Comparable}
|
9
9
|
# @param operator [String] the operator
|
10
|
-
|
10
|
+
# @param adapter [NodeQuery::Adapter]
|
11
|
+
def initialize(key:, value:, operator: '=', adapter:)
|
11
12
|
@key = key
|
12
13
|
@value = value
|
13
14
|
@operator = operator
|
15
|
+
@adapter = adapter
|
14
16
|
end
|
15
17
|
|
16
18
|
# Check if the node matches the attribute.
|
@@ -18,7 +20,7 @@ module NodeQuery::Compiler
|
|
18
20
|
# @param base_node [Node] the bae node for evaluated value
|
19
21
|
# @return [Boolean]
|
20
22
|
def match?(node, base_node)
|
21
|
-
node && @value.match?(NodeQuery::Helper.get_target_node(node, @key), base_node, @operator)
|
23
|
+
node && @value.match?(NodeQuery::Helper.get_target_node(node, @key, @adapter), base_node, @operator)
|
22
24
|
end
|
23
25
|
|
24
26
|
def to_s
|
@@ -6,9 +6,11 @@ module NodeQuery::Compiler
|
|
6
6
|
# Initialize a BasicSelector.
|
7
7
|
# @param node_type [String] the node type
|
8
8
|
# @param attribute_list [NodeQuery::Compiler::AttributeList] the attribute list
|
9
|
-
|
9
|
+
# @param adapter [NodeQuery::Adapter]
|
10
|
+
def initialize(node_type:, attribute_list: nil, adapter:)
|
10
11
|
@node_type = node_type
|
11
12
|
@attribute_list = attribute_list
|
13
|
+
@adapter = adapter
|
12
14
|
end
|
13
15
|
|
14
16
|
# Check if node matches the selector.
|
@@ -18,7 +20,7 @@ module NodeQuery::Compiler
|
|
18
20
|
def match?(node, base_node, _operator = '=')
|
19
21
|
return false unless node
|
20
22
|
|
21
|
-
@node_type.to_sym ==
|
23
|
+
@node_type.to_sym == @adapter.get_node_type(node) && (!@attribute_list || @attribute_list.match?(
|
22
24
|
node,
|
23
25
|
base_node
|
24
26
|
))
|
@@ -7,8 +7,10 @@ module NodeQuery::Compiler
|
|
7
7
|
|
8
8
|
# Initialize a Boolean.
|
9
9
|
# @param value [Boolean] the boolean value
|
10
|
-
|
10
|
+
# @param adapter [NodeQuery::Adapter]
|
11
|
+
def initialize(value:, adapter:)
|
11
12
|
@value = value
|
13
|
+
@adapter = adapter
|
12
14
|
end
|
13
15
|
|
14
16
|
# Get valid operators.
|
@@ -16,6 +16,7 @@ module NodeQuery::Compiler
|
|
16
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>
|
17
17
|
# @return [Boolean] true if actual value matches the expected value
|
18
18
|
# @raise [NodeQuery::Compiler::InvalidOperatorError] if operator is invalid
|
19
|
+
# @param adapter [NodeQuery::Adapter]
|
19
20
|
def match?(node, base_node, operator)
|
20
21
|
raise InvalidOperatorError, "invalid operator #{operator}" unless valid_operator?(operator)
|
21
22
|
|
@@ -89,7 +90,7 @@ module NodeQuery::Compiler
|
|
89
90
|
# @param node [Node] ast node
|
90
91
|
# @return the node value, could be integer, float, string, boolean, nil, range, and etc.
|
91
92
|
def actual_value(node)
|
92
|
-
if
|
93
|
+
if @adapter.is_node?(node)
|
93
94
|
node.to_value
|
94
95
|
else
|
95
96
|
node
|
@@ -7,8 +7,10 @@ module NodeQuery::Compiler
|
|
7
7
|
|
8
8
|
# Initialize a Float.
|
9
9
|
# @param value [Float] the float value
|
10
|
-
|
10
|
+
# @param adapter [NodeQuery::Adapter]
|
11
|
+
def initialize(value:, adapter:)
|
11
12
|
@value = value
|
13
|
+
@adapter = adapter
|
12
14
|
end
|
13
15
|
|
14
16
|
# Get valid operators.
|
@@ -8,8 +8,10 @@ module NodeQuery::Compiler
|
|
8
8
|
|
9
9
|
# Initialize an Identifier.
|
10
10
|
# @param value [String] the identifier value
|
11
|
-
|
11
|
+
# @param adapter [NodeQuery::Adapter]
|
12
|
+
def initialize(value:, adapter:)
|
12
13
|
@value = value
|
14
|
+
@adapter = adapter
|
13
15
|
end
|
14
16
|
|
15
17
|
# Get the actual value.
|
@@ -19,8 +21,8 @@ module NodeQuery::Compiler
|
|
19
21
|
# if the node is an Array, return the array of each element's actual value,
|
20
22
|
# otherwise, return the String value.
|
21
23
|
def actual_value(node)
|
22
|
-
if
|
23
|
-
|
24
|
+
if @adapter.is_node?(node)
|
25
|
+
@adapter.get_source(node)
|
24
26
|
elsif node.is_a?(::Array)
|
25
27
|
node.map { |n| actual_value(n) }
|
26
28
|
else
|
@@ -7,8 +7,10 @@ module NodeQuery::Compiler
|
|
7
7
|
|
8
8
|
# Initialize a Integer.
|
9
9
|
# @param value [Integer] the integer value
|
10
|
-
|
10
|
+
# @param adapter [NodeQuery::Adapter]
|
11
|
+
def initialize(value:, adapter:)
|
11
12
|
@value = value
|
13
|
+
@adapter = adapter
|
12
14
|
end
|
13
15
|
|
14
16
|
# Get valid operators.
|
@@ -7,8 +7,10 @@ module NodeQuery::Compiler
|
|
7
7
|
|
8
8
|
# Initialize a Nil.
|
9
9
|
# @param value [nil] the nil value
|
10
|
-
|
10
|
+
# @param adapter [NodeQuery::Adapter]
|
11
|
+
def initialize(value:, adapter:)
|
11
12
|
@value = value
|
13
|
+
@adapter = adapter
|
12
14
|
end
|
13
15
|
|
14
16
|
# Get valid operators.
|
@@ -7,8 +7,10 @@ module NodeQuery::Compiler
|
|
7
7
|
|
8
8
|
# Initialize a Regexp.
|
9
9
|
# @param value [Regexp] the regexp value
|
10
|
-
|
10
|
+
# @param adapter [NodeQuery::Adapter]
|
11
|
+
def initialize(value:, adapter:)
|
11
12
|
@value = value
|
13
|
+
@adapter = adapter
|
12
14
|
end
|
13
15
|
|
14
16
|
# Check if the regexp value matches the node value.
|
@@ -18,8 +20,8 @@ module NodeQuery::Compiler
|
|
18
20
|
# @return [Boolean] true if the regexp value matches the node value, otherwise, false.
|
19
21
|
def match?(node, _base_node, operator = '=~')
|
20
22
|
match =
|
21
|
-
if
|
22
|
-
@value.match(
|
23
|
+
if @adapter.is_node?(node)
|
24
|
+
@value.match(@adapter.get_source(node))
|
23
25
|
else
|
24
26
|
@value.match(node.to_s)
|
25
27
|
end
|
@@ -12,6 +12,7 @@ module NodeQuery::Compiler
|
|
12
12
|
# @param attribute_list [NodeQuery::Compiler::AttributeList] the attribute list
|
13
13
|
# @param pseudo_class [String] the pseudo class, can be <code>has</code> or <code>not_has</code>
|
14
14
|
# @param pseudo_selector [NodeQuery::Compiler::Expression] the pseudo selector
|
15
|
+
# @param adapter [NodeQuery::Adapter]
|
15
16
|
def initialize(
|
16
17
|
goto_scope: nil,
|
17
18
|
relationship: nil,
|
@@ -19,7 +20,8 @@ module NodeQuery::Compiler
|
|
19
20
|
basic_selector: nil,
|
20
21
|
position: nil,
|
21
22
|
pseudo_class: nil,
|
22
|
-
pseudo_selector: nil
|
23
|
+
pseudo_selector: nil,
|
24
|
+
adapter:
|
23
25
|
)
|
24
26
|
@goto_scope = goto_scope
|
25
27
|
@relationship = relationship
|
@@ -28,6 +30,7 @@ module NodeQuery::Compiler
|
|
28
30
|
@position = position
|
29
31
|
@pseudo_class = pseudo_class
|
30
32
|
@pseudo_selector = pseudo_selector
|
33
|
+
@adapter = adapter
|
31
34
|
end
|
32
35
|
|
33
36
|
# Check if node matches the selector.
|
@@ -44,7 +47,7 @@ module NodeQuery::Compiler
|
|
44
47
|
return false
|
45
48
|
end
|
46
49
|
end
|
47
|
-
|
50
|
+
@adapter.is_node?(node) && (!@basic_selector || (operator == "!=" ? !@basic_selector.match?(
|
48
51
|
node,
|
49
52
|
base_node
|
50
53
|
) : @basic_selector.match?(node, base_node))) && match_pseudo_class?(node)
|
@@ -83,7 +86,7 @@ module NodeQuery::Compiler
|
|
83
86
|
end
|
84
87
|
if @basic_selector
|
85
88
|
if options[:recursive]
|
86
|
-
NodeQuery::Helper.handle_recursive_child(node) do |child_node|
|
89
|
+
NodeQuery::Helper.handle_recursive_child(node, @adapter) do |child_node|
|
87
90
|
if match?(child_node, child_node)
|
88
91
|
nodes << child_node
|
89
92
|
break if options[:stop_at_first_match]
|
@@ -153,13 +156,13 @@ module NodeQuery::Compiler
|
|
153
156
|
nodes << child_node if @rest.match?(child_node, child_node)
|
154
157
|
end
|
155
158
|
else
|
156
|
-
|
159
|
+
@adapter.get_children(node).each do |child_node|
|
157
160
|
if child_node.is_a?(Array) # SyntaxTree may return an array in child node.
|
158
161
|
child_node.each do |child_child_node|
|
159
162
|
nodes << child_child_node if @rest.match?(child_child_node, child_child_node)
|
160
163
|
end
|
161
|
-
elsif
|
162
|
-
|
164
|
+
elsif @adapter.is_node?(child_node) && :begin == @adapter.get_node_type(child_node)
|
165
|
+
@adapter.get_children(child_node).each do |child_child_node|
|
163
166
|
nodes << child_child_node if @rest.match?(child_child_node, child_child_node)
|
164
167
|
end
|
165
168
|
elsif @rest.match?(child_node, child_node)
|
@@ -7,8 +7,10 @@ module NodeQuery::Compiler
|
|
7
7
|
|
8
8
|
# Initialize a String.
|
9
9
|
# @param value [String] the string value
|
10
|
-
|
10
|
+
# @param adapter [NodeQuery::Adapter]
|
11
|
+
def initialize(value:, adapter:)
|
11
12
|
@value = value
|
13
|
+
@adapter = adapter
|
12
14
|
end
|
13
15
|
|
14
16
|
# Get the expected value.
|
@@ -19,7 +21,7 @@ module NodeQuery::Compiler
|
|
19
21
|
# @param base_node [Node] the base node for evaluated value
|
20
22
|
# @return [String] the expected string, if it contains evaluated value, evaluate the node value.
|
21
23
|
def expected_value(base_node)
|
22
|
-
NodeQuery::Helper.evaluate_node_value(base_node, @value)
|
24
|
+
NodeQuery::Helper.evaluate_node_value(base_node, @value, @adapter)
|
23
25
|
end
|
24
26
|
|
25
27
|
# Check if the actual value equals the node value.
|
@@ -27,7 +29,7 @@ module NodeQuery::Compiler
|
|
27
29
|
# @param base_node [Node] the base node for evaluated value
|
28
30
|
# @return [Boolean] true if the actual value equals the node value.
|
29
31
|
def is_equal?(actual, expected)
|
30
|
-
NodeQuery::Helper.to_string(actual) == expected
|
32
|
+
NodeQuery::Helper.to_string(actual, @adapter) == expected
|
31
33
|
end
|
32
34
|
|
33
35
|
# Get valid operators.
|
@@ -7,8 +7,10 @@ module NodeQuery::Compiler
|
|
7
7
|
|
8
8
|
# Initliaze a Symobol.
|
9
9
|
# @param value [Symbol] the symbol value
|
10
|
-
|
10
|
+
# @param adapter [NodeQuery::Adapter]
|
11
|
+
def initialize(value:, adapter:)
|
11
12
|
@value = value
|
13
|
+
@adapter = adapter
|
12
14
|
end
|
13
15
|
|
14
16
|
# Get valid operators.
|
data/lib/node_query/helper.rb
CHANGED
@@ -5,13 +5,14 @@ class NodeQuery::Helper
|
|
5
5
|
# Get target node by the keys.
|
6
6
|
# @param node [Node] ast node
|
7
7
|
# @param keys [String|Array] keys of child node.
|
8
|
+
# @param adapter [NodeQuery::Adapter]
|
8
9
|
# @return [Node|] the target node.
|
9
|
-
def get_target_node(node, keys)
|
10
|
+
def get_target_node(node, keys, adapter)
|
10
11
|
return unless node
|
11
12
|
|
12
13
|
first_key, rest_keys = keys.to_s.split('.', 2)
|
13
14
|
if node.is_a?(Array) && first_key === "*"
|
14
|
-
return node.map { |child_node| get_target_node(child_node, rest_keys) }
|
15
|
+
return node.map { |child_node| get_target_node(child_node, rest_keys, adapter) }
|
15
16
|
end
|
16
17
|
|
17
18
|
if node.is_a?(Array) && first_key =~ /\d+/
|
@@ -19,21 +20,22 @@ class NodeQuery::Helper
|
|
19
20
|
elsif node.respond_to?(first_key)
|
20
21
|
child_node = node.send(first_key)
|
21
22
|
elsif first_key == "node_type"
|
22
|
-
child_node =
|
23
|
+
child_node = adapter.get_node_type(node)
|
23
24
|
end
|
24
25
|
|
25
26
|
return child_node unless rest_keys
|
26
27
|
|
27
|
-
return get_target_node(child_node, rest_keys)
|
28
|
+
return get_target_node(child_node, rest_keys, adapter)
|
28
29
|
end
|
29
30
|
|
30
31
|
# Recursively handle child nodes.
|
31
32
|
# @param node [Node] ast node
|
33
|
+
# @param adapter [NodeQuery::Adapter] adapter
|
32
34
|
# @yield [child] Gives a child node.
|
33
35
|
# @yieldparam child [Node] child node
|
34
|
-
def handle_recursive_child(node, &block)
|
35
|
-
|
36
|
-
handle_child(child, &block)
|
36
|
+
def handle_recursive_child(node, adapter, &block)
|
37
|
+
adapter.get_children(node).each do |child|
|
38
|
+
handle_child(child, adapter, &block)
|
37
39
|
end
|
38
40
|
end
|
39
41
|
|
@@ -43,18 +45,19 @@ class NodeQuery::Helper
|
|
43
45
|
# evaluated_node_value(node, "@{{value}}") # => @id
|
44
46
|
# @param node [Node] ast node
|
45
47
|
# @param str [String] string to be evaluated
|
48
|
+
# @param adapter [NodeQuery::Adapter] adapter
|
46
49
|
# @return [String] evaluated string
|
47
|
-
def evaluate_node_value(node, str)
|
50
|
+
def evaluate_node_value(node, str, adapter)
|
48
51
|
str.scan(/{{(.+?)}}/).each do |match_data|
|
49
|
-
target_node = NodeQuery::Helper.get_target_node(node, match_data.first)
|
50
|
-
str = str.sub("{{#{match_data.first}}}", to_string(target_node))
|
52
|
+
target_node = NodeQuery::Helper.get_target_node(node, match_data.first, adapter)
|
53
|
+
str = str.sub("{{#{match_data.first}}}", to_string(target_node, adapter))
|
51
54
|
end
|
52
55
|
str
|
53
56
|
end
|
54
57
|
|
55
|
-
def to_string(node)
|
56
|
-
if
|
57
|
-
return
|
58
|
+
def to_string(node, adapter)
|
59
|
+
if adapter.is_node?(node)
|
60
|
+
return adapter.get_source(node)
|
58
61
|
end
|
59
62
|
|
60
63
|
node.to_s
|
@@ -62,13 +65,13 @@ class NodeQuery::Helper
|
|
62
65
|
|
63
66
|
private
|
64
67
|
|
65
|
-
def handle_child(node, &block)
|
66
|
-
if
|
68
|
+
def handle_child(node, adapter, &block)
|
69
|
+
if adapter.is_node?(node)
|
67
70
|
block.call(node)
|
68
|
-
handle_recursive_child(node, &block)
|
71
|
+
handle_recursive_child(node, adapter, &block)
|
69
72
|
elsif node.is_a?(Array)
|
70
73
|
node.each do |child_node|
|
71
|
-
handle_child(child_node, &block) unless child_node.nil?
|
74
|
+
handle_child(child_node, adapter, &block) unless child_node.nil?
|
72
75
|
end
|
73
76
|
end
|
74
77
|
end
|
@@ -5,8 +5,10 @@ class NodeQuery::NodeRules
|
|
5
5
|
|
6
6
|
# Initialize a NodeRules.
|
7
7
|
# @param rules [Hash] the nod rules
|
8
|
-
|
8
|
+
# @param adapter [NodeQuery::Adapter]
|
9
|
+
def initialize(rules, adapter:)
|
9
10
|
@rules = rules
|
11
|
+
@adapter = adapter
|
10
12
|
end
|
11
13
|
|
12
14
|
# Query nodes by the rules.
|
@@ -28,14 +30,14 @@ class NodeQuery::NodeRules
|
|
28
30
|
return matching_nodes if options[:stop_at_first_match]
|
29
31
|
end
|
30
32
|
if options[:recursive]
|
31
|
-
NodeQuery::Helper.handle_recursive_child(node) do |child_node|
|
33
|
+
NodeQuery::Helper.handle_recursive_child(node, @adapter) do |child_node|
|
32
34
|
if match_node?(child_node)
|
33
35
|
matching_nodes.push(child_node)
|
34
36
|
break if options[:stop_at_first_match]
|
35
37
|
end
|
36
38
|
end
|
37
39
|
else
|
38
|
-
|
40
|
+
@adapter.get_children(node).each do |child_node|
|
39
41
|
if match_node?(child_node)
|
40
42
|
matching_nodes.push(child_node)
|
41
43
|
break if options[:stop_at_first_match]
|
@@ -53,10 +55,10 @@ class NodeQuery::NodeRules
|
|
53
55
|
last_key = multi_keys.last
|
54
56
|
actual =
|
55
57
|
KEYWORDS.include?(last_key) ?
|
56
|
-
NodeQuery::Helper.get_target_node(node, multi_keys[0...-1].join('.')) :
|
57
|
-
NodeQuery::Helper.get_target_node(node, multi_keys.join('.'))
|
58
|
+
NodeQuery::Helper.get_target_node(node, multi_keys[0...-1].join('.'), @adapter) :
|
59
|
+
NodeQuery::Helper.get_target_node(node, multi_keys.join('.'), @adapter)
|
58
60
|
expected = expected_value(@rules, multi_keys)
|
59
|
-
expected = NodeQuery::Helper.evaluate_node_value(node, expected) if expected.is_a?(String)
|
61
|
+
expected = NodeQuery::Helper.evaluate_node_value(node, expected, @adapter) if expected.is_a?(String)
|
60
62
|
case last_key
|
61
63
|
when :includes
|
62
64
|
actual.any? { |actual_value| match_value?(actual_value, expected) }
|
@@ -95,22 +97,22 @@ class NodeQuery::NodeRules
|
|
95
97
|
|
96
98
|
case expected
|
97
99
|
when Symbol
|
98
|
-
if
|
99
|
-
actual_source =
|
100
|
+
if @adapter.is_node?(actual)
|
101
|
+
actual_source = @adapter.get_source(actual)
|
100
102
|
actual_source == ":#{expected}" || actual_source == expected.to_s
|
101
103
|
else
|
102
104
|
actual.to_sym == expected
|
103
105
|
end
|
104
106
|
when String
|
105
|
-
if
|
106
|
-
actual_source =
|
107
|
+
if @adapter.is_node?(actual)
|
108
|
+
actual_source = @adapter.get_source(actual)
|
107
109
|
actual_source == expected || actual_source == unwrap_quote(expected) ||
|
108
110
|
unwrap_quote(actual_source) == expected || unwrap_quote(actual_source) == unwrap_quote(expected)
|
109
111
|
else
|
110
112
|
actual.to_s == expected || wrap_quote(actual.to_s) == expected
|
111
113
|
end
|
112
114
|
when Regexp
|
113
|
-
if
|
115
|
+
if @adapter.is_node?(actual)
|
114
116
|
actual.to_source =~ Regexp.new(expected.to_s, Regexp::MULTILINE)
|
115
117
|
else
|
116
118
|
actual.to_s =~ Regexp.new(expected.to_s, Regexp::MULTILINE)
|
@@ -120,13 +122,13 @@ class NodeQuery::NodeRules
|
|
120
122
|
|
121
123
|
actual.zip(expected).all? { |a, e| match_value?(a, e) }
|
122
124
|
when NilClass
|
123
|
-
if
|
125
|
+
if @adapter.is_node?(actual)
|
124
126
|
actual.to_value.nil?
|
125
127
|
else
|
126
128
|
actual.nil?
|
127
129
|
end
|
128
130
|
when Numeric
|
129
|
-
if
|
131
|
+
if @adapter.is_node?(actual)
|
130
132
|
actual.children[0] == expected
|
131
133
|
else
|
132
134
|
actual == expected
|
@@ -136,7 +138,7 @@ class NodeQuery::NodeRules
|
|
136
138
|
when FalseClass
|
137
139
|
false == actual&.to_value
|
138
140
|
else
|
139
|
-
if
|
141
|
+
if @adapter.is_node?(expected)
|
140
142
|
actual == expected
|
141
143
|
else
|
142
144
|
raise NodeQuery::MethodNotSupported, "#{expected} is not supported"
|
data/lib/node_query/version.rb
CHANGED
data/lib/node_query.rb
CHANGED
@@ -6,6 +6,7 @@ require_relative "./node_query_parser.racc"
|
|
6
6
|
|
7
7
|
class NodeQuery
|
8
8
|
class MethodNotSupported < StandardError; end
|
9
|
+
class InvalidAdapterError < StandardError; end
|
9
10
|
|
10
11
|
autoload :Adapter, "node_query/adapter"
|
11
12
|
autoload :ParserAdapter, "node_query/adapter/parser"
|
@@ -14,26 +15,15 @@ class NodeQuery
|
|
14
15
|
autoload :Helper, "node_query/helper"
|
15
16
|
autoload :NodeRules, "node_query/node_rules"
|
16
17
|
|
17
|
-
# Configure NodeQuery
|
18
|
-
# @param [Hash] options options to configure
|
19
|
-
# @option options [NodeQuery::Adapter] :adapter the adpater
|
20
|
-
def self.configure(options)
|
21
|
-
@adapter = options[:adapter]
|
22
|
-
end
|
23
|
-
|
24
|
-
# Get the adapter
|
25
|
-
# @return [NodeQuery::Adapter] current adapter, by default is {NodeQuery::ParserAdapter}
|
26
|
-
def self.adapter
|
27
|
-
@adapter ||= ParserAdapter.new
|
28
|
-
end
|
29
|
-
|
30
18
|
# Initialize a NodeQuery.
|
31
19
|
# @param nql_or_ruls [String | Hash] node query language or node rules
|
32
|
-
|
20
|
+
# @param adapter [Symbol] :parser or :syntax_tree
|
21
|
+
def initialize(nql_or_ruls, adapter: :parser)
|
22
|
+
adapter_instance = get_adapter_instance(adapter)
|
33
23
|
if nql_or_ruls.is_a?(String)
|
34
|
-
@expression = NodeQueryParser.new.parse(nql_or_ruls)
|
24
|
+
@expression = NodeQueryParser.new(adapter: adapter_instance).parse(nql_or_ruls)
|
35
25
|
else
|
36
|
-
@rules = NodeRules.new(nql_or_ruls)
|
26
|
+
@rules = NodeRules.new(nql_or_ruls, adapter: adapter_instance)
|
37
27
|
end
|
38
28
|
end
|
39
29
|
|
@@ -66,4 +56,17 @@ class NodeQuery
|
|
66
56
|
false
|
67
57
|
end
|
68
58
|
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def get_adapter_instance(adapter)
|
63
|
+
case adapter.to_sym
|
64
|
+
when :parser
|
65
|
+
ParserAdapter.new
|
66
|
+
when :syntax_tree
|
67
|
+
SyntaxTreeAdapter.new
|
68
|
+
else
|
69
|
+
raise InvalidAdapterError, "adapter #{adapter} is not supported"
|
70
|
+
end
|
71
|
+
end
|
69
72
|
end
|
@@ -7,18 +7,19 @@
|
|
7
7
|
require 'racc/parser.rb'
|
8
8
|
class NodeQueryParser < Racc::Parser
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
10
|
+
def initialize(adapter:)
|
11
|
+
@lexer = NodeQueryLexer.new
|
12
|
+
@adapter = adapter
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse string
|
16
|
+
@lexer.parse string
|
17
|
+
do_parse
|
18
|
+
end
|
19
|
+
|
20
|
+
def next_token
|
21
|
+
@lexer.next_token
|
22
|
+
end
|
22
23
|
##### State transition tables begin ###
|
23
24
|
|
24
25
|
racc_action_table = [
|
@@ -213,31 +214,31 @@ def _reduce_4(val, _values)
|
|
213
214
|
end
|
214
215
|
|
215
216
|
def _reduce_5(val, _values)
|
216
|
-
NodeQuery::Compiler::Selector.new(basic_selector: val[0], position: val[1] )
|
217
|
+
NodeQuery::Compiler::Selector.new(basic_selector: val[0], position: val[1], adapter: @adapter )
|
217
218
|
end
|
218
219
|
|
219
220
|
def _reduce_6(val, _values)
|
220
|
-
NodeQuery::Compiler::Selector.new(basic_selector: val[0])
|
221
|
+
NodeQuery::Compiler::Selector.new(basic_selector: val[0], adapter: @adapter)
|
221
222
|
end
|
222
223
|
|
223
224
|
def _reduce_7(val, _values)
|
224
|
-
NodeQuery::Compiler::Selector.new(pseudo_class: val[0], pseudo_selector: val[2])
|
225
|
+
NodeQuery::Compiler::Selector.new(pseudo_class: val[0], pseudo_selector: val[2], adapter: @adapter)
|
225
226
|
end
|
226
227
|
|
227
228
|
def _reduce_8(val, _values)
|
228
|
-
NodeQuery::Compiler::Selector.new(relationship: val[0], rest: val[1])
|
229
|
+
NodeQuery::Compiler::Selector.new(relationship: val[0], rest: val[1], adapter: @adapter)
|
229
230
|
end
|
230
231
|
|
231
232
|
def _reduce_9(val, _values)
|
232
|
-
NodeQuery::Compiler::Selector.new(goto_scope: val[0], rest: val[1])
|
233
|
+
NodeQuery::Compiler::Selector.new(goto_scope: val[0], rest: val[1], adapter: @adapter)
|
233
234
|
end
|
234
235
|
|
235
236
|
def _reduce_10(val, _values)
|
236
|
-
NodeQuery::Compiler::BasicSelector.new(node_type: val[0])
|
237
|
+
NodeQuery::Compiler::BasicSelector.new(node_type: val[0], adapter: @adapter)
|
237
238
|
end
|
238
239
|
|
239
240
|
def _reduce_11(val, _values)
|
240
|
-
NodeQuery::Compiler::BasicSelector.new(node_type: val[0], attribute_list: val[1])
|
241
|
+
NodeQuery::Compiler::BasicSelector.new(node_type: val[0], attribute_list: val[1], adapter: @adapter)
|
241
242
|
end
|
242
243
|
|
243
244
|
def _reduce_12(val, _values)
|
@@ -249,57 +250,57 @@ def _reduce_13(val, _values)
|
|
249
250
|
end
|
250
251
|
|
251
252
|
def _reduce_14(val, _values)
|
252
|
-
NodeQuery::Compiler::Attribute.new(key: val[1], value: val[3], operator: val[2])
|
253
|
+
NodeQuery::Compiler::Attribute.new(key: val[1], value: val[3], operator: val[2], adapter: @adapter)
|
253
254
|
end
|
254
255
|
|
255
256
|
def _reduce_15(val, _values)
|
256
|
-
NodeQuery::Compiler::Attribute.new(key: val[1], value: NodeQuery::Compiler::ArrayValue.new, operator: val[2])
|
257
|
+
NodeQuery::Compiler::Attribute.new(key: val[1], value: NodeQuery::Compiler::ArrayValue.new, operator: val[2], adapter: @adapter)
|
257
258
|
end
|
258
259
|
|
259
260
|
def _reduce_16(val, _values)
|
260
|
-
NodeQuery::Compiler::Attribute.new(key: val[1], value: val[4], operator: val[2])
|
261
|
+
NodeQuery::Compiler::Attribute.new(key: val[1], value: val[4], operator: val[2], adapter: @adapter)
|
261
262
|
end
|
262
263
|
|
263
264
|
def _reduce_17(val, _values)
|
264
|
-
NodeQuery::Compiler::ArrayValue.new(value: val[0], rest: val[1])
|
265
|
+
NodeQuery::Compiler::ArrayValue.new(value: val[0], rest: val[1], adapter: @adapter)
|
265
266
|
end
|
266
267
|
|
267
268
|
def _reduce_18(val, _values)
|
268
|
-
NodeQuery::Compiler::ArrayValue.new(value: val[0])
|
269
|
+
NodeQuery::Compiler::ArrayValue.new(value: val[0], adapter: @adapter)
|
269
270
|
end
|
270
271
|
|
271
272
|
# reduce 19 omitted
|
272
273
|
|
273
274
|
def _reduce_20(val, _values)
|
274
|
-
NodeQuery::Compiler::Boolean.new(value: val[0])
|
275
|
+
NodeQuery::Compiler::Boolean.new(value: val[0], adapter: @adapter)
|
275
276
|
end
|
276
277
|
|
277
278
|
def _reduce_21(val, _values)
|
278
|
-
NodeQuery::Compiler::Float.new(value: val[0])
|
279
|
+
NodeQuery::Compiler::Float.new(value: val[0], adapter: @adapter)
|
279
280
|
end
|
280
281
|
|
281
282
|
def _reduce_22(val, _values)
|
282
|
-
NodeQuery::Compiler::Integer.new(value: val[0])
|
283
|
+
NodeQuery::Compiler::Integer.new(value: val[0], adapter: @adapter)
|
283
284
|
end
|
284
285
|
|
285
286
|
def _reduce_23(val, _values)
|
286
|
-
NodeQuery::Compiler::Nil.new(value: val[0])
|
287
|
+
NodeQuery::Compiler::Nil.new(value: val[0], adapter: @adapter)
|
287
288
|
end
|
288
289
|
|
289
290
|
def _reduce_24(val, _values)
|
290
|
-
NodeQuery::Compiler::Regexp.new(value: val[0])
|
291
|
+
NodeQuery::Compiler::Regexp.new(value: val[0], adapter: @adapter)
|
291
292
|
end
|
292
293
|
|
293
294
|
def _reduce_25(val, _values)
|
294
|
-
NodeQuery::Compiler::String.new(value: val[0])
|
295
|
+
NodeQuery::Compiler::String.new(value: val[0], adapter: @adapter)
|
295
296
|
end
|
296
297
|
|
297
298
|
def _reduce_26(val, _values)
|
298
|
-
NodeQuery::Compiler::Symbol.new(value: val[0])
|
299
|
+
NodeQuery::Compiler::Symbol.new(value: val[0], adapter: @adapter)
|
299
300
|
end
|
300
301
|
|
301
302
|
def _reduce_27(val, _values)
|
302
|
-
NodeQuery::Compiler::Identifier.new(value: val[0])
|
303
|
+
NodeQuery::Compiler::Identifier.new(value: val[0], adapter: @adapter)
|
303
304
|
end
|
304
305
|
|
305
306
|
def _reduce_none(val, _values)
|
data/lib/node_query_parser.y
CHANGED
@@ -13,44 +13,45 @@ rule
|
|
13
13
|
| selector { NodeQuery::Compiler::Expression.new(selector: val[0]) }
|
14
14
|
|
15
15
|
selector
|
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]) }
|
18
|
-
| tPSEUDO_CLASS tOPEN_SELECTOR selector tCLOSE_SELECTOR { NodeQuery::Compiler::Selector.new(pseudo_class: val[0], pseudo_selector: val[2]) }
|
19
|
-
| tRELATIONSHIP selector { NodeQuery::Compiler::Selector.new(relationship: val[0], rest: val[1]) }
|
20
|
-
| tGOTO_SCOPE selector { NodeQuery::Compiler::Selector.new(goto_scope: val[0], rest: val[1]) }
|
16
|
+
: basic_selector tPOSITION { NodeQuery::Compiler::Selector.new(basic_selector: val[0], position: val[1], adapter: @adapter ) }
|
17
|
+
| basic_selector { NodeQuery::Compiler::Selector.new(basic_selector: val[0], adapter: @adapter) }
|
18
|
+
| tPSEUDO_CLASS tOPEN_SELECTOR selector tCLOSE_SELECTOR { NodeQuery::Compiler::Selector.new(pseudo_class: val[0], pseudo_selector: val[2], adapter: @adapter) }
|
19
|
+
| tRELATIONSHIP selector { NodeQuery::Compiler::Selector.new(relationship: val[0], rest: val[1], adapter: @adapter) }
|
20
|
+
| tGOTO_SCOPE selector { NodeQuery::Compiler::Selector.new(goto_scope: val[0], rest: val[1], adapter: @adapter) }
|
21
21
|
|
22
22
|
basic_selector
|
23
|
-
: tNODE_TYPE { NodeQuery::Compiler::BasicSelector.new(node_type: val[0]) }
|
24
|
-
| tNODE_TYPE attribute_list { NodeQuery::Compiler::BasicSelector.new(node_type: val[0], attribute_list: val[1]) }
|
23
|
+
: tNODE_TYPE { NodeQuery::Compiler::BasicSelector.new(node_type: val[0], adapter: @adapter) }
|
24
|
+
| tNODE_TYPE attribute_list { NodeQuery::Compiler::BasicSelector.new(node_type: val[0], attribute_list: val[1], adapter: @adapter) }
|
25
25
|
|
26
26
|
attribute_list
|
27
27
|
: attribute attribute_list { NodeQuery::Compiler::AttributeList.new(attribute: val[0], rest: val[1]) }
|
28
28
|
| attribute { NodeQuery::Compiler::AttributeList.new(attribute: val[0]) }
|
29
29
|
|
30
30
|
attribute
|
31
|
-
: tOPEN_ATTRIBUTE tKEY tOPERATOR value tCLOSE_ATTRIBUTE { NodeQuery::Compiler::Attribute.new(key: val[1], value: val[3], operator: val[2]) }
|
32
|
-
| tOPEN_ATTRIBUTE tKEY tOPERATOR tOPEN_ARRAY tCLOSE_ARRAY tCLOSE_ATTRIBUTE { NodeQuery::Compiler::Attribute.new(key: val[1], value: NodeQuery::Compiler::ArrayValue.new, operator: val[2]) }
|
33
|
-
| tOPEN_ATTRIBUTE tKEY tOPERATOR tOPEN_ARRAY array_value tCLOSE_ARRAY tCLOSE_ATTRIBUTE { NodeQuery::Compiler::Attribute.new(key: val[1], value: val[4], operator: val[2]) }
|
31
|
+
: tOPEN_ATTRIBUTE tKEY tOPERATOR value tCLOSE_ATTRIBUTE { NodeQuery::Compiler::Attribute.new(key: val[1], value: val[3], operator: val[2], adapter: @adapter) }
|
32
|
+
| tOPEN_ATTRIBUTE tKEY tOPERATOR tOPEN_ARRAY tCLOSE_ARRAY tCLOSE_ATTRIBUTE { NodeQuery::Compiler::Attribute.new(key: val[1], value: NodeQuery::Compiler::ArrayValue.new, operator: val[2], adapter: @adapter) }
|
33
|
+
| tOPEN_ATTRIBUTE tKEY tOPERATOR tOPEN_ARRAY array_value tCLOSE_ARRAY tCLOSE_ATTRIBUTE { NodeQuery::Compiler::Attribute.new(key: val[1], value: val[4], operator: val[2], adapter: @adapter) }
|
34
34
|
|
35
35
|
array_value
|
36
|
-
: value array_value { NodeQuery::Compiler::ArrayValue.new(value: val[0], rest: val[1]) }
|
37
|
-
| value { NodeQuery::Compiler::ArrayValue.new(value: val[0]) }
|
36
|
+
: value array_value { NodeQuery::Compiler::ArrayValue.new(value: val[0], rest: val[1], adapter: @adapter) }
|
37
|
+
| value { NodeQuery::Compiler::ArrayValue.new(value: val[0], adapter: @adapter) }
|
38
38
|
|
39
39
|
value
|
40
40
|
: selector
|
41
|
-
| tBOOLEAN { NodeQuery::Compiler::Boolean.new(value: val[0]) }
|
42
|
-
| tFLOAT { NodeQuery::Compiler::Float.new(value: val[0]) }
|
43
|
-
| tINTEGER { NodeQuery::Compiler::Integer.new(value: val[0])}
|
44
|
-
| tNIL { NodeQuery::Compiler::Nil.new(value: val[0]) }
|
45
|
-
| tREGEXP { NodeQuery::Compiler::Regexp.new(value: val[0]) }
|
46
|
-
| tSTRING { NodeQuery::Compiler::String.new(value: val[0]) }
|
47
|
-
| tSYMBOL { NodeQuery::Compiler::Symbol.new(value: val[0]) }
|
48
|
-
| tIDENTIFIER_VALUE { NodeQuery::Compiler::Identifier.new(value: val[0]) }
|
41
|
+
| tBOOLEAN { NodeQuery::Compiler::Boolean.new(value: val[0], adapter: @adapter) }
|
42
|
+
| tFLOAT { NodeQuery::Compiler::Float.new(value: val[0], adapter: @adapter) }
|
43
|
+
| tINTEGER { NodeQuery::Compiler::Integer.new(value: val[0], adapter: @adapter) }
|
44
|
+
| tNIL { NodeQuery::Compiler::Nil.new(value: val[0], adapter: @adapter) }
|
45
|
+
| tREGEXP { NodeQuery::Compiler::Regexp.new(value: val[0], adapter: @adapter) }
|
46
|
+
| tSTRING { NodeQuery::Compiler::String.new(value: val[0], adapter: @adapter) }
|
47
|
+
| tSYMBOL { NodeQuery::Compiler::Symbol.new(value: val[0], adapter: @adapter) }
|
48
|
+
| tIDENTIFIER_VALUE { NodeQuery::Compiler::Identifier.new(value: val[0], adapter: @adapter) }
|
49
49
|
end
|
50
50
|
|
51
51
|
---- inner
|
52
|
-
def initialize
|
52
|
+
def initialize(adapter:)
|
53
53
|
@lexer = NodeQueryLexer.new
|
54
|
+
@adapter = adapter
|
54
55
|
end
|
55
56
|
|
56
57
|
def parse string
|
data/sig/node_query.rbs
CHANGED
@@ -1,11 +1,7 @@
|
|
1
1
|
class NodeQuery[T]
|
2
2
|
VERSION: String
|
3
3
|
|
4
|
-
def
|
5
|
-
|
6
|
-
def self.adapter: () -> NodeQuery::Adapter
|
7
|
-
|
8
|
-
def initialize: (nqlOrRues: String | Hash) -> NodeQuery
|
4
|
+
def initialize: (nqlOrRues: String | Hash, adapter: Symbol) -> NodeQuery
|
9
5
|
|
10
6
|
def query_nodes: (node: T, options: Hash) -> Array[T]
|
11
7
|
|
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.
|
4
|
+
version: 1.14.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: 2023-
|
11
|
+
date: 2023-11-27 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: ast node query language
|
14
14
|
email:
|
@@ -78,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
78
|
- !ruby/object:Gem::Version
|
79
79
|
version: '0'
|
80
80
|
requirements: []
|
81
|
-
rubygems_version: 3.4.
|
81
|
+
rubygems_version: 3.4.20
|
82
82
|
signing_key:
|
83
83
|
specification_version: 4
|
84
84
|
summary: ast node query language
|