synvert-core 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 tPSEUDO_CLASS tCOMMA
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 tOPEN_ARRAY tCLOSE_ARRAY tOPEN_SELECTOR tCLOSE_SELECTOR
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
- : selector tCHILD expression { Compiler::Expression.new(selector: val[0], rest: val[2], relationship: :child) }
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 tPSEUDO_CLASS tOPEN_SELECTOR expression tCLOSE_SELECTOR { Compiler::Selector.new(node_type: val[0], attribute_list: val[1], pseudo_class: val[2], pseudo_expression: val[4]) }
24
- | tNODE_TYPE tPSEUDO_CLASS tOPEN_SELECTOR expression tCLOSE_SELECTOR { Compiler::Selector.new(node_type: val[0], pseudo_class: val[1], pseudo_expression: val[3]) }
25
- | attribute_list tPSEUDO_CLASS tOPEN_SELECTOR expression tCLOSE_SELECTOR { Compiler::Selector.new(attribute_list: val[0], pseudo_class: val[1], pseudo_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 tCOMMA array_value { Compiler::Array.new(value: val[0], rest: val[2]) }
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Synvert
4
4
  module Core
5
- VERSION = '1.1.1'
5
+ VERSION = '1.2.0'
6
6
  end
7
7
  end
@@ -226,6 +226,19 @@ module Synvert::Core::NodeQuery
226
226
  assert_tokens source, expected_tokens
227
227
  end
228
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
+
229
242
  it 'matches attribute value' do
230
243
  source = '.pair[key={{value}}]'
231
244
  expected_tokens = [
@@ -429,7 +442,7 @@ module Synvert::Core::NodeQuery
429
442
  end
430
443
 
431
444
  it 'matches IN' do
432
- source = '.send[message IN (create, build)]'
445
+ source = '.send[message IN (create build)]'
433
446
  expected_tokens = [
434
447
  [:tNODE_TYPE, "send"],
435
448
  [:tOPEN_ATTRIBUTE, "["],
@@ -437,7 +450,6 @@ module Synvert::Core::NodeQuery
437
450
  [:tIN, "IN"],
438
451
  [:tOPEN_ARRAY, "("],
439
452
  [:tIDENTIFIER_VALUE, "create"],
440
- [:tCOMMA, ","],
441
453
  [:tIDENTIFIER_VALUE, "build"],
442
454
  [:tCLOSE_ARRAY, ")"],
443
455
  [:tCLOSE_ATTRIBUTE, "]"]
@@ -446,7 +458,7 @@ module Synvert::Core::NodeQuery
446
458
  end
447
459
 
448
460
  it 'matches NOT IN' do
449
- source = '.send[message NOT IN (create, build)]'
461
+ source = '.send[message NOT IN (create build)]'
450
462
  expected_tokens = [
451
463
  [:tNODE_TYPE, "send"],
452
464
  [:tOPEN_ATTRIBUTE, "["],
@@ -454,7 +466,6 @@ module Synvert::Core::NodeQuery
454
466
  [:tNOT_IN, "NOT IN"],
455
467
  [:tOPEN_ARRAY, "("],
456
468
  [:tIDENTIFIER_VALUE, "create"],
457
- [:tCOMMA, ","],
458
469
  [:tIDENTIFIER_VALUE, "build"],
459
470
  [:tCLOSE_ARRAY, ")"],
460
471
  [:tCLOSE_ATTRIBUTE, "]"]
@@ -610,5 +621,20 @@ module Synvert::Core::NodeQuery
610
621
  assert_tokens source, expected_tokens
611
622
  end
612
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
613
639
  end
614
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,12 +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)'
53
58
  assert_parser(source)
54
59
  end
55
60
 
56
61
  it 'parses :not_has selector' do
57
- source = '.class:not_has(> .def)'
62
+ source = '.class :not_has(> .def)'
63
+ assert_parser(source)
64
+ end
65
+
66
+ it 'parses root :has selector' do
67
+ source = ':has(.def)'
58
68
  assert_parser(source)
59
69
  end
60
70
 
@@ -99,12 +109,12 @@ module Synvert::Core::NodeQuery
99
109
  end
100
110
 
101
111
  it 'parses in operator' do
102
- source = '.def[name in (foo, bar)]'
112
+ source = '.def[name in (foo bar)]'
103
113
  assert_parser(source)
104
114
  end
105
115
 
106
116
  it 'parses not_in operator' do
107
- source = '.def[name not in (foo, bar)]'
117
+ source = '.def[name not in (foo bar)]'
108
118
  assert_parser(source)
109
119
  end
110
120
 
@@ -142,15 +152,22 @@ module Synvert::Core::NodeQuery
142
152
 
143
153
  def foobar(a, b)
144
154
  { a: a, b: b }
145
- foo.merge(bar)
146
155
  arr[index]
147
156
  arr[index] = value
157
+ nil?
148
158
  call('')
149
159
  end
150
160
  end
151
161
  EOS
152
162
  }
153
163
 
164
+ let(:test_node) {
165
+ parse(<<~EOS)
166
+ RSpec.describe Synvert do
167
+ end
168
+ EOS
169
+ }
170
+
154
171
  it 'matches class node' do
155
172
  expression = parser.parse('.class[name=Synvert]')
156
173
  expect(expression.query_nodes(node)).to eq [node]
@@ -192,12 +209,12 @@ module Synvert::Core::NodeQuery
192
209
  end
193
210
 
194
211
  it 'matches in' do
195
- expression = parser.parse('.def[name IN (foo, bar)]')
212
+ expression = parser.parse('.def[name IN (foo bar)]')
196
213
  expect(expression.query_nodes(node)).to eq [node.body.first, node.body.second]
197
214
  end
198
215
 
199
216
  it 'matches not in' do
200
- expression = parser.parse('.def[name NOT IN (foo, bar)]')
217
+ expression = parser.parse('.def[name NOT IN (foo bar)]')
201
218
  expect(expression.query_nodes(node)).to eq [node.body.last]
202
219
  end
203
220
 
@@ -207,18 +224,18 @@ module Synvert::Core::NodeQuery
207
224
  end
208
225
 
209
226
  it 'matches equal array' do
210
- expression = parser.parse('.def[arguments=(a, b)]')
227
+ expression = parser.parse('.def[arguments=(a b)]')
211
228
  expect(expression.query_nodes(node)).to eq [node.body.last]
212
229
 
213
- expression = parser.parse('.def[arguments=(b, a)]')
230
+ expression = parser.parse('.def[arguments=(b a)]')
214
231
  expect(expression.query_nodes(node)).to eq []
215
232
  end
216
233
 
217
234
  it 'matches not equal array' do
218
- expression = parser.parse('.def[arguments!=(a, b)]')
235
+ expression = parser.parse('.def[arguments!=(a b)]')
219
236
  expect(expression.query_nodes(node)).to eq [node.body.first, node.body.second]
220
237
 
221
- expression = parser.parse('.def[arguments!=(b, a)]')
238
+ expression = parser.parse('.def[arguments!=(b a)]')
222
239
  expect(expression.query_nodes(node)).to eq [node.body.first, node.body.second, node.body.last]
223
240
  end
224
241
 
@@ -247,6 +264,19 @@ module Synvert::Core::NodeQuery
247
264
  expect(expression.query_nodes(node)).to eq [node.body.last]
248
265
  end
249
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
+
250
280
  it 'matches has selector' do
251
281
  expression = parser.parse('.def:has(> .send[receiver=FactoryBot])')
252
282
  expect(expression.query_nodes(node)).to eq [node.body.first, node.body.second]
@@ -257,12 +287,17 @@ module Synvert::Core::NodeQuery
257
287
  expect(expression.query_nodes(node)).to eq [node.body.last]
258
288
  end
259
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
+
260
295
  it 'matches arguments.size' do
261
296
  expression = parser.parse('.def .send[arguments.size=2]')
262
297
  expect(expression.query_nodes(node)).to eq [
263
298
  node.body.first.body.last,
264
299
  node.body.second.body.last,
265
- node.body.third.body.fourth
300
+ node.body.third.body.third
266
301
  ]
267
302
  expression = parser.parse('.def .send[arguments.size>2]')
268
303
  expect(expression.query_nodes(node)).to eq []
@@ -270,7 +305,7 @@ module Synvert::Core::NodeQuery
270
305
  expect(expression.query_nodes(node)).to eq [
271
306
  node.body.first.body.last,
272
307
  node.body.second.body.last,
273
- node.body.third.body.fourth
308
+ node.body.third.body.third
274
309
  ]
275
310
  end
276
311
 
@@ -291,18 +326,18 @@ module Synvert::Core::NodeQuery
291
326
  expect(expression.query_nodes(node)).to eq node.body.last.body.first.children
292
327
  end
293
328
 
294
- it 'matches identifier' do
295
- expression = parser.parse('.send[receiver=foo][message=merge]')
296
- expect(expression.query_nodes(node)).to eq [node.body.last.body.second]
297
- end
298
-
299
329
  it 'matches []' do
300
330
  expression = parser.parse('.send[message=[]]')
301
- expect(expression.query_nodes(node)).to eq [node.body.last.body.third]
331
+ expect(expression.query_nodes(node)).to eq [node.body.last.body.second]
302
332
  end
303
333
 
304
334
  it 'matches []=' do
305
335
  expression = parser.parse('.send[message=:[]=]')
336
+ expect(expression.query_nodes(node)).to eq [node.body.last.body.third]
337
+ end
338
+
339
+ it 'matches nil and nil?' do
340
+ expression = parser.parse('.send[receiver=nil][message=nil?]')
306
341
  expect(expression.query_nodes(node)).to eq [node.body.last.body.fourth]
307
342
  end
308
343
 
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.1.1
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-27 00:00:00.000000000 Z
11
+ date: 2022-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport