synvert-core 1.1.1 → 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.
@@ -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