public JsCallExpression(JsToken callee, params JsToken[] arguments)
 {
     Callee    = callee;
     Arguments = arguments;
 }
Exemple #2
0
 public static Dictionary <string, object> ToJsAst(this JsToken token) => token is JsExpression expression
Exemple #3
0
        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();
                }
            }
        }
Exemple #4
0
 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");
 }
Exemple #5
0
        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);
        }