1 /** 2 An alias to `Result<Any, Exception>` which can be passed to the function callback. 3 */ 4 public typealias FunctionCallResult = Result<Any, Exception> 5 6 /** 7 A protocol for any type-erased function. 8 */ 9 internal protocol AnyFunction: AnyDefinition, JavaScriptObjectBuilder { 10 /** 11 Name of the function. JavaScript refers to the function by this name. 12 */ 13 var name: String { get } 14 15 /** 16 An array of the dynamic types that the function takes. If the last type is `Promise`, it's not included. 17 */ 18 var dynamicArgumentTypes: [AnyDynamicType] { get } 19 20 /** 21 A number of arguments the function takes. If the function expects to receive an owner (`this`) as the first argument, it's not counted. 22 Similarly, if the last argument is of type `Promise`, it is not counted. 23 */ 24 var argumentsCount: Int { get } 25 26 /** 27 A minimum number of arguments the functions needs which equals to `argumentsCount` reduced by the number of trailing optional arguments. 28 */ 29 var requiredArgumentsCount: Int { get } 30 31 /** 32 Indicates whether the function's arguments starts from the owner that calls this function. 33 */ 34 var takesOwner: Bool { get set } 35 36 /** 37 Calls the function with a given owner and arguments and returns a result through the callback block. 38 - Parameters: 39 - owner: An object that calls this function. If the `takesOwner` property is true 40 and type of the first argument matches the owner type, it's being passed as the argument. 41 - args: An array of arguments to pass to the function. They could be Swift primitives 42 when invoked through the bridge and in unit tests or `JavaScriptValue`s 43 when the function is called through the JSI. 44 - appContext: An app context where the function is being executed. 45 - callback: A callback that receives a result of the function execution. 46 */ 47 func call(by owner: AnyObject?, withArguments args: [Any], appContext: AppContext, callback: @escaping (FunctionCallResult) -> ()) 48 } 49 50 extension AnyFunction { 51 var requiredArgumentsCount: Int { 52 var trailingOptionalArgumentsCount: Int = 0 53 54 for dynamicArgumentType in dynamicArgumentTypes.reversed() { 55 if dynamicArgumentType is DynamicOptionalType { 56 trailingOptionalArgumentsCount += 1 57 } else { 58 break 59 } 60 } 61 return argumentsCount - trailingOptionalArgumentsCount 62 } 63 64 var argumentsCount: Int { 65 return dynamicArgumentTypes.count 66 } 67 68 /** 69 Calls the function just like `call(by:withArguments:appContext:callback:)`, but without an owner 70 and with an empty callback. Might be useful when you only want to call the function, 71 but don't care about the result. 72 */ 73 func call(withArguments args: [Any], appContext: AppContext) { 74 call(by: nil, withArguments: args, appContext: appContext, callback: { _ in }) 75 } 76 } 77 78 internal class FunctionCallException: GenericException<String> { 79 override var reason: String { 80 "Calling the '\(param)' function has failed" 81 } 82 } 83