Add _selectorPseudoIsSuperselector.

This commit is contained in:
Natalie Weizenbaum 2016-08-12 16:53:19 -07:00
parent b5b4cd5a8b
commit 51c8213a6d
6 changed files with 101 additions and 1 deletions

View File

@ -2,6 +2,8 @@
// 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 '../../extend/functions.dart';
import '../../utils.dart';
import '../selector.dart'; import '../selector.dart';
class ComplexSelector extends Selector { class ComplexSelector extends Selector {
@ -27,6 +29,9 @@ class ComplexSelector extends Selector {
: components = new List.unmodifiable(components), : components = new List.unmodifiable(components),
lineBreaks = new List.unmodifiable(lineBreaks); lineBreaks = new List.unmodifiable(lineBreaks);
bool isSuperselector(ComplexSelector other) =>
complexIsSuperselector(components, other.components);
void _computeSpecificity() { void _computeSpecificity() {
_minSpecificity = 0; _minSpecificity = 0;
_maxSpecificity = 0; _maxSpecificity = 0;
@ -38,6 +43,11 @@ class ComplexSelector extends Selector {
} }
} }
int get hashCode => listHash(components);
bool operator ==(other) =>
other is ComplexSelector && listEquals(components, other.components);
String toString() => components.join(" "); String toString() => components.join(" ");
} }

View File

@ -3,6 +3,7 @@
// https://opensource.org/licenses/MIT. // https://opensource.org/licenses/MIT.
import '../../extend/functions.dart'; import '../../extend/functions.dart';
import '../../utils.dart';
import '../selector.dart'; import '../selector.dart';
class CompoundSelector extends Selector implements ComplexSelectorComponent { class CompoundSelector extends Selector implements ComplexSelectorComponent {
@ -35,5 +36,10 @@ class CompoundSelector extends Selector implements ComplexSelectorComponent {
} }
} }
int get hashCode => listHash(components);
bool operator ==(other) =>
other is ComplexSelector && listEquals(components, other.components);
String toString() => components.join(""); String toString() => components.join("");
} }

View File

@ -2,6 +2,8 @@
// 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 '../../extend/functions.dart';
import '../../utils.dart';
import '../selector.dart'; import '../selector.dart';
class SelectorList extends Selector { class SelectorList extends Selector {
@ -14,5 +16,13 @@ class SelectorList extends Selector {
: components = new List.unmodifiable(components), : components = new List.unmodifiable(components),
lineBreaks = new List.unmodifiable(lineBreaks); lineBreaks = new List.unmodifiable(lineBreaks);
bool isSuperselector(SelectorList other) =>
listIsSuperslector(components, other.components);
int get hashCode => listHash(components);
bool operator ==(other) =>
other is ComplexSelector && listEquals(components, other.components);
String toString() => components.join(", "); String toString() => components.join(", ");
} }

View File

@ -8,7 +8,7 @@ import 'package:charcode/charcode.dart';
import '../selector.dart'; import '../selector.dart';
final _vendorPrefix = new Regex(r'^-[a-zA-Z0-9]+-'); final _vendorPrefix = new RegExp(r'^-[a-zA-Z0-9]+-');
class PseudoSelector extends SimpleSelector { class PseudoSelector extends SimpleSelector {
final String name; final String name;

View File

@ -61,6 +61,11 @@ SimpleSelector unifyUniversalAndElement(SimpleSelector selector1,
new NamespacedIdentifier(name, namespace: namespace)); new NamespacedIdentifier(name, namespace: namespace));
} }
bool listIsSuperslector(List<ComplexSelector> list1,
List<ComplexSelector> list2) =>
list2.every((complex1) =>
list1.any((complex2) => complex2.isSuperselector(complex1)));
bool complexIsParentSuperselector(List<ComplexSelectorComponent> complex1, bool complexIsParentSuperselector(List<ComplexSelectorComponent> complex1,
List<ComplexSelectorComponent> complex2) { List<ComplexSelectorComponent> complex2) {
// Try some simple heuristics to see if we can avoid allocations. // Try some simple heuristics to see if we can avoid allocations.
@ -198,3 +203,70 @@ bool _simpleIsSuperselectorOfCompound(SimpleSelector simple,
} }
}); });
} }
bool _selectorPseudoIsSuperselector(PseudoSelector pseudo1,
CompoundSelector compound2, {Iterable<ComplexSelectorComponent> parents}) {
switch (pseudo1.normalizedName) {
case 'matches':
case 'any':
var pseudos = _selectorPseudosNamed(compound2, pseudo1.normalizedName);
return pseudos.any((pseudo2) {
return pseudo1.selector.isSuperselector(pseudo2.selector);
}) || pseudo1.selector.components.any((complex1) {
var complex2 = (parents?.toList() ?? [])..add(compound2);
return complexIsSuperselector(complex1.components, complex2);
});
case 'has':
case 'host':
case 'host-context':
return _selectorPseudosNamed(compound2, pseudo1.normalizedName)
.any((pseudo2) => pseudo1.selector.isSuperselector(pseudo2.selector));
case 'not':
return pseudo1.selector.components.every((complex) {
return compound2.components.every((simple2) {
if (simple2 is TypeSelector) {
var compound1 = complex.components.last;
return compound1 is CompoundSelector &&
compound1.components.any((simple1) =>
simple1 is TypeSelector && simple1 != simple2);
} else if (simple2 is IDSelector) {
var compound1 = complex.components.last;
return compound1 is CompoundSelector &&
compound1.components.any((simple1) =>
simple1 is IDSelector && simple1 != simple2);
} else if (simple2 is PseudoSelector &&
simple2.name == pseudo1.name &&
simple2.selector != null) {
return listIsSuperslector(simple2.selector.components, [complex]);
} else {
return false;
}
});
});
case 'current':
return _selectorPseudosNamed(compound2, 'current')
.any((pseudo2) => pseudo1.selector == pseudo2.selector);
case 'nth-child':
case 'nth-last-child':
return compound2.components.any((pseudo2) =>
pseudo2 is PseudoSelector &&
pseudo2.name == pseudo1.name &&
pseudo2.argument == pseudo1.argument &&
pseudo1.selector.isSuperselector(pseudo2.selector));
default:
throw "unreachable";
}
}
Iterable<PseudoSelector> _selectorPseudosNamed(CompoundSelector compound,
String name) =>
compound.components.where((simple) =>
simple is PseudoSelector &&
simple.type == PseudoType.klass &&
simple.selector != null &&
simple.name == name);

View File

@ -23,6 +23,8 @@ class LinkedListValue<T> extends LinkedListEntry<LinkedListValue<T>> {
bool listEquals/*<T>*/(List/*<T>*/ list1, List/*<T>*/ list2) => bool listEquals/*<T>*/(List/*<T>*/ list1, List/*<T>*/ list2) =>
const ListEquality().equals(list1, list2); const ListEquality().equals(list1, list2);
int listHash(List list) => const ListEquality().hash(list);
FileSpan spanForList(List<AstNode> nodes) { FileSpan spanForList(List<AstNode> nodes) {
if (nodes.isEmpty) return null; if (nodes.isEmpty) return null;
return nodes.first.span.expand(nodes.last.span); return nodes.first.span.expand(nodes.last.span);