/// <summary> /// selectors : ws selector (s ',' ws selector)* ws ; /// </summary> /// <param name="node"></param> /// <param name="action"></param> /// <returns></returns> private IEnumerable<ElementBlock> Selectors(LessPegNode node, Func<IEnumerable<ElementBlock>, IEnumerable<ElementBlock>> action) { foreach(var selector in node.Children(x => x.Type() == EnLess.selector)) { var selectors = Selector(selector); foreach(var s in action(selectors)) yield return s; } }
/// <summary> /// primary: (import / declaration / ruleset / comment)* ; /// </summary> /// <param name="node"></param> /// <param name="elementBlock"></param> private ElementBlock Primary(LessPegNode node, ElementBlock elementBlock) { foreach (var nextPrimary in node.Children()) { switch (nextPrimary.Type()) { case EnLess.import: Import(nextPrimary.Child, elementBlock); //element.Children.AddRange(import); break; case EnLess.insert: Insert(nextPrimary.Child, elementBlock); //element.Children.AddRange(import); break; case EnLess.standard_ruleset: RuleSet(nextPrimary, elementBlock); break; case EnLess.mixin_ruleset: Mixin(nextPrimary,elementBlock); break; case EnLess.declaration: Declaration(nextPrimary.Child, elementBlock); break; } } return elementBlock; }
/// <summary> /// selector : (s select element s)+ arguments? ; /// </summary> /// <param name="node"></param> /// <returns></returns> private IEnumerable<ElementBlock> Selector(LessPegNode node) { var enumerator = node.Children().GetEnumerator(); while(enumerator.MoveNext()) { ElementBlock block; var selector = enumerator.Current.GetAsString(Src).Trim(); enumerator.MoveNext(); var name = enumerator.Current.GetAsString(Src); var next = enumerator.Current.Next; var isMixinWithArgs = next != null && next.Type() == EnLess.arguments; if (isMixinWithArgs) { var mixinBlock = new MixinBlock(name, selector); block = mixinBlock; var arguments = GetMixinArguments(next, block); enumerator.MoveNext(); foreach (var argument in arguments) mixinBlock.Arguments.Add(argument); } else block = new ElementBlock(name, selector); yield return block; } }
/// <summary> /// TODO: Added quick fix for multipule mixins, but need to add mixins with variables which will changes things a bit /// </summary> /// <param name="node"></param> /// <param name="elementBlock"></param> // private void OldMixin(LessPegNode node, Element element) // { // var root = element.GetRoot(); // foreach (var el in Selectors(node.Child, els => els)) // root = root.Descend(el.Selector, el); // if (root.Children != null) element.Children.AddRange(root.Children); // } private void Mixin(LessPegNode node, ElementBlock elementBlock) { var root = elementBlock.GetRoot(); var rules = new List<INode>(); foreach (var mixins in node.Children()) { var selectors = Selectors(mixins, els => els).ToList(); if (selectors.Count() > 1) { foreach (var el in selectors) root = root.Descend(el.Selector, el); var last = selectors.Last(); var children = GetMixinChildren(elementBlock, last, root); if(children != null) rules.AddRange(children); } else { var el = selectors.First(); foreach (var mixinElement in root.Nearests(el.Name)) { var children = GetMixinChildren(elementBlock, el, mixinElement); if(children != null) rules.AddRange(children); } } } elementBlock.Children.AddRange(rules); }
private IEnumerable<Variable> GetMixinArguments(LessPegNode arguments, ElementBlock block) { var enumerator = arguments.Children().GetEnumerator(); var variables = new List<Variable>(); var position = 0; while (enumerator.MoveNext()) { var node = enumerator.Current; string name; IEnumerable<INode> value; if (node.Child.Type() == EnLess.variable) // expect "@variable: expression" { name = node.Child.GetAsString(Src); value = Expressions(node.Child.Next, block); } else // expect "expresion" { // HACK: to make Arguments return as expected. var tmpNode = new LessPegNode(null, (int) EnLess.arguments, Root); tmpNode.Child = new LessPegNode(tmpNode, (int)EnLess.argument, Root); tmpNode.Child.Child = node.Child; name = position.ToString(); value = Arguments(tmpNode, block).ToList(); } variables.Add(new Variable(name, value)); if(node.Next == null || node.Next.Type() != EnLess.argument) break; position++; } return variables; }
/// <summary> /// fonts : font (s ',' s font)+ ; /// </summary> /// <param name="node"></param> /// <returns></returns> private INode Fonts(LessPegNode node) { var fonts = from childNode in node.Children() select (childNode.Child ?? childNode).GetAsString(Src); return new FontFamily(fonts.ToArray()); }
/// <summary> /// cursor (s ',' s cursor)+ ; /// </summary> /// <param name="node"></param> /// <returns></returns> private INode Cursors(LessPegNode node) { var set = from childNode in node.Children() select (childNode.Child ?? childNode).GetAsString(Src); return new CursorSet(set.ToArray()); }
/// <summary> /// arguments : '(' s argument s (',' s argument s)* ')'; /// argument : color / number unit / string / [a-zA-Z]+ '=' dimension / function / expressions / [-a-zA-Z0-9_%$/.&=:;#+?]+ / keyword (S keyword)*; /// </summary> /// <param name="node"></param> /// <param name="element"></param> /// <returns></returns> private IEnumerable<INode> Arguments(LessPegNode node, ElementBlock element) { foreach (var argument in node.Children()) { if (argument.Child == null) yield return new Anonymous(argument.GetAsString(Src)); else { switch (argument.Child.Type()) { case EnLess.color: yield return Color(argument.Child); break; case EnLess.number: yield return Number(argument.Child); break; case EnLess.function: yield return Function(argument.Child, element); break; case EnLess.expressions: yield return Expression(argument.Child, element); break; case EnLess.@string: yield return new String(argument.GetAsString(Src)); break; case EnLess.keyword: yield return new Keyword(argument.GetAsString(Src)); break; default: yield return new Anonymous(argument.GetAsString(Src)); break; } } } }