private JsValue GetPropertyValue(BaristaContext context, PropertyInfo prop, string propertyName, JsObject thisObj) { object targetObj = null; if (thisObj == null) { context.CurrentScope.SetException(context.CreateTypeError($"Could not retrieve property '{propertyName}': Invalid 'this' context.")); return(context.Undefined); } if (thisObj.TryGetBean(out JsExternalObject xoObj)) { targetObj = xoObj.Target; } try { var result = prop.GetValue(targetObj); if (context.Converter.TryFromObject(context, result, out JsValue resultValue)) { return(resultValue); } else { return(context.Undefined); } } catch (Exception ex) { context.CurrentScope.SetException(context.CreateError(ex.Message)); return(context.Undefined); } }
public BaristaModuleRecord(string name, JavaScriptValueSafeHandle moduleSpecifier, BaristaModuleRecord parentModule, IJavaScriptEngine engine, BaristaContext context, IBaristaModuleRecordFactory moduleRecordFactory, IBaristaModuleLoader moduleLoader, JavaScriptModuleRecord moduleRecord) : base(engine, moduleRecord) { m_name = name ?? throw new ArgumentNullException(nameof(name)); m_moduleSpecifier = moduleSpecifier ?? throw new ArgumentNullException(nameof(moduleSpecifier)); m_parentModule = parentModule; m_context = context ?? throw new ArgumentNullException(nameof(context)); m_moduleRecordFactory = moduleRecordFactory ?? throw new ArgumentNullException(nameof(moduleRecordFactory)); //Module loader is not required, but if not specified, imports will fail. m_moduleLoader = moduleLoader; //Associate functions that will handle module loading if (m_parentModule == null) { //Set the fetch module callback for the module. m_fetchImportedModuleCallbackHandle = InitFetchImportedModuleCallback(Handle); //Set the notify callback for the module. m_notifyCallbackHandle = InitNotifyModuleReadyCallback(Handle); } //Set the event that will be called prior to the engine collecting the context. JavaScriptObjectBeforeCollectCallback beforeCollectCallback = (IntPtr handle, IntPtr callbackState) => { OnBeforeCollect(handle, callbackState); }; m_beforeCollectCallbackDelegateHandle = GCHandle.Alloc(beforeCollectCallback); Engine.JsSetObjectBeforeCollectCallback(moduleRecord, IntPtr.Zero, beforeCollectCallback); }
public BaristaContext CreateContext(BaristaRuntime runtime) { if (runtime == null) { throw new ArgumentNullException(nameof(runtime)); } if (runtime.IsDisposed) { throw new ObjectDisposedException(nameof(runtime)); } var contextHandle = m_engine.JsCreateContext(runtime.Handle); return(m_contextPool.GetOrAdd(contextHandle, () => { var moduleRecordFactory = m_serviceProvider.GetRequiredService <IBaristaModuleRecordFactory>(); var valueFactoryBuilder = m_serviceProvider.GetRequiredService <IBaristaValueFactoryBuilder>(); var conversionStrategy = m_serviceProvider.GetRequiredService <IBaristaConversionStrategy>(); //For flexability, a promise task queue is not required. var promiseTaskQueue = m_serviceProvider.GetService <IPromiseTaskQueue>(); //Set the handle that will be called prior to the engine collecting the context. var context = new BaristaContext(m_engine, valueFactoryBuilder, conversionStrategy, moduleRecordFactory, promiseTaskQueue, contextHandle); void beforeCollect(object sender, BaristaObjectBeforeCollectEventArgs args) { context.BeforeCollect -= beforeCollect; m_contextPool.RemoveHandle(new JavaScriptContextSafeHandle(args.Handle)); } context.BeforeCollect += beforeCollect; return context; })); }
protected JsValue(IJavaScriptEngine engine, BaristaContext context, JavaScriptValueSafeHandle valueHandle) { m_javaScriptEngine = engine ?? throw new ArgumentNullException(nameof(engine)); m_context = context ?? throw new ArgumentNullException(nameof(context)); m_javaScriptReference = valueHandle ?? throw new ArgumentNullException(nameof(valueHandle)); //Let's just make sure that we're the correct type. var reportedType = engine.JsGetValueType(valueHandle); //if (reportedType != Type) // throw new InvalidOperationException($"The underlying type ({reportedType}) does not match the type that is being created ({Type}). Ensure that correct value is being created."); //Set the event that will be called prior to the engine collecting the value. if ((this is JsNumber) == false) { //Set the event that will be called prior to the engine collecting the value. JavaScriptObjectBeforeCollectCallback beforeCollectCallback = (IntPtr handle, IntPtr callbackState) => { try { OnBeforeCollect(handle, callbackState); } catch { //Do Nothing. } }; m_beforeCollectCallbackDelegateHandle = GCHandle.Alloc(beforeCollectCallback); //An exception thrown here is usually due to trying to associate a callback to a JsNumber. Engine.JsSetObjectBeforeCollectCallback(valueHandle, IntPtr.Zero, beforeCollectCallback); } }
public static byte[] GetSerializedScript(string resourceName, BaristaContext context, bool mapWindowToGlobal = false) { if (context == null) { throw new ArgumentNullException(nameof(context)); } return(s_serializedScripts.GetOrAdd(resourceName, new Func <string, byte[]>((name) => { var script = EmbeddedResourceHelper.LoadResource(name); string mapWindowToGlobalString = mapWindowToGlobal ? "const window = global;" : null; var scriptWithModuleWrapper = $@"(() => {{ 'use strict'; {mapWindowToGlobalString} const module = {{ exports: {{}} }}; let exports = module.exports; {script} return module.exports; }})();"; return context.SerializeScript(scriptWithModuleWrapper); }))); }
internal BaristaExecutionScope(BaristaContext context, IPromiseTaskQueue taskQueue, Action release) { m_context = context; m_promiseTaskQueue = taskQueue; m_release = release; //Clear and set the task queue if specified m_promiseContinuationCallbackDelegateHandle = default(GCHandle); if (m_promiseTaskQueue != null) { m_promiseTaskQueue.Clear(); JavaScriptPromiseContinuationCallback promiseContinuationCallback = (IntPtr taskHandle, IntPtr callbackState) => { try { PromiseContinuationCallback(taskHandle, callbackState); } catch { //Do Nothing. } }; m_promiseContinuationCallbackDelegateHandle = GCHandle.Alloc(promiseContinuationCallback); m_context.Engine.JsSetPromiseContinuationCallback(promiseContinuationCallback, IntPtr.Zero); } }
/// <summary> /// Projects the [[iterator]] protocol on IEnumerable objects. /// </summary> /// <param name="context"></param> /// <param name="targetObject"></param> /// <param name="reflector"></param> private void ProjectIEnumerable(BaristaContext context, JsObject targetObject, ObjectReflector reflector) { if (typeof(IEnumerable).IsAssignableFrom(reflector.Type)) { var fnIterator = context.CreateFunction(new Func <JsObject, JsValue>((thisObj) => { IEnumerable targetObj = null; if (thisObj == null) { context.CurrentScope.SetException(context.CreateTypeError($"Could not retrieve iterator on object {targetObject.ToString()}: Invalid 'this' context.")); return(context.Undefined); } if (thisObj.TryGetBean(out JsExternalObject xoObj)) { targetObj = xoObj.Target as IEnumerable; } return(context.CreateIterator(targetObj.GetEnumerator())); })); var iteratorDescriptor = context.CreateObject(); iteratorDescriptor.SetProperty("value", fnIterator); targetObject.SetProperty(context.Symbol.Iterator, iteratorDescriptor); } }
public JsManagedExternalArrayBuffer(IJavaScriptEngine engine, BaristaContext context, JavaScriptValueSafeHandle valueHandle, IntPtr bufferHandle) : base(engine, context, valueHandle) { if (bufferHandle == default(IntPtr) || bufferHandle == null) { throw new ArgumentNullException(nameof(bufferHandle)); } m_bufferHandle = bufferHandle; }
public IBaristaValueFactory CreateValueFactory(BaristaContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } var jsEngine = m_serviceProvider.GetRequiredService <IJavaScriptEngine>(); return(new BaristaValueFactory(jsEngine, context)); }
public Response(Response response) { m_context = response.m_context; m_response = response.m_response; m_body = new Body(m_context, m_response); m_headers = new Headers(m_context); foreach (var header in m_response.Headers.Where(h => h.Type == ParameterType.HttpHeader)) { m_headers.Append(header.Name, header.Value.ToString()); } }
public Response(BaristaContext context, IRestResponse response) { m_context = context ?? throw new ArgumentNullException(nameof(context)); m_response = response ?? throw new ArgumentNullException(nameof(response)); m_body = new Body(m_context, m_response); m_headers = new Headers(context); foreach (var header in m_response.Headers.Where(h => h.Type == ParameterType.HttpHeader)) { m_headers.Append(header.Name, header.Value.ToString()); } }
public BaristaModuleRecord CreateBaristaModuleRecord(BaristaContext context, string moduleName, BaristaModuleRecord parentModule = null, bool setAsHost = false, IBaristaModuleLoader moduleLoader = null) { if (context == null) { throw new ArgumentNullException(nameof(context)); } var moduleNameValue = context.CreateString(moduleName); return(CreateBaristaModuleRecordInternal(context, moduleName, moduleNameValue.Handle, parentModule, setAsHost, moduleLoader)); }
public JsIterator(IJavaScriptEngine engine, BaristaContext context, JavaScriptValueSafeHandle valueHandle, IEnumerator enumerator) : base(engine, context, valueHandle) { m_enumerator = enumerator ?? throw new ArgumentNullException(nameof(enumerator)); var fnNext = context.CreateFunction(new Func <JsObject, JsObject>((thisObj) => { return(Next()); })); SetProperty("next", fnNext); }
private BaristaModuleRecord CreateBaristaModuleRecordInternal(BaristaContext context, string moduleName, JavaScriptValueSafeHandle specifier, BaristaModuleRecord parentModule = null, bool setAsHost = false, IBaristaModuleLoader moduleLoader = null) { JavaScriptModuleRecord moduleRecord = null; if (m_specifierModuleLookup.ContainsKey(specifier)) { moduleRecord = m_specifierModuleLookup[specifier]; } if (moduleRecord == null || moduleRecord.IsClosed || moduleRecord.IsInvalid) { if (m_specifierModuleLookup.ContainsKey(specifier)) { m_specifierModuleLookup.Remove(specifier); } moduleRecord = m_engine.JsInitializeModuleRecord(parentModule == null ? JavaScriptModuleRecord.Invalid : parentModule.Handle, specifier); } return(m_moduleReferencePool.GetOrAdd(moduleRecord, () => { //If a module loader hasn't be specified in the parameters, obtain one from DI. if (moduleLoader == null) { moduleLoader = m_serviceProvider.GetRequiredService <IBaristaModuleLoader>(); } var module = new BaristaModuleRecord(moduleName.ToString(), specifier, parentModule, m_engine, context, this, moduleLoader, moduleRecord); m_specifierModuleLookup.Add(specifier, moduleRecord); //If specified, indicate as host module. if (setAsHost == true) { m_engine.JsSetModuleHostInfo(moduleRecord, JavaScriptModuleHostInfoKind.HostDefined, specifier.DangerousGetHandle()); } void beforeCollect(object sender, BaristaObjectBeforeCollectEventArgs args) { context.BeforeCollect -= beforeCollect; m_moduleReferencePool.RemoveHandle(new JavaScriptModuleRecord(args.Handle)); if (sender is BaristaModuleRecord baristaModuleRecord) { m_specifierModuleLookup.Remove(baristaModuleRecord.Specifier); } } module.BeforeCollect += beforeCollect; return module; })); }
private JsValue GetIndexerPropertyValue(BaristaContext context, PropertyInfo indexerProp, string propertyName, JsObject thisObj, object[] args) { object targetObj = null; if (thisObj == null) { context.CurrentScope.SetException(context.CreateTypeError($"Could not get indexer property '{propertyName}': Invalid 'this' context.")); return(context.Undefined); } if (args.Length < 1) { context.CurrentScope.SetException(context.CreateTypeError($"Could not get indexer property '{propertyName}': At least one index must be specified.")); return(context.Undefined); } if (thisObj.TryGetBean(out JsExternalObject xoObj)) { targetObj = xoObj.Target; } try { var indexParameters = indexerProp.GetIndexParameters(); var indexArgs = new object[indexParameters.Length]; for (int i = 0; i < indexParameters.Length; i++) { indexArgs[i] = Convert.ChangeType(args.ElementAtOrDefault(i), indexParameters[i].ParameterType); } var result = indexerProp.GetValue(targetObj, indexArgs); if (context.Converter.TryFromObject(context, result, out JsValue resultValue)) { return(resultValue); } else { return(context.Undefined); } } catch (Exception ex) { context.CurrentScope.SetException(context.CreateError(ex.Message)); return(context.Undefined); } }
private JsValue SetIndexerPropertyValue(BaristaContext context, PropertyInfo indexerProp, string propertyName, JsObject thisObj, object[] args) { object targetObj = null; if (thisObj == null) { context.CurrentScope.SetException(context.CreateTypeError($"Could not set indexer property '{propertyName}': Invalid 'this' context.")); return(context.Undefined); } if (args.Length < 2) { context.CurrentScope.SetException(context.CreateTypeError($"Could not set indexer property '{propertyName}': At least one index and a value be specified.")); return(context.Undefined); } if (thisObj.TryGetBean(out JsExternalObject xoObj)) { targetObj = xoObj.Target; } try { var value = args.LastOrDefault(); var nativeArgs = args.Take(args.Length - 1).ToArray(); var indexParameters = indexerProp.GetIndexParameters(); var indexArgs = new object[indexParameters.Length]; for (int i = 0; i < indexParameters.Length; i++) { indexArgs[i] = Convert.ChangeType(nativeArgs.ElementAtOrDefault(i), indexParameters[i].ParameterType); } indexerProp.SetValue(targetObj, value, indexArgs); return(context.Undefined); } catch (Exception ex) { context.CurrentScope.SetException(context.CreateError(ex.Message)); return(context.Undefined); } }
public BaristaModuleRecord CreateBaristaModuleRecord(BaristaContext context, JavaScriptValueSafeHandle specifier, BaristaModuleRecord parentModule = null, bool setAsHost = false, IBaristaModuleLoader moduleLoader = null) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (specifier == null || specifier.IsClosed || specifier.IsInvalid) { throw new ArgumentNullException(nameof(specifier)); } var moduleNameValue = context.CreateValue <JsString>(specifier); if (moduleNameValue == null) { throw new InvalidOperationException("Specifier is expected to be a string value."); } return(CreateBaristaModuleRecordInternal(context, moduleNameValue.ToString(), specifier, parentModule, setAsHost, moduleLoader)); }
private void ProjectProperties(BaristaContext context, JsObject targetObject, IEnumerable <PropertyInfo> properties) { foreach (var prop in properties) { var propertyAttribute = BaristaPropertyAttribute.GetAttribute(prop); var propertyName = propertyAttribute.Name; var propertyDescriptor = context.CreateObject(); if (propertyAttribute.Configurable) { propertyDescriptor.SetProperty("configurable", context.True); } if (propertyAttribute.Enumerable) { propertyDescriptor.SetProperty("enumerable", context.True); } if (prop.GetMethod != null) { var jsGet = context.CreateFunction(new BaristaFunctionDelegate((calleeObj, isConstructCall, thisObj, args) => { return(GetPropertyValue(context, prop, propertyName, thisObj)); })); propertyDescriptor.SetProperty("get", jsGet); } if (prop.SetMethod != null) { var jsSet = context.CreateFunction(new BaristaFunctionDelegate((calleeObj, isConstructCall, thisObj, args) => { return(SetPropertyValue(context, prop, propertyName, thisObj, args)); })); propertyDescriptor.SetProperty("set", jsSet); } targetObject.SetProperty(context.CreateString(propertyName), propertyDescriptor); } }
private JsValue SetPropertyValue(BaristaContext context, PropertyInfo prop, string propertyName, JsObject thisObj, object[] args) { object targetObj = null; if (thisObj == null) { context.CurrentScope.SetException(context.CreateTypeError($"Could not set property '{propertyName}': Invalid 'this' context.")); return(context.Undefined); } if (thisObj.TryGetBean(out JsExternalObject xoObj)) { targetObj = xoObj.Target; } var setPropertyValueType = prop.SetMethod.GetParameters().First().ParameterType; var argumentValue = args.ElementAtOrDefault(0); try { //If the exposed property is a JsValue, Attempt to convert and then set the property. if (typeof(JsValue).IsSameOrSubclass(setPropertyValueType) && context.Converter.TryFromObject(context, argumentValue, out JsValue jsValue) && setPropertyValueType.IsSameOrSubclass(jsValue.GetType())) { prop.SetValue(targetObj, jsValue); return(context.Undefined); } var value = Convert.ChangeType(args.ElementAtOrDefault(0), setPropertyValueType); prop.SetValue(targetObj, value); return(context.Undefined); } catch (Exception ex) { context.CurrentScope.SetException(context.CreateError(ex.Message)); return(context.Undefined); } }
private bool TryConvertFromNonPrimitiveObject(BaristaContext context, object obj, out JsValue value) { if (m_typeConversionStrategy == null) { //TODO: think about cheating with a JsonConversion value = null; return(false); } Type typeToConvert = obj.GetType(); if (m_typeConversionStrategy.TryCreatePrototypeFunction(context, typeToConvert, out JsFunction fnCtor)) { var exObj = context.CreateExternalObject(obj); var resultValue = fnCtor.Construct(null, exObj); value = resultValue; return(true); } value = null; return(false); }
private object[] ConvertArgsToParamTypes(BaristaContext context, object[] args, ParameterInfo[] parameters) { //TODO: BaristaValueFactory.CreateNativeFunctionForDelegate has very similar code. Consolidate if possible. var convertedArgs = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { var currentParam = parameters[i]; var currentParamType = currentParam.ParameterType; //For nullable values get the underlying type. if (currentParamType.IsGenericType && currentParamType.GetGenericTypeDefinition() == typeof(Nullable <>)) { currentParamType = Nullable.GetUnderlyingType(currentParamType); } var currentArg = args.ElementAtOrDefault(i); if (currentParamType == typeof(BaristaContext)) { convertedArgs[i] = context; } else { try { convertedArgs[i] = Convert.ChangeType(currentArg, currentParamType); } catch (Exception) { //Something went wrong, use the default value. convertedArgs[i] = currentParamType.GetDefaultValue(); } } } return(convertedArgs); }
public JsPromiseConstructor(IJavaScriptEngine engine, BaristaContext context, JavaScriptValueSafeHandle valueHandle) : base(engine, context, valueHandle) { }
public JsUndefined(IJavaScriptEngine engine, BaristaContext context, JavaScriptValueSafeHandle handle) : base(engine, context, handle) { }
public Body(BaristaContext context, IRestResponse response) { m_context = context ?? throw new ArgumentNullException(nameof(context)); m_response = response ?? throw new ArgumentNullException(nameof(response)); }
public Headers(BaristaContext context) { m_context = context ?? throw new ArgumentNullException(nameof(context)); AllHeaders = new Dictionary <string, IList <string> >(); }
public bool TryCreatePrototypeFunction(BaristaContext context, Type typeToConvert, out JsFunction ctor) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (typeToConvert == null) { throw new ArgumentNullException(nameof(typeToConvert)); } if (m_prototypes.ContainsKey(typeToConvert)) { ctor = m_prototypes[typeToConvert]; return(true); } var reflector = new ObjectReflector(typeToConvert); JsFunction superCtor = null; var baseType = reflector.GetBaseType(); if (baseType != null && !baseType.IsSameOrSubclass(typeof(JsValue)) && TryCreatePrototypeFunction(context, baseType, out JsFunction fnSuper)) { superCtor = fnSuper; } var objectName = BaristaObjectAttribute.GetBaristaObjectNameFromType(typeToConvert); //Get all the property descriptors for the specified type. var staticPropertyDescriptors = context.CreateObject(); var instancePropertyDescriptors = context.CreateObject(); //Get static and instance properties. ProjectProperties(context, staticPropertyDescriptors, reflector.GetProperties(false)); ProjectProperties(context, instancePropertyDescriptors, reflector.GetProperties(true)); //Get static and instance indexer properties. ProjectIndexerProperties(context, staticPropertyDescriptors, reflector.GetIndexerProperties(false)); ProjectIndexerProperties(context, instancePropertyDescriptors, reflector.GetIndexerProperties(true)); //Get static and instance methods. ProjectMethods(context, staticPropertyDescriptors, reflector, reflector.GetUniqueMethodsByName(false)); ProjectMethods(context, instancePropertyDescriptors, reflector, reflector.GetUniqueMethodsByName(true)); //Get static and instance events. ProjectEvents(context, staticPropertyDescriptors, reflector, reflector.GetEventTable(false)); ProjectEvents(context, instancePropertyDescriptors, reflector, reflector.GetEventTable(true)); //Get the [[iterator]] property. ProjectIEnumerable(context, instancePropertyDescriptors, reflector); JsFunction fnCtor; var publicConstructors = reflector.GetConstructors(); if (publicConstructors.Any()) { fnCtor = context.CreateFunction(new BaristaFunctionDelegate((calleeObj, isConstructCall, thisObj, args) => { if (thisObj == null) { var ex = context.CreateTypeError($"Failed to construct '{objectName}': 'this' must be specified."); context.CurrentScope.SetException(ex); return(context.Undefined); } if (superCtor != null) { superCtor.Call(thisObj); } context.Object.DefineProperties(thisObj, instancePropertyDescriptors); //If this isn't a construct call, don't attempt to set the bean if (!isConstructCall) { return(thisObj); } //Set our native object. JsExternalObject externalObject = null; //!!Special condition -- if there's exactly one argument, and if it matches the enclosing type, //don't invoke the type's constructor, rather, just wrap the object with the JsObject. if (args.Length == 1 && args[0].GetType() == typeToConvert) { externalObject = context.CreateExternalObject(args[0]); } else { try { var bestConstructor = reflector.GetConstructorBestMatch(args); if (bestConstructor == null) { var ex = context.CreateTypeError($"Failed to construct '{objectName}': Could not find a matching constructor for the provided arguments."); context.CurrentScope.SetException(ex); return(context.Undefined); } //Convert the args into the native args of the constructor. var constructorParams = bestConstructor.GetParameters(); var convertedArgs = ConvertArgsToParamTypes(context, args, constructorParams); var newObj = bestConstructor.Invoke(convertedArgs); externalObject = context.CreateExternalObject(newObj); } catch (Exception ex) { context.CurrentScope.SetException(context.CreateError(ex.Message)); return(context.Undefined); } } thisObj.SetBean(externalObject); return(thisObj); }), objectName); } else { fnCtor = context.CreateFunction(new BaristaFunctionDelegate((calleeObj, isConstructCall, thisObj, args) => { var ex = context.CreateTypeError($"Failed to construct '{objectName}': This object cannot be constructed."); context.CurrentScope.SetException(ex); return(context.Undefined); }), objectName); } //We've got everything we need. fnCtor.Prototype = context.Object.Create(superCtor == null ? context.Object.Prototype : superCtor.Prototype); context.Object.DefineProperties(fnCtor, staticPropertyDescriptors); m_prototypes.Add(typeToConvert, fnCtor); ctor = fnCtor; return(true); }
private void ProjectMethods(BaristaContext context, JsObject targetObject, ObjectReflector reflector, IDictionary <string, IList <MethodInfo> > methods) { foreach (var method in methods) { var methodName = method.Key; var methodInfos = method.Value; var fn = context.CreateFunction(new BaristaFunctionDelegate((calleeObj, isConstructCall, thisObj, args) => { object targetObj = null; if (thisObj == null) { context.CurrentScope.SetException(context.CreateTypeError($"Could not call function '{methodName}': Invalid 'this' context.")); return(context.Undefined); } if (thisObj.TryGetBean(out JsExternalObject xoObj)) { targetObj = xoObj.Target; } try { var bestMethod = reflector.GetMethodBestMatch(methodInfos, args); if (bestMethod == null) { var ex = context.CreateTypeError($"Failed to call function '{methodName}': Could not find a matching function for the provided arguments."); context.CurrentScope.SetException(ex); return(context.Undefined); } //Convert the args into the native args of the method. var methodParams = bestMethod.GetParameters(); var convertedArgs = ConvertArgsToParamTypes(context, args, methodParams); var result = bestMethod.Invoke(targetObj, convertedArgs); if (context.Converter.TryFromObject(context, result, out JsValue resultValue)) { return(resultValue); } else { context.CurrentScope.SetException(context.CreateTypeError($"The call to '{methodName}' was successful, but the result could not be converted into a JavaScript object.")); return(context.Undefined); } } catch (Exception ex) { context.CurrentScope.SetException(context.CreateError(ex.Message)); return(context.Undefined); } })); var functionDescriptor = context.CreateObject(); if (methodInfos.All(mi => BaristaPropertyAttribute.GetAttribute(mi).Configurable)) { functionDescriptor.SetProperty("configurable", context.True); } if (methodInfos.All(mi => BaristaPropertyAttribute.GetAttribute(mi).Enumerable)) { functionDescriptor.SetProperty("enumerable", context.True); } if (methodInfos.All(mi => BaristaPropertyAttribute.GetAttribute(mi).Writable)) { functionDescriptor.SetProperty("writable", context.True); } functionDescriptor.SetProperty("value", fn); targetObject.SetProperty(context.CreateString(methodName), functionDescriptor); } }
private void ProjectEvents(BaristaContext context, JsObject targetObject, ObjectReflector reflector, IDictionary <string, EventInfo> eventsTable) { if (eventsTable.Count == 0) { return; } var fnAddEventListener = context.CreateFunction(new Func <JsObject, string, JsFunction, JsValue>((thisObj, eventName, fnCallback) => { if (String.IsNullOrWhiteSpace(eventName)) { context.CurrentScope.SetException(context.CreateTypeError($"The name of the event listener to register must be specified.")); return(context.Undefined); } object targetObj = null; if (thisObj == null) { context.CurrentScope.SetException(context.CreateTypeError($"Could not register event listener '{eventName}': Invalid 'this' context.")); return(context.Undefined); } if (thisObj.TryGetBean(out JsExternalObject xoObj)) { targetObj = xoObj.Target; } if (!eventsTable.TryGetValue(eventName, out EventInfo targetEvent)) { return(context.False); } Action <object[]> invokeListener = (args) => { //TODO: Object conversion. fnCallback.Call(thisObj, null); }; var targetEventMethod = targetEvent.EventHandlerType.GetMethod("Invoke"); var targetEventParameters = targetEventMethod.GetParameters().Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray(); var exprInvokeListener = Expression.Lambda(targetEvent.EventHandlerType, Expression.Block( Expression.Call( Expression.Constant(invokeListener.Target), invokeListener.Method, Expression.NewArrayInit(typeof(object), targetEventParameters)) ), targetEventParameters); var invokeListenerDelegate = exprInvokeListener.Compile(); IDictionary <string, IList <Tuple <JsFunction, Delegate> > > eventListeners; if (thisObj.HasProperty(BaristaEventListenersPropertyName)) { var xoListeners = thisObj.GetProperty <JsExternalObject>(BaristaEventListenersPropertyName); eventListeners = xoListeners.Target as IDictionary <string, IList <Tuple <JsFunction, Delegate> > >; } else { eventListeners = new Dictionary <string, IList <Tuple <JsFunction, Delegate> > >(); //Set the listeners as a non-configurable, non-enumerable, non-writable property var xoListeners = context.CreateExternalObject(eventListeners); var baristaEventListenersPropertyDescriptor = context.CreateObject(); baristaEventListenersPropertyDescriptor.SetProperty("value", xoListeners); context.Object.DefineProperty(thisObj, context.CreateString(BaristaEventListenersPropertyName), baristaEventListenersPropertyDescriptor); } if (eventListeners != null) { if (eventListeners.ContainsKey(eventName)) { eventListeners[eventName].Add(new Tuple <JsFunction, Delegate>(fnCallback, invokeListenerDelegate)); } else { eventListeners.Add(eventName, new List <Tuple <JsFunction, Delegate> >() { new Tuple <JsFunction, Delegate>(fnCallback, invokeListenerDelegate) }); } } targetEvent.AddMethod.Invoke(targetObj, new object[] { invokeListenerDelegate }); return(context.True); }), "addEventListener"); var fnRemoveEventListener = context.CreateFunction(new Func <JsObject, string, JsFunction, JsValue>((thisObj, eventName, eventListener) => { if (String.IsNullOrWhiteSpace(eventName)) { context.CurrentScope.SetException(context.CreateTypeError($"The name of the event listener to remove must be specified.")); return(context.Undefined); } if (eventListener == null) { context.CurrentScope.SetException(context.CreateTypeError($"The event listener to remove must be specified.")); return(context.Undefined); } object targetObj = null; if (thisObj == null) { context.CurrentScope.SetException(context.CreateTypeError($"Could not unregister event listener '{eventName}': Invalid 'this' context.")); return(context.Undefined); } if (thisObj.TryGetBean(out JsExternalObject xoObj)) { targetObj = xoObj.Target; } if (!eventsTable.TryGetValue(eventName, out EventInfo targetEvent)) { return(context.False); } //Get the event listeners. IDictionary <string, IList <Tuple <JsFunction, Delegate> > > eventListeners = null; if (thisObj.HasProperty(BaristaEventListenersPropertyName)) { var xoListeners = thisObj.GetProperty <JsExternalObject>(BaristaEventListenersPropertyName); eventListeners = xoListeners.Target as IDictionary <string, IList <Tuple <JsFunction, Delegate> > >; } if (eventListeners == null) { return(context.False); } var hasRemoved = false; if (eventListeners.ContainsKey(eventName)) { var listeners = eventListeners[eventName]; var toRemove = new List <Tuple <JsFunction, Delegate> >(); foreach (var listener in listeners) { if (listener.Item1 == eventListener) { targetEvent.RemoveMethod.Invoke(targetObj, new object[] { listener.Item2 }); toRemove.Add(listener); hasRemoved = true; } } eventListeners[eventName] = listeners.Where(l => toRemove.Any(tl => tl == l)).ToList(); } return(hasRemoved ? context.True : context.False); }), "removeEventListener"); var fnRemoveAllEventListeners = context.CreateFunction(new Func <JsObject, string, JsValue>((thisObj, eventName) => { if (String.IsNullOrWhiteSpace(eventName)) { context.CurrentScope.SetException(context.CreateTypeError($"The name of the event listener to remove must be specified.")); return(context.Undefined); } object targetObj = null; if (thisObj == null) { context.CurrentScope.SetException(context.CreateTypeError($"Could not unregister event listener '{eventName}': Invalid 'this' context.")); return(context.Undefined); } if (thisObj.TryGetBean(out JsExternalObject xoObj)) { targetObj = xoObj.Target; } if (!eventsTable.TryGetValue(eventName, out EventInfo targetEvent)) { return(context.False); } //Get the event listeners. IDictionary <string, IList <Tuple <JsFunction, Delegate> > > eventListeners = null; if (thisObj.HasProperty(BaristaEventListenersPropertyName)) { var xoListeners = thisObj.GetProperty <JsExternalObject>(BaristaEventListenersPropertyName); eventListeners = xoListeners.Target as IDictionary <string, IList <Tuple <JsFunction, Delegate> > >; } if (eventListeners == null) { return(context.False); } if (eventListeners.ContainsKey(eventName)) { foreach (var listener in eventListeners[eventName]) { targetEvent.RemoveMethod.Invoke(targetObj, new object[] { listener.Item2 }); } eventListeners.Remove(eventName); } return(context.True); }), "removeAllEventListeners"); var addEventListenerFunctionDescriptor = context.CreateObject(); addEventListenerFunctionDescriptor.SetProperty("enumerable", context.True); addEventListenerFunctionDescriptor.SetProperty("value", fnAddEventListener); targetObject.SetProperty(context.CreateString("addEventListener"), addEventListenerFunctionDescriptor); var removeEventListenerFunctionDescriptor = context.CreateObject(); removeEventListenerFunctionDescriptor.SetProperty("enumerable", context.True); removeEventListenerFunctionDescriptor.SetProperty("value", fnRemoveEventListener); targetObject.SetProperty(context.CreateString("removeEventListener"), removeEventListenerFunctionDescriptor); var removeAllEventListenersFunctionDescriptor = context.CreateObject(); removeAllEventListenersFunctionDescriptor.SetProperty("enumerable", context.True); removeAllEventListenersFunctionDescriptor.SetProperty("value", fnRemoveAllEventListeners); targetObject.SetProperty(context.CreateString("removeAllEventListeners"), removeAllEventListenersFunctionDescriptor); }
public JsString(IJavaScriptEngine engine, BaristaContext context, JavaScriptValueSafeHandle valueHandle) : base(engine, context, valueHandle) { }
public BaristaValueFactory(IJavaScriptEngine engine, BaristaContext context) { m_engine = engine ?? throw new ArgumentNullException(nameof(engine)); m_context = context ?? throw new ArgumentNullException(nameof(context)); m_valuePool = new BaristaObjectPool <JsValue, JavaScriptValueSafeHandle>(); }