syntax_tree-css 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,969 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SyntaxTree
4
+ module CSS
5
+ # This represents a location in the source file. It maps constructs like
6
+ # tokens and parse nodes to their original location.
7
+ class Location
8
+ attr_reader :start_char, :end_char
9
+
10
+ def initialize(start_char:, end_char:)
11
+ @start_char = start_char
12
+ @end_char = end_char
13
+ end
14
+
15
+ def to(other)
16
+ Location.new(start_char: start_char, end_char: other.end_char)
17
+ end
18
+
19
+ def to_range
20
+ start_char...end_char
21
+ end
22
+
23
+ def self.from(range)
24
+ Location.new(start_char: range.begin, end_char: range.end)
25
+ end
26
+ end
27
+
28
+ # A parent class for all of the various nodes in the tree. Provides common
29
+ # functionality between them.
30
+ class Node
31
+ def format(q)
32
+ Format.new(q).visit(self)
33
+ end
34
+
35
+ def pretty_print(q)
36
+ PrettyPrint.new(q).visit(self)
37
+ end
38
+ end
39
+
40
+ # A parsed token that is an identifier that starts with an @ sign.
41
+ # https://www.w3.org/TR/css-syntax-3/#typedef-at-keyword-token
42
+ class AtKeywordToken < Node
43
+ attr_reader :value, :location
44
+
45
+ def initialize(value:, location:)
46
+ @value = value
47
+ @location = Location.from(location)
48
+ end
49
+
50
+ def accept(visitor)
51
+ visitor.visit_at_keyword_token(self)
52
+ end
53
+
54
+ def child_nodes
55
+ []
56
+ end
57
+
58
+ alias deconstruct child_nodes
59
+
60
+ def deconstruct_keys(keys)
61
+ { value: value, location: location }
62
+ end
63
+ end
64
+
65
+ # A rule that starts with an at-keyword and then accepts arbitrary tokens.
66
+ # A common example is an @media rule.
67
+ # https://www.w3.org/TR/css-syntax-3/#at-rule
68
+ class AtRule < Node
69
+ attr_reader :name, :prelude, :block, :location
70
+
71
+ def initialize(name:, prelude:, block:, location:)
72
+ @name = name
73
+ @prelude = prelude
74
+ @block = block
75
+ @location = location
76
+ end
77
+
78
+ def accept(visitor)
79
+ visitor.visit_at_rule(self)
80
+ end
81
+
82
+ def child_nodes
83
+ [*prelude, block].compact
84
+ end
85
+
86
+ alias deconstruct child_nodes
87
+
88
+ def deconstruct_keys(keys)
89
+ { name: name, prelude: prelude, block: block, location: location }
90
+ end
91
+ end
92
+
93
+ # A parsed token that was a quotes string that had a syntax error. It is
94
+ # mostly here for error recovery.
95
+ # https://www.w3.org/TR/css-syntax-3/#typedef-bad-string-token
96
+ class BadStringToken < Node
97
+ attr_reader :value, :location
98
+
99
+ def initialize(value:, location:)
100
+ @value = value
101
+ @location = Location.from(location)
102
+ end
103
+
104
+ def accept(visitor)
105
+ visitor.visit_bad_string_token(self)
106
+ end
107
+
108
+ def child_nodes
109
+ []
110
+ end
111
+
112
+ alias deconstruct child_nodes
113
+
114
+ def deconstruct_keys(keys)
115
+ { value: value, location: location }
116
+ end
117
+ end
118
+
119
+ # A parsed token that was a call to "url" that had a syntax error. It is
120
+ # mostly here for error recovery.
121
+ # https://www.w3.org/TR/css-syntax-3/#typedef-bad-url-token
122
+ class BadURLToken < Node
123
+ attr_reader :value, :location
124
+
125
+ def initialize(value:, location:)
126
+ @value = value
127
+ @location = Location.from(location)
128
+ end
129
+
130
+ def accept(visitor)
131
+ visitor.visit_bad_url_token(self)
132
+ end
133
+
134
+ def child_nodes
135
+ []
136
+ end
137
+
138
+ alias deconstruct child_nodes
139
+
140
+ def deconstruct_keys(keys)
141
+ { value: value, location: location }
142
+ end
143
+ end
144
+
145
+ # A parsed token containing a CDC (-->).
146
+ # https://www.w3.org/TR/css-syntax-3/#typedef-cdc-token
147
+ class CDCToken < Node
148
+ attr_reader :location
149
+
150
+ def initialize(location:)
151
+ @location = Location.from(location)
152
+ end
153
+
154
+ def accept(visitor)
155
+ visitor.visit_cdc_token(self)
156
+ end
157
+
158
+ def child_nodes
159
+ []
160
+ end
161
+
162
+ alias deconstruct child_nodes
163
+
164
+ def deconstruct_keys(keys)
165
+ { location: location }
166
+ end
167
+ end
168
+
169
+ # A parsed token containing a CDO (<!--).
170
+ # https://www.w3.org/TR/css-syntax-3/#typedef-cdo-token
171
+ class CDOToken < Node
172
+ attr_reader :location
173
+
174
+ def initialize(location:)
175
+ @location = Location.from(location)
176
+ end
177
+
178
+ def accept(visitor)
179
+ visitor.visit_cdo_token(self)
180
+ end
181
+
182
+ def child_nodes
183
+ []
184
+ end
185
+
186
+ alias deconstruct child_nodes
187
+
188
+ def deconstruct_keys(keys)
189
+ { location: location }
190
+ end
191
+ end
192
+
193
+ # A parsed token that represents the use of a }.
194
+ # https://www.w3.org/TR/css-syntax-3/#tokendef-close-curly
195
+ class CloseCurlyToken < Node
196
+ attr_reader :location
197
+
198
+ def initialize(location:)
199
+ @location = Location.from(location)
200
+ end
201
+
202
+ def accept(visitor)
203
+ visitor.visit_close_curly_token(self)
204
+ end
205
+
206
+ def child_nodes
207
+ []
208
+ end
209
+
210
+ alias deconstruct child_nodes
211
+
212
+ def deconstruct_keys(keys)
213
+ { location: location }
214
+ end
215
+
216
+ # Here for convenience for comparing between block types.
217
+ def value
218
+ "}"
219
+ end
220
+ end
221
+
222
+ # A parsed token that represents the use of a ).
223
+ # https://www.w3.org/TR/css-syntax-3/#tokendef-close-paren
224
+ class CloseParenToken < Node
225
+ attr_reader :location
226
+
227
+ def initialize(location:)
228
+ @location = Location.from(location)
229
+ end
230
+
231
+ def accept(visitor)
232
+ visitor.visit_close_paren_token(self)
233
+ end
234
+
235
+ def child_nodes
236
+ []
237
+ end
238
+
239
+ alias deconstruct child_nodes
240
+
241
+ def deconstruct_keys(keys)
242
+ { location: location }
243
+ end
244
+
245
+ # Here for convenience for comparing between block types.
246
+ def value
247
+ ")"
248
+ end
249
+ end
250
+
251
+ # A parsed token that represents the use of a ].
252
+ # https://www.w3.org/TR/css-syntax-3/#tokendef-close-square
253
+ class CloseSquareToken < Node
254
+ attr_reader :location
255
+
256
+ def initialize(location:)
257
+ @location = Location.from(location)
258
+ end
259
+
260
+ def accept(visitor)
261
+ visitor.visit_close_square_token(self)
262
+ end
263
+
264
+ def child_nodes
265
+ []
266
+ end
267
+
268
+ alias deconstruct child_nodes
269
+
270
+ def deconstruct_keys(keys)
271
+ { location: location }
272
+ end
273
+
274
+ # Here for convenience for comparing between block types.
275
+ def value
276
+ "]"
277
+ end
278
+ end
279
+
280
+ # A parsed token containing a colon.
281
+ # https://www.w3.org/TR/css-syntax-3/#typedef-colon-token
282
+ class ColonToken < Node
283
+ attr_reader :location
284
+
285
+ def initialize(location:)
286
+ @location = Location.from(location)
287
+ end
288
+
289
+ def accept(visitor)
290
+ visitor.visit_colon_token(self)
291
+ end
292
+
293
+ def child_nodes
294
+ []
295
+ end
296
+
297
+ alias deconstruct child_nodes
298
+
299
+ def deconstruct_keys(keys)
300
+ { location: location }
301
+ end
302
+ end
303
+
304
+ # A parsed token that contains a comma.
305
+ # https://www.w3.org/TR/css-syntax-3/#typedef-comma-token
306
+ class CommaToken < Node
307
+ attr_reader :location
308
+
309
+ def initialize(location:)
310
+ @location = Location.from(location)
311
+ end
312
+
313
+ def accept(visitor)
314
+ visitor.visit_comma_token(self)
315
+ end
316
+
317
+ def child_nodes
318
+ []
319
+ end
320
+
321
+ alias deconstruct child_nodes
322
+
323
+ def deconstruct_keys(keys)
324
+ { location: location }
325
+ end
326
+ end
327
+
328
+ # A parsed token that contains a comment. These aren't actually declared in
329
+ # the spec because it assumes you can just drop them. We parse them into
330
+ # tokens, however, so that we can keep track of their location.
331
+ class CommentToken < Node
332
+ attr_reader :value, :location
333
+
334
+ def initialize(value:, location:)
335
+ @value = value
336
+ @location = Location.from(location)
337
+ end
338
+
339
+ def accept(visitor)
340
+ visitor.visit_comment_token(self)
341
+ end
342
+
343
+ def child_nodes
344
+ []
345
+ end
346
+
347
+ alias deconstruct child_nodes
348
+
349
+ def deconstruct_keys(keys)
350
+ { value: value, location: location }
351
+ end
352
+ end
353
+
354
+ # This is the top node in the tree if it has been converted into a CSS
355
+ # stylesheet.
356
+ class CSSStyleSheet < Node
357
+ attr_reader :rules, :location
358
+
359
+ def initialize(rules:, location:)
360
+ @rules = rules
361
+ @location = location
362
+ end
363
+
364
+ def accept(visitor)
365
+ visitor.visit_css_stylesheet(self)
366
+ end
367
+
368
+ def child_nodes
369
+ rules
370
+ end
371
+
372
+ alias deconstruct child_nodes
373
+
374
+ def deconstruct_keys(keys)
375
+ { rules: rules, location: location }
376
+ end
377
+ end
378
+
379
+ # Declarations are a particular instance of associating a property or
380
+ # descriptor name with a value.
381
+ # https://www.w3.org/TR/css-syntax-3/#declaration
382
+ class Declaration < Node
383
+ attr_reader :name, :value, :location
384
+
385
+ def initialize(name:, value:, important:, location:)
386
+ @name = name
387
+ @value = value
388
+ @important = important
389
+ @location = location
390
+ end
391
+
392
+ def accept(visitor)
393
+ visitor.visit_declaration(self)
394
+ end
395
+
396
+ def child_nodes
397
+ value
398
+ end
399
+
400
+ alias deconstruct child_nodes
401
+
402
+ def deconstruct_keys(keys)
403
+ { name: name, value: value, important: important?, location: location }
404
+ end
405
+
406
+ def important?
407
+ @important
408
+ end
409
+ end
410
+
411
+ # A parsed token that has a value composed of a single code point.
412
+ # https://www.w3.org/TR/css-syntax-3/#typedef-delim-token
413
+ class DelimToken < Node
414
+ attr_reader :value, :location
415
+
416
+ def initialize(value:, location:)
417
+ @value = value
418
+ @location = Location.from(location)
419
+ end
420
+
421
+ def accept(visitor)
422
+ visitor.visit_delim_token(self)
423
+ end
424
+
425
+ def child_nodes
426
+ []
427
+ end
428
+
429
+ alias deconstruct child_nodes
430
+
431
+ def deconstruct_keys(keys)
432
+ { value: value, location: location }
433
+ end
434
+ end
435
+
436
+ # A parsed token that contains a numeric value with a dimension.
437
+ # https://www.w3.org/TR/css-syntax-3/#typedef-dimension-token
438
+ class DimensionToken < Node
439
+ attr_reader :value, :unit, :type, :location
440
+
441
+ def initialize(value:, unit:, type:, location:)
442
+ @value = value
443
+ @unit = unit
444
+ @type = type
445
+ @location = Location.from(location)
446
+ end
447
+
448
+ def accept(visitor)
449
+ visitor.visit_dimension_token(self)
450
+ end
451
+
452
+ def child_nodes
453
+ []
454
+ end
455
+
456
+ alias deconstruct child_nodes
457
+
458
+ def deconstruct_keys(keys)
459
+ { value: value, type: type, location: location }
460
+ end
461
+ end
462
+
463
+ # A conceptual token representing the end of the list of tokens. Whenever
464
+ # the list of tokens is empty, the next input token is always an EOFToken.
465
+ # https://www.w3.org/TR/css-syntax-3/#typedef-eof-token
466
+ class EOFToken < Node
467
+ attr_reader :location
468
+
469
+ def initialize(location:)
470
+ @location = Location.from(location)
471
+ end
472
+
473
+ def accept(visitor)
474
+ visitor.visit_eof_token(self)
475
+ end
476
+
477
+ def child_nodes
478
+ []
479
+ end
480
+
481
+ alias deconstruct child_nodes
482
+
483
+ def deconstruct_keys(keys)
484
+ { location: location }
485
+ end
486
+
487
+ # Since we create EOFToken objects a lot with ranges that are empty, it's
488
+ # nice to have this convenience method.
489
+ def self.[](index)
490
+ new(location: index...index)
491
+ end
492
+ end
493
+
494
+ # A function has a name and a value consisting of a list of component
495
+ # values.
496
+ # https://www.w3.org/TR/css-syntax-3/#function
497
+ class Function < Node
498
+ attr_reader :name, :value, :location
499
+
500
+ def initialize(name:, value:, location:)
501
+ @name = name
502
+ @value = value
503
+ @location = location
504
+ end
505
+
506
+ def accept(visitor)
507
+ visitor.visit_function(self)
508
+ end
509
+
510
+ def child_nodes
511
+ value
512
+ end
513
+
514
+ alias deconstruct child_nodes
515
+
516
+ def deconstruct_keys(keys)
517
+ { name: name, value: value, location: location }
518
+ end
519
+ end
520
+
521
+ # A parsed token that contains the beginning of a call to a function, e.g.,
522
+ # "url(".
523
+ # https://www.w3.org/TR/css-syntax-3/#typedef-function-token
524
+ class FunctionToken < Node
525
+ attr_reader :value, :location
526
+
527
+ def initialize(value:, location:)
528
+ @value = value
529
+ @location = Location.from(location)
530
+ end
531
+
532
+ def accept(visitor)
533
+ visitor.visit_function_token(self)
534
+ end
535
+
536
+ def child_nodes
537
+ []
538
+ end
539
+
540
+ alias deconstruct child_nodes
541
+
542
+ def deconstruct_keys(keys)
543
+ { value: value, location: location }
544
+ end
545
+ end
546
+
547
+ # A parsed token that contains an identifier that starts with a # sign.
548
+ # https://www.w3.org/TR/css-syntax-3/#typedef-hash-token
549
+ class HashToken < Node
550
+ attr_reader :value, :type, :location
551
+
552
+ def initialize(value:, type:, location:)
553
+ @value = value
554
+ @type = type
555
+ @location = Location.from(location)
556
+ end
557
+
558
+ def accept(visitor)
559
+ visitor.visit_hash_token(self)
560
+ end
561
+
562
+ def child_nodes
563
+ []
564
+ end
565
+
566
+ alias deconstruct child_nodes
567
+
568
+ def deconstruct_keys(keys)
569
+ { value: value, type: type, location: location }
570
+ end
571
+ end
572
+
573
+ # A parsed token that contains an plaintext identifier.
574
+ # https://www.w3.org/TR/css-syntax-3/#typedef-ident-token
575
+ class IdentToken < Node
576
+ attr_reader :value, :location
577
+
578
+ def initialize(value:, location:)
579
+ @value = value
580
+ @location = Location.from(location)
581
+ end
582
+
583
+ def accept(visitor)
584
+ visitor.visit_ident_token(self)
585
+ end
586
+
587
+ def child_nodes
588
+ []
589
+ end
590
+
591
+ alias deconstruct child_nodes
592
+
593
+ def deconstruct_keys(keys)
594
+ { value: value, location: location }
595
+ end
596
+ end
597
+
598
+ # A parsed token that contains a numeric value.
599
+ # https://www.w3.org/TR/css-syntax-3/#typedef-number-token
600
+ class NumberToken < Node
601
+ attr_reader :value, :type, :location
602
+
603
+ def initialize(value:, type:, location:)
604
+ @value = value
605
+ @type = type
606
+ @location = Location.from(location)
607
+ end
608
+
609
+ def accept(visitor)
610
+ visitor.visit_number_token(self)
611
+ end
612
+
613
+ def child_nodes
614
+ []
615
+ end
616
+
617
+ alias deconstruct child_nodes
618
+
619
+ def deconstruct_keys(keys)
620
+ { value: value, type: type, location: location }
621
+ end
622
+ end
623
+
624
+ # A parsed token that represents the use of a {.
625
+ # https://www.w3.org/TR/css-syntax-3/#tokendef-open-curly
626
+ class OpenCurlyToken < Node
627
+ attr_reader :location
628
+
629
+ def initialize(location:)
630
+ @location = Location.from(location)
631
+ end
632
+
633
+ def accept(visitor)
634
+ visitor.visit_open_curly_token(self)
635
+ end
636
+
637
+ def child_nodes
638
+ []
639
+ end
640
+
641
+ alias deconstruct child_nodes
642
+
643
+ def deconstruct_keys(keys)
644
+ { location: location }
645
+ end
646
+
647
+ # Here for convenience for comparing between block types.
648
+ def value
649
+ "{"
650
+ end
651
+ end
652
+
653
+ # A parsed token that represents the use of a (.
654
+ # https://www.w3.org/TR/css-syntax-3/#tokendef-open-paren
655
+ class OpenParenToken < Node
656
+ attr_reader :location
657
+
658
+ def initialize(location:)
659
+ @location = Location.from(location)
660
+ end
661
+
662
+ def accept(visitor)
663
+ visitor.visit_open_paren_token(self)
664
+ end
665
+
666
+ def child_nodes
667
+ []
668
+ end
669
+
670
+ alias deconstruct child_nodes
671
+
672
+ def deconstruct_keys(keys)
673
+ { location: location }
674
+ end
675
+
676
+ # Here for convenience for comparing between block types.
677
+ def value
678
+ "("
679
+ end
680
+ end
681
+
682
+ # A parsed token that represents the use of a [.
683
+ # https://www.w3.org/TR/css-syntax-3/#tokendef-open-square
684
+ class OpenSquareToken < Node
685
+ attr_reader :location
686
+
687
+ def initialize(location:)
688
+ @location = Location.from(location)
689
+ end
690
+
691
+ def accept(visitor)
692
+ visitor.visit_open_square_token(self)
693
+ end
694
+
695
+ def child_nodes
696
+ []
697
+ end
698
+
699
+ alias deconstruct child_nodes
700
+
701
+ def deconstruct_keys(keys)
702
+ { location: location }
703
+ end
704
+
705
+ # Here for convenience for comparing between block types.
706
+ def value
707
+ "["
708
+ end
709
+ end
710
+
711
+ # A parsed token that contains a numeric value with a percentage sign.
712
+ # https://www.w3.org/TR/css-syntax-3/#typedef-percentage-token
713
+ class PercentageToken < Node
714
+ attr_reader :value, :type, :location
715
+
716
+ def initialize(value:, type:, location:)
717
+ @value = value
718
+ @type = type
719
+ @location = Location.from(location)
720
+ end
721
+
722
+ def accept(visitor)
723
+ visitor.visit_percentage_token(self)
724
+ end
725
+
726
+ def child_nodes
727
+ []
728
+ end
729
+
730
+ alias deconstruct child_nodes
731
+
732
+ def deconstruct_keys(keys)
733
+ { value: value, type: type, location: location }
734
+ end
735
+ end
736
+
737
+ # Associates a prelude consisting of a list of component values with a block
738
+ # consisting of a simple {} block.
739
+ # https://www.w3.org/TR/css-syntax-3/#qualified-rule
740
+ class QualifiedRule < Node
741
+ attr_reader :prelude, :block, :location
742
+
743
+ def initialize(prelude:, block:, location:)
744
+ @prelude = prelude
745
+ @block = block
746
+ @location = location
747
+ end
748
+
749
+ def accept(visitor)
750
+ visitor.visit_qualified_rule(self)
751
+ end
752
+
753
+ def child_nodes
754
+ [*prelude, block].compact
755
+ end
756
+
757
+ alias deconstruct child_nodes
758
+
759
+ def deconstruct_keys(keys)
760
+ { prelude: prelude, block: block, location: location }
761
+ end
762
+ end
763
+
764
+ # A parsed token that contains a comma.
765
+ # https://www.w3.org/TR/css-syntax-3/#typedef-semicolon-token
766
+ class SemicolonToken < Node
767
+ attr_reader :location
768
+
769
+ def initialize(location:)
770
+ @location = Location.from(location)
771
+ end
772
+
773
+ def accept(visitor)
774
+ visitor.visit_semicolon_token(self)
775
+ end
776
+
777
+ def child_nodes
778
+ []
779
+ end
780
+
781
+ alias deconstruct child_nodes
782
+
783
+ def deconstruct_keys(keys)
784
+ { location: location }
785
+ end
786
+ end
787
+
788
+ # A simple block has an associated token (either a <[-token>, <(-token>, or
789
+ # <{-token>) and a value consisting of a list of component values.
790
+ # https://www.w3.org/TR/css-syntax-3/#simple-block
791
+ class SimpleBlock < Node
792
+ attr_reader :token, :value, :location
793
+
794
+ def initialize(token:, value:, location:)
795
+ @token = token
796
+ @value = value
797
+ @location = location
798
+ end
799
+
800
+ def accept(visitor)
801
+ visitor.visit_simple_block(self)
802
+ end
803
+
804
+ def child_nodes
805
+ value
806
+ end
807
+
808
+ alias deconstruct child_nodes
809
+
810
+ def deconstruct_keys(keys)
811
+ { token: token, value: value, location: location }
812
+ end
813
+ end
814
+
815
+ # A parsed token that contains a quoted string.
816
+ # https://www.w3.org/TR/css-syntax-3/#typedef-string-token
817
+ class StringToken < Node
818
+ attr_reader :value, :location
819
+
820
+ def initialize(value:, location:)
821
+ @value = value
822
+ @location = Location.from(location)
823
+ end
824
+
825
+ def accept(visitor)
826
+ visitor.visit_string_token(self)
827
+ end
828
+
829
+ def child_nodes
830
+ []
831
+ end
832
+
833
+ alias deconstruct child_nodes
834
+
835
+ def deconstruct_keys(keys)
836
+ { value: value, location: location }
837
+ end
838
+ end
839
+
840
+ # A style rule is a qualified rule that associates a selector list with a
841
+ # list of property declarations and possibly a list of nested rules.
842
+ # https://www.w3.org/TR/css-syntax-3/#style-rule
843
+ class StyleRule < Node
844
+ attr_reader :selectors, :declarations, :location
845
+
846
+ def initialize(selectors:, declarations:, location:)
847
+ @selectors = selectors
848
+ @declarations = declarations
849
+ @location = location
850
+ end
851
+
852
+ def accept(visitor)
853
+ visitor.visit_style_rule(self)
854
+ end
855
+
856
+ def child_nodes
857
+ [*selectors, *declarations]
858
+ end
859
+
860
+ alias deconstruct child_nodes
861
+
862
+ def deconstruct_keys(keys)
863
+ { selectors: selectors, declarations: declarations, location: location }
864
+ end
865
+ end
866
+
867
+ # This is the top node in the tree if it hasn't been converted into a CSS
868
+ # stylesheet.
869
+ class StyleSheet < Node
870
+ attr_reader :rules, :location
871
+
872
+ def initialize(rules:, location:)
873
+ @rules = rules
874
+ @location = location
875
+ end
876
+
877
+ def accept(visitor)
878
+ visitor.visit_stylesheet(self)
879
+ end
880
+
881
+ def child_nodes
882
+ rules
883
+ end
884
+
885
+ alias deconstruct child_nodes
886
+
887
+ def deconstruct_keys(keys)
888
+ { rules: rules, location: location }
889
+ end
890
+ end
891
+
892
+ # This node represents the use of the urange micro syntax, e.g. U+1F601.
893
+ # https://www.w3.org/TR/css-syntax-3/#typedef-urange
894
+ class URange < Node
895
+ attr_reader :start_value, :end_value, :location
896
+
897
+ def initialize(start_value:, end_value:, location:)
898
+ @start_value = start_value
899
+ @end_value = end_value
900
+ @location = location
901
+ end
902
+
903
+ def accept(visitor)
904
+ visitor.visit_urange(self)
905
+ end
906
+
907
+ def child_nodes
908
+ []
909
+ end
910
+
911
+ alias deconstruct child_nodes
912
+
913
+ def deconstruct_keys(keys)
914
+ { start_value: start_value, end_value: end_value, location: location }
915
+ end
916
+ end
917
+
918
+ # A parsed token that contains a URL. Note that this is different from a
919
+ # function call to the "url" function only if quotes aren't used.
920
+ # https://www.w3.org/TR/css-syntax-3/#typedef-url-token
921
+ class URLToken < Node
922
+ attr_reader :value, :location
923
+
924
+ def initialize(value:, location:)
925
+ @value = value
926
+ @location = Location.from(location)
927
+ end
928
+
929
+ def accept(visitor)
930
+ visitor.visit_url_token(self)
931
+ end
932
+
933
+ def child_nodes
934
+ []
935
+ end
936
+
937
+ alias deconstruct child_nodes
938
+
939
+ def deconstruct_keys(keys)
940
+ { value: value, location: location }
941
+ end
942
+ end
943
+
944
+ # A parsed token that contains only whitespace.
945
+ # https://www.w3.org/TR/css-syntax-3/#typedef-whitespace-token
946
+ class WhitespaceToken < Node
947
+ attr_reader :value, :location
948
+
949
+ def initialize(value:, location:)
950
+ @value = value
951
+ @location = Location.from(location)
952
+ end
953
+
954
+ def accept(visitor)
955
+ visitor.visit_whitespace_token(self)
956
+ end
957
+
958
+ def child_nodes
959
+ []
960
+ end
961
+
962
+ alias deconstruct child_nodes
963
+
964
+ def deconstruct_keys(keys)
965
+ { value: value, location: location }
966
+ end
967
+ end
968
+ end
969
+ end