node_query 1.4.0 → 1.6.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 +11 -0
- data/Gemfile.lock +1 -1
- data/README.md +22 -22
- data/lib/node_query/compiler/expression.rb +2 -2
- data/lib/node_query/compiler/expression_list.rb +2 -2
- data/lib/node_query/compiler/regexp.rb +10 -7
- data/lib/node_query/compiler/selector.rb +10 -6
- data/lib/node_query/compiler/string.rb +1 -1
- data/lib/node_query/helper.rb +10 -2
- data/lib/node_query/node_rules.rb +10 -6
- data/lib/node_query/version.rb +1 -1
- data/lib/node_query.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86cae1819b055b5c50aa47879d3da1902805a24fa484f9697270e1591f4af73f
|
4
|
+
data.tar.gz: 59c4f42f81cd67758c0e3e6d237c3e23e3f35aec2175ae9d4798d93b3b4d11c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1b10e103621f14acc695c6b27c26d15a4751c804a907273b95056516697934d381aefdb8396aa90056385b90a741052bc9d5dc8a2a2c2afe05e69101d06af958
|
7
|
+
data.tar.gz: 36063af159d24d01bdf7e447aab58fc0800a95d3c764915635a31f2f26ae7ff401a8243287c3d1b01ca5cae1ddc6753ad952dee7c7f3ffa62c66834114bc572d
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 1.6.0 (2022-09-16)
|
4
|
+
|
5
|
+
* Rename `nodeType` to `node_type`
|
6
|
+
|
7
|
+
## 1.5.0 (2022-09-15)
|
8
|
+
|
9
|
+
* Add `Helper.to_string`
|
10
|
+
* Only check the current node if `including_self` is true and `recursive` is false
|
11
|
+
* Fix `Regexp#match?` and `String#match?`
|
12
|
+
* Rename `stop_on_match` to `stop_at_first_match`
|
13
|
+
|
3
14
|
## 1.4.0 (2022-09-14)
|
4
15
|
|
5
16
|
* Add options `including_self`, `stop_on_match` and `recursive`
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -62,7 +62,7 @@ It provides two apis: `query_nodes` and `match_node?`
|
|
62
62
|
|
63
63
|
```ruby
|
64
64
|
node_query = NodeQuery.new(nqlOrRules: String | Hash) # Initialize NodeQuery
|
65
|
-
node_query.query_nodes(node: Node, options = { including_self: true,
|
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
|
```
|
68
68
|
|
@@ -83,7 +83,7 @@ node = Parser::CurrentRuby.parse(source)
|
|
83
83
|
|
84
84
|
# It will get the node of initialize.
|
85
85
|
NodeQuery.new('.def[name=initialize]').query_nodes(node)
|
86
|
-
NodeQuery.new({
|
86
|
+
NodeQuery.new({ node_type: 'def', name: 'initialize' }).query_nodes(node)
|
87
87
|
```
|
88
88
|
|
89
89
|
## Node Query Language
|
@@ -313,7 +313,7 @@ It matches ivasgn node whose left value is either @id or @name.
|
|
313
313
|
### rules matches node type
|
314
314
|
|
315
315
|
```
|
316
|
-
{
|
316
|
+
{ node_type: 'class' }
|
317
317
|
```
|
318
318
|
|
319
319
|
It matches class node
|
@@ -321,13 +321,13 @@ It matches class node
|
|
321
321
|
### rules matches attribute
|
322
322
|
|
323
323
|
```
|
324
|
-
{
|
324
|
+
{ node_type: 'def', name: 'initialize' }
|
325
325
|
```
|
326
326
|
|
327
327
|
It matches def node whose name is initialize
|
328
328
|
|
329
329
|
```
|
330
|
-
{
|
330
|
+
{ node_type: 'def', arguments: { "0": 1, "1": "Murphy" } }
|
331
331
|
```
|
332
332
|
|
333
333
|
It matches def node whose arguments are 1 and Murphy.
|
@@ -335,7 +335,7 @@ It matches def node whose arguments are 1 and Murphy.
|
|
335
335
|
### rules matches nested attribute
|
336
336
|
|
337
337
|
```
|
338
|
-
{
|
338
|
+
{ node_type: 'class', parent_class: { name: 'Base' } }
|
339
339
|
```
|
340
340
|
|
341
341
|
It matches class node whose parent class name is Base
|
@@ -343,7 +343,7 @@ It matches class node whose parent class name is Base
|
|
343
343
|
### rules matches evaluated value
|
344
344
|
|
345
345
|
```
|
346
|
-
{
|
346
|
+
{ node_type: 'ivasgn', left_value: '@{{right_value}}' }
|
347
347
|
```
|
348
348
|
|
349
349
|
It matches ivasgn node whose left value equals '@' plus the evaluated value of right value.
|
@@ -351,7 +351,7 @@ It matches ivasgn node whose left value equals '@' plus the evaluated value of r
|
|
351
351
|
### rules matches nested selector
|
352
352
|
|
353
353
|
```
|
354
|
-
{
|
354
|
+
{ node_type: 'def', body: { "0": { node_type: 'ivasgn' } } }
|
355
355
|
```
|
356
356
|
|
357
357
|
It matches def node whose first child node is an ivasgn node.
|
@@ -359,7 +359,7 @@ It matches def node whose first child node is an ivasgn node.
|
|
359
359
|
### rules matches method result
|
360
360
|
|
361
361
|
```
|
362
|
-
{
|
362
|
+
{ node_type: 'def', arguments: { size: 2 } }
|
363
363
|
```
|
364
364
|
|
365
365
|
It matches def node whose arguments size is 2.
|
@@ -367,73 +367,73 @@ It matches def node whose arguments size is 2.
|
|
367
367
|
### rules matches operators
|
368
368
|
|
369
369
|
```
|
370
|
-
{
|
370
|
+
{ node_type: 'class', name: 'User' }
|
371
371
|
```
|
372
372
|
|
373
373
|
Value of name is equal to User
|
374
374
|
|
375
375
|
```
|
376
|
-
{
|
376
|
+
{ node_type: 'def', arguments: { size { not: 2 } }
|
377
377
|
```
|
378
378
|
|
379
379
|
Size of arguments is not equal to 2
|
380
380
|
|
381
381
|
```
|
382
|
-
{
|
382
|
+
{ node_type: 'def', arguments: { size { gte: 2 } }
|
383
383
|
```
|
384
384
|
|
385
385
|
Size of arguments is greater than or equal to 2
|
386
386
|
|
387
387
|
```
|
388
|
-
{
|
388
|
+
{ node_type: 'def', arguments: { size { gt: 2 } }
|
389
389
|
```
|
390
390
|
|
391
391
|
Size of arguments is greater than 2
|
392
392
|
|
393
393
|
```
|
394
|
-
{
|
394
|
+
{ node_type: 'def', arguments: { size { lte: 2 } }
|
395
395
|
```
|
396
396
|
|
397
397
|
Size of arguments is less than or equal to 2
|
398
398
|
|
399
399
|
```
|
400
|
-
{
|
400
|
+
{ node_type: 'def', arguments: { size { lt: 2 } }
|
401
401
|
```
|
402
402
|
|
403
403
|
Size of arguments is less than 2
|
404
404
|
|
405
405
|
```
|
406
|
-
{
|
406
|
+
{ node_type: 'class', name: { in: ['User', 'Account'] } }
|
407
407
|
```
|
408
408
|
|
409
409
|
Value of name is either User or Account
|
410
410
|
|
411
411
|
```
|
412
|
-
{
|
412
|
+
{ node_type: 'class', name: { not_in: ['User', 'Account'] } }
|
413
413
|
```
|
414
414
|
|
415
415
|
Value of name is neither User nor Account
|
416
416
|
|
417
417
|
```
|
418
|
-
{
|
418
|
+
{ node_type: 'def', arguments: { includes: 'id' } }
|
419
419
|
```
|
420
420
|
|
421
421
|
Value of arguments includes id
|
422
422
|
|
423
423
|
```
|
424
|
-
{
|
424
|
+
{ node_type: 'class', name: /User/ }
|
425
425
|
```
|
426
426
|
|
427
427
|
Value of name matches User
|
428
428
|
|
429
429
|
```
|
430
|
-
{
|
430
|
+
{ node_type: 'class', name: { not: /User/ } }
|
431
431
|
```
|
432
432
|
|
433
433
|
Value of name does not match User
|
434
434
|
|
435
435
|
```
|
436
|
-
{
|
436
|
+
{ node_type: 'class', name: { in: [/User/, /Account/] } }
|
437
437
|
```
|
438
438
|
|
439
439
|
Value of name matches either /User/ or /Account/
|
@@ -441,7 +441,7 @@ Value of name matches either /User/ or /Account/
|
|
441
441
|
### rules matches array nodes attribute
|
442
442
|
|
443
443
|
```
|
444
|
-
{
|
444
|
+
{ node_type: 'def', arguments: ['id', 'name'] }
|
445
445
|
```
|
446
446
|
|
447
447
|
It matches def node whose arguments are id and name.
|
@@ -15,8 +15,8 @@ module NodeQuery::Compiler
|
|
15
15
|
# @param node [Node] node to match
|
16
16
|
# @param options [Hash] if query the current node
|
17
17
|
# @option options [boolean] :including_self if query the current node, default is ture
|
18
|
-
# @option options [boolean] :
|
19
|
-
# @option options [boolean] :recursive if
|
18
|
+
# @option options [boolean] :stop_at_first_match if stop at first match, default is false
|
19
|
+
# @option options [boolean] :recursive if recursively query child nodes, default is true
|
20
20
|
# @return [Array<Node>] matching nodes.
|
21
21
|
def query_nodes(node, options = {})
|
22
22
|
matching_nodes = @selector.query_nodes(node, options)
|
@@ -15,8 +15,8 @@ module NodeQuery::Compiler
|
|
15
15
|
# @param node [Node] node to match
|
16
16
|
# @param options [Hash] if query the current node
|
17
17
|
# @option options [boolean] :including_self if query the current node, default is ture
|
18
|
-
# @option options [boolean] :
|
19
|
-
# @option options [boolean] :recursive if
|
18
|
+
# @option options [boolean] :stop_at_first_match if stop at first match, default is false
|
19
|
+
# @option options [boolean] :recursive if recursively query child nodes, default is true
|
20
20
|
# @return [Array<Node>] matching nodes.
|
21
21
|
def query_nodes(node, options = {})
|
22
22
|
matching_nodes = @expression.query_nodes(node, options)
|
@@ -13,13 +13,16 @@ module NodeQuery::Compiler
|
|
13
13
|
|
14
14
|
# Check if the regexp value matches the node value.
|
15
15
|
# @param node [Node] the node
|
16
|
-
# @
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
16
|
+
# @param operator [String] the operator
|
17
|
+
# @return [Boolean] true if the regexp value matches the node value, otherwise, false.
|
18
|
+
def match?(node, operator = '=~')
|
19
|
+
match =
|
20
|
+
if NodeQuery.adapter.is_node?(node)
|
21
|
+
@value.match(NodeQuery.adapter.get_source(node))
|
22
|
+
else
|
23
|
+
@value.match(node.to_s)
|
24
|
+
end
|
25
|
+
operator == '=~' ? match : !match
|
23
26
|
end
|
24
27
|
|
25
28
|
# Get valid operators.
|
@@ -35,11 +35,11 @@ module NodeQuery::Compiler
|
|
35
35
|
# @param node [Node] node to match
|
36
36
|
# @param options [Hash] if query the current node
|
37
37
|
# @option options [boolean] :including_self if query the current node, default is ture
|
38
|
-
# @option options [boolean] :
|
39
|
-
# @option options [boolean] :recursive if
|
38
|
+
# @option options [boolean] :stop_at_first_match if stop at first match, default is false
|
39
|
+
# @option options [boolean] :recursive if recursively query child nodes, default is true
|
40
40
|
# @return [Array<Node>] matching nodes.
|
41
41
|
def query_nodes(node, options = {})
|
42
|
-
options = { including_self: true,
|
42
|
+
options = { including_self: true, stop_at_first_match: false, recursive: true }.merge(options)
|
43
43
|
return find_nodes_by_relationship(node) if @relationship
|
44
44
|
|
45
45
|
if node.is_a?(::Array)
|
@@ -48,24 +48,28 @@ module NodeQuery::Compiler
|
|
48
48
|
|
49
49
|
return find_nodes_by_goto_scope(node) if @goto_scope
|
50
50
|
|
51
|
+
if options[:including_self] && !options[:recursive]
|
52
|
+
return match?(node) ? [node] : []
|
53
|
+
end
|
54
|
+
|
51
55
|
nodes = []
|
52
56
|
if options[:including_self] && match?(node)
|
53
57
|
nodes << node
|
54
|
-
return
|
58
|
+
return nodes if options[:stop_at_first_match]
|
55
59
|
end
|
56
60
|
if @basic_selector
|
57
61
|
if options[:recursive]
|
58
62
|
NodeQuery::Helper.handle_recursive_child(node) do |child_node|
|
59
63
|
if match?(child_node)
|
60
64
|
nodes << child_node
|
61
|
-
break if options[:
|
65
|
+
break if options[:stop_at_first_match]
|
62
66
|
end
|
63
67
|
end
|
64
68
|
else
|
65
69
|
NodeQuery.adapter.get_children(node).each do |child_node|
|
66
70
|
if match?(child_node)
|
67
71
|
nodes << child_node
|
68
|
-
break if options[:
|
72
|
+
break if options[:stop_at_first_match]
|
69
73
|
end
|
70
74
|
end
|
71
75
|
end
|
@@ -27,7 +27,7 @@ module NodeQuery::Compiler
|
|
27
27
|
# @param node [Node] the node
|
28
28
|
# @return [Boolean] true if the actual value equals the node value.
|
29
29
|
def is_equal?(node)
|
30
|
-
actual_value(node)
|
30
|
+
NodeQuery::Helper.to_string(actual_value(node)) == expected_value
|
31
31
|
end
|
32
32
|
|
33
33
|
# Get valid operators.
|
data/lib/node_query/helper.rb
CHANGED
@@ -18,7 +18,7 @@ class NodeQuery::Helper
|
|
18
18
|
child_node = node[first_key.to_i]
|
19
19
|
elsif node.respond_to?(first_key)
|
20
20
|
child_node = node.send(first_key)
|
21
|
-
elsif first_key == "
|
21
|
+
elsif first_key == "node_type"
|
22
22
|
child_node = NodeQuery.adapter.get_node_type(node)
|
23
23
|
end
|
24
24
|
|
@@ -50,9 +50,17 @@ class NodeQuery::Helper
|
|
50
50
|
def evaluate_node_value(node, str)
|
51
51
|
str.scan(/{{(.*?)}}/).each do |match_data|
|
52
52
|
target_node = NodeQuery::Helper.get_target_node(node, match_data.first)
|
53
|
-
str = str.sub("{{#{match_data.first}}}",
|
53
|
+
str = str.sub("{{#{match_data.first}}}", to_string(target_node))
|
54
54
|
end
|
55
55
|
str
|
56
56
|
end
|
57
|
+
|
58
|
+
def to_string(node)
|
59
|
+
if NodeQuery.adapter.is_node?(node)
|
60
|
+
return NodeQuery.adapter.get_source(node)
|
61
|
+
end
|
62
|
+
|
63
|
+
node.to_s
|
64
|
+
end
|
57
65
|
end
|
58
66
|
end
|
@@ -13,28 +13,32 @@ class NodeQuery::NodeRules
|
|
13
13
|
# @param node [Node] node to query
|
14
14
|
# @param options [Hash] if query the current node
|
15
15
|
# @option options [boolean] :including_self if query the current node, default is ture
|
16
|
-
# @option options [boolean] :
|
17
|
-
# @option options [boolean] :recursive if
|
16
|
+
# @option options [boolean] :stop_at_first_match if stop at first match, default is false
|
17
|
+
# @option options [boolean] :recursive if recursively query child nodes, default is true
|
18
18
|
# @return [Array<Node>] matching nodes.
|
19
19
|
def query_nodes(node, options = {})
|
20
|
-
options = { including_self: true,
|
20
|
+
options = { including_self: true, stop_at_first_match: false, recursive: true }.merge(options)
|
21
|
+
if options[:including_self] && !options[:recursive]
|
22
|
+
return match_node?(node) ? [node] : []
|
23
|
+
end
|
24
|
+
|
21
25
|
matching_nodes = []
|
22
26
|
if options[:including_self] && match_node?(node)
|
23
27
|
matching_nodes.push(node)
|
24
|
-
return matching_nodes if options[:
|
28
|
+
return matching_nodes if options[:stop_at_first_match]
|
25
29
|
end
|
26
30
|
if options[:recursive]
|
27
31
|
NodeQuery::Helper.handle_recursive_child(node) do |child_node|
|
28
32
|
if match_node?(child_node)
|
29
33
|
matching_nodes.push(child_node)
|
30
|
-
break if options[:
|
34
|
+
break if options[:stop_at_first_match]
|
31
35
|
end
|
32
36
|
end
|
33
37
|
else
|
34
38
|
NodeQuery.adapter.get_children(node).each do |child_node|
|
35
39
|
if match_node?(child_node)
|
36
40
|
matching_nodes.push(child_node)
|
37
|
-
break if options[:
|
41
|
+
break if options[:stop_at_first_match]
|
38
42
|
end
|
39
43
|
end
|
40
44
|
end
|
data/lib/node_query/version.rb
CHANGED
data/lib/node_query.rb
CHANGED
@@ -40,8 +40,8 @@ class NodeQuery
|
|
40
40
|
# @param node [Node] ast node
|
41
41
|
# @param options [Hash] if query the current node
|
42
42
|
# @option options [boolean] :including_self if query the current node, default is ture
|
43
|
-
# @option options [boolean] :
|
44
|
-
# @option options [boolean] :recursive if
|
43
|
+
# @option options [boolean] :stop_at_first_match if stop at first match, default is false
|
44
|
+
# @option options [boolean] :recursive if recursively query child nodes, default is true
|
45
45
|
# @return [Array<Node>] matching child nodes
|
46
46
|
def query_nodes(node, options = {})
|
47
47
|
if @expression
|
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.6.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-
|
11
|
+
date: 2022-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|