public static ExpressionNode Parse(HandlebarsParserState state, HandlebarsBlockStack blockStack, SourceLocation location, string expression, IMemberLocator memberLocator = null) { int recursionLevel = 0; memberLocator = memberLocator ?? MemberLocator.Default; expression = expression.Trim(); if (expression == "this") { return SyntaxTreeExpression.Self(blockStack.GetCurrentModelType(), location); } if (expression.StartsWith("../")) { var blockNode = blockStack.FirstNode(); while (expression.StartsWith("../")) { var parentBlockNode = blockStack.GetParentNode(blockNode); if (parentBlockNode != null) { blockNode = parentBlockNode; expression = expression.Substring(3); location = location.MoveIndex(3); } recursionLevel++; } return ParseAgainstModel(blockStack.GetCurrentModelType(blockNode), expression, ExpressionScope.ModelOfParentScope, recursionLevel, memberLocator, location); } return ParseAgainstModel(blockStack.GetCurrentModelType(), expression, ExpressionScope.CurrentModelOnStack, recursionLevel, memberLocator, location); }
private static ExpressionNode ParseAgainstModel(Type modelType, string expression, ExpressionScope expressionScope, int recursionLevel, IMemberLocator memberLocator, SourceLocation location) { var dotIndex = expression.IndexOf('.'); if (dotIndex >= 0) { var subModel = ParseAgainstModel(modelType, expression.Substring(0, dotIndex), expressionScope, recursionLevel, memberLocator, location.SetLength(dotIndex)); return SyntaxTreeExpression.SubModel( subModel, ParseAgainstModel(subModel.ResultType, expression.Substring(dotIndex + 1), ExpressionScope.CurrentModelOnStack, 0, memberLocator, location.MoveIndex(dotIndex + 1)), location ); } if (expression.EndsWith("()")) { var func = memberLocator.FindMember(modelType, expression.Substring(0, expression.Length - 2), MemberTypes.Method); if (func != null) return SyntaxTreeExpression.Function(modelType, func.Name, location, expressionScope); } var prop = memberLocator.FindMember(modelType, expression, MemberTypes.Property | MemberTypes.Field); if (prop != null) { switch (prop.MemberType) { case MemberTypes.Property: return SyntaxTreeExpression.Property(modelType, prop.Name, location, expressionScope, recursionLevel); case MemberTypes.Field: return SyntaxTreeExpression.Field(modelType, prop.Name, location, expressionScope, recursionLevel); } } if (IsLateBoundAcceptingType(modelType)) return SyntaxTreeExpression.LateBound(expression, location, memberLocator, false, expressionScope, recursionLevel); throw new VeilParserException(String.Format("Unable to parse model expression '{0}' againt model '{1}'", expression, modelType.Name), location); }
private static ExpressionNode ParseAgainstModel(Type modelType, string expression, ExpressionScope expressionScope, IMemberLocator memberLocator, SourceLocation location) { var dotIndex = expression.IndexOf('.'); if (dotIndex >= 0) { var subModel = ParseAgainstModel(modelType, expression.Substring(0, dotIndex), expressionScope, memberLocator, location.SetLength(dotIndex)); return SyntaxTreeExpression.SubModel( subModel, ParseAgainstModel(subModel.ResultType, expression.Substring(dotIndex + 1), ExpressionScope.CurrentModelOnStack, memberLocator, location.MoveIndex(dotIndex + 1)), location ); } if (expression.EndsWith("()")) { var func = memberLocator.FindMethod(modelType, expression.Substring(0, expression.Length - 2)); if (func != null) return SyntaxTreeExpression.Function(modelType, func.Name, location, expressionScope); } var prop = memberLocator.FindProperty(modelType, expression); if (prop != null) return SyntaxTreeExpression.Property(modelType, prop.Name, location, expressionScope); var field = memberLocator.FindField(modelType, expression); if (field != null) return SyntaxTreeExpression.Field(modelType, field.Name, location, expressionScope); if (IsLateBoundAcceptingType(modelType)) return SyntaxTreeExpression.LateBound(expression, location, memberLocator, false, expressionScope); throw new VeilParserException( $"Unable to parse model expression '{expression}' againt model '{modelType.Name}'", location); }
/// <summary> /// Write a string literal to the TextWriter /// </summary> /// <param name="content">The string to be written</param> public static WriteLiteralNode WriteString(string content, SourceLocation location) { return new WriteLiteralNode { Location = location, LiteralContent = content }; }
public void WriteLiteral(string s, SourceLocation location) { if (TrimNextLiteral) { s = s.TrimStart(); TrimNextLiteral = false; } AddNodeToCurrentBlock(SyntaxTree.WriteString(s, location)); }
/// <summary> /// Evaluate a field on the model object /// </summary> /// <param name="modelType">The type of the scoped model</param> /// <param name="fieldName">The name of the field</param> /// <param name="scope">The scope this expression evaluated in</param> public static FieldExpressionNode Field(Type modelType, string fieldName, SourceLocation location, ExpressionScope scope = ExpressionScope.CurrentModelOnStack) { return new FieldExpressionNode { Location = location, FieldInfo = modelType.GetField(fieldName), Scope = scope }; }
/// <summary> /// Evaluate a property on the model object /// </summary> /// <param name="modelType">The type of the scoped model</param> /// <param name="propertyName">The name of the property</param> /// <param name="scope">The scope this expression evaluated in</param> public static PropertyExpressionNode Property(Type modelType, string propertyName, SourceLocation location, ExpressionScope scope = ExpressionScope.CurrentModelOnStack) { return new PropertyExpressionNode { Location = location, PropertyInfo = modelType.GetProperty(propertyName), Scope = scope }; }
/// <summary> /// Evaluate a function call on the model /// </summary> /// <param name="modelType">The type of the scoped model</param> /// <param name="functionName">The name of the function</param> /// <param name="scope">The scope this expression evaluated in</param> public static FunctionCallExpressionNode Function(Type modelType, string functionName, SourceLocation location, ExpressionScope scope = ExpressionScope.CurrentModelOnStack) { return new FunctionCallExpressionNode { Location = location, MethodInfo = modelType.GetMethod(functionName, new Type[0]), Scope = scope }; }
/// <summary> /// Evaluate the model itself e.g. Value types /// </summary> /// <param name="modelType">The type of the scoped model</param> /// <param name="scope">The scope this expression evaluated in</param> public static SelfExpressionNode Self(Type modelType, SourceLocation location, ExpressionScope scope = ExpressionScope.CurrentModelOnStack) { return new SelfExpressionNode { Location = location, ModelType = modelType, Scope = scope }; }
/// <summary> /// Evaluate an expression and write the value to the TextWriter /// </summary> /// <param name="expression">The expression to be written</param> /// <param name="htmlEncode">Indicates whether the content should be html encoded before being written</param> public static WriteExpressionNode WriteExpression(ExpressionNode expression, SourceLocation location, bool htmlEncode = false) { return new WriteExpressionNode { Location = location, Expression = expression, HtmlEncode = htmlEncode }; }
/// <summary> /// Create a sequential block of nodes /// </summary> public static BlockNode Block(SourceLocation location, params SyntaxTreeNode[] nodes) { var block = new BlockNode { Location = location }; block.AddRange(nodes); return block; }
/// <summary> /// Evaluate an expression on a sub model, can be nested to traverse any depth of sub models /// </summary> /// <param name="modelExpression">An expression referencing the model to traverse to</param> /// <param name="subModelExpression">An expression to evaluate in the scope of the model that has been traversed to</param> /// <param name="scope">The scope this expression evaluated in</param> public static SubModelExpressionNode SubModel(ExpressionNode modelExpression, ExpressionNode subModelExpression, SourceLocation location, ExpressionScope scope = ExpressionScope.CurrentModelOnStack) { return new SubModelExpressionNode { Location = location, ModelExpression = modelExpression, SubModelExpression = subModelExpression, Scope = scope }; }
/// <summary> /// Evaluates an expression and chooses between two blocks based on the truthy-ness of the result /// </summary> /// <param name="expression">The expression to evaluate</param> /// <param name="trueBlock">The block to execute when the expression is true</param> /// <param name="falseBlock">The block to evaluate when the expression is false</param> /// <returns></returns> public static ConditionalNode Conditional(ExpressionNode expression, SourceLocation location, BlockNode trueBlock, BlockNode falseBlock = null) { return new ConditionalNode { Location = location, Expression = expression, TrueBlock = trueBlock, FalseBlock = falseBlock }; }
/// <summary> /// Iterate a collection and execute the body block scoped to each item in the collection. /// Optionally execute an empty block when there are no items to iterate /// </summary> /// <param name="collectionExpression">expression to load the collection</param> /// <param name="body">Block to execute in the scope of each item</param> /// <param name="emptyBody">Block to execute when there are no items in the collection</param> public static IterateNode Iterate(ExpressionNode collectionExpression, SourceLocation location, BlockNode body, BlockNode emptyBody = null) { return new IterateNode { Location = location, Collection = collectionExpression, Body = body, EmptyBody = emptyBody ?? SyntaxTree.Block(location) }; }
protected async Task GetErrorPage(StreamWriter writer, Exception error, SourceLocation location) { var fileSystem = new EmbeddedResourceFileSystem(typeof(WebInitializer).Assembly); string content; using (var reader = new StreamReader(fileSystem.OpenRead(PathInfo.Create("Core/error_partial.html")))) { content = await reader.ReadToEndAsync(); } var templateInfo = new StringTemplateInfo("error", content); var view = await ((IViewEngine)Resolver.GetService(typeof(IViewEngine))) .CreateViewAsync(templateInfo, typeof(ErrorViewModel)).ConfigureAwait(false); if (location == null) { var modelWithoutLocation = new ErrorViewModel { ErrorMessage = error.Message, Details = error.StackTrace }; view.Render(modelWithoutLocation, new RenderingContext(writer)); return; } var templateRepository = (ITemplateRepository)this.Resolver.GetService(typeof(ITemplateRepository)); var sourceTemplate = await templateRepository.GetTemplateAsync(location.TemplateId).ConfigureAwait(false); string sourceTemplateSource; using (var reader = new StreamReader(sourceTemplate.Open())) { sourceTemplateSource = await reader.ReadToEndAsync().ConfigureAwait(false); } var model = new ErrorViewModel { TemplateId = location.TemplateId, ErrorMessage = error.Message, Details = error.StackTrace, Before = sourceTemplateSource.Substring(0, location.Index), Node = sourceTemplateSource.Substring(location.Index, location.Length), After = sourceTemplateSource.Substring(location.Index + location.Length), Text = HttpUtility.JavaScriptStringEncode(sourceTemplateSource), Range = GetRange(sourceTemplateSource, location) }; view.Render(model, new RenderingContext(writer)); }
public static ExpressionNode Parse(HandlebarsParserState state, HandlebarsBlockStack blockStack, SourceLocation location, string expression, IMemberLocator memberLocator = null) { memberLocator = memberLocator ?? MemberLocator.Default; expression = expression.Trim(); if (expression == "this") { return SyntaxTreeExpression.Self(blockStack.GetCurrentModelType(), location, ExpressionScope.CurrentModelOnStack); } if (expression.StartsWith("../")) { return ParseAgainstModel(blockStack.GetParentModelType(), expression.Substring(3), ExpressionScope.ModelOfParentScope, memberLocator, location.MoveIndex(3)); } return ParseAgainstModel(blockStack.GetCurrentModelType(), expression, ExpressionScope.CurrentModelOnStack, memberLocator, location); }
private static void AssertLocation(string input, string templateId, SourceLocation location, string enclosedText, int index) { Assert.Equal(enclosedText, input.Substring(location.Index, location.Length)); Assert.Equal(index, location.Index); Assert.Equal(enclosedText.Length, location.Length); Assert.Equal(templateId, location.TemplateId); }
/// <summary> /// Execute another template in the scope of the provided model /// </summary> /// <param name="templateName">The name of the template to execute. It will be loaded from the <see cref="IVeilContext"/></param> /// <param name="modelExpression">An expression for the model to be used as the root scope when executing the template</param> public static IncludeTemplateNode Include(string templateName, ExpressionNode modelExpression, SourceLocation location) { return new IncludeTemplateNode { Location = location, ModelExpression = modelExpression, TemplateName = templateName }; }
/// <summary> /// Evaluate whether the collectionExpression has Count > 0 /// Can only be used on types that implement <see cref="System.Collections.ICollection"/> /// </summary> /// <param name="collectionExpression">An expression referencing a Collection</param> /// <param name="location"></param> /// <param name="recursionLevel"></param> public static CollectionHasItemsExpressionNode HasItems(ExpressionNode collectionExpression, SourceLocation location, int recursionLevel = 0) { return new CollectionHasItemsExpressionNode { Location = location, CollectionExpression = collectionExpression, Scope = collectionExpression.Scope, RecursionLevel = recursionLevel }; }
/// <summary> /// Create an exception with the supplied message /// </summary> public VeilParserException(string message, SourceLocation location) : base(message) { Location = location; }
/// <summary> /// Evaluate whether the collectionExpression has Count > 0 /// Can only be used on types that implement <see cref="System.Collections.ICollection"/> /// </summary> /// <param name="collectionExpression">An expression referencing a Collection</param> /// <param name="location"></param> /// <param name="recursionLevel"></param> public static CollectionHasItemsExpressionNode HasItems(ExpressionNode collectionExpression, SourceLocation location, int recursionLevel = 0) { return(new CollectionHasItemsExpressionNode { Location = location, CollectionExpression = collectionExpression, Scope = collectionExpression.Scope, RecursionLevel = recursionLevel }); }
public static HelperExpressionNode Helper(string expression, IHelperHandler helperHandler, SourceLocation location) { var parts = expression.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); return(Helper(parts, helperHandler, location)); }
/// <summary> /// Evaluate an expression on a sub model, can be nested to traverse any depth of sub models /// </summary> /// <param name="modelExpression">An expression referencing the model to traverse to</param> /// <param name="subModelExpression">An expression to evaluate in the scope of the model that has been traversed to</param> /// <param name="location"></param> /// <param name="scope">The scope this expression evaluated in</param> public static SubModelExpressionNode SubModel(ExpressionNode modelExpression, ExpressionNode subModelExpression, SourceLocation location, ExpressionScope scope = ExpressionScope.CurrentModelOnStack) { return(new SubModelExpressionNode { Location = location, ModelExpression = modelExpression, SubModelExpression = subModelExpression, Scope = scope }); }
public static HelperExpressionNode Helper(string expression, IHelperHandler helperHandler, SourceLocation location) { var parts = expression.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); return Helper(parts, helperHandler, location); }
/// <summary> /// Evaluate a property at runtime against an unknown model type /// </summary> /// <param name="itemName">The name of the proeprty that will be searched for</param> /// <param name="isCaseSenstiive">Indcates whether the expression should be evaluated with case sensitivity</param> /// <param name="scope">The scope this expression evaluated in</param> public static LateBoundExpressionNode LateBound(string itemName, SourceLocation location, IMemberLocator memberLocator = null, bool isCaseSenstiive = true, ExpressionScope scope = ExpressionScope.CurrentModelOnStack) { return new LateBoundExpressionNode { Location = location, MemberLocator = memberLocator ?? MemberLocator.Default, ItemName = itemName, Scope = scope }; }
public static HelperExpressionNode Helper(string[] parameter, IHelperHandler helperHandler, SourceLocation location) { var data = new Dictionary <string, string>(); if (parameter.Length > 1) { foreach (var value in parameter.Skip(1)) { var tmp = value.Split(new[] { '=' }, 2); data.Add(tmp[0], tmp.Length == 2 ? tmp[1] : string.Empty); } } return(new HelperExpressionNode { Location = location, Name = parameter[0], Parameters = data, HelperHandler = helperHandler }); }
/// <summary> /// Scopes a node to a new model /// </summary> /// <param name="modelToScopeTo">An expression that evaluates to the model to scope to</param> /// <param name="node">The node to execute in the new scope</param> public static ScopedNode ScopeNode(ExpressionNode modelToScopeTo, SyntaxTreeNode node, SourceLocation location) { return new ScopedNode { Location = location, ModelToScope = modelToScopeTo, Node = node }; }
/// <summary> /// Evaluate a function call on the model /// </summary> /// <param name="modelType">The type of the scoped model</param> /// <param name="functionName">The name of the function</param> /// <param name="location"></param> /// <param name="scope">The scope this expression evaluated in</param> public static FunctionCallExpressionNode Function(Type modelType, string functionName, SourceLocation location, ExpressionScope scope = ExpressionScope.CurrentModelOnStack) { return(new FunctionCallExpressionNode { Location = location, MethodInfo = modelType.GetMethod(functionName, new Type[0]), Scope = scope }); }
private static ErrorRange GetRange(string sourceTemplateSource, SourceLocation location) { int lineNumber = 0; int idx = 0; int lastIdx = 0; while ((idx = sourceTemplateSource.IndexOf('\n', idx)) >= 0 && idx < location.Index) { lineNumber++; idx++; lastIdx = idx; } int startLineNumber = lineNumber; int startIdx = lastIdx; while ((idx = sourceTemplateSource.IndexOf('\n', idx)) >= 0 && idx < location.Index + location.Length) { lineNumber++; idx++; lastIdx = idx; } return new ErrorRange { StartRow = startLineNumber, StartColumn = location.Index - startIdx, EndRow = lineNumber, EndColumn = location.Index - lastIdx + location.Length }; }
public static HelperExpressionNode Helper(string[] parameter, IHelperHandler helperHandler, SourceLocation location) { var data = new Dictionary<string, string>(); if (parameter.Length > 1) { foreach (var value in parameter.Skip(1)) { var tmp = value.Split(new[] {'='}, 2); data.Add(tmp[0], tmp.Length == 2 ? tmp[1] : string.Empty); } } return new HelperExpressionNode { Location = location, Name = parameter[0], Parameters = data, HelperHandler = helperHandler }; }
/// <summary> /// Defines an optional point in a template that can be overridden when the template is extended. /// If the point is not overridden then the specified content is used by default /// </summary> /// <param name="overrideName">The name of the override which must match that specified in the overriding template</param> /// <param name="defaultContent">The content to use when the point is not overridden</param> public static OverridePointNode Override(string overrideName, SyntaxTreeNode defaultContent, SourceLocation location) { return new OverridePointNode { Location = location, OverrideName = overrideName, IsRequired = false, DefaultContent = defaultContent }; }
/// <summary> /// Evaluate a property on the model object /// </summary> /// <param name="modelType">The type of the scoped model</param> /// <param name="propertyName">The name of the property</param> /// <param name="location"></param> /// <param name="scope">The scope this expression evaluated in</param> /// <param name="recursionLevel"></param> public static PropertyExpressionNode Property(Type modelType, string propertyName, SourceLocation location, ExpressionScope scope = ExpressionScope.CurrentModelOnStack, int recursionLevel = 0) { return(new PropertyExpressionNode { Location = location, PropertyInfo = modelType.GetProperty(propertyName), Scope = scope, RecursionLevel = recursionLevel }); }
/// <summary> /// Flushes the TextWriter. /// Used to optimize responses in web applications. /// </summary> public static FlushNode Flush(SourceLocation location) { return new FlushNode { Location = location }; }
public ExpressionNode ParseExpression(string expression, SourceLocation location) { return HandlebarsExpressionParser.Parse(this, BlockStack, location, expression, _memberLocator); }
/// <summary> /// Evaluate whether the collectionExpression has Count > 0 /// Can only be used on types that implement <see cref="System.Collections.ICollection"/> /// </summary> /// <param name="collectionExpression">An expression referencing a Collection</param> public static CollectionHasItemsExpressionNode HasItems(ExpressionNode collectionExpression, SourceLocation location) { return new CollectionHasItemsExpressionNode { Location = location, CollectionExpression = collectionExpression, Scope = collectionExpression.Scope }; }
public static SyntaxTreeNode Helper(HelperExpressionNode helperExpression, BlockNode block, SourceLocation location) { return new HelperBlockNode { Location = location, HelperExpression = helperExpression, Block = block }; }