internal static extern JsErrorCode JsCreateFunction(JsNativeFunction nativeFunction, IntPtr externalData, out JsValue function);
internal static extern JsErrorCode JsCreateNamedFunction(JsValue name, JsNativeFunction nativeFunction, IntPtr callbackState, out JsValue function);
private EmbeddedType CreateEmbeddedType(Type type) { #if NET40 Type typeInfo = type; #else TypeInfo typeInfo = type.GetTypeInfo(); #endif string typeName = type.FullName; BindingFlags defaultBindingFlags = ReflectionHelpers.GetDefaultBindingFlags(true); ConstructorInfo[] constructors = type.GetConstructors(defaultBindingFlags); JsNativeFunction nativeConstructorFunction = (callee, isConstructCall, args, argCount, callbackData) => { object result; JsValue resultValue; object[] processedArgs = GetHostItemMemberArguments(args); if (processedArgs.Length == 0 && typeInfo.IsValueType) { result = Activator.CreateInstance(type); resultValue = MapToScriptType(result); return(resultValue); } if (constructors.Length == 0) { JsValue undefinedValue = JsValue.Undefined; JsValue errorValue = JsErrorHelpers.CreateError( string.Format(Strings.Runtime_HostTypeConstructorNotFound, typeName)); JsErrorHelpers.SetException(errorValue); return(undefinedValue); } var bestFitConstructor = (ConstructorInfo)ReflectionHelpers.GetBestFitMethod( constructors, processedArgs); if (bestFitConstructor == null) { JsValue undefinedValue = JsValue.Undefined; JsValue errorValue = JsErrorHelpers.CreateReferenceError( string.Format(Strings.Runtime_SuitableConstructorOfHostTypeNotFound, typeName)); JsErrorHelpers.SetException(errorValue); return(undefinedValue); } ReflectionHelpers.FixArgumentTypes(ref processedArgs, bestFitConstructor.GetParameters()); try { result = bestFitConstructor.Invoke(processedArgs); } catch (Exception e) { JsValue undefinedValue = JsValue.Undefined; JsValue errorValue = JsErrorHelpers.CreateError( string.Format(Strings.Runtime_HostTypeConstructorInvocationFailed, typeName, e.Message)); JsErrorHelpers.SetException(errorValue); return(undefinedValue); } resultValue = MapToScriptType(result); return(resultValue); }; GCHandle embeddedTypeHandle = GCHandle.Alloc(type); IntPtr embeddedTypePtr = GCHandle.ToIntPtr(embeddedTypeHandle); JsValue objValue = JsValue.CreateExternalObject(embeddedTypePtr, _embeddedTypeFinalizeCallback); JsValue typeValue = JsValue.CreateFunction(nativeConstructorFunction); SetNonEnumerableProperty(typeValue, ExternalObjectPropertyName, objValue); var embeddedType = new EmbeddedType(type, typeValue, new List <JsNativeFunction> { nativeConstructorFunction }); ProjectFields(embeddedType); ProjectProperties(embeddedType); ProjectMethods(embeddedType); FreezeObject(typeValue); return(embeddedType); }
private void ProjectProperties(EmbeddedItem externalItem) { Type type = externalItem.HostType; object obj = externalItem.HostObject; JsValue typeValue = externalItem.ScriptValue; IList <JsNativeFunction> nativeFunctions = externalItem.NativeFunctions; bool instance = externalItem.IsInstance; string typeName = type.FullName; BindingFlags defaultBindingFlags = ReflectionHelpers.GetDefaultBindingFlags(instance); PropertyInfo[] properties = type.GetProperties(defaultBindingFlags); foreach (PropertyInfo property in properties) { string propertyName = property.Name; JsValue descriptorValue = JsValue.CreateObject(); descriptorValue.SetProperty("enumerable", JsValue.True, true); if (property.GetGetMethod() != null) { JsNativeFunction nativeGetFunction = (callee, isConstructCall, args, argCount, callbackData) => { if (instance && obj == null) { JsValue undefinedValue = JsValue.Undefined; JsValue errorValue = JsErrorHelpers.CreateTypeError( string.Format(Strings.Runtime_InvalidThisContextForHostObjectProperty, propertyName)); JsErrorHelpers.SetException(errorValue); return(undefinedValue); } object result; try { result = property.GetValue(obj, new object[0]); } catch (Exception e) { string errorMessage = instance ? string.Format( Strings.Runtime_HostObjectPropertyGettingFailed, propertyName, e.Message) : string.Format( Strings.Runtime_HostTypePropertyGettingFailed, propertyName, typeName, e.Message) ; JsValue undefinedValue = JsValue.Undefined; JsValue errorValue = JsErrorHelpers.CreateError(errorMessage); JsErrorHelpers.SetException(errorValue); return(undefinedValue); } JsValue resultValue = MapToScriptType(result); return(resultValue); }; nativeFunctions.Add(nativeGetFunction); JsValue getMethodValue = JsValue.CreateFunction(nativeGetFunction); descriptorValue.SetProperty("get", getMethodValue, true); } if (property.GetSetMethod() != null) { JsNativeFunction nativeSetFunction = (callee, isConstructCall, args, argCount, callbackData) => { if (instance && obj == null) { JsValue undefinedValue = JsValue.Undefined; JsValue errorValue = JsErrorHelpers.CreateTypeError( string.Format(Strings.Runtime_InvalidThisContextForHostObjectProperty, propertyName)); JsErrorHelpers.SetException(errorValue); return(undefinedValue); } object value = MapToHostType(args[1]); ReflectionHelpers.FixPropertyValueType(ref value, property); try { property.SetValue(obj, value, new object[0]); } catch (Exception e) { string errorMessage = instance ? string.Format( Strings.Runtime_HostObjectPropertySettingFailed, propertyName, e.Message) : string.Format( Strings.Runtime_HostTypePropertySettingFailed, propertyName, typeName, e.Message) ; JsValue undefinedValue = JsValue.Undefined; JsValue errorValue = JsErrorHelpers.CreateError(errorMessage); JsErrorHelpers.SetException(errorValue); return(undefinedValue); } return(JsValue.Undefined); }; nativeFunctions.Add(nativeSetFunction); JsValue setMethodValue = JsValue.CreateFunction(nativeSetFunction); descriptorValue.SetProperty("set", setMethodValue, true); } typeValue.DefineProperty(propertyName, descriptorValue); } }
/// <summary> /// Creates a new JavaScript function /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="function">The method to call when the function is invoked</param> /// <param name="callbackData">Data to be provided to all function callbacks</param> /// <returns>The new function object</returns> public static JsValue CreateFunction(JsNativeFunction function, IntPtr callbackData) { JsValue reference; JsErrorHelpers.ThrowIfError(NativeMethods.JsCreateFunction(function, callbackData, out reference)); return reference; }
public static extern JsErrorCode JsCreateNamedFunction(JsValueRef name, JsNativeFunction nativeFunction, IntPtr callbackState, out JsValueRef function);
private void ProjectFields(EmbeddedItem externalItem) { Type type = externalItem.HostType; object obj = externalItem.HostObject; JsValue typeValue = externalItem.ScriptValue; bool instance = externalItem.IsInstance; IList <JsNativeFunction> nativeFunctions = externalItem.NativeFunctions; string typeName = type.FullName; BindingFlags defaultBindingFlags = ReflectionHelpers.GetDefaultBindingFlags(instance); FieldInfo[] fields = type.GetFields(defaultBindingFlags); foreach (FieldInfo field in fields) { string fieldName = field.Name; JsValue descriptorValue = JsValue.CreateObject(); descriptorValue.SetProperty("enumerable", JsValue.True, true); JsNativeFunction nativeGetFunction = (callee, isConstructCall, args, argCount, callbackData) => { if (instance && obj == null) { CreateAndSetTypeError(string.Format( Strings.Runtime_InvalidThisContextForHostObjectField, fieldName)); return(JsValue.Undefined); } object result; try { result = field.GetValue(obj); } catch (Exception e) { Exception exception = UnwrapException(e); var wrapperException = exception as WrapperException; JsValue errorValue; if (wrapperException != null) { errorValue = CreateErrorFromWrapperException(wrapperException); } else { string errorMessage = instance ? string.Format(Strings.Runtime_HostObjectFieldGettingFailed, fieldName, exception.Message) : string.Format(Strings.Runtime_HostTypeFieldGettingFailed, fieldName, typeName, exception.Message) ; errorValue = JsErrorHelpers.CreateError(errorMessage); } JsContext.SetException(errorValue); return(JsValue.Undefined); } JsValue resultValue = MapToScriptType(result); return(resultValue); }; nativeFunctions.Add(nativeGetFunction); JsValue getMethodValue = JsValue.CreateFunction(nativeGetFunction); descriptorValue.SetProperty("get", getMethodValue, true); JsNativeFunction nativeSetFunction = (callee, isConstructCall, args, argCount, callbackData) => { if (instance && obj == null) { CreateAndSetTypeError(string.Format( Strings.Runtime_InvalidThisContextForHostObjectField, fieldName)); return(JsValue.Undefined); } object value = MapToHostType(args[1]); ReflectionHelpers.FixFieldValueType(ref value, field); try { field.SetValue(obj, value); } catch (Exception e) { Exception exception = UnwrapException(e); var wrapperException = exception as WrapperException; JsValue errorValue; if (wrapperException != null) { errorValue = CreateErrorFromWrapperException(wrapperException); } else { string errorMessage = instance ? string.Format(Strings.Runtime_HostObjectFieldSettingFailed, fieldName, exception.Message) : string.Format(Strings.Runtime_HostTypeFieldSettingFailed, fieldName, typeName, exception.Message) ; errorValue = JsErrorHelpers.CreateError(errorMessage); } JsContext.SetException(errorValue); return(JsValue.Undefined); } return(JsValue.Undefined); }; nativeFunctions.Add(nativeSetFunction); JsValue setMethodValue = JsValue.CreateFunction(nativeSetFunction); descriptorValue.SetProperty("set", setMethodValue, true); typeValue.DefineProperty(fieldName, descriptorValue); } }
private void ProjectMethods(EmbeddedItem externalItem) { Type type = externalItem.HostType; object obj = externalItem.HostObject; JsValue typeValue = externalItem.ScriptValue; IList <JsNativeFunction> nativeFunctions = externalItem.NativeFunctions; bool instance = externalItem.IsInstance; string typeName = type.FullName; BindingFlags defaultBindingFlags = ReflectionHelpers.GetDefaultBindingFlags(instance); IEnumerable <MethodInfo> methods = type.GetMethods(defaultBindingFlags) .Where(ReflectionHelpers.IsFullyFledgedMethod); IEnumerable <IGrouping <string, MethodInfo> > methodGroups = methods.GroupBy(m => m.Name); foreach (IGrouping <string, MethodInfo> methodGroup in methodGroups) { string methodName = methodGroup.Key; MethodInfo[] methodCandidates = methodGroup.ToArray(); JsNativeFunction nativeFunction = (callee, isConstructCall, args, argCount, callbackData) => { if (instance && obj == null) { CreateAndSetTypeError(string.Format( Strings.Runtime_InvalidThisContextForHostObjectMethod, methodName)); return(JsValue.Undefined); } object[] processedArgs = GetHostItemMemberArguments(args); var bestFitMethod = (MethodInfo)ReflectionHelpers.GetBestFitMethod( methodCandidates, processedArgs); if (bestFitMethod == null) { CreateAndSetReferenceError(string.Format( Strings.Runtime_SuitableMethodOfHostObjectNotFound, methodName)); return(JsValue.Undefined); } ReflectionHelpers.FixArgumentTypes(ref processedArgs, bestFitMethod.GetParameters()); object result; try { result = bestFitMethod.Invoke(obj, processedArgs); } catch (Exception e) { Exception exception = UnwrapException(e); var wrapperException = exception as WrapperException; JsValue errorValue; if (wrapperException != null) { errorValue = CreateErrorFromWrapperException(wrapperException); } else { string errorMessage = instance ? string.Format(Strings.Runtime_HostObjectMethodInvocationFailed, methodName, exception.Message) : string.Format(Strings.Runtime_HostTypeMethodInvocationFailed, methodName, typeName, exception.Message) ; errorValue = JsErrorHelpers.CreateError(errorMessage); } JsContext.SetException(errorValue); return(JsValue.Undefined); } JsValue resultValue = MapToScriptType(result); return(resultValue); }; nativeFunctions.Add(nativeFunction); JsValue methodValue = JsValue.CreateFunction(nativeFunction); typeValue.SetProperty(methodName, methodValue, true); } }
private void ProjectFields(EmbeddedItem externalItem, EmbeddingObjectOptions options) { Type type = externalItem.HostType; object obj = externalItem.HostObject; JsValue typeValue = externalItem.ScriptValue; bool instance = externalItem.IsInstance; IList <JsNativeFunction> nativeFunctions = externalItem.NativeFunctions; string typeName = type.FullName; BindingFlags defaultBindingFlags = ReflectionHelpers.GetDefaultBindingFlags(instance); FieldInfo[] fields = type.GetFields(defaultBindingFlags).Where(options.IsMapped).ToArray(); foreach (FieldInfo field in fields) { string fieldName = field.Name; JsValue descriptorValue = JsValue.CreateObject(); descriptorValue.SetProperty("enumerable", JsValue.True, true); JsNativeFunction nativeGetFunction = (callee, isConstructCall, args, argCount, callbackData) => { if (instance && obj == null) { CreateAndSetError($"Context error while invoking getter '{fieldName}'."); return(JsValue.Undefined); } object result; try { result = field.GetValue(obj); } catch (Exception e) { Exception exception = UnwrapException(e); var wrapperException = exception as JsException; JsValue errorValue; if (wrapperException != null) { errorValue = CreateErrorFromWrapperException(wrapperException); } else { string errorMessage = instance ? $"Error ocured while reading field '{fieldName}': {exception.Message}" : $"Erorr ocured while reading static field '{fieldName}' from type '{typeName}': {exception.Message}" ; errorValue = JsValue.CreateError(JsValue.FromString(errorMessage)); } JsContext.SetException(errorValue); return(JsValue.Undefined); } JsValue resultValue = MapToScriptType(result); return(resultValue); }; nativeFunctions.Add(nativeGetFunction); JsValue getMethodValue = JsValue.CreateFunction(nativeGetFunction); descriptorValue.SetProperty("get", getMethodValue, true); JsNativeFunction nativeSetFunction = (callee, isConstructCall, args, argCount, callbackData) => { if (instance && obj == null) { CreateAndSetError($"Invalid context got host object field {fieldName}."); return(JsValue.Undefined); } object value = MapToHostType(args[1]); ReflectionHelpers.FixFieldValueType(ref value, field); try { field.SetValue(obj, value); } catch (Exception e) { Exception exception = UnwrapException(e); var wrapperException = exception as JsException; JsValue errorValue; if (wrapperException != null) { errorValue = CreateErrorFromWrapperException(wrapperException); } else { string errorMessage = instance ? $"Failed to set value for hosts object field '{fieldName}': {exception.Message}" : $"Failed to set value for static type '{typeName}' field '{fieldName}': {exception.Message}" ; errorValue = JsValue.CreateError(JsValue.FromString(errorMessage)); } JsContext.SetException(errorValue); return(JsValue.Undefined); } return(JsValue.Undefined); }; nativeFunctions.Add(nativeSetFunction); JsValue setMethodValue = JsValue.CreateFunction(nativeSetFunction); descriptorValue.SetProperty("set", setMethodValue, true); typeValue.DefineProperty(fieldName, descriptorValue); } }
private void ProjectMethods(JsValue target, Type type, bool instance) { string typeName = type.FullName; BindingFlags defaultBindingFlags = ReflectionHelpers.GetDefaultBindingFlags(instance); MethodInfo[] methods = type.GetMethods(defaultBindingFlags); IEnumerable <IGrouping <string, MethodInfo> > methodGroups = methods.GroupBy(m => m.Name); foreach (IGrouping <string, MethodInfo> methodGroup in methodGroups) { string methodName = methodGroup.Key; MethodInfo[] methodCandidates = methodGroup.ToArray(); JsNativeFunction nativeFunction = (callee, isConstructCall, args, argCount, callbackData) => { JsValue thisValue = args[0]; JsValue undefinedValue = JsValue.Undefined; object thisObj = null; if (instance) { if (!thisValue.HasExternalData) { JsValue errorValue = JsErrorHelpers.CreateTypeError( string.Format(Strings.Runtime_InvalidThisContextForHostObjectMethod, methodName)); JsErrorHelpers.SetException(errorValue); return(undefinedValue); } thisObj = MapToHostType(thisValue); } object[] processedArgs = MapToHostType(args.Skip(1).ToArray()); var bestFitMethod = (MethodInfo)ReflectionHelpers.GetBestFitMethod( methodCandidates, processedArgs); if (bestFitMethod == null) { JsValue errorValue = JsErrorHelpers.CreateReferenceError( string.Format(Strings.Runtime_SuitableMethodOfHostObjectNotFound, methodName)); JsErrorHelpers.SetException(errorValue); return(undefinedValue); } ReflectionHelpers.FixArgumentTypes(ref processedArgs, bestFitMethod.GetParameters()); object result; try { result = bestFitMethod.Invoke(thisObj, processedArgs); } catch (Exception e) { string errorMessage = instance ? string.Format( Strings.Runtime_HostObjectMethodInvocationFailed, methodName, e.Message) : string.Format( Strings.Runtime_HostTypeMethodInvocationFailed, methodName, typeName, e.Message) ; JsValue errorValue = JsErrorHelpers.CreateError(errorMessage); JsErrorHelpers.SetException(errorValue); return(undefinedValue); } JsValue resultValue = MapToScriptType(result); return(resultValue); }; _nativeFunctions.Add(nativeFunction); JsValue methodValue = JsValue.CreateFunction(nativeFunction); target.SetProperty(methodName, methodValue, true); } }
private void ProjectProperties(JsValue target, Type type, bool instance) { string typeName = type.FullName; BindingFlags defaultBindingFlags = ReflectionHelpers.GetDefaultBindingFlags(instance); PropertyInfo[] properties = type.GetProperties(defaultBindingFlags); foreach (PropertyInfo property in properties) { string propertyName = property.Name; JsValue descriptorValue = JsValue.CreateObject(); descriptorValue.SetProperty("enumerable", JsValue.True, true); if (property.GetGetMethod() != null) { JsNativeFunction nativeFunction = (callee, isConstructCall, args, argCount, callbackData) => { JsValue thisValue = args[0]; JsValue undefinedValue = JsValue.Undefined; object thisObj = null; if (instance) { if (!thisValue.HasExternalData) { JsValue errorValue = JsErrorHelpers.CreateTypeError( string.Format(Strings.Runtime_InvalidThisContextForHostObjectProperty, propertyName)); JsErrorHelpers.SetException(errorValue); return(undefinedValue); } thisObj = MapToHostType(thisValue); } object result; try { result = property.GetValue(thisObj, new object[0]); } catch (Exception e) { string errorMessage = instance ? string.Format( Strings.Runtime_HostObjectPropertyGettingFailed, propertyName, e.Message) : string.Format( Strings.Runtime_HostTypePropertyGettingFailed, propertyName, typeName, e.Message) ; JsValue errorValue = JsErrorHelpers.CreateError(errorMessage); JsErrorHelpers.SetException(errorValue); return(undefinedValue); } JsValue resultValue = MapToScriptType(result); return(resultValue); }; _nativeFunctions.Add(nativeFunction); JsValue getMethodValue = JsValue.CreateFunction(nativeFunction); descriptorValue.SetProperty("get", getMethodValue, true); } if (property.GetSetMethod() != null) { JsNativeFunction nativeFunction = (callee, isConstructCall, args, argCount, callbackData) => { JsValue thisValue = args[0]; JsValue undefinedValue = JsValue.Undefined; object thisObj = null; if (instance) { if (!thisValue.HasExternalData) { JsValue errorValue = JsErrorHelpers.CreateTypeError( string.Format(Strings.Runtime_InvalidThisContextForHostObjectProperty, propertyName)); JsErrorHelpers.SetException(errorValue); return(undefinedValue); } thisObj = MapToHostType(thisValue); } object value = MapToHostType(args.Skip(1).First()); ReflectionHelpers.FixPropertyValueType(ref value, property); try { property.SetValue(thisObj, value, new object[0]); } catch (Exception e) { string errorMessage = instance ? string.Format( Strings.Runtime_HostObjectPropertySettingFailed, propertyName, e.Message) : string.Format( Strings.Runtime_HostTypePropertySettingFailed, propertyName, typeName, e.Message) ; JsValue errorValue = JsErrorHelpers.CreateError(errorMessage); JsErrorHelpers.SetException(errorValue); return(undefinedValue); } return(undefinedValue); }; _nativeFunctions.Add(nativeFunction); JsValue setMethodValue = JsValue.CreateFunction(nativeFunction); descriptorValue.SetProperty("set", setMethodValue, true); } target.DefineProperty(propertyName, descriptorValue); } }
private JsValue CreateConstructor(Type type) { TypeInfo typeInfo = type.GetTypeInfo(); string typeName = type.FullName; BindingFlags defaultBindingFlags = ReflectionHelpers.GetDefaultBindingFlags(true); ConstructorInfo[] constructors = type.GetConstructors(defaultBindingFlags); JsNativeFunction nativeFunction = (callee, isConstructCall, args, argCount, callbackData) => { JsValue resultValue; JsValue undefinedValue = JsValue.Undefined; object[] processedArgs = MapToHostType(args.Skip(1).ToArray()); object result; if (processedArgs.Length == 0 && typeInfo.IsValueType) { result = Activator.CreateInstance(type); resultValue = MapToScriptType(result); return(resultValue); } if (constructors.Length == 0) { JsValue errorValue = JsErrorHelpers.CreateError( string.Format(Strings.Runtime_HostTypeConstructorNotFound, typeName)); JsErrorHelpers.SetException(errorValue); return(undefinedValue); } var bestFitConstructor = (ConstructorInfo)ReflectionHelpers.GetBestFitMethod( constructors, processedArgs); if (bestFitConstructor == null) { JsValue errorValue = JsErrorHelpers.CreateReferenceError( string.Format(Strings.Runtime_SuitableConstructorOfHostTypeNotFound, typeName)); JsErrorHelpers.SetException(errorValue); return(undefinedValue); } ReflectionHelpers.FixArgumentTypes(ref processedArgs, bestFitConstructor.GetParameters()); try { result = bestFitConstructor.Invoke(processedArgs); } catch (Exception e) { JsValue errorValue = JsErrorHelpers.CreateError( string.Format(Strings.Runtime_HostTypeConstructorInvocationFailed, typeName, e.Message)); JsErrorHelpers.SetException(errorValue); return(undefinedValue); } resultValue = MapToScriptType(result); return(resultValue); }; _nativeFunctions.Add(nativeFunction); JsValue constructorValue = JsValue.CreateFunction(nativeFunction); return(constructorValue); }
private JsObject GeneratePrototype(Type type) { var ret = new JsObject(GlobalScope); var methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance).Where(m => m.GetCustomAttribute(typeof(JsMethodAttribute)) != null); var properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance).Where(m => m.GetCustomAttribute(typeof(JsPropertyAttribute)) != null); if (type == typeof(JsObject)) { ret.JsProto = JsNull.Instance; } else { ret.JsProto = GetPrototype(type.BaseType); } foreach (var method in methods) { var methodProps = method.GetCustomAttribute <JsMethodAttribute>(); var parameters = method.GetParameters(); if (method.ReturnType != typeof(JsValue)) { throw new JsInternalException("Method of native javascript type must have JsValue return type"); } if (parameters.Length != 1 || parameters[0].ParameterType != typeof(LexicalEnvironment)) { throw new JsInternalException("Method of native javascript type must have one input paramter with LexicalEnvironment type"); } var jsFunc = new JsNativeFunction(CreateMethodDelegate(method), methodProps.Name, GlobalScope); SetProperty(methodProps.Name, jsFunc); } foreach (var property in properties) { var propProps = property.GetCustomAttribute <JsPropertyAttribute>(); var setter = property.SetMethod; var getter = property.GetMethod; var jsProperty = new JsProperty(ret); if (property.PropertyType != typeof(JsValue)) { throw new JsInternalException("Javascript native property type must be JsValue"); } if (propProps.IsInline) { jsProperty.RawValue = (JsValue)getter.Invoke(ret, null); } else { if (getter != null) { jsProperty.Getter = new JsNativeFunction(CreateGetterDelegate(getter), "", GlobalScope); } if (setter != null) { jsProperty.Setter = new JsNativeFunction(CreateSetterDelegate(setter), "", GlobalScope); } } ret._properties.Add(propProps.Name, jsProperty); } return(ret); }