Add support for attribute selector modifiers (#658)

Closes #656
This commit is contained in:
Natalie Weizenbaum 2019-04-30 11:31:18 -07:00 committed by GitHub
parent 797d18f27c
commit 407eefded1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 43 additions and 6 deletions

View File

@ -1,3 +1,7 @@
## 1.20.0
* Support attribute selector modifiers, such as the `i` in `[title="test" i]`.
## 1.19.0
* Allow `!` in `url()`s without quotes.

View File

@ -27,15 +27,27 @@ class AttributeSelector extends SimpleSelector {
/// regardless of this value. It's `null` if and only if [op] is `null`.
final String value;
/// The modifier which indicates how the attribute selector should be
/// processed.
///
/// See for example [case-sensitivity][] modifiers.
///
/// [case-sensitivity]: https://www.w3.org/TR/selectors-4/#attribute-case
///
/// If [op] is `null`, this is always `null` as well.
final String modifier;
/// Creates an attribute selector that matches any element with a property of
/// the given name.
AttributeSelector(this.name)
: op = null,
value = null;
value = null,
modifier = null;
/// Creates an attribute selector that matches an element with a property
/// named [name], whose value matches [value] based on the semantics of [op].
AttributeSelector.withOperator(this.name, this.op, this.value);
AttributeSelector.withOperator(this.name, this.op, this.value,
{this.modifier});
T accept<T>(SelectorVisitor<T> visitor) =>
visitor.visitAttributeSelector(this);
@ -44,9 +56,11 @@ class AttributeSelector extends SimpleSelector {
other is AttributeSelector &&
other.name == name &&
other.op == op &&
other.value == value;
other.value == value &&
other.modifier == modifier;
int get hashCode => name.hashCode ^ op.hashCode ^ value.hashCode;
int get hashCode =>
name.hashCode ^ op.hashCode ^ value.hashCode ^ modifier.hashCode;
}
/// An operator that defines the semantics of an [AttributeSelector].

View File

@ -201,8 +201,13 @@ class SelectorParser extends Parser {
: identifier();
whitespace();
var modifier = isAlphabetic(scanner.peekChar())
? String.fromCharCode(scanner.readChar())
: null;
scanner.expectChar($rbracket);
return AttributeSelector.withOperator(name, operator, value);
return AttributeSelector.withOperator(name, operator, value,
modifier: modifier);
}
/// Consumes a qualified name as part of an attribute selector.

View File

@ -914,9 +914,13 @@ class _SerializeVisitor implements CssVisitor, ValueVisitor, SelectorVisitor {
// doesn't consider them to be valid identifiers.
!attribute.value.startsWith('--')) {
_buffer.write(attribute.value);
if (attribute.modifier != null) _buffer.writeCharCode($space);
} else {
_visitQuotedString(attribute.value);
if (attribute.modifier != null) _writeOptionalSpace();
}
if (attribute.modifier != null) _buffer.write(attribute.modifier);
}
_buffer.writeCharCode($rbracket);
}

View File

@ -1,5 +1,5 @@
name: sass
version: 1.19.0
version: 1.20.0-dev
description: A Sass implementation in Dart.
author: Dart Team <misc@dartlang.org>
homepage: https://github.com/sass/dart-sass

View File

@ -42,6 +42,16 @@ void main() {
equals("a:nth-child(2n of b,c){x:y}"));
});
});
group("in attribute selectors with modifiers", () {
test("removes whitespace when quotes are required", () {
expect(_compile('[a=" " b] {x: y}'), equals('[a=" "b]{x:y}'));
});
test("doesn't remove whitespace when quotes aren't required", () {
expect(_compile('[a="b"c] {x: y}'), equals('[a=b c]{x:y}'));
});
});
});
group("for declarations", () {