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)); }
public static ScriptScopeContext AddItemToScope(this ScriptScopeContext scope, string itemBinding, object item, int index) { scope.ScopedParams[ScriptConstants.Index] = index; return(scope.AddItemToScope(itemBinding, item)); }