-
Notifications
You must be signed in to change notification settings - Fork 362
/
Copy pathmedia_query.dart
131 lines (112 loc) · 3.55 KB
/
media_query.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2016 Google Inc. Use of this source code is governed by an
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'package:charcode/charcode.dart';
import '../ast/css.dart';
import '../utils.dart';
import 'parser.dart';
/// A parser for `@media` queries.
class MediaQueryParser extends Parser {
MediaQueryParser(super.contents, {super.url, super.interpolationMap});
List<CssMediaQuery> parse() {
return wrapSpanFormatException(() {
var queries = <CssMediaQuery>[];
do {
_whitespace();
queries.add(_mediaQuery());
_whitespace();
} while (scanner.scanChar($comma));
scanner.expectDone();
return queries;
});
}
/// Consumes a single media query.
CssMediaQuery _mediaQuery() {
// This is somewhat duplicated in StylesheetParser._mediaQuery.
if (scanner.peekChar() == $lparen) {
var conditions = [_mediaInParens()];
_whitespace();
var conjunction = true;
if (scanIdentifier("and")) {
expectWhitespace();
conditions.addAll(_mediaLogicSequence("and"));
} else if (scanIdentifier("or")) {
expectWhitespace();
conjunction = false;
conditions.addAll(_mediaLogicSequence("or"));
}
return CssMediaQuery.condition(conditions, conjunction: conjunction);
}
String? modifier;
String? type;
var identifier1 = identifier();
if (equalsIgnoreCase(identifier1, "not")) {
expectWhitespace();
if (!lookingAtIdentifier()) {
// For example, "@media not (...) {"
return CssMediaQuery.condition(["(not ${_mediaInParens()})"]);
}
}
_whitespace();
if (!lookingAtIdentifier()) {
// For example, "@media screen {"
return CssMediaQuery.type(identifier1);
}
var identifier2 = identifier();
if (equalsIgnoreCase(identifier2, "and")) {
expectWhitespace();
// For example, "@media screen and ..."
type = identifier1;
} else {
_whitespace();
modifier = identifier1;
type = identifier2;
if (scanIdentifier("and")) {
// For example, "@media only screen and ..."
expectWhitespace();
} else {
// For example, "@media only screen {"
return CssMediaQuery.type(type, modifier: modifier);
}
}
// We've consumed either `IDENTIFIER "and"` or
// `IDENTIFIER IDENTIFIER "and"`.
if (scanIdentifier("not")) {
// For example, "@media screen and not (...) {"
expectWhitespace();
return CssMediaQuery.type(
type,
modifier: modifier,
conditions: ["(not ${_mediaInParens()})"],
);
}
return CssMediaQuery.type(
type,
modifier: modifier,
conditions: _mediaLogicSequence("and"),
);
}
/// Consumes one or more `<media-in-parens>` expressions separated by
/// [operator] and returns them.
List<String> _mediaLogicSequence(String operator) {
var result = <String>[];
while (true) {
result.add(_mediaInParens());
_whitespace();
if (!scanIdentifier(operator)) return result;
expectWhitespace();
}
}
/// Consumes a `<media-in-parens>` expression and returns it, parentheses
/// included.
String _mediaInParens() {
scanner.expectChar($lparen, name: "media condition in parentheses");
var result = "(${declarationValue()})";
scanner.expectChar($rparen);
return result;
}
/// The value of `consumeNewlines` is not relevant for this class.
void _whitespace() {
whitespace(consumeNewlines: true);
}
}