/// <inheritdoc /> protected override void Render(Block block, object[] arguments, Dictionary<string, object> maps, RenderContext context, TextWriter writer) { if (context.Service == null) { // There is nothing we can do, no service has been assigned. return; } var options = new HelperOptions() { Arguments = arguments, Parameters = maps, RenderContext = context }; if (block.Type == BlockType.Tag) { var children = block.Children.ToList(); children.RemoveAt(0); children.RemoveAt(children.Count - 1); options.Render = (data) => RenderHelperChildren(children, context, data); } string result = context.Service.RunHelper(block.Name, options); Write(context, writer, new SafeString(result)); }
/// <inheritdoc /> protected override void Render(Block block, object[] arguments, Dictionary<string, object> maps, RenderContext context, TextWriter writer) { var enumerable = arguments[0]; if (!(enumerable is IEnumerable)) { enumerable = new object[] { enumerable }; } var children = block.Children.ToList(); children.RemoveAt(0); children.RemoveAt(children.Count - 1); var elseChildren = new List<SyntaxTreeNode>(); // Determine if there is an alternate {{else}} block which denotes content to display when there are no items. var elseNode = children.Find(n => n.IsBlock && (((Block)n).Name == "else" || ((Block)n).Name == "^")); if (elseNode != null) { int elseIndex = children.IndexOf(elseNode); elseChildren = children.Skip(elseIndex + 1).ToList(); children = children.Take(elseIndex).ToList(); } RenderEnumerable((IEnumerable)enumerable, context, children, elseChildren); }
/// <inheritdoc /> protected override void Render(Block block, object[] arguments, Dictionary<string, object> maps, RenderContext context, TextWriter writer) { if (context.Service == null) { // No service, can't do anything. return; } var span = block.Children.FirstOrDefault(c => !c.IsBlock && ((Span)c).Kind == SpanKind.Expression) as Span; if (span == null) { // Malformed tag? return; } string name = span.Content; object model = arguments.FirstOrDefault(); if (model != null) { using (var scope = context.BeginScope(model)) { Write(scope.ScopeContext, writer, new SafeString(context.Service.RunPartial(name, scope.ScopeContext))); } } else { Write(context, writer, new SafeString(context.Service.RunPartial(name, context))); } }
/// <inheritdoc /> protected override void Render(Block block, object[] arguments, Dictionary<string, object> maps, RenderContext context, TextWriter writer) { var children = block.Children.ToList(); children.RemoveAt(0); children.RemoveAt(children.Count - 1); var elseChildren = new List<SyntaxTreeNode>(); // Determine if there is an alternate {{else}} block which denotes content to display when predicate is false. var elseNode = children.Find(n => n.IsBlock && (((Block)n).Name == "else" || ((Block)n).Name == "^")); if (elseNode != null) { int elseIndex = children.IndexOf(elseNode); elseChildren = children.Skip(elseIndex + 1).ToList(); children = children.Take(elseIndex).ToList(); } if (!IsTruthy(arguments[0])) { RenderChildren(children, context); } else if (elseChildren.Count > 0) { RenderChildren(elseChildren, context); } }
/// <summary> /// Initialises a new instance of <see cref="BlockBuilder"/> /// </summary> /// <param name="original">The original block.</param> public BlockBuilder(Block original) { Type = original.Type; Name = original.Name; Descriptor = original.Descriptor; Children = new List<SyntaxTreeNode>(original.Children); }
/// <inheritdoc /> public virtual void VisitBlock(Block block) { VisitStartBlock(block); foreach (var node in block.Children) { node.Accept(this); } VisitEndBlock(block); }
/// <inheritdoc /> protected override void Render(Block block, object[] arguments, Dictionary<string, object> maps, RenderContext context, TextWriter writer) { string name = block.Name; var children = block.Children.ToList(); // Get the TagElement block. var tagElement = (Block)children[0]; // Determine if the block prefix symbol (either # or ^) is a caret. bool isNegatedSection = tagElement.Children.Cast<Span>().Where(s => s.Kind == SpanKind.MetaCode).ToArray()[1].Content == "^"; children.RemoveAt(0); children.RemoveAt(children.Count - 1); if (string.IsNullOrEmpty(name)) { // Nothing we can do. return; } object value = context.ResolveValue(name, false); if (value == null && !isNegatedSection) { // No value, nothing we can do :-( return; } if ((value is IEnumerable) && !(value is string) && !isNegatedSection) { RenderEnumerable((IEnumerable)value, context, children, null); } else { bool isTruthy = IsTruthy(value); // Treat this as a conditional block. if (isTruthy != isNegatedSection) { if (isTruthy) { // Create a scope around the value. using (var scope = context.BeginScope(value)) { RenderChildren(children, context); } } else { RenderChildren(children, context); } } } }
/// <summary> /// Collapses the next whitespace element from the given block, offset by the child element. /// </summary> /// <param name="block">The block.</param> /// <param name="element">The child element.</param> private void CollapseNextWhiteSpace(Block block, SyntaxTreeNode element) { if (block == null) { return; } var children = block.Children.ToList(); int index = children.IndexOf(element); if (index < (children.Count - 1)) { var potential = children[index + 1] as Span; if (potential != null && potential.Kind == SpanKind.WhiteSpace) { potential.Collapsed = true; } } }
/// <summary> /// Parses the conditional blocks. /// </summary> /// <param name="target">The target.</param> /// <returns>The set of parsed conditional blocks.</returns> private IEnumerable<Tuple<Block, List<SyntaxTreeNode>>> ParseConditionalBlocks(Block target) { var result = new List<Tuple<Block, List<SyntaxTreeNode>>>(); Block current = null; var nodes = new List<SyntaxTreeNode>(); var children = target.Children.ToList(); children.RemoveAt(children.Count - 1); foreach (var node in children) { bool isNewElement = false; if (node.IsBlock) { var block = (Block)node; if (block.Type == BlockType.TagElement && (block.Name == "if" || block.Name == "elseif" || block.Name == "else" || block.Name == "^")) { if (current != null) { result.Add(Tuple.Create(current, nodes)); nodes = new List<SyntaxTreeNode>(); } current = block; isNewElement = true; } } if (!isNewElement) { nodes.Add(node); } } if (current != null) { result.Add(Tuple.Create(current, nodes)); } return result; }
/// <inheritdoc /> public override void Render(Block target, RenderContext context, TextWriter writer) { // 1. Figure out branching blocks. // 2. For each branching block (first to last), resolve conditional argument. var blocks = ParseConditionalBlocks(target); foreach (var block in blocks) { var arguments = GetArgumentsAndMappedParameters(block.Item1, context); if (block.Item1.Name == "if" || block.Item1.Name == "elseif") { if (IsTruthy(arguments.Item1[0])) { RenderChildren(block.Item2, context); break; } } else { RenderChildren(block.Item2, context); break; } } }
/// <summary> /// Initializes a new instance of the <see cref="ParserResults"/> class. /// </summary> /// <param name="succes">We parsing succesful?</param> /// <param name="document">The document.</param> /// <param name="errors">The errors.</param> public ParserResults(bool succes, Block document, IList<Error> errors) { Success = succes; Document = document; Errors = errors; }
/// <summary> /// Initializes a new instance of the <see cref="ParserResults"/> class. /// </summary> /// <param name="document">The document.</param> /// <param name="errors">The errors.</param> public ParserResults(Block document, IList<Error> errors) : this(errors == null || errors.Count == 0, document, errors) { }
/// <inheritdoc /> protected override void Render(Block block, object[] arguments, Dictionary<string, object> maps, RenderContext context, TextWriter writer) { }
private void ParserTest(string content, Block document, TagProvidersCollection providers = null) { providers = providers ?? TagProvidersCollection.Default; var output = new StringBuilder(); using (var reader = new StringReader(content)) { using (var source = new SeekableTextReader(reader)) { var errors = new ParserErrorSink(); var parser = new HandlebarsParser(); var context = new ParserContext(source, parser, errors, providers); parser.Context = context; parser.ParseDocument(); var results = context.CompleteParse(); var comparer = new EquivalanceComparer(output, 0); Assert.True(comparer.Equals(document, results.Document), output.ToString()); } } }
/// <summary> /// Processed before any child nodes of a block are visited. /// </summary> /// <param name="block">The block.</param> public virtual void VisitStartBlock(Block block) { }
/// <summary> /// Processed after a all child nodes of a block are visited. /// </summary> /// <param name="block">The block.</param> public virtual void VisitEndBlock(Block block) { }