public object reduce(ScriptScopeContext scope, object target, object expression, object scopeOptions)
        {
            var  items    = target.AssertEnumerable(nameof(reduce));
            Type itemType = null;

            if (!(expression is JsArrowFunctionExpression arrowExpr))
            {
                throw new NotSupportedException($"{nameof(reduce)} expects an arrow expression but was instead '{expression.GetType().Name}'");
            }

            if (arrowExpr.Params.Length != 2)
            {
                throw new NotSupportedException($"{nameof(reduce)} expects 2 params but was instead {arrowExpr.Params.Length}");
            }

            var accumulatorBinding = arrowExpr.Params[0].Name;
            var itemBinding        = arrowExpr.Params[1].Name;
            var expr = arrowExpr.Body;

            var scopedParams = scopeOptions as Dictionary <string, object> ?? new Dictionary <string, object>();

            var accumulator = scopedParams.TryGetValue("initialValue", out object initialValue)
                ? initialValue.ConvertTo <double>()
                : !(scopeOptions is IDictionary)
                    ? scopeOptions.ConvertTo <double>()
                    : 0;

            var i = 0;

            scope = scope.Clone();
            foreach (var item in items)
            {
                if (item == null)
                {
                    continue;
                }

                scope.AddItemToScope(accumulatorBinding, accumulator);
                scope.AddItemToScope("index", i++);
                scope.AddItemToScope(itemBinding, item);

                var result = expr.Evaluate(scope);
                if (result == null)
                {
                    continue;
                }
                if (itemType == null)
                {
                    itemType = result.GetType();
                }

                accumulator = result.ConvertTo <double>();
            }

            return(itemType == null || itemType == typeof(double)
                ? accumulator
                : accumulator.ConvertTo(itemType));
        }
        public IEnumerable <object> skipWhile(ScriptScopeContext scope, object target, object expression, object scopeOptions)
        {
            var items = target.AssertEnumerable(nameof(skipWhile));
            var expr  = scope.AssertExpression(nameof(skipWhile), expression, scopeOptions, out var itemBinding);

            var to           = new List <object>();
            var i            = 0;
            var keepSkipping = true;

            foreach (var item in items)
            {
                scope.AddItemToScope(itemBinding, item, i++);
                var result = expr.EvaluateToBool(scope);
                if (!result)
                {
                    keepSkipping = false;
                }

                if (!keepSkipping)
                {
                    to.Add(item);
                }
            }

            return(to);
        }
        public List <object[]> zip(ScriptScopeContext scope, IEnumerable original, object itemsOrBinding)
        {
            var    to        = new List <object[]>();
            string literal   = itemsOrBinding as string;
            var    arrowExpr = itemsOrBinding as JsArrowFunctionExpression;

            if (literal != null || arrowExpr != null)
            {
                var token = literal != null
                    ? literal.GetCachedJsExpression(scope)
                    : arrowExpr.Body;

                var binding = arrowExpr != null
                    ? arrowExpr.Params[0].Name
                    : "it";

                var i = 0;
                foreach (var a in original)
                {
                    scope.AddItemToScope(binding, a, i++);
                    var bindValue = token.Evaluate(scope);
                    if (bindValue is IEnumerable current)
                    {
                        foreach (var b in current)
                        {
                            to.Add(new[] { a, b });
                        }
                    }
                    else if (bindValue != null)
                    {
                        throw new ArgumentException($"{nameof(zip)} in '{scope.Page.VirtualPath}' requires '{literal}' to evaluate to an IEnumerable, but evaluated to a '{bindValue.GetType().Name}' instead");
                    }
                }
            }
            else if (itemsOrBinding is IEnumerable current)
            {
                var currentArray = current.Cast <object>().ToArray();
                foreach (var a in original)
                {
                    foreach (var b in currentArray)
                    {
                        to.Add(new[] { a, b });
                    }
                }
            }

            return(to);
        }
        public IgnoreResult forEach(ScriptScopeContext scope, object target, JsArrowFunctionExpression arrowExpr)
        {
            var token = arrowExpr.Body;

            scope = scope.Clone();
            if (target is IList list)
            {
                var itemBinding  = arrowExpr.Params[0].Name;
                var indexBinding = arrowExpr.Params.Length > 1 ? arrowExpr.Params[1].Name : ScriptConstants.Index;
                var arrayBinding = arrowExpr.Params.Length > 2 ? arrowExpr.Params[2].Name : null;

                for (var i = 0; i < list.Count; i++)
                {
                    scope.ScopedParams[indexBinding] = i;
                    if (arrayBinding != null)
                    {
                        scope.ScopedParams[arrayBinding] = list;
                    }

                    scope = scope.AddItemToScope(itemBinding, list[i]);
                    token.Evaluate(scope);
                }
            }
            else if (target is IDictionary d)
            {
                if (arrowExpr.Params.Length != 2)
                {
                    throw new NotSupportedException("Dictionary.forEach requires 2 lambda params");
                }

                var keyBinding   = arrowExpr.Params[0].Name;
                var valueBinding = arrowExpr.Params[1].Name;

                foreach (var key in d.Keys)
                {
                    scope.ScopedParams[keyBinding]   = key;
                    scope.ScopedParams[valueBinding] = d[key];
                    token.Evaluate(scope);
                }
            }
            else
            {
                throw new NotSupportedException("Can only use forEach on Lists or Dictionaries");
            }

            return(IgnoreResult.Value);
        }
        public bool all(ScriptScopeContext scope, object target, object expression, object scopeOptions)
        {
            var items = target.AssertEnumerable(nameof(all));
            var expr  = scope.AssertExpression(nameof(all), expression, scopeOptions, out var itemBinding);

            var i = 0;

            foreach (var item in items)
            {
                scope.AddItemToScope(itemBinding, item, i++);
                var result = expr.EvaluateToBool(scope);
                if (!result)
                {
                    return(false);
                }
            }

            return(true);
        }
        public int count(ScriptScopeContext scope, object target, object expression, object scopeOptions)
        {
            var items = target.AssertEnumerable(nameof(count));
            var expr  = scope.AssertExpression(nameof(count), expression, scopeOptions, out var itemBinding);

            var total = 0;
            var i     = 0;

            foreach (var item in items)
            {
                scope.AddItemToScope(itemBinding, item, i++);
                var result = expr.EvaluateToBool(scope);
                if (result)
                {
                    total++;
                }
            }

            return(total);
        }
        public int findIndex(ScriptScopeContext scope, IList list, JsArrowFunctionExpression expression)
        {
            var items       = list.AssertEnumerable(nameof(findIndex));
            var itemBinding = expression.Params[0].Name;
            var expr        = expression.Body;

            var i = 0;

            foreach (var item in items)
            {
                scope.AddItemToScope(itemBinding, item, i);
                var result = expr.EvaluateToBool(scope);
                if (result)
                {
                    return(i);
                }
                i++;
            }

            return(-1);
        }
        private object applyInternal(string filterName, ScriptScopeContext scope, object target, object expression, object scopeOptions,
                                     Func <double, double, double> fn)
        {
            if (target is double d)
            {
                return(fn(d, expression.ConvertTo <double>()));
            }
            if (target is int i)
            {
                return((int)fn(i, expression.ConvertTo <double>()));
            }
            if (target is long l)
            {
                return((long)fn(l, expression.ConvertTo <double>()));
            }

            var items = target.AssertEnumerable(filterName);
            var total = filterName == nameof(min)
                ? double.MaxValue
                : 0;
            Type itemType = null;

            if (expression != null)
            {
                var expr = scope.AssertExpression(filterName, expression, scopeOptions, out var itemBinding);

                foreach (var item in items)
                {
                    if (item == null)
                    {
                        continue;
                    }

                    scope.AddItemToScope(itemBinding, item);
                    var result = expr.Evaluate(scope);
                    if (result == null)
                    {
                        continue;
                    }
                    if (itemType == null)
                    {
                        itemType = result.GetType();
                    }

                    total = fn(total, result.ConvertTo <double>());
                }
            }
            else
            {
                foreach (var item in items)
                {
                    if (item == null)
                    {
                        continue;
                    }
                    if (itemType == null)
                    {
                        itemType = item.GetType();
                    }
                    total = fn(total, item.ConvertTo <double>());
                }
            }

            if (filterName == nameof(min) && itemType == null)
            {
                return(0);
            }

            if (expression == null && itemType == null)
            {
                itemType = target.GetType().FirstGenericType()?.GetGenericArguments().FirstOrDefault();
            }

            return(itemType == null || itemType == typeof(double)
                ? total
                : total.ConvertTo(itemType));
        }
Exemple #9
0
 public static ScriptScopeContext AddItemToScope(this ScriptScopeContext scope, string itemBinding, object item, int index)
 {
     scope.ScopedParams[ScriptConstants.Index] = index;
     return(scope.AddItemToScope(itemBinding, item));
 }