diff --git a/src/dotless.Core/Parser/Infrastructure/Context.cs b/src/dotless.Core/Parser/Infrastructure/Context.cs index 1b3d889a..6b83b194 100644 --- a/src/dotless.Core/Parser/Infrastructure/Context.cs +++ b/src/dotless.Core/Parser/Infrastructure/Context.cs @@ -1,4 +1,6 @@ -namespace dotless.Core.Parser.Infrastructure +using System; + +namespace dotless.Core.Parser.Infrastructure { using System.Collections; using System.Collections.Generic; @@ -23,12 +25,35 @@ public void AppendSelectors(Context context, IEnumerable selectors) return; } - foreach (var selector in selectors) - { - Paths.AddRange(context.Paths.Select(path => path.Concat(new[] {selector}).ToList())); + foreach (var selector in selectors) + { + AppendSelector(context, selector); } - } - + } + + private void AppendSelector(Context context, Selector selector) + { + if (!selector.Elements.Any(e => e.Combinator.Value[0] == '&')) + { + Paths.AddRange(context.Paths.Select(path => path.Concat(new[] {selector}).ToList())); + return; + } + + var beforeEl = selector.Elements.TakeWhile(s => s.Combinator.Value[0] != '&'); + var afterEl = selector.Elements.SkipWhile(s => s.Combinator.Value[0] != '&'); + + var before = new List(); + var after = new List(); + + if (beforeEl.Any()) + before.Add(new Selector(beforeEl)); + + if (afterEl.Any()) + after.Add(new Selector(afterEl)); + + Paths.AddRange(context.Paths.Select(path => before.Concat(path).Concat(after).ToList())); + } + public string ToCSS(Env env) { return Paths diff --git a/src/dotless.Core/Parser/Parsers.cs b/src/dotless.Core/Parser/Parsers.cs index 1d4b36e0..d15f9c66 100644 --- a/src/dotless.Core/Parser/Parsers.cs +++ b/src/dotless.Core/Parser/Parsers.cs @@ -543,7 +543,10 @@ public Element Element(Parser parser) parser.Tokenizer.Match(@"\([^)@]+\)"); if (e) - return NodeProvider.Element(c, e.Value, index); + return NodeProvider.Element(c, e.Value, index); + + if (!string.IsNullOrEmpty(c.Value) && c.Value[0] == '&') + return NodeProvider.Element(c, null, index); return null; } @@ -561,8 +564,8 @@ public Combinator Combinator(Parser parser) { var index = parser.Tokenizer.Location.Index; - Node match; - if (match = parser.Tokenizer.Match(@"[+>~]") || parser.Tokenizer.Match('&') || parser.Tokenizer.Match(@"::")) + Node match; + if (match = parser.Tokenizer.Match(@"[+>~]") || parser.Tokenizer.Match(@"&[ ]?") || parser.Tokenizer.Match(@"::")) return NodeProvider.Combinator(match.ToString(), index); return NodeProvider.Combinator(parser.Tokenizer.PreviousChar == ' ' ? " " : null, index); diff --git a/src/dotless.Core/Parser/Tree/Combinator.cs b/src/dotless.Core/Parser/Tree/Combinator.cs index 1c046595..db25bdd3 100644 --- a/src/dotless.Core/Parser/Tree/Combinator.cs +++ b/src/dotless.Core/Parser/Tree/Combinator.cs @@ -10,10 +10,12 @@ public class Combinator : Node public Combinator(string value) { - if (string.IsNullOrEmpty(value)) - Value = ""; - else if (value == " ") - Value = " "; + if (string.IsNullOrEmpty(value)) + Value = ""; + else if (value == " ") + Value = " "; + else if (value == "& ") + Value = "& "; else Value = value.Trim(); } @@ -24,6 +26,7 @@ public override string ToCSS(Env env) { "", "" }, { " ", " " }, { "&", "" }, + { "& ", " " }, { ":", " :" }, { "::", "::" }, { "+", env.Compress ? "+" : " + " }, diff --git a/src/dotless.Core/Parser/Tree/Element.cs b/src/dotless.Core/Parser/Tree/Element.cs index fd136fd3..15a46b7a 100644 --- a/src/dotless.Core/Parser/Tree/Element.cs +++ b/src/dotless.Core/Parser/Tree/Element.cs @@ -11,7 +11,7 @@ public class Element : Node public Element(Combinator combinator, string value) { Combinator = combinator ?? new Combinator(""); - Value = value.Trim(); + Value = value == null ? "" : value.Trim(); } public override string ToCSS(Env env) diff --git a/src/dotless.Core/Parser/Tree/Selector.cs b/src/dotless.Core/Parser/Tree/Selector.cs index 6ca5fac3..84dd6e8c 100644 --- a/src/dotless.Core/Parser/Tree/Selector.cs +++ b/src/dotless.Core/Parser/Tree/Selector.cs @@ -13,9 +13,12 @@ public class Selector : Node public NodeList PreComments { get; set; } public NodeList PostComments { get; set; } - public Selector(NodeList elements) - { - Elements = elements; + public Selector(IEnumerable elements) + { + if (elements is NodeList) + Elements = elements as NodeList; + else + Elements = new NodeList(elements); if (Elements[0].Combinator.Value == "") Elements[0].Combinator.Value = " "; diff --git a/src/dotless.Test/Specs/SelectorsFixture.cs b/src/dotless.Test/Specs/SelectorsFixture.cs index 8138f788..bab2514a 100644 --- a/src/dotless.Test/Specs/SelectorsFixture.cs +++ b/src/dotless.Test/Specs/SelectorsFixture.cs @@ -33,7 +33,7 @@ public void ParentSelector1() AssertLess(input, expected); } - [Test, Ignore("Unsupported")] + [Test] public void ParentSelector2() { // Note: http://github.com/cloudhead/less.js/issues/issue/9 @@ -70,6 +70,38 @@ public void ParentSelector2() AssertLess(input, expected); } + [Test] + public void ParentSelector3() + { + // Note: http://github.com/cloudhead/less.js/issues/issue/9 + + var input = + @" +.foo { + .bar, .baz { + & .qux { + display: block; + } + .qux & { + display:inline; + } + } +} +"; + + var expected = + @" +.foo .bar .qux, .foo .baz .qux { + display: block; +} +.qux .foo .bar, .qux .foo .baz { + display: inline; +} +"; + + AssertLess(input, expected); + } + [Test] public void IdSelectors() {