private void BuildElement(ElementBlock elementBlock, ICollection<string> path) { if (!elementBlock.IsRoot()) { path.Add(elementBlock.Selector.ToCss()); path.Add(elementBlock.Name); //Only add an element to the document when we have reached the end of the path if (elementBlock.Properties.Count != 0) { var cssProperties = new List<CssProperty>(); foreach (var property in elementBlock.Properties) cssProperties.Add(new CssProperty(property.Key, property.Evaluate().ToCss())); //Get path content i.e. "p > a:Hover" var pathContent = path.Where(p => !string.IsNullOrEmpty(p)).JoinStrings(string.Empty); pathContent = pathContent.StartsWith(" ") ? pathContent.Substring(1) : pathContent; document.Elements.Add(new CssElement(pathContent, cssProperties)); } } if (elementBlock.Inserts.Count == 0) return; foreach (var insert in elementBlock.Inserts) document.Elements.Add(new CssElement { InsertContent = insert.ToString() }); }
private static ElementBlock GetElementBlock() { var elementShouldBeRendered = new ElementBlock(".showme"); elementShouldBeRendered.Add(new Property("height", new Number("px", 1))); elementShouldBeRendered.Add(new Property("width", new Number("px", 1))); return elementShouldBeRendered; }
public void ShouldConvertElementBlocksInLessDomToCssDom() { var root = new ElementBlock("*"); root.Add(GetElementBlock()); var cssDocument = converter.BuildCssDocument(root); Assert.That(cssDocument.Elements.Count, Is.EqualTo(1)); }
public void CanAddSubElements() { var e2 = new ElementBlock("E2"); var element = new ElementBlock("El"); element.Add(e2); Assert.That(element.Elements.Contains(e2)); }
public ElementBlock Parse(string source, ElementBlock tail) { var parser = new nLess.LessImpl(source, Console.Out); if (!parser.Parse()) throw new ParsingException("FAILURE: Parser did not match input file"); new TreePrint(Console.Out, source, 60, new NodePrinter(parser).GetNodeName, false) .PrintTree(parser.GetRoot(), 0, 0); return new TreeBuilder(parser.GetRoot(), source).Build(tail); }
public void CanInstansiateElement() { var element = new ElementBlock("El"); Assert.AreEqual(element.Name, "El"); element = new ElementBlock("El", ">"); Assert.AreEqual(element.Name, "El"); Assert.That(element.Selector is Child); }
public void ShouldNotConvertElementBlocksInLessDomToCssDomIfInNestedFalseIfBlock() { var root = new ElementBlock("*"); var ifBlock = new IfBlock(new BoolExpression(new List<INode> {new Bool(false)})); root.Add(ifBlock); ifBlock.Add(GetElementBlock()); var cssDocument = converter.BuildCssDocument(root); Assert.That(cssDocument.Elements.Count, Is.EqualTo(0)); }
public void CanRetrieveElementPath() { var e2 = new ElementBlock("E2"); var e3 = new ElementBlock("E3"); var element = new ElementBlock("El"); element.Add(e2); e2.Add(e3); Assert.That(e3.Path().Contains(element)); }
public List<INode> GetClonedChildren(ElementBlock newParent, IEnumerable<Variable> arguments) { Guard.ExpectMaxArguments(Arguments.Count, arguments.Count(), GetMixinString(arguments)); var argumentBlock = new ElementBlock(Name) {Parent = newParent}; var rulesBlock = new ElementBlock(Name + "_rules") {Parent = argumentBlock}; var rules = new List<INode>(); var clonedChildren = Children.Select(n => n.AdoptClone(rulesBlock)).ToList(); rules.AddRange(clonedChildren); var clonedArguments = Arguments.Select(n => n.AdoptClone(argumentBlock)).Cast<Variable>().ToList(); var overridenArguments = new List<Variable>(); var foundNamedArgument = false; foreach (var arg in arguments) { int position; Variable newArgument = null; if (int.TryParse(arg.Key, out position)) { if (foundNamedArgument) throw new ParsingException(string.Format("Positional arguments must appear before all named arguments. in {0}", GetMixinString(arguments))); if (position < Arguments.Count) newArgument = clonedArguments[position]; } else { foundNamedArgument = true; newArgument = clonedArguments.FirstOrDefault(v => v.Key == arg.Key); if (newArgument == null) throw new ParsingException(string.Format("Argument '{0}' not found. in {1}", arg.Name, GetMixinString(arguments))); } if (newArgument != null) // should not be null here, should throw if null above. { newArgument.Value = (Expression) arg.Value.AdoptClone(newParent); overridenArguments.Add(newArgument); } } // avoid recursion in the case where you give an argument the same name as it's value foreach (var argument in clonedArguments.Except(overridenArguments)) argument.Value = (Expression) argument.Value.AdoptClone(newParent.Parent); argumentBlock.Children.AddRange(clonedArguments.Cast<INode>()); return rules; }
public ExtensibleEngineImpl(string source, ElementBlock tail) { //Parse the source file and run any Less preprocessors set LessDom = PipelineFactory.LessParser.Parse(source, tail); RunLessDomPreprocessors(); //Convert the LessDom to the CssDom and run any CSS Dom preprocessors set CssDom = PipelineFactory.LessToCssDomConverter.BuildCssDocument(LessDom); RunCssDomPreprocessors(); //Convert the CssDom to Css Css = PipelineFactory.CssBuilder.ToCss(CssDom); }
public ElementCommon( ElementSymbol Symbol, string Name, int Number, float AtomicWeight, ElementGroup Group, ElementPeriod Period, ElementBlock Block ) { this.Symbol = Symbol; this.Name = Name; this.Number = Number; this.AtomicWeight = AtomicWeight; this.Group = Group; this.Period = Period; this.Block = Block; }
private static IEnumerable<INode> GetMixinChildren(ElementBlock newParentBlock, ElementBlock mixinRule, ElementBlock mixinBlock) { if (mixinBlock.Children == null) return null; IEnumerable<INode> children; if (mixinBlock is MixinBlock) { var mixin = ((MixinBlock)mixinBlock); List<Variable> arguments = null; if (mixinRule is MixinBlock) arguments = (mixinRule as MixinBlock).Arguments; children = mixin.GetClonedChildren(newParentBlock, arguments ?? new List<Variable>()); } else children = mixinBlock.Children; return children; }
private static IEnumerable<INode> GetMixinChildren(ElementBlock elementBlock, IEnumerable<Variable> variables, IEnumerable<INode> mixinChildren) { var detatchedElementBlock = new ElementBlock(elementBlock.Name + "_detatched"); detatchedElementBlock.Parent = elementBlock; var clonedChildren = mixinChildren.Select(n => n.AdoptClone(detatchedElementBlock)).ToList(); var rules = new List<INode>(); var clonedVariables = clonedChildren.Where(n => n is Variable).Cast<Variable>().ToList(); var otherChildren = clonedChildren.Where(n => !(n is Variable)); rules.AddRange(otherChildren); foreach (var variable in variables) { int position; Variable newVariable = null; if( int.TryParse(variable.Key, out position) ) { if(position < clonedVariables.Count) newVariable = clonedVariables[position]; } else { newVariable = clonedVariables.FirstOrDefault(v => v.Key == variable.Key); } if (newVariable == null) // throw continue; newVariable.Value = variable.Value; } detatchedElementBlock.Children.AddRange(clonedVariables.Cast<INode>()); rules.AddRange(clonedVariables.Cast<INode>()); return rules; }
/// <summary> /// selector : (s select element s)+ arguments? ; /// </summary> /// <param name="node"></param> /// <returns></returns> private IEnumerable<ElementBlock> Selector(PegNode node) { var enumerator = node.AsEnumerable().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.ToEnLess() == EnLess.arguments; if (isMixinWithArgs) block = new PureMixinBlock(name, selector); else block = new ElementBlock(name, selector); if (isMixinWithArgs) { var arguments = GetMixinArguments(next, block); enumerator.MoveNext(); foreach (var argument in arguments) block.Add(argument); } yield return block; } }
/// <summary> /// ruleset: selectors [{] ws prsimary ws [}] ws / ws selectors ';' ws; /// </summary> /// <param name="node"></param> /// <param name="elementBlock"></param> private void RuleSet(PegNode node, ElementBlock elementBlock) { foreach (var el in Selectors(node.child_, els => StandardSelectors(elementBlock, els))) Primary(node.child_.next_, el); }
/// <summary> /// primary: (import / declaration / ruleset / comment)* ; /// </summary> /// <param name="node"></param> /// <param name="elementBlock"></param> private ElementBlock Primary(PegNode node, ElementBlock elementBlock) { foreach (var nextPrimary in node.AsEnumerable()) { switch (nextPrimary.id_.ToEnLess()) { 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; }
private ElementBlock Primary(PegNode node) { var element = new ElementBlock(""); return Primary(node, element); }
/// <summary> /// operation_expressions: expression (operator expression)+; /// </summary> /// <param name="node"></param> /// <param name="elementBlock"></param> /// <returns></returns> private IEnumerable<INode> OperationExpressions(PegNode node, ElementBlock elementBlock) { yield return Expression(node.child_, elementBlock); node = node.next_; //Tail while (node != null) { switch (node.id_.ToEnLess()) { case EnLess.@operator: yield return new Operator(node.GetAsString(Src), elementBlock); break; case EnLess.expression: yield return Expression(node.child_, elementBlock); break; case EnLess.comment: node.ToString(); break; } node = node.next_; } }
/// <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(PegNode node, ElementBlock element) { foreach (var argument in node.AsEnumerable()) { if (argument.child_ == null) yield return new Anonymous(argument.GetAsString(Src)); else { switch (argument.child_.id_.ToEnLess()) { 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; } } } }
/// <summary> /// import : ws '@import' S import_url medias? s ';' ; /// </summary> /// <param name="node"></param> private IEnumerable<INode> Import(PegNode node, ElementBlock elementBlock) { node = (node.child_ ?? node); // // var path = ""; // if(node.ToEnLess()==EnLess.expressions) // { // var values = Expressions(node, element); // var fakeVariableName = new Variable(string.Format("@{0}", DateTime.Now.Ticks), values); // element.Add(fakeVariableName); // path = fakeVariableName.ToCss(); // } // else // { // path = (node).GetAsString(Src) // .Replace("\"", "").Replace("'", ""); // } var path = (node).GetAsString(Src) .Replace("\"", "").Replace("'", ""); if(HttpContext.Current!=null){ path = HttpContext.Current.Server.MapPath(path); } if(File.Exists(path)) { var engine = new ExtensibleEngineImpl(File.ReadAllText(path), elementBlock); return engine.LessDom.Children; } return new List<INode>(); }
private IEnumerable<Variable> GetMixinArguments(PegNode arguments, ElementBlock block) { var enumerator = arguments.AsEnumerable().GetEnumerator(); var variables = new List<Variable>(); var position = 0; while (enumerator.MoveNext()) { var node = enumerator.Current; string name; IEnumerable<INode> value; if (node.child_.ToEnLess() == 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 PegNode(null, (int) EnLess.arguments); tmpNode.child_ = new PegNode(tmpNode, (int)EnLess.argument); 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_.ToEnLess() != EnLess.argument) break; position++; } return variables; }
/// <summary> /// function: function_name arguments ; /// </summary> /// <param name="node"></param> /// <param name="element"></param> /// <returns></returns> private INode Function(PegNode node, ElementBlock element) { var funcName = node.child_.GetAsString(Src); var arguments = Arguments(node.child_.next_, element); return new Function(funcName, arguments.ToList()); }
/// <summary> /// expressions: operation_expressions / space_delimited_expressions / [-a-zA-Z0-9_%*/.&=:,#+? \[\]()]+ ; /// </summary> /// <param name="node"></param> /// <param name="elementBlock"></param> /// <returns></returns> private IEnumerable<INode> Expressions(PegNode node, ElementBlock elementBlock) { // Expression switch (node.id_.ToEnLess()) { case EnLess.operation_expressions: return OperationExpressions(node.child_, elementBlock).ToList(); case EnLess.space_delimited_expressions: return SpaceDelimitedExpressions(node.child_, elementBlock).ToList(); default: if (node.child_ == null) //CatchAll return new List<INode> { new Anonymous(node.GetAsString(Src)) }; return Expressions(node.child_, elementBlock); } }
/// <summary> /// entity : function / fonts / accessor / keyword / variable / literal ; /// </summary> /// <param name="node"></param> /// <param name="elementBlock"></param> /// <returns></returns> private INode Entity(PegNode node, ElementBlock elementBlock) { switch (node.id_.ToEnLess()) { case EnLess.literal: return Entity(node.child_, elementBlock); case EnLess.number: return Number(node); case EnLess.color: return Color(node); case EnLess.variable: return Variable(node); case EnLess.accessor: return Accessor(node.child_, elementBlock); case EnLess.fonts: return Fonts(node); case EnLess.keyword: return Keyword(node); case EnLess.function: return Function(node, elementBlock); case EnLess.cursors: return Cursors(node); default: return new Anonymous(node.GetAsString(Src)); } }
/// <summary> /// declaration: standard_declaration / catchall_declaration ; /// </summary> /// <param name="node"></param> /// <param name="elementBlock"></param> private void Declaration(PegNode node, ElementBlock elementBlock) { var name = node.GetAsString(Src).Replace(" ", ""); var nextNode = node.next_; if(nextNode == null){ // TODO: emit warning: empty declaration // return; } if (nextNode.ToEnLess() == EnLess.comment) nextNode = nextNode.next_; var values = Expressions(nextNode, elementBlock); var property = name.StartsWith("@") ? new Variable(name, values) : new Property(name, values); elementBlock.Add(property); }
/// <summary> /// space_delimited_expressions: expression (WS expression)* important? ; /// </summary> /// <param name="node"></param> /// <param name="elementBlock"></param> /// <returns></returns> private IEnumerable<INode> SpaceDelimitedExpressions(PegNode node, ElementBlock elementBlock) { yield return Expression(node.child_, elementBlock); node = node.next_; //Tail while (node != null) { switch (node.id_.ToEnLess()) { case EnLess.expression: yield return Expression(node.child_, elementBlock); break; case EnLess.important: yield return new Keyword("!important"); break; } node = node.next_; } }
private IEnumerable<INode> Insert(PegNode node, ElementBlock elementBlock) { node = (node.child_ ?? node); var path = (node).GetAsString(Src) .Replace("\"", "").Replace("'", ""); if (HttpContext.Current != null){ path = HttpContext.Current.Server.MapPath(path); } if (File.Exists(path)){ var text = File.ReadAllText(path); elementBlock.Add(new Insert(text)); } return new List<INode>(); }
/// <summary> /// Main entry point for the build /// </summary> /// <returns></returns> public ElementBlock Build(ElementBlock tail) { return tail == null ? Build() : Primary(Root.child_, tail); }
/// <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(PegNode 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(PegNode node, ElementBlock elementBlock) { var root = elementBlock.GetRoot(); var rules = new List<INode>(); foreach (var mixins in node.AsEnumerable()) { var selectors = Selectors(mixins, els => els).ToList(); if (selectors.Count() > 1) { foreach (var el in selectors) root = root.Descend(el.Selector, el); if (root.Children != null) rules.AddRange(root.Children); } else { var el = selectors.First(); foreach (var mixinElement in root.Nearests(el.Name)) { if (mixinElement.Children == null) continue; var children = GetMixinChildren(elementBlock, el.Variables, mixinElement.Children); rules.AddRange(children); el.Parent = elementBlock; } } } elementBlock.Children.AddRange(rules); }
/// <summary> /// expression: '(' s expressions s ')' / entity ; /// </summary> /// <param name="node"></param> /// <param name="elementBlock"></param> /// <returns></returns> private INode Expression(PegNode node, ElementBlock elementBlock) { switch (node.id_.ToEnLess()) { case EnLess.expressions: return new Expression(Expressions(node, elementBlock), elementBlock); case EnLess.entity: var entity = Entity(node.child_, elementBlock); entity.Parent = elementBlock; return entity; default: throw new ParsingException("Expression should either be child expressions or an entity"); } }
/// <summary> /// accessor: accessor_name '[' accessor_key ']'; /// </summary> /// <param name="node"></param> /// <param name="elementBlock"></param> /// <returns></returns> private INode Accessor(PegNode node, ElementBlock elementBlock) { var ident = node.GetAsString(Src); var key = node.next_.GetAsString(Src).Replace("'", ""); var el = elementBlock.NearestAs<ElementBlock>(ident); if (el != null) { var prop = el.GetAs<Property>(key); if (prop != null) return prop.Value; } return new Anonymous(""); }