diff --git a/src/lib/js/array.rs b/src/lib/js/array.rs index 07f252fed1..cd1e6a8d62 100644 --- a/src/lib/js/array.rs +++ b/src/lib/js/array.rs @@ -271,6 +271,41 @@ pub fn unshift(this: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue Ok(to_value(temp)) } +/// Array.prototype.every ( callback, [ thisArg ] ) +/// +/// The every method executes the provided callback function once for each +/// element present in the array until it finds the one where callback returns +/// a falsy value. It returns `false` if it finds such element, otherwise it +/// returns `true`. +/// +pub fn every(this: &Value, args: &[Value], interpreter: &mut Interpreter) -> ResultValue { + if args.is_empty() { + return Err(to_value( + "missing callback when calling function Array.prototype.every".to_string(), + )); + } + let callback = &args[0]; + let this_arg = if args.len() > 1 { + args[1].clone() + } else { + Gc::new(ValueData::Undefined) + }; + let mut i = 0; + let max_len: i32 = from_value(this.get_field_slice("length")).unwrap(); + let mut len = max_len; + while i < len { + let element = this.get_field(&i.to_string()); + let arguments = vec![element.clone(), to_value(i), this.clone()]; + let result = interpreter.call(callback, &this_arg, arguments)?.is_true(); + if !result { + return Ok(to_value(false)); + } + len = std::cmp::min(max_len, from_value(this.get_field_slice("length")).unwrap()); + i += 1; + } + Ok(to_value(true)) +} + /// Array.prototype.indexOf ( searchElement[, fromIndex ] ) /// /// @@ -431,6 +466,7 @@ pub fn create_constructor(global: &Value) -> Value { array_prototype.set_field_slice("reverse", to_value(reverse as NativeFunctionData)); array_prototype.set_field_slice("shift", to_value(shift as NativeFunctionData)); array_prototype.set_field_slice("unshift", to_value(unshift as NativeFunctionData)); + array_prototype.set_field_slice("every", to_value(every as NativeFunctionData)); array_prototype.set_field_slice("find", to_value(find as NativeFunctionData)); array_prototype.set_field_slice("indexOf", index_of_func); array_prototype.set_field_slice("lastIndexOf", last_index_of_func); @@ -493,6 +529,51 @@ mod tests { assert_eq!(many, String::from("a.b.c")); } + #[test] + fn every() { + let realm = Realm::create(); + let mut engine = Executor::new(realm); + // taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every + let init = r#" + let empty = []; + + let array = [11, 23, 45]; + function callback(element) { + return element > 10; + } + function callback2(element) { + return element < 10; + } + + let appendArray = [1,2,3,4]; + function appendingCallback(elem,index,arr) { + arr.push('new'); + return elem !== "new"; + } + + let delArray = [1,2,3,4]; + function deletingCallback(elem,index,arr) { + arr.pop() + return elem < 3; + } + "#; + forward(&mut engine, init); + let result = forward(&mut engine, "array.every(callback);"); + assert_eq!(result, "true"); + + let result = forward(&mut engine, "empty.every(callback);"); + assert_eq!(result, "true"); + + let result = forward(&mut engine, "array.every(callback2);"); + assert_eq!(result, "false"); + + let result = forward(&mut engine, "appendArray.every(appendingCallback);"); + assert_eq!(result, "true"); + + let result = forward(&mut engine, "delArray.every(deletingCallback);"); + assert_eq!(result, "true"); + } + #[test] fn find() { let realm = Realm::create();