public JsCallExpression(JsToken callee, params JsToken[] arguments) { Callee = callee; Arguments = arguments; }
public static Dictionary <string, object> ToJsAst(this JsToken token) => token is JsExpression expression
public override async Task WriteAsync(ScriptScopeContext scope, PageBlockFragment block, CancellationToken token) { var htmlAttrs = block.Argument.GetJsExpressionAndEvaluate(scope) as Dictionary <string, object>; var hasEach = false; IEnumerable each = null; var binding = "it"; var hasExplicitBinding = false; JsToken where = null; if (htmlAttrs != null) { if (htmlAttrs.TryGetValue("if", out var oIf)) { if (Script.DefaultScripts.isFalsy(oIf)) { return; } htmlAttrs.Remove("if"); } if (htmlAttrs.TryGetValue(nameof(where), out var oWhere)) { if (!(oWhere is string whereExpr)) { throw new NotSupportedException($"'where' should be a string expression but instead found '{oWhere.GetType().Name}'"); } where = whereExpr.GetCachedJsExpression(scope); htmlAttrs.Remove(nameof(where)); } if (htmlAttrs.TryGetValue(nameof(each), out var oEach)) { hasEach = true; htmlAttrs.Remove(nameof(each)); } each = oEach as IEnumerable; if (htmlAttrs.TryGetValue("it", out var oIt) && oIt is string it) { binding = it; hasExplicitBinding = true; htmlAttrs.Remove("it"); } if (htmlAttrs.TryGetValue("class", out var oClass)) { var cls = scope.Context.HtmlMethods.htmlClassList(oClass); if (string.IsNullOrEmpty(cls)) { htmlAttrs.Remove("class"); } else { htmlAttrs["class"] = cls; } } } var attrString = scope.Context.HtmlMethods.htmlAttrsList(htmlAttrs); if (HtmlScripts.VoidElements.Contains(Tag)) //e.g. img, input, br, etc { await scope.OutputStream.WriteAsync($"<{Tag}{attrString}>{Suffix}", token).ConfigAwait(); } else { if (hasEach) { var hasElements = each != null && each.GetEnumerator().MoveNext(); if (hasElements) { await scope.OutputStream.WriteAsync($"<{Tag}{attrString}>{Suffix}", token).ConfigAwait(); var index = 0; var whereIndex = 0; foreach (var element in each) { // Add all properties into scope if called without explicit in argument var scopeArgs = !hasExplicitBinding && CanExportScopeArgs(element) ? element.ToObjectDictionary() : new Dictionary <string, object>(); scopeArgs[binding] = element; scopeArgs[nameof(index)] = AssertWithinMaxQuota(whereIndex++); var itemScope = scope.ScopeWithParams(scopeArgs); if (where != null) { var result = where.EvaluateToBool(itemScope); if (!result) { continue; } } itemScope.ScopedParams[nameof(index)] = AssertWithinMaxQuota(index++); await WriteBodyAsync(itemScope, block, token).ConfigAwait(); } await scope.OutputStream.WriteAsync($"</{Tag}>{Suffix}", token).ConfigAwait(); } else { await WriteElseAsync(scope, block.ElseBlocks, token).ConfigAwait(); } } else { await scope.OutputStream.WriteAsync($"<{Tag}{attrString}>{Suffix}", token).ConfigAwait(); await WriteBodyAsync(scope, block, token).ConfigAwait(); await scope.OutputStream.WriteAsync($"</{Tag}>{Suffix}", token).ConfigAwait(); } } }
public JsBinaryExpression(JsToken left, JsBinaryOperator @operator, JsToken right) { Left = left ?? throw new SyntaxErrorException($"Left Expression missing in Binary Expression"); Operator = @operator ?? throw new SyntaxErrorException($"Operator missing in Binary Expression"); Right = right ?? throw new SyntaxErrorException($"Right Expression missing in Binary Expression"); }
private static Expression CreateBindingExpression(Type type, ReadOnlyMemory <char> expr, ParameterExpression scope, ParameterExpression instance) { Expression body = Expression.Convert(instance, type); var currType = type; var pos = 0; var depth = 0; var delim = ".".AsMemory(); while (expr.TryReadPart(delim, out ReadOnlyMemory <char> member, ref pos)) { try { if (member.IndexOf('(') >= 0) { throw new BindingExpressionException( $"Calling methods in '{expr}' is not allowed in binding expressions, use a filter instead.", member.ToString(), expr.ToString()); } var indexerPos = member.IndexOf('['); if (indexerPos >= 0) { var prop = member.LeftPart('['); var indexer = member.RightPart('['); indexer.Span.ParseJsExpression(out var token); if (token is JsCallExpression) { throw new BindingExpressionException($"Only constant binding expressions are supported: '{expr}'", member.ToString(), expr.ToString()); } var value = JsToken.UnwrapValue(token); var valueExpr = value == null ? (Expression)Expression.Call( typeof(ScriptTemplateUtils).GetStaticMethod(nameof(EvaluateBinding)), scope, Expression.Constant(token)) : Expression.Constant(value); if (currType == typeof(string)) { body = CreateStringIndexExpression(body, token, scope, valueExpr, ref currType); } else if (currType.IsArray) { if (token != null) { var evalAsInt = typeof(ScriptTemplateUtils).GetStaticMethod(nameof(EvaluateBindingAs)) .MakeGenericMethod(typeof(int)); body = Expression.ArrayIndex(body, Expression.Call(evalAsInt, scope, Expression.Constant(token))); } else { body = Expression.ArrayIndex(body, valueExpr); } } else if (depth == 0) { var pi = AssertProperty(currType, "Item", expr); currType = pi.PropertyType; if (token != null) { var indexType = pi.GetGetMethod()?.GetParameters().FirstOrDefault()?.ParameterType; if (indexType != typeof(object)) { var evalAsInt = typeof(ScriptTemplateUtils).GetStaticMethod(nameof(EvaluateBindingAs)) .MakeGenericMethod(indexType); valueExpr = Expression.Call(evalAsInt, scope, Expression.Constant(token)); } } body = Expression.Property(body, "Item", valueExpr); } else { var pi = AssertProperty(currType, prop.ToString(), expr); currType = pi.PropertyType; body = Expression.PropertyOrField(body, prop.ToString()); if (currType == typeof(string)) { body = CreateStringIndexExpression(body, token, scope, valueExpr, ref currType); } else { var indexMethod = currType.GetMethod("get_Item", new[] { value.GetType() }); body = Expression.Call(body, indexMethod, valueExpr); currType = indexMethod.ReturnType; } } } else { if (depth >= 1) { var memberName = member.ToString(); if (typeof(IDictionary).IsAssignableFrom(currType)) { var pi = AssertProperty(currType, "Item", expr); currType = pi.PropertyType; body = Expression.Property(body, "Item", Expression.Constant(memberName)); } else { body = Expression.PropertyOrField(body, memberName); var pi = currType.GetProperty(memberName); if (pi != null) { currType = pi.PropertyType; } else { var fi = currType.GetField(memberName); if (fi != null) { currType = fi.FieldType; } } } } } depth++; } catch (BindingExpressionException) { throw; } catch (Exception e) { throw new BindingExpressionException($"Could not compile '{member}' from expression '{expr}'", member.ToString(), expr.ToString(), e); } } return(body); }