mirror of
https://github.com/danog/dart-sass.git
synced 2024-12-12 09:09:39 +01:00
Reparse media queries at perform-time.
This commit is contained in:
parent
6f6eb79dae
commit
868286911b
@ -2,42 +2,38 @@
|
|||||||
// MIT-style license that can be found in the LICENSE file or at
|
// MIT-style license that can be found in the LICENSE file or at
|
||||||
// https://opensource.org/licenses/MIT.
|
// https://opensource.org/licenses/MIT.
|
||||||
|
|
||||||
import 'package:source_span/source_span.dart';
|
import '../../parse/media_query.dart';
|
||||||
|
|
||||||
import '../../utils.dart';
|
|
||||||
import '../node.dart';
|
|
||||||
import 'value.dart';
|
|
||||||
|
|
||||||
/// A plain CSS media query, as used in `@media` and `@import`.
|
/// A plain CSS media query, as used in `@media` and `@import`.
|
||||||
class CssMediaQuery implements AstNode {
|
class CssMediaQuery {
|
||||||
/// The modifier, probably either "not" or "only".
|
/// The modifier, probably either "not" or "only".
|
||||||
///
|
///
|
||||||
/// This may be `null` if no modifier is in use.
|
/// This may be `null` if no modifier is in use.
|
||||||
final CssValue<String> modifier;
|
final String modifier;
|
||||||
|
|
||||||
/// The media type, for example "screen" or "print".
|
/// The media type, for example "screen" or "print".
|
||||||
///
|
///
|
||||||
/// This may be `null`. If so, [features] will not be empty.
|
/// This may be `null`. If so, [features] will not be empty.
|
||||||
final CssValue<String> type;
|
final String type;
|
||||||
|
|
||||||
/// Feature queries, including parentheses.
|
/// Feature queries, including parentheses.
|
||||||
final List<CssValue<String>> features;
|
final List<String> features;
|
||||||
|
|
||||||
FileSpan get span {
|
/// Parses a media query from [contents].
|
||||||
var components = <AstNode>[];
|
///
|
||||||
if (modifier != null) components.add(modifier);
|
/// If passed, [url] is the name of the file from which [contents] comes.
|
||||||
if (type != null) components.add(type);
|
///
|
||||||
components.addAll(features);
|
/// Throws a [SassFormatException] if parsing fails.
|
||||||
return spanForList(components);
|
static List<CssMediaQuery> parseList(String contents, {url}) =>
|
||||||
}
|
new MediaQueryParser(contents, url: url).parse();
|
||||||
|
|
||||||
/// Creates a media query specifies a type and, optionally, features.
|
/// Creates a media query specifies a type and, optionally, features.
|
||||||
CssMediaQuery(this.type, {this.modifier, Iterable<CssValue<String>> features})
|
CssMediaQuery(this.type, {this.modifier, Iterable<String> features})
|
||||||
: features =
|
: features =
|
||||||
features == null ? const [] : new List.unmodifiable(features);
|
features == null ? const [] : new List.unmodifiable(features);
|
||||||
|
|
||||||
/// Creates a media query that only specifies features.
|
/// Creates a media query that only specifies features.
|
||||||
CssMediaQuery.condition(Iterable<CssValue<String>> features)
|
CssMediaQuery.condition(Iterable<String> features)
|
||||||
: modifier = null,
|
: modifier = null,
|
||||||
type = null,
|
type = null,
|
||||||
features = new List.unmodifiable(features);
|
features = new List.unmodifiable(features);
|
||||||
@ -45,10 +41,10 @@ class CssMediaQuery implements AstNode {
|
|||||||
/// Merges this with [other] to return a query that matches the intersection
|
/// Merges this with [other] to return a query that matches the intersection
|
||||||
/// of both inputs.
|
/// of both inputs.
|
||||||
CssMediaQuery merge(CssMediaQuery other) {
|
CssMediaQuery merge(CssMediaQuery other) {
|
||||||
var ourModifier = this.modifier?.value?.toLowerCase();
|
var ourModifier = this.modifier?.toLowerCase();
|
||||||
var ourType = this.type?.value?.toLowerCase();
|
var ourType = this.type?.toLowerCase();
|
||||||
var theirModifier = other.modifier?.value?.toLowerCase();
|
var theirModifier = other.modifier?.toLowerCase();
|
||||||
var theirType = other.type?.value?.toLowerCase();
|
var theirType = other.type?.toLowerCase();
|
||||||
|
|
||||||
if (ourType == null && theirType == null) {
|
if (ourType == null && theirType == null) {
|
||||||
return new CssMediaQuery.condition(
|
return new CssMediaQuery.condition(
|
||||||
@ -84,4 +80,15 @@ class CssMediaQuery implements AstNode {
|
|||||||
modifier: modifier == ourModifier ? this.modifier : other.modifier,
|
modifier: modifier == ourModifier ? this.modifier : other.modifier,
|
||||||
features: features.toList()..addAll(other.features));
|
features: features.toList()..addAll(other.features));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String toString() {
|
||||||
|
var buffer = new StringBuffer();
|
||||||
|
if (modifier != null) buffer.write("$modifier ");
|
||||||
|
if (type != null) {
|
||||||
|
buffer.write(type);
|
||||||
|
if (features.isNotEmpty) buffer.write(" and ");
|
||||||
|
}
|
||||||
|
buffer.write(features.join(" and "));
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,8 @@ class CssMediaRule extends CssParentNode {
|
|||||||
|
|
||||||
final FileSpan span;
|
final FileSpan span;
|
||||||
|
|
||||||
CssMediaRule(this.queries, this.span) {
|
CssMediaRule(Iterable<CssMediaQuery> queries, this.span)
|
||||||
|
: queries = new List.unmodifiable(queries) {
|
||||||
if (queries.isEmpty) {
|
if (queries.isEmpty) {
|
||||||
throw new ArgumentError.value(queries, "queries", "may not be empty.");
|
throw new ArgumentError.value(queries, "queries", "may not be empty.");
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ export 'sass/expression/unary_operation.dart';
|
|||||||
export 'sass/expression/value.dart';
|
export 'sass/expression/value.dart';
|
||||||
export 'sass/expression/variable.dart';
|
export 'sass/expression/variable.dart';
|
||||||
export 'sass/interpolation.dart';
|
export 'sass/interpolation.dart';
|
||||||
export 'sass/media_query.dart';
|
|
||||||
export 'sass/node.dart';
|
export 'sass/node.dart';
|
||||||
export 'sass/statement.dart';
|
export 'sass/statement.dart';
|
||||||
export 'sass/statement/at_root_rule.dart';
|
export 'sass/statement/at_root_rule.dart';
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
// 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:source_span/source_span.dart';
|
|
||||||
|
|
||||||
import '../../utils.dart';
|
|
||||||
import '../node.dart';
|
|
||||||
import 'interpolation.dart';
|
|
||||||
import 'node.dart';
|
|
||||||
|
|
||||||
/// A media query, as used in `@media` and `@import`.
|
|
||||||
class MediaQuery implements SassNode {
|
|
||||||
/// The modifier, which is expected (but not required) to evaluate to "not" or
|
|
||||||
/// "only".
|
|
||||||
///
|
|
||||||
/// This may be `null` if no modifier is in use.
|
|
||||||
final Interpolation modifier;
|
|
||||||
|
|
||||||
/// The media type.
|
|
||||||
///
|
|
||||||
/// This may be `null`. If so, [features] will not be empty.
|
|
||||||
final Interpolation type;
|
|
||||||
|
|
||||||
/// Feature queries.
|
|
||||||
final List<Interpolation> features;
|
|
||||||
|
|
||||||
FileSpan get span {
|
|
||||||
var components = <AstNode>[];
|
|
||||||
if (modifier != null) components.add(modifier);
|
|
||||||
if (type != null) components.add(type);
|
|
||||||
components.addAll(features);
|
|
||||||
return spanForList(components);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a media query specifies a type and, optionally, features.
|
|
||||||
MediaQuery(this.type, {this.modifier, Iterable<Interpolation> features})
|
|
||||||
: features =
|
|
||||||
features == null ? const [] : new List.unmodifiable(features);
|
|
||||||
|
|
||||||
/// Creates a media query that only specifies features.
|
|
||||||
MediaQuery.condition(Iterable<Interpolation> features,
|
|
||||||
{this.modifier, this.type})
|
|
||||||
: features = new List.unmodifiable(features);
|
|
||||||
|
|
||||||
String toString() {
|
|
||||||
var buffer = new StringBuffer();
|
|
||||||
if (modifier != null) buffer.write("$modifier ");
|
|
||||||
if (type != null) {
|
|
||||||
buffer.write(type);
|
|
||||||
if (features.isNotEmpty) buffer.write(" and ");
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.write(features.join(" and "));
|
|
||||||
return buffer.toString();
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,32 +5,26 @@
|
|||||||
import 'package:source_span/source_span.dart';
|
import 'package:source_span/source_span.dart';
|
||||||
|
|
||||||
import '../../../visitor/interface/statement.dart';
|
import '../../../visitor/interface/statement.dart';
|
||||||
import '../media_query.dart';
|
import '../interpolation.dart';
|
||||||
import '../statement.dart';
|
import '../statement.dart';
|
||||||
|
|
||||||
/// A `@media` rule.
|
/// A `@media` rule.
|
||||||
class MediaRule implements Statement {
|
class MediaRule implements Statement {
|
||||||
/// The queries that select what browsers and conditions this rule targets.
|
/// The query that determines on which platforms the styles will be in effect.
|
||||||
///
|
///
|
||||||
/// This is never empty.
|
/// This is only parsed after the interpolation has been resolved.
|
||||||
final List<MediaQuery> queries;
|
final Interpolation query;
|
||||||
|
|
||||||
/// The contents of this rule.
|
/// The contents of this rule.
|
||||||
final List<Statement> children;
|
final List<Statement> children;
|
||||||
|
|
||||||
final FileSpan span;
|
final FileSpan span;
|
||||||
|
|
||||||
MediaRule(
|
MediaRule(this.query, Iterable<Statement> children, this.span)
|
||||||
Iterable<MediaQuery> queries, Iterable<Statement> children, this.span)
|
: children = new List.unmodifiable(children);
|
||||||
: queries = new List.unmodifiable(queries),
|
|
||||||
children = new List.unmodifiable(children) {
|
|
||||||
if (this.queries.isEmpty) {
|
|
||||||
throw new ArgumentError("queries may not be empty.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*=T*/ accept/*<T>*/(StatementVisitor/*<T>*/ visitor) =>
|
/*=T*/ accept/*<T>*/(StatementVisitor/*<T>*/ visitor) =>
|
||||||
visitor.visitMediaRule(this);
|
visitor.visitMediaRule(this);
|
||||||
|
|
||||||
String toString() => "@media ${queries.join(", ")} {${children.join(" ")}}";
|
String toString() => "@media $query {${children.join(" ")}}";
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import 'package:source_span/source_span.dart';
|
|||||||
|
|
||||||
import '../../../visitor/interface/statement.dart';
|
import '../../../visitor/interface/statement.dart';
|
||||||
import '../interpolation.dart';
|
import '../interpolation.dart';
|
||||||
import '../media_query.dart';
|
|
||||||
import '../statement.dart';
|
import '../statement.dart';
|
||||||
import '../supports_condition.dart';
|
import '../supports_condition.dart';
|
||||||
|
|
||||||
@ -24,13 +23,11 @@ class PlainImportRule implements Statement {
|
|||||||
|
|
||||||
/// The media query attached to this import, or `null` if no condition is
|
/// The media query attached to this import, or `null` if no condition is
|
||||||
/// attached.
|
/// attached.
|
||||||
final List<MediaQuery> media;
|
final Interpolation media;
|
||||||
|
|
||||||
final FileSpan span;
|
final FileSpan span;
|
||||||
|
|
||||||
PlainImportRule(this.url, this.span,
|
PlainImportRule(this.url, this.span, {this.supports, this.media});
|
||||||
{this.supports, Iterable<MediaQuery> media})
|
|
||||||
: media = media == null ? null : new List.unmodifiable(media);
|
|
||||||
|
|
||||||
/*=T*/ accept/*<T>*/(StatementVisitor/*<T>*/ visitor) =>
|
/*=T*/ accept/*<T>*/(StatementVisitor/*<T>*/ visitor) =>
|
||||||
visitor.visitPlainImportRule(this);
|
visitor.visitPlainImportRule(this);
|
||||||
|
77
lib/src/parse/media_query.dart
Normal file
77
lib/src/parse/media_query.dart
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// 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(String contents, {url}) : super(contents, url: url);
|
||||||
|
|
||||||
|
List<CssMediaQuery> parse() {
|
||||||
|
return wrapSpanFormatException(() {
|
||||||
|
var queries = <CssMediaQuery>[];
|
||||||
|
do {
|
||||||
|
whitespace();
|
||||||
|
queries.add(_mediaQuery());
|
||||||
|
} while (scanner.scanChar($comma));
|
||||||
|
return queries;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consumes a single media query.
|
||||||
|
CssMediaQuery _mediaQuery() {
|
||||||
|
// This is somewhat duplicated in StylesheetParser._mediaQuery.
|
||||||
|
String modifier;
|
||||||
|
String type;
|
||||||
|
if (scanner.peekChar() != $lparen) {
|
||||||
|
var identifier1 = identifier();
|
||||||
|
whitespace();
|
||||||
|
|
||||||
|
if (!lookingAtIdentifier()) {
|
||||||
|
// For example, "@media screen {"
|
||||||
|
return new CssMediaQuery(identifier1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var identifier2 = identifier();
|
||||||
|
whitespace();
|
||||||
|
|
||||||
|
if (equalsIgnoreCase(identifier2, "and")) {
|
||||||
|
// For example, "@media screen and ..."
|
||||||
|
type = identifier1;
|
||||||
|
} else {
|
||||||
|
modifier = identifier1;
|
||||||
|
type = identifier2;
|
||||||
|
if (scanIdentifier("and", ignoreCase: true)) {
|
||||||
|
// For example, "@media only screen and ..."
|
||||||
|
whitespace();
|
||||||
|
} else {
|
||||||
|
// For example, "@media only screen {"
|
||||||
|
return new CssMediaQuery(type, modifier: modifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We've consumed either `IDENTIFIER "and"` or
|
||||||
|
// `IDENTIFIER IDENTIFIER "and"`.
|
||||||
|
|
||||||
|
var features = <String>[];
|
||||||
|
do {
|
||||||
|
whitespace();
|
||||||
|
scanner.expectChar($lparen);
|
||||||
|
features.add("(${declarationValue()})");
|
||||||
|
scanner.expectChar($rparen);
|
||||||
|
whitespace();
|
||||||
|
} while (scanIdentifier("and", ignoreCase: true));
|
||||||
|
|
||||||
|
if (type == null) {
|
||||||
|
return new CssMediaQuery.condition(features);
|
||||||
|
} else {
|
||||||
|
return new CssMediaQuery(type, modifier: modifier, features: features);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -437,11 +437,13 @@ abstract class Parser {
|
|||||||
// See also [ScssParser._lookingAtInterpolatedIdentifier].
|
// See also [ScssParser._lookingAtInterpolatedIdentifier].
|
||||||
|
|
||||||
var first = scanner.peekChar();
|
var first = scanner.peekChar();
|
||||||
|
if (first == null) return false;
|
||||||
if (isNameStart(first) || first == $backslash) return true;
|
if (isNameStart(first) || first == $backslash) return true;
|
||||||
|
|
||||||
if (first != $dash) return false;
|
if (first != $dash) return false;
|
||||||
var second = scanner.peekChar(1);
|
var second = scanner.peekChar(1);
|
||||||
return isNameStart(second) || second == $dash || second == $backslash;
|
return second != null &&
|
||||||
|
(isNameStart(second) || second == $dash || second == $backslash);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes an identifier if its name exactly matches [text].
|
/// Consumes an identifier if its name exactly matches [text].
|
||||||
|
@ -675,7 +675,7 @@ abstract class StylesheetParser extends Parser {
|
|||||||
/// Consumes a supports condition and/or a media query after an `@import`.
|
/// Consumes a supports condition and/or a media query after an `@import`.
|
||||||
///
|
///
|
||||||
/// Returns `null` if neither type of query can be found.
|
/// Returns `null` if neither type of query can be found.
|
||||||
Tuple2<SupportsCondition, List<MediaQuery>> _tryImportQueries() {
|
Tuple2<SupportsCondition, Interpolation> _tryImportQueries() {
|
||||||
SupportsCondition supports;
|
SupportsCondition supports;
|
||||||
if (scanIdentifier("supports", ignoreCase: true)) {
|
if (scanIdentifier("supports", ignoreCase: true)) {
|
||||||
scanner.expectChar($lparen);
|
scanner.expectChar($lparen);
|
||||||
@ -731,8 +731,11 @@ abstract class StylesheetParser extends Parser {
|
|||||||
/// Consumes a `@media` rule.
|
/// Consumes a `@media` rule.
|
||||||
///
|
///
|
||||||
/// [start] should point before the `@`.
|
/// [start] should point before the `@`.
|
||||||
MediaRule _mediaRule(LineScannerState start) => new MediaRule(
|
MediaRule _mediaRule(LineScannerState start) {
|
||||||
_mediaQueryList(), children(_ruleChild), scanner.spanFrom(start));
|
var query = _mediaQueryList();
|
||||||
|
var children = this.children(_ruleChild);
|
||||||
|
return new MediaRule(query, children, scanner.spanFrom(start));
|
||||||
|
}
|
||||||
|
|
||||||
/// Consumes a mixin declaration.
|
/// Consumes a mixin declaration.
|
||||||
///
|
///
|
||||||
@ -2169,43 +2172,47 @@ abstract class StylesheetParser extends Parser {
|
|||||||
// ## Media Queries
|
// ## Media Queries
|
||||||
|
|
||||||
/// Consumes a list of media queries.
|
/// Consumes a list of media queries.
|
||||||
List<MediaQuery> _mediaQueryList() {
|
Interpolation _mediaQueryList() {
|
||||||
var queries = <MediaQuery>[];
|
var start = scanner.state;
|
||||||
do {
|
var buffer = new InterpolationBuffer();
|
||||||
|
while (true) {
|
||||||
whitespace();
|
whitespace();
|
||||||
queries.add(_mediaQuery());
|
_mediaQuery(buffer);
|
||||||
} while (scanner.scanChar($comma));
|
if (!scanner.scanChar($comma)) break;
|
||||||
return queries;
|
buffer.writeCharCode($comma);
|
||||||
|
buffer.writeCharCode($space);
|
||||||
|
}
|
||||||
|
return buffer.interpolation(scanner.spanFrom(start));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes a single media query.
|
/// Consumes a single media query.
|
||||||
MediaQuery _mediaQuery() {
|
void _mediaQuery(InterpolationBuffer buffer) {
|
||||||
Interpolation modifier;
|
// This is somewhat duplicated in MediaQueryParser._mediaQuery.
|
||||||
Interpolation type;
|
|
||||||
if (scanner.peekChar() != $lparen) {
|
if (scanner.peekChar() != $lparen) {
|
||||||
var identifier1 = _interpolatedIdentifier();
|
buffer.addInterpolation(_interpolatedIdentifier());
|
||||||
whitespace();
|
whitespace();
|
||||||
|
|
||||||
if (!_lookingAtInterpolatedIdentifier()) {
|
if (!_lookingAtInterpolatedIdentifier()) {
|
||||||
// For example, "@media screen {"
|
// For example, "@media screen {".
|
||||||
return new MediaQuery(identifier1);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var identifier2 = _interpolatedIdentifier();
|
buffer.writeCharCode($space);
|
||||||
|
var identifier = _interpolatedIdentifier();
|
||||||
whitespace();
|
whitespace();
|
||||||
|
|
||||||
if (equalsIgnoreCase(identifier2.asPlain, "and")) {
|
if (equalsIgnoreCase(identifier.asPlain, "and")) {
|
||||||
// For example, "@media screen and ..."
|
// For example, "@media screen and ..."
|
||||||
type = identifier1;
|
buffer.write("and ");
|
||||||
} else {
|
} else {
|
||||||
modifier = identifier1;
|
buffer.addInterpolation(identifier);
|
||||||
type = identifier2;
|
|
||||||
if (scanIdentifier("and", ignoreCase: true)) {
|
if (scanIdentifier("and", ignoreCase: true)) {
|
||||||
// For example, "@media only screen and ..."
|
// For example, "@media only screen and ..."
|
||||||
whitespace();
|
whitespace();
|
||||||
|
buffer.write("and ");
|
||||||
} else {
|
} else {
|
||||||
// For example, "@media only screen {"
|
// For example, "@media only screen {"
|
||||||
return new MediaQuery(type, modifier: modifier);
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2213,17 +2220,12 @@ abstract class StylesheetParser extends Parser {
|
|||||||
// We've consumed either `IDENTIFIER "and"` or
|
// We've consumed either `IDENTIFIER "and"` or
|
||||||
// `IDENTIFIER IDENTIFIER "and"`.
|
// `IDENTIFIER IDENTIFIER "and"`.
|
||||||
|
|
||||||
var features = <Interpolation>[];
|
while (true) {
|
||||||
do {
|
|
||||||
whitespace();
|
whitespace();
|
||||||
features.add(_queryExpression());
|
buffer.addInterpolation(_queryExpression());
|
||||||
whitespace();
|
whitespace();
|
||||||
} while (scanIdentifier("and", ignoreCase: true));
|
if (!scanIdentifier("and", ignoreCase: true)) break;
|
||||||
|
buffer.write(" and ");
|
||||||
if (type == null) {
|
|
||||||
return new MediaQuery.condition(features);
|
|
||||||
} else {
|
|
||||||
return new MediaQuery(type, modifier: modifier, features: features);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -585,11 +585,11 @@ class _PerformVisitor
|
|||||||
"Media rules may not be used within nested declarations.", node.span);
|
"Media rules may not be used within nested declarations.", node.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
var queryIterable = node.queries.map(_visitMediaQuery);
|
var queries = _visitMediaQueries(node.query);
|
||||||
var queries = _mediaQueries == null
|
if (_mediaQueries != null) {
|
||||||
? new List<CssMediaQuery>.unmodifiable(queryIterable)
|
queries = _mergeMediaQueries(_mediaQueries, queries);
|
||||||
: _mergeMediaQueries(_mediaQueries, queryIterable);
|
if (queries.isEmpty) return null;
|
||||||
if (queries.isEmpty) return null;
|
}
|
||||||
|
|
||||||
_withParent(new CssMediaRule(queries, node.span), () {
|
_withParent(new CssMediaRule(queries, node.span), () {
|
||||||
_withMediaQueries(queries, () {
|
_withMediaQueries(queries, () {
|
||||||
@ -615,6 +615,12 @@ class _PerformVisitor
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evaluates [interpolation] and parses the result as a list of media
|
||||||
|
/// queries.
|
||||||
|
List<CssMediaQuery> _visitMediaQueries(Interpolation interpolation) =>
|
||||||
|
_adjustParseError(interpolation.span,
|
||||||
|
() => CssMediaQuery.parseList(_performInterpolation(interpolation)));
|
||||||
|
|
||||||
/// Returns a list of queries that selects for platforms that match both
|
/// Returns a list of queries that selects for platforms that match both
|
||||||
/// [queries1] and [queries2].
|
/// [queries1] and [queries2].
|
||||||
List<CssMediaQuery> _mergeMediaQueries(
|
List<CssMediaQuery> _mergeMediaQueries(
|
||||||
@ -624,20 +630,6 @@ class _PerformVisitor
|
|||||||
}).where((query) => query != null));
|
}).where((query) => query != null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates [query] and converts it to a plain CSS query.
|
|
||||||
CssMediaQuery _visitMediaQuery(MediaQuery query) {
|
|
||||||
var modifier =
|
|
||||||
query.modifier == null ? null : _interpolationToValue(query.modifier);
|
|
||||||
|
|
||||||
var type = query.type == null ? null : _interpolationToValue(query.type);
|
|
||||||
|
|
||||||
var features =
|
|
||||||
query.features.map((feature) => _interpolationToValue(feature));
|
|
||||||
|
|
||||||
if (type == null) return new CssMediaQuery.condition(features);
|
|
||||||
return new CssMediaQuery(type, modifier: modifier, features: features);
|
|
||||||
}
|
|
||||||
|
|
||||||
Value visitPlainImportRule(PlainImportRule node) {
|
Value visitPlainImportRule(PlainImportRule node) {
|
||||||
var url = _interpolationToValue(node.url);
|
var url = _interpolationToValue(node.url);
|
||||||
var supports = node.supports;
|
var supports = node.supports;
|
||||||
@ -645,11 +637,12 @@ class _PerformVisitor
|
|||||||
? "${supports.name.accept(this).toCssString()}: "
|
? "${supports.name.accept(this).toCssString()}: "
|
||||||
"${supports.value.accept(this).toCssString()})"
|
"${supports.value.accept(this).toCssString()})"
|
||||||
: (supports == null ? null : _visitSupportsCondition(supports));
|
: (supports == null ? null : _visitSupportsCondition(supports));
|
||||||
|
var mediaQuery = node.media == null ? null : _visitMediaQueries(node.media);
|
||||||
_parent.addChild(new CssImport(url, node.span,
|
_parent.addChild(new CssImport(url, node.span,
|
||||||
supports: resolvedSupports == null
|
supports: resolvedSupports == null
|
||||||
? null
|
? null
|
||||||
: new CssValue(resolvedSupports, node.supports.span),
|
: new CssValue(resolvedSupports, node.supports.span),
|
||||||
media: node?.media?.map(_visitMediaQuery)));
|
media: mediaQuery));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ class _SerializeCssVisitor
|
|||||||
void visitMediaRule(CssMediaRule node) {
|
void visitMediaRule(CssMediaRule node) {
|
||||||
_writeIndentation();
|
_writeIndentation();
|
||||||
_buffer.write("@media ");
|
_buffer.write("@media ");
|
||||||
_writeBetween(node.queries, ", ", visitMediaQuery);
|
_writeBetween(node.queries, ", ", _visitMediaQuery);
|
||||||
_buffer.writeCharCode($space);
|
_buffer.writeCharCode($space);
|
||||||
_visitChildren(node.children);
|
_visitChildren(node.children);
|
||||||
}
|
}
|
||||||
@ -149,7 +149,7 @@ class _SerializeCssVisitor
|
|||||||
|
|
||||||
if (node.media != null) {
|
if (node.media != null) {
|
||||||
_buffer.writeCharCode($space);
|
_buffer.writeCharCode($space);
|
||||||
_writeBetween(node.media, ', ', visitMediaQuery);
|
_writeBetween(node.media, ', ', _visitMediaQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
_buffer.writeCharCode($semicolon);
|
_buffer.writeCharCode($semicolon);
|
||||||
@ -162,14 +162,14 @@ class _SerializeCssVisitor
|
|||||||
_visitChildren(node.children);
|
_visitChildren(node.children);
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitMediaQuery(CssMediaQuery query) {
|
void _visitMediaQuery(CssMediaQuery query) {
|
||||||
if (query.modifier != null) {
|
if (query.modifier != null) {
|
||||||
_buffer.write(query.modifier.value);
|
_buffer.write(query.modifier);
|
||||||
_buffer.writeCharCode($space);
|
_buffer.writeCharCode($space);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (query.type != null) {
|
if (query.type != null) {
|
||||||
_buffer.write(query.type.value);
|
_buffer.write(query.type);
|
||||||
if (query.features.isNotEmpty) _buffer.write(" and ");
|
if (query.features.isNotEmpty) _buffer.write(" and ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user