node_query 1.13.12 → 1.14.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 +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
|