synvert-core 1.0.5 → 1.2.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 +19 -0
- data/lib/synvert/core/array_ext.rb +9 -2
- data/lib/synvert/core/node_ext.rb +72 -151
- data/lib/synvert/core/node_query/compiler/array.rb +1 -1
- data/lib/synvert/core/node_query/compiler/expression.rb +69 -31
- data/lib/synvert/core/node_query/compiler/selector.rb +23 -18
- data/lib/synvert/core/node_query/compiler/string.rb +0 -11
- data/lib/synvert/core/node_query/lexer.rex +14 -2
- data/lib/synvert/core/node_query/lexer.rex.rb +31 -3
- data/lib/synvert/core/node_query/parser.racc.rb +223 -249
- data/lib/synvert/core/node_query/parser.y +9 -12
- data/lib/synvert/core/node_query.rb +1 -0
- data/lib/synvert/core/version.rb +1 -1
- data/spec/synvert/core/node_ext_spec.rb +41 -15
- data/spec/synvert/core/node_query/lexer_spec.rb +72 -5
- data/spec/synvert/core/node_query/parser_spec.rb +98 -23
- metadata +2 -2
@@ -1,28 +1,25 @@
|
|
1
1
|
class Synvert::Core::NodeQuery::Parser
|
2
2
|
options no_result_var
|
3
|
-
token tNODE_TYPE tATTRIBUTE tKEY tIDENTIFIER tIDENTIFIER_VALUE tINDEX
|
3
|
+
token tNODE_TYPE tATTRIBUTE tKEY tIDENTIFIER tIDENTIFIER_VALUE tINDEX tPSEUDO_CLASS
|
4
4
|
tCHILD tSUBSEQUENT_SIBLING tNEXT_SIBLING
|
5
|
-
tOPEN_ATTRIBUTE tCLOSE_ATTRIBUTE tOPEN_DYNAMIC_ATTRIBUTE tCLOSE_DYNAMIC_ATTRIBUTE
|
5
|
+
tOPEN_ATTRIBUTE tCLOSE_ATTRIBUTE tOPEN_DYNAMIC_ATTRIBUTE tCLOSE_DYNAMIC_ATTRIBUTE
|
6
|
+
tOPEN_ARRAY tCLOSE_ARRAY tOPEN_SELECTOR tCLOSE_SELECTOR tOPEN_GOTO_SCOPE tCLOSE_GOTO_SCOPE
|
6
7
|
tEQUAL tNOT_EQUAL tMATCH tNOT_MATCH tGREATER_THAN tGREATER_THAN_OR_EQUAL tLESS_THAN tLESS_THAN_OR_EQUAL tIN tNOT_IN tINCLUDES
|
7
8
|
tARRAY_VALUE tDYNAMIC_ATTRIBUTE tBOOLEAN tFLOAT tINTEGER tNIL tREGEXP tSTRING tSYMBOL
|
8
9
|
rule
|
9
10
|
expression
|
10
|
-
:
|
11
|
-
| selector tSUBSEQUENT_SIBLING expression { Compiler::Expression.new(selector: val[0], rest: val[2], relationship: :subsequent_sibling) }
|
12
|
-
| selector tNEXT_SIBLING expression { Compiler::Expression.new(selector: val[0], rest: val[2], relationship: :next_sibling) }
|
13
|
-
| selector expression { Compiler::Expression.new(selector: val[0], rest: val[1], relationship: :descendant) }
|
14
|
-
| selector { Compiler::Expression.new(selector: val[0]) }
|
15
|
-
| tCHILD expression { Compiler::Expression.new(rest: val[1], relationship: :child) }
|
11
|
+
: tCHILD expression { Compiler::Expression.new(rest: val[1], relationship: :child) }
|
16
12
|
| tSUBSEQUENT_SIBLING expression { Compiler::Expression.new(rest: val[1], relationship: :subsequent_sibling) }
|
17
13
|
| tNEXT_SIBLING expression { Compiler::Expression.new(rest: val[1], relationship: :next_sibling) }
|
14
|
+
| tOPEN_GOTO_SCOPE tIDENTIFIER tCLOSE_GOTO_SCOPE expression { Compiler::Expression.new(goto_scope: val[1], rest: val[3]) }
|
15
|
+
| tPSEUDO_CLASS tOPEN_SELECTOR expression tCLOSE_SELECTOR { Compiler::Expression.new(relationship: val[0].to_sym, rest: val[2]) }
|
16
|
+
| selector expression { Compiler::Expression.new(selector: val[0], rest: val[1]) }
|
17
|
+
| selector { Compiler::Expression.new(selector: val[0]) }
|
18
18
|
|
19
19
|
selector
|
20
20
|
: tNODE_TYPE attribute_list tINDEX { Compiler::Selector.new(node_type: val[0], attribute_list: val[1], index: val[2]) }
|
21
21
|
| tNODE_TYPE tINDEX { Compiler::Selector.new(node_type: val[0], index: val[1]) }
|
22
22
|
| attribute_list tINDEX { Compiler::Selector.new(attribute_list: val[0], index: val[1]) }
|
23
|
-
| tNODE_TYPE attribute_list tHAS tOPEN_SELECTOR expression tCLOSE_SELECTOR { Compiler::Selector.new(node_type: val[0], attribute_list: val[1], has_expression: val[4]) }
|
24
|
-
| tNODE_TYPE tHAS tOPEN_SELECTOR expression tCLOSE_SELECTOR { Compiler::Selector.new(node_type: val[0], has_expression: val[3]) }
|
25
|
-
| attribute_list tHAS tOPEN_SELECTOR expression tCLOSE_SELECTOR { Compiler::Selector.new(attribute_list: val[0], has_expression: val[3]) }
|
26
23
|
| tNODE_TYPE attribute_list { Compiler::Selector.new(node_type: val[0], attribute_list: val[1]) }
|
27
24
|
| tNODE_TYPE { Compiler::Selector.new(node_type: val[0]) }
|
28
25
|
| attribute_list { Compiler::Selector.new(attribute_list: val[0]) }
|
@@ -53,7 +50,7 @@ rule
|
|
53
50
|
| tKEY tIN tOPEN_ARRAY array_value tCLOSE_ARRAY { Compiler::Attribute.new(key: val[0], value: val[3], operator: :in) }
|
54
51
|
|
55
52
|
array_value
|
56
|
-
: value
|
53
|
+
: value array_value { Compiler::Array.new(value: val[0], rest: val[1]) }
|
57
54
|
| value { Compiler::Array.new(value: val[0]) }
|
58
55
|
|
59
56
|
value
|
@@ -19,6 +19,7 @@
|
|
19
19
|
#
|
20
20
|
# It also supports some custom selectors:
|
21
21
|
#
|
22
|
+
# * not_has: +.class:not_has(.def)+, it's same as +:not(:has())+ in css, just to make implementation easy.
|
22
23
|
# * nested selector: +.send[arguments = [size = 2][first = .sym][last = .hash]]+
|
23
24
|
# * array value: +.send[arguments = (a, b)]+
|
24
25
|
# * IN operator: +.send[message IN (try, try!)]+
|
data/lib/synvert/core/version.rb
CHANGED
@@ -76,11 +76,6 @@ describe Parser::AST::Node do
|
|
76
76
|
expect(node.name).to eq :@@foo
|
77
77
|
end
|
78
78
|
|
79
|
-
it 'gets for mlhs node' do
|
80
|
-
node = parse('var.each { |(param1, param2)| }')
|
81
|
-
expect(node.arguments.first.name).to eq node.arguments.first
|
82
|
-
end
|
83
|
-
|
84
79
|
it 'gets for restarg node' do
|
85
80
|
node = parse('object.each { |*entry| }')
|
86
81
|
expect(node.arguments.first.name).to eq :entry
|
@@ -116,16 +111,6 @@ describe Parser::AST::Node do
|
|
116
111
|
node = parse('user&.update(name: name)')
|
117
112
|
expect(node.message).to eq :update
|
118
113
|
end
|
119
|
-
|
120
|
-
it 'gets for super node' do
|
121
|
-
node = parse('super(params)')
|
122
|
-
expect(node.message).to eq :super
|
123
|
-
end
|
124
|
-
|
125
|
-
it 'gets for zuper node' do
|
126
|
-
node = parse('super do; end')
|
127
|
-
expect(node.caller.message).to eq :super
|
128
|
-
end
|
129
114
|
end
|
130
115
|
|
131
116
|
describe '#parent_const' do
|
@@ -1042,4 +1027,45 @@ describe Parser::AST::Node do
|
|
1042
1027
|
end
|
1043
1028
|
end
|
1044
1029
|
end
|
1030
|
+
|
1031
|
+
describe '#to_hash' do
|
1032
|
+
it 'gets hash' do
|
1033
|
+
node = parse(<<~EOS)
|
1034
|
+
class Synvert
|
1035
|
+
def foobar(foo, bar)
|
1036
|
+
foo + bar
|
1037
|
+
end
|
1038
|
+
end
|
1039
|
+
EOS
|
1040
|
+
expect(node.to_hash).to eq(
|
1041
|
+
{
|
1042
|
+
type: :class,
|
1043
|
+
parent_class: nil,
|
1044
|
+
name: {
|
1045
|
+
type: :const,
|
1046
|
+
parent_const: nil,
|
1047
|
+
name: :Synvert
|
1048
|
+
},
|
1049
|
+
body: [
|
1050
|
+
{
|
1051
|
+
type: :def,
|
1052
|
+
name: :foobar,
|
1053
|
+
arguments: [
|
1054
|
+
{ type: :arg, name: :foo },
|
1055
|
+
{ type: :arg, name: :bar }
|
1056
|
+
],
|
1057
|
+
body: [
|
1058
|
+
{
|
1059
|
+
type: :send,
|
1060
|
+
receiver: { name: :foo, type: :lvar },
|
1061
|
+
message: :+,
|
1062
|
+
arguments: [{ name: :bar, type: :lvar }]
|
1063
|
+
}
|
1064
|
+
]
|
1065
|
+
}
|
1066
|
+
]
|
1067
|
+
}
|
1068
|
+
)
|
1069
|
+
end
|
1070
|
+
end
|
1045
1071
|
end
|
@@ -200,6 +200,45 @@ module Synvert::Core::NodeQuery
|
|
200
200
|
assert_tokens source, expected_tokens
|
201
201
|
end
|
202
202
|
|
203
|
+
it 'matches :[] message' do
|
204
|
+
source = ".send[message=[]]"
|
205
|
+
expected_tokens = [
|
206
|
+
[:tNODE_TYPE, "send"],
|
207
|
+
[:tOPEN_ATTRIBUTE, "["],
|
208
|
+
[:tKEY, "message"],
|
209
|
+
[:tEQUAL, "="],
|
210
|
+
[:tIDENTIFIER_VALUE, "[]"],
|
211
|
+
[:tCLOSE_ATTRIBUTE, "]"]
|
212
|
+
]
|
213
|
+
assert_tokens source, expected_tokens
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'matches :[] message' do
|
217
|
+
source = ".send[message=:[]=]"
|
218
|
+
expected_tokens = [
|
219
|
+
[:tNODE_TYPE, "send"],
|
220
|
+
[:tOPEN_ATTRIBUTE, "["],
|
221
|
+
[:tKEY, "message"],
|
222
|
+
[:tEQUAL, "="],
|
223
|
+
[:tSYMBOL, :[]=],
|
224
|
+
[:tCLOSE_ATTRIBUTE, "]"]
|
225
|
+
]
|
226
|
+
assert_tokens source, expected_tokens
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'matches nil?' do
|
230
|
+
source = ".send[message=nil?]"
|
231
|
+
expected_tokens = [
|
232
|
+
[:tNODE_TYPE, "send"],
|
233
|
+
[:tOPEN_ATTRIBUTE, "["],
|
234
|
+
[:tKEY, "message"],
|
235
|
+
[:tEQUAL, "="],
|
236
|
+
[:tIDENTIFIER_VALUE, "nil?"],
|
237
|
+
[:tCLOSE_ATTRIBUTE, "]"]
|
238
|
+
]
|
239
|
+
assert_tokens source, expected_tokens
|
240
|
+
end
|
241
|
+
|
203
242
|
it 'matches attribute value' do
|
204
243
|
source = '.pair[key={{value}}]'
|
205
244
|
expected_tokens = [
|
@@ -403,7 +442,7 @@ module Synvert::Core::NodeQuery
|
|
403
442
|
end
|
404
443
|
|
405
444
|
it 'matches IN' do
|
406
|
-
source = '.send[message IN (create
|
445
|
+
source = '.send[message IN (create build)]'
|
407
446
|
expected_tokens = [
|
408
447
|
[:tNODE_TYPE, "send"],
|
409
448
|
[:tOPEN_ATTRIBUTE, "["],
|
@@ -411,7 +450,6 @@ module Synvert::Core::NodeQuery
|
|
411
450
|
[:tIN, "IN"],
|
412
451
|
[:tOPEN_ARRAY, "("],
|
413
452
|
[:tIDENTIFIER_VALUE, "create"],
|
414
|
-
[:tCOMMA, ","],
|
415
453
|
[:tIDENTIFIER_VALUE, "build"],
|
416
454
|
[:tCLOSE_ARRAY, ")"],
|
417
455
|
[:tCLOSE_ATTRIBUTE, "]"]
|
@@ -420,7 +458,7 @@ module Synvert::Core::NodeQuery
|
|
420
458
|
end
|
421
459
|
|
422
460
|
it 'matches NOT IN' do
|
423
|
-
source = '.send[message NOT IN (create
|
461
|
+
source = '.send[message NOT IN (create build)]'
|
424
462
|
expected_tokens = [
|
425
463
|
[:tNODE_TYPE, "send"],
|
426
464
|
[:tOPEN_ATTRIBUTE, "["],
|
@@ -428,7 +466,6 @@ module Synvert::Core::NodeQuery
|
|
428
466
|
[:tNOT_IN, "NOT IN"],
|
429
467
|
[:tOPEN_ARRAY, "("],
|
430
468
|
[:tIDENTIFIER_VALUE, "create"],
|
431
|
-
[:tCOMMA, ","],
|
432
469
|
[:tIDENTIFIER_VALUE, "build"],
|
433
470
|
[:tCLOSE_ARRAY, ")"],
|
434
471
|
[:tCLOSE_ATTRIBUTE, "]"]
|
@@ -560,7 +597,7 @@ module Synvert::Core::NodeQuery
|
|
560
597
|
source = '.class:has(> .def)'
|
561
598
|
expected_tokens = [
|
562
599
|
[:tNODE_TYPE, "class"],
|
563
|
-
[:
|
600
|
+
[:tPSEUDO_CLASS, "has"],
|
564
601
|
[:tOPEN_SELECTOR, "("],
|
565
602
|
[:tCHILD, ">"],
|
566
603
|
[:tNODE_TYPE, "def"],
|
@@ -569,5 +606,35 @@ module Synvert::Core::NodeQuery
|
|
569
606
|
assert_tokens source, expected_tokens
|
570
607
|
end
|
571
608
|
end
|
609
|
+
|
610
|
+
context ':not_has' do
|
611
|
+
it 'matches' do
|
612
|
+
source = '.class:not_has(> .def)'
|
613
|
+
expected_tokens = [
|
614
|
+
[:tNODE_TYPE, "class"],
|
615
|
+
[:tPSEUDO_CLASS, "not_has"],
|
616
|
+
[:tOPEN_SELECTOR, "("],
|
617
|
+
[:tCHILD, ">"],
|
618
|
+
[:tNODE_TYPE, "def"],
|
619
|
+
[:tCLOSE_SELECTOR, ")"]
|
620
|
+
]
|
621
|
+
assert_tokens source, expected_tokens
|
622
|
+
end
|
623
|
+
end
|
624
|
+
|
625
|
+
context 'goto_scope' do
|
626
|
+
it 'matches' do
|
627
|
+
source = '.block <body> > .def'
|
628
|
+
expected_tokens = [
|
629
|
+
[:tNODE_TYPE, "block"],
|
630
|
+
[:tOPEN_GOTO_SCOPE, "<"],
|
631
|
+
[:tIDENTIFIER, "body"],
|
632
|
+
[:tCLOSE_GOTO_SCOPE, ">"],
|
633
|
+
[:tCHILD, ">"],
|
634
|
+
[:tNODE_TYPE, "def"]
|
635
|
+
]
|
636
|
+
assert_tokens source, expected_tokens
|
637
|
+
end
|
638
|
+
end
|
572
639
|
end
|
573
640
|
end
|
@@ -28,6 +28,11 @@ module Synvert::Core::NodeQuery
|
|
28
28
|
assert_parser(source)
|
29
29
|
end
|
30
30
|
|
31
|
+
it 'parses scope' do
|
32
|
+
source = '.block <body> > .send'
|
33
|
+
assert_parser(source)
|
34
|
+
end
|
35
|
+
|
31
36
|
it 'parses :first-child' do
|
32
37
|
source = '.class .def:first-child'
|
33
38
|
assert_parser(source)
|
@@ -49,7 +54,17 @@ module Synvert::Core::NodeQuery
|
|
49
54
|
end
|
50
55
|
|
51
56
|
it 'parses :has selector' do
|
52
|
-
source = '.class:has(> .def)'
|
57
|
+
source = '.class :has(> .def)'
|
58
|
+
assert_parser(source)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'parses :not_has selector' do
|
62
|
+
source = '.class :not_has(> .def)'
|
63
|
+
assert_parser(source)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'parses root :has selector' do
|
67
|
+
source = ':has(.def)'
|
53
68
|
assert_parser(source)
|
54
69
|
end
|
55
70
|
|
@@ -94,12 +109,12 @@ module Synvert::Core::NodeQuery
|
|
94
109
|
end
|
95
110
|
|
96
111
|
it 'parses in operator' do
|
97
|
-
source = '.def[name in (foo
|
112
|
+
source = '.def[name in (foo bar)]'
|
98
113
|
assert_parser(source)
|
99
114
|
end
|
100
115
|
|
101
116
|
it 'parses not_in operator' do
|
102
|
-
source = '.def[name not in (foo
|
117
|
+
source = '.def[name not in (foo bar)]'
|
103
118
|
assert_parser(source)
|
104
119
|
end
|
105
120
|
|
@@ -113,6 +128,16 @@ module Synvert::Core::NodeQuery
|
|
113
128
|
assert_parser(source)
|
114
129
|
end
|
115
130
|
|
131
|
+
it 'parses []=' do
|
132
|
+
source = '.send[message=[]=]'
|
133
|
+
assert_parser(source)
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'parses :[]' do
|
137
|
+
source = '.send[message=:[]]'
|
138
|
+
assert_parser(source)
|
139
|
+
end
|
140
|
+
|
116
141
|
describe '#query_nodes' do
|
117
142
|
let(:node) {
|
118
143
|
parse(<<~EOS)
|
@@ -127,13 +152,22 @@ module Synvert::Core::NodeQuery
|
|
127
152
|
|
128
153
|
def foobar(a, b)
|
129
154
|
{ a: a, b: b }
|
130
|
-
foo.merge(bar)
|
131
155
|
arr[index]
|
156
|
+
arr[index] = value
|
157
|
+
nil?
|
158
|
+
call('')
|
132
159
|
end
|
133
160
|
end
|
134
161
|
EOS
|
135
162
|
}
|
136
163
|
|
164
|
+
let(:test_node) {
|
165
|
+
parse(<<~EOS)
|
166
|
+
RSpec.describe Synvert do
|
167
|
+
end
|
168
|
+
EOS
|
169
|
+
}
|
170
|
+
|
137
171
|
it 'matches class node' do
|
138
172
|
expression = parser.parse('.class[name=Synvert]')
|
139
173
|
expect(expression.query_nodes(node)).to eq [node]
|
@@ -175,12 +209,12 @@ module Synvert::Core::NodeQuery
|
|
175
209
|
end
|
176
210
|
|
177
211
|
it 'matches in' do
|
178
|
-
expression = parser.parse('.def[name IN (foo
|
212
|
+
expression = parser.parse('.def[name IN (foo bar)]')
|
179
213
|
expect(expression.query_nodes(node)).to eq [node.body.first, node.body.second]
|
180
214
|
end
|
181
215
|
|
182
216
|
it 'matches not in' do
|
183
|
-
expression = parser.parse('.def[name NOT IN (foo
|
217
|
+
expression = parser.parse('.def[name NOT IN (foo bar)]')
|
184
218
|
expect(expression.query_nodes(node)).to eq [node.body.last]
|
185
219
|
end
|
186
220
|
|
@@ -190,34 +224,34 @@ module Synvert::Core::NodeQuery
|
|
190
224
|
end
|
191
225
|
|
192
226
|
it 'matches equal array' do
|
193
|
-
expression = parser.parse('.def[arguments=(a
|
227
|
+
expression = parser.parse('.def[arguments=(a b)]')
|
194
228
|
expect(expression.query_nodes(node)).to eq [node.body.last]
|
195
229
|
|
196
|
-
expression = parser.parse('.def[arguments=(b
|
230
|
+
expression = parser.parse('.def[arguments=(b a)]')
|
197
231
|
expect(expression.query_nodes(node)).to eq []
|
198
232
|
end
|
199
233
|
|
200
234
|
it 'matches not equal array' do
|
201
|
-
expression = parser.parse('.def[arguments!=(a
|
235
|
+
expression = parser.parse('.def[arguments!=(a b)]')
|
202
236
|
expect(expression.query_nodes(node)).to eq [node.body.first, node.body.second]
|
203
237
|
|
204
|
-
expression = parser.parse('.def[arguments!=(b
|
238
|
+
expression = parser.parse('.def[arguments!=(b a)]')
|
205
239
|
expect(expression.query_nodes(node)).to eq [node.body.first, node.body.second, node.body.last]
|
206
240
|
end
|
207
241
|
|
208
242
|
it 'matches descendant node' do
|
209
243
|
expression = parser.parse('.class .send[message=:create]')
|
210
|
-
expect(expression.query_nodes(node)).to eq [node.body.first.
|
244
|
+
expect(expression.query_nodes(node)).to eq [node.body.first.body.last, node.body.second.body.last]
|
211
245
|
end
|
212
246
|
|
213
247
|
it 'matches three level descendant node' do
|
214
248
|
expression = parser.parse('.class .def .send[message=:create]')
|
215
|
-
expect(expression.query_nodes(node)).to eq [node.body.first.
|
249
|
+
expect(expression.query_nodes(node)).to eq [node.body.first.body.last, node.body.second.body.last]
|
216
250
|
end
|
217
251
|
|
218
252
|
it 'matches child node' do
|
219
253
|
expression = parser.parse('.def > .send[message=:create]')
|
220
|
-
expect(expression.query_nodes(node)).to eq [node.body.first.
|
254
|
+
expect(expression.query_nodes(node)).to eq [node.body.first.body.last, node.body.second.body.last]
|
221
255
|
end
|
222
256
|
|
223
257
|
it 'matches next sibling node' do
|
@@ -230,23 +264,54 @@ module Synvert::Core::NodeQuery
|
|
230
264
|
expect(expression.query_nodes(node)).to eq [node.body.last]
|
231
265
|
end
|
232
266
|
|
267
|
+
it 'matches goto scope' do
|
268
|
+
expression = parser.parse('.def <body> > .send[message=:create]')
|
269
|
+
expect(expression.query_nodes(node)).to eq [node.body.first.body.last, node.body.second.body.last]
|
270
|
+
|
271
|
+
expression = parser.parse('.def <body> .send[message=:create]')
|
272
|
+
expect(expression.query_nodes(node)).to eq [node.body.first.body.last, node.body.second.body.last]
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'matches multiple goto scope' do
|
276
|
+
expression = parser.parse('.block <caller.arguments> .const[name=Synvert]')
|
277
|
+
expect(expression.query_nodes(test_node)).to eq [test_node.caller.arguments.first]
|
278
|
+
end
|
279
|
+
|
233
280
|
it 'matches has selector' do
|
234
281
|
expression = parser.parse('.def:has(> .send[receiver=FactoryBot])')
|
235
282
|
expect(expression.query_nodes(node)).to eq [node.body.first, node.body.second]
|
236
283
|
end
|
237
284
|
|
285
|
+
it 'matches not_has selector' do
|
286
|
+
expression = parser.parse('.def:not_has(> .send[receiver=FactoryBot])')
|
287
|
+
expect(expression.query_nodes(node)).to eq [node.body.last]
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'matches root has selector' do
|
291
|
+
expression = parser.parse(':has(.def[name=foobar])')
|
292
|
+
expect(expression.query_nodes(node)).to eq [node]
|
293
|
+
end
|
294
|
+
|
238
295
|
it 'matches arguments.size' do
|
239
|
-
expression = parser.parse('.send[arguments.size=2]')
|
240
|
-
expect(expression.query_nodes(node)).to eq [
|
241
|
-
|
296
|
+
expression = parser.parse('.def .send[arguments.size=2]')
|
297
|
+
expect(expression.query_nodes(node)).to eq [
|
298
|
+
node.body.first.body.last,
|
299
|
+
node.body.second.body.last,
|
300
|
+
node.body.third.body.third
|
301
|
+
]
|
302
|
+
expression = parser.parse('.def .send[arguments.size>2]')
|
242
303
|
expect(expression.query_nodes(node)).to eq []
|
243
|
-
expression = parser.parse('.send[arguments.size>=2]')
|
244
|
-
expect(expression.query_nodes(node)).to eq [
|
304
|
+
expression = parser.parse('.def .send[arguments.size>=2]')
|
305
|
+
expect(expression.query_nodes(node)).to eq [
|
306
|
+
node.body.first.body.last,
|
307
|
+
node.body.second.body.last,
|
308
|
+
node.body.third.body.third
|
309
|
+
]
|
245
310
|
end
|
246
311
|
|
247
312
|
it 'matches arguments' do
|
248
313
|
expression = parser.parse('.send[arguments=[size=2][first=.sym][last=.hash]]')
|
249
|
-
expect(expression.query_nodes(node)).to eq [node.body.first.
|
314
|
+
expect(expression.query_nodes(node)).to eq [node.body.first.body.last, node.body.second.body.last]
|
250
315
|
end
|
251
316
|
|
252
317
|
it 'matches regexp value' do
|
@@ -261,15 +326,25 @@ module Synvert::Core::NodeQuery
|
|
261
326
|
expect(expression.query_nodes(node)).to eq node.body.last.body.first.children
|
262
327
|
end
|
263
328
|
|
264
|
-
it 'matches
|
265
|
-
expression = parser.parse('.send[
|
329
|
+
it 'matches []' do
|
330
|
+
expression = parser.parse('.send[message=[]]')
|
266
331
|
expect(expression.query_nodes(node)).to eq [node.body.last.body.second]
|
267
332
|
end
|
268
333
|
|
269
|
-
it 'matches []' do
|
270
|
-
expression = parser.parse('.send[message
|
334
|
+
it 'matches []=' do
|
335
|
+
expression = parser.parse('.send[message=:[]=]')
|
271
336
|
expect(expression.query_nodes(node)).to eq [node.body.last.body.third]
|
272
337
|
end
|
338
|
+
|
339
|
+
it 'matches nil and nil?' do
|
340
|
+
expression = parser.parse('.send[receiver=nil][message=nil?]')
|
341
|
+
expect(expression.query_nodes(node)).to eq [node.body.last.body.fourth]
|
342
|
+
end
|
343
|
+
|
344
|
+
it 'matches empty string' do
|
345
|
+
expression = parser.parse('.send[message=call][arguments.first=""]')
|
346
|
+
expect(expression.query_nodes(node)).to eq [node.body.last.body.last]
|
347
|
+
end
|
273
348
|
end
|
274
349
|
end
|
275
350
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: synvert-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Huang
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-04-
|
11
|
+
date: 2022-04-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|