mirror of
https://github.com/danog/dart-sass.git
synced 2024-11-30 04:39:03 +01:00
Partial selector newline support.
In particular, newlines in selectors lists are now preserved during parent selector resolution and emitted by the serializer. The output matches Ruby Sass, but I'm not sure it's actually the best possible.
This commit is contained in:
parent
98c5ffae9a
commit
99c83a5834
@ -10,8 +10,8 @@ import '../selector.dart';
|
||||
class ComplexSelector extends Selector {
|
||||
final List<ComplexSelectorComponent> components;
|
||||
|
||||
// Indices of [components] that are followed by line breaks.
|
||||
final List<int> lineBreaks;
|
||||
// There's a line break *before* this selector.
|
||||
final bool lineBreak;
|
||||
|
||||
int get minSpecificity {
|
||||
if (_minSpecificity == null) _computeSpecificity();
|
||||
@ -38,10 +38,8 @@ class ComplexSelector extends Selector {
|
||||
bool _containsPlaceholder;
|
||||
|
||||
ComplexSelector(Iterable<ComplexSelectorComponent> components,
|
||||
{Iterable<int> lineBreaks})
|
||||
: components = new List.unmodifiable(components),
|
||||
lineBreaks =
|
||||
lineBreaks == null ? const [] : new List.unmodifiable(lineBreaks);
|
||||
{this.lineBreak: false})
|
||||
: components = new List.unmodifiable(components);
|
||||
|
||||
/*=T*/ accept/*<T>*/(SelectorVisitor/*<T>*/ visitor) =>
|
||||
visitor.visitComplexSelector(this);
|
||||
|
@ -13,9 +13,6 @@ import '../selector.dart';
|
||||
class SelectorList extends Selector {
|
||||
final List<ComplexSelector> components;
|
||||
|
||||
// Indices of [components] that are followed by line breaks.
|
||||
final List<int> lineBreaks;
|
||||
|
||||
bool get _containsParentSelector {
|
||||
return components.any((complex) {
|
||||
return complex.components.any((component) =>
|
||||
@ -37,10 +34,8 @@ class SelectorList extends Selector {
|
||||
}), ListSeparator.comma);
|
||||
}
|
||||
|
||||
SelectorList(Iterable<ComplexSelector> components, {Iterable<int> lineBreaks})
|
||||
: components = new List.unmodifiable(components),
|
||||
lineBreaks =
|
||||
lineBreaks == null ? const [] : new List.unmodifiable(lineBreaks);
|
||||
SelectorList(Iterable<ComplexSelector> components)
|
||||
: components = new List.unmodifiable(components);
|
||||
|
||||
factory SelectorList.parse(String contents, {url, bool allowParent: true}) =>
|
||||
new SelectorParser(contents, url: url, allowParent: allowParent).parse();
|
||||
@ -71,39 +66,51 @@ class SelectorList extends Selector {
|
||||
if (!_containsParentSelector) {
|
||||
return new SelectorList(parent.components.expand((parentComplex) {
|
||||
return components.map((childComplex) => new ComplexSelector(
|
||||
parentComplex.components.toList()
|
||||
..addAll(childComplex.components)));
|
||||
parentComplex.components.toList()..addAll(childComplex.components),
|
||||
lineBreak: childComplex.lineBreak || parentComplex.lineBreak));
|
||||
}));
|
||||
}
|
||||
|
||||
// TODO: handle line breaks
|
||||
return new SelectorList(flattenVertically(components.map((complex) {
|
||||
var newComplexes = [<ComplexSelectorComponent>[]];
|
||||
var lineBreaks = <bool>[false];
|
||||
for (var component in complex.components) {
|
||||
if (component is CompoundSelector) {
|
||||
var resultList = _resolveParentSelectorsCompound(component, parent);
|
||||
if (resultList == null) {
|
||||
var resolved = _resolveParentSelectorsCompound(component, parent);
|
||||
if (resolved == null) {
|
||||
for (var newComplex in newComplexes) {
|
||||
newComplex.add(component);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
newComplexes = newComplexes
|
||||
.expand((newComplex) => resultList.map((resultComplex) =>
|
||||
newComplex.toList()..addAll(resultComplex)))
|
||||
.toList();
|
||||
var previousComplexes = newComplexes;
|
||||
var previousLineBreaks = lineBreaks;
|
||||
newComplexes = <List<ComplexSelectorComponent>>[];
|
||||
lineBreaks = <bool>[];
|
||||
var i = 0;
|
||||
for (var newComplex in previousComplexes) {
|
||||
var lineBreak = previousLineBreaks[i++];
|
||||
for (var resolvedComplex in resolved) {
|
||||
newComplexes
|
||||
.add(newComplex.toList()..addAll(resolvedComplex.components));
|
||||
lineBreaks.add(lineBreak || resolvedComplex.lineBreak);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (var newComplex in newComplexes) {
|
||||
newComplex.add(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newComplexes.map((newComplex) => new ComplexSelector(newComplex));
|
||||
|
||||
var i = 0;
|
||||
return newComplexes.map((newComplex) =>
|
||||
new ComplexSelector(newComplex, lineBreak: lineBreaks[i++]));
|
||||
})));
|
||||
}
|
||||
|
||||
Iterable<Iterable<ComplexSelectorComponent>> _resolveParentSelectorsCompound(
|
||||
Iterable<ComplexSelector> _resolveParentSelectorsCompound(
|
||||
CompoundSelector compound, SelectorList parent) {
|
||||
var containsSelectorPseudo = compound.components.any((simple) =>
|
||||
simple is PseudoSelector &&
|
||||
@ -130,11 +137,11 @@ class SelectorList extends Selector {
|
||||
var parentSelector = compound.components.first;
|
||||
if (parentSelector is ParentSelector) {
|
||||
if (compound.components.length == 1 && parentSelector.suffix == null) {
|
||||
return parent.components.map((complex) => complex.components);
|
||||
return parent.components;
|
||||
}
|
||||
} else {
|
||||
return [
|
||||
[new CompoundSelector(resolvedMembers)]
|
||||
new ComplexSelector([new CompoundSelector(resolvedMembers)])
|
||||
];
|
||||
}
|
||||
|
||||
@ -157,8 +164,10 @@ class SelectorList extends Selector {
|
||||
last.components.toList()..addAll(resolvedMembers.skip(1)));
|
||||
}
|
||||
|
||||
return complex.components.take(complex.components.length - 1).toList()
|
||||
..add(last);
|
||||
return new ComplexSelector(
|
||||
complex.components.take(complex.components.length - 1).toList()
|
||||
..add(last),
|
||||
lineBreak: complex.lineBreak);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,6 @@ class SelectorParser extends Parser {
|
||||
|
||||
SelectorList _selectorList() {
|
||||
var components = <ComplexSelector>[];
|
||||
var lineBreaks = <int>[];
|
||||
|
||||
whitespace();
|
||||
var previousLine = scanner.line;
|
||||
@ -58,21 +57,17 @@ class SelectorParser extends Parser {
|
||||
if (next == $comma) continue;
|
||||
if (next == $lbrace) break;
|
||||
|
||||
if (scanner.line != previousLine) {
|
||||
lineBreaks.add(components.length);
|
||||
previousLine = scanner.line;
|
||||
}
|
||||
components.add(_complexSelector());
|
||||
var lineBreak = scanner.line != previousLine;
|
||||
if (lineBreak) previousLine = scanner.line;
|
||||
components.add(_complexSelector(lineBreak: lineBreak));
|
||||
} while (scanner.scanChar($comma));
|
||||
|
||||
return new SelectorList(components, lineBreaks: lineBreaks);
|
||||
return new SelectorList(components);
|
||||
}
|
||||
|
||||
ComplexSelector _complexSelector() {
|
||||
ComplexSelector _complexSelector({bool lineBreak: false}) {
|
||||
var components = <ComplexSelectorComponent>[];
|
||||
var lineBreaks = <int>[];
|
||||
|
||||
var previousLine = scanner.line;
|
||||
loop:
|
||||
while (true) {
|
||||
whitespace();
|
||||
@ -112,14 +107,10 @@ class SelectorParser extends Parser {
|
||||
break;
|
||||
}
|
||||
|
||||
if (scanner.line != previousLine) {
|
||||
lineBreaks.add(components.length);
|
||||
previousLine = scanner.line;
|
||||
}
|
||||
components.add(component);
|
||||
}
|
||||
|
||||
return new ComplexSelector(components, lineBreaks: lineBreaks);
|
||||
return new ComplexSelector(components, lineBreak: lineBreak);
|
||||
}
|
||||
|
||||
CompoundSelector _compoundSelector() {
|
||||
@ -247,7 +238,9 @@ class SelectorParser extends Parser {
|
||||
ParentSelector _parentSelector() {
|
||||
scanner.expectChar($ampersand);
|
||||
var next = scanner.peekChar();
|
||||
var suffix = isName(next) || next == $backslash ? identifier() : null;
|
||||
var suffix = next != null && (isName(next) || next == $backslash)
|
||||
? identifier()
|
||||
: null;
|
||||
return new ParentSelector(suffix: suffix);
|
||||
}
|
||||
|
||||
|
@ -427,7 +427,17 @@ class _SerializeCssVisitor
|
||||
var complexes = _inspect
|
||||
? list.components
|
||||
: list.components.where((complex) => !complex.containsPlaceholder);
|
||||
_writeBetween(complexes, ", ", (complex) => visitComplexSelector(complex));
|
||||
|
||||
var first = true;
|
||||
for (var complex in complexes) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
_buffer.writeCharCode($comma);
|
||||
_buffer.writeCharCode(complex.lineBreak ? $lf : $space);
|
||||
}
|
||||
visitComplexSelector(complex);
|
||||
}
|
||||
}
|
||||
|
||||
void visitParentSelector(ParentSelector parent) {
|
||||
|
Loading…
Reference in New Issue
Block a user