synvert-core 1.0.5 → 1.2.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 +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
|