public static extern JsObject apply(this JsObject target, JsObject thisReference, JsArray arguments);
public static extern void forin(this JsObject obj, Action <JsObject> iteration);
/// <summary> /// Normally when you `new` a class in C#, it will go through several hops, assuming it to be /// a C# class with a constructor. Using `Jsni.new` you can simply generate Javascript that /// will apply the `new` operator to any 'ol expression. The result of /// `Jsni.new(Jsni.reference("Date"))` would be `new Date()`. /// </summary> public static extern JsObject @new(JsObject target, params JsObject[] arguments);
/// <summary> /// Allows you to represent a Javascript `instanceof` expression in C#. /// /// Jsni.instanceOf(foo, Foo) /// /// is compiled to: /// /// foo instanceof Foo /// </summary> /// <param name="expression"></param> /// <param name="type"></param> /// <returns></returns> public static extern bool instanceof(JsObject expression, JsObject type);
// todo: Move this to Window object in WootzJs.Mvc public static extern JsObject getComputedStyle(JsObject element);
public static extern JsObject call <T>(Action <T> method, JsObject thisReference, params JsObject[] arguments);
public static object FromJsonObject(this JsObject o, Type type) { if (o == null) { return(null); } else if (type.IsArray) { var arrayValue = o.As <JsArray>(); var elementType = type.GetElementType(); var array = Array.CreateInstance(elementType, arrayValue.length); for (var i = 0; i < arrayValue.length; i++) { array.SetValue(FromJsonObject(arrayValue[i], elementType), i); } return(array.As <JsObject>()); } else if (type.IsEnum) { return(Enum.Parse(type, o.As <string>())); } else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List <>)) { var arrayValue = o.As <JsArray>(); var elementType = type.GetGenericArguments()[0]; var list = (IList)Activator.CreateInstance(type); if (arrayValue != null) { for (var i = 0; i < arrayValue.length; i++) { list.Add(FromJsonObject(arrayValue[i], elementType)); } } return(list.As <JsObject>()); } else if (type == typeof(DateTime) || (type.IsNullableValueType() && type.GetGenericArguments()[0] == typeof(DateTime))) { return(DateTime.ParseExact(o.As <string>(), Iso8601).As <JsObject>()); } else if (type.IsPrimitive) { return(Convert.ChangeType(o, type)); } else if (type == typeof(string)) { return(o.As <string>()); } else { var result = Activator.CreateInstance(type); Dictionary <string, PropertyInfo> properties; if (!propertiesByType.TryGetValue(type, out properties)) { properties = type.GetProperties().Where(x => x.CanWrite).ToDictionary(x => x.Name.ToUpper()); propertiesByType[type] = properties; } foreach (var propertyName in o) { var value = o[propertyName]; PropertyInfo property; if (properties.TryGetValue(propertyName.ToUpper(), out property)) { var newValue = FromJsonObject(value, property.PropertyType); property.SetValue(result, newValue, null); } } return(result); } }
public static extern JsString _typeof(JsObject o);
public static extern JsObject member(this JsObject target, string name);
public static extern void clearTimeout(JsObject token);
public static extern void clearInterval(JsObject token);
internal static JsTypeFunction MakeGenericTypeFactory(JsTypeFunction unconstructedType, JsArray typeArgs) { var cache = Jsni.member(unconstructedType, SpecialNames.TypeCache); if (cache == null) { cache = new JsObject(); unconstructedType.memberset(SpecialNames.TypeCache, cache); } var keyArray = Jsni.call <JsArray>(x => x.slice(0), typeArgs, 0.As < JsNumber > ()).As <JsArray>(); var keyParts = new JsArray(); for (var i = 0; i < keyArray.length; i++) { keyParts[i] = keyArray[i].member(SpecialNames.TypeName); } var keyString = keyParts.join(", "); var result = cache[keyString]; if (result == null) { var lastIndexOfDollar = unconstructedType.TypeName.LastIndexOf('`'); var newTypeName = unconstructedType.TypeName.Substring(0, lastIndexOfDollar) + "<" + keyString + ">"; var prototype = unconstructedType.BaseType; if (prototype.member("$")) { prototype = prototype.member("$").apply(null, typeArgs).As <JsTypeFunction>(); } var generic = Define(newTypeName, prototype); generic.memberset(SpecialNames.UnconstructedType, unconstructedType); // unconstructedType.$TypeInitializer.apply(this, [generic, generic.prototype].concat(Array.prototype.slice.call(arguments, 0))); Jsni.apply( Jsni.member(unconstructedType, SpecialNames.TypeInitializer), unconstructedType, Jsni.invoke( Jsni.member(Jsni.array(generic, generic.prototype), "concat"), keyArray ).As <JsArray>()); generic.TypeInitializer = Jsni.procedure((t, p) => { p.___type = generic; t.As <JsTypeFunction>().BaseType = unconstructedType; t.As <JsTypeFunction>().GetTypeFromType = Jsni.function(() => Type._GetTypeFromTypeFunc(Jsni.@this().As <JsTypeFunction>()).As <JsObject>()); t.As <JsTypeFunction>().TypeName = newTypeName; t.As <JsTypeFunction>().CreateTypeField = Jsni.function(() => { var unconstructedTypeType = Type._GetTypeFromTypeFunc(unconstructedType); var type = new Type(newTypeName, new Attribute[0]); generic.Type = type; type.thisType = generic; var typeParameters = unconstructedTypeType.typeArguments; var typeArguments = InitializeArray(typeArgs, Jsni.type <JsTypeFunction>()).As <JsTypeFunction[]>(); Func <Type, JsTypeFunction> reifyGenerics = null; reifyGenerics = theType => { if (theType == null) { return(null); } if (theType.IsArray) { var elementType = theType.GetElementType(); var arrayType = MakeArrayType(reifyGenerics(elementType)); return(arrayType); } if (theType.IsGenericParameter) { for (int i = 0; i < typeArguments.Length; i++) { var typeParameter = typeParameters[i]; var typeArgument = typeArguments[i]; if (typeParameter.TypeName == theType.FullName) { return(typeArgument); } } } else if (theType.IsGenericTypeDefinition) { return(MakeGenericTypeFactory(theType.thisType, theType.GenericTypeArguments.Select(x => reifyGenerics(x)).ToArray().As <JsArray>())); } else if (theType.IsGenericType) { JsTypeFunction[] newTypeArguments = null; for (var i = 0; i < theType.typeArguments.Length; i++) { var theTypeArgument = theType.typeArguments[i]; for (var j = 0; j < typeParameters.Length; j++) { var typeParameter = typeParameters[j]; var typeArgument = typeArguments[j]; if (theTypeArgument == typeParameter) { if (newTypeArguments == null) { newTypeArguments = new JsTypeFunction[theType.typeArguments.Length]; for (var k = 0; k < theType.typeArguments.Length; k++) { newTypeArguments[k] = theType.typeArguments[k]; } } newTypeArguments[i] = typeArgument; } } } if (newTypeArguments != null) { return(MakeGenericTypeFactory(theType.unconstructedType, newTypeArguments.As <JsArray>())); } else { return(theType.thisType); } } return(theType.thisType); }; var newInterfaces = unconstructedTypeType.interfaces.ToArray(); for (var i = 0; i < newInterfaces.Length; i++) { var intf = newInterfaces[i]; intf = reifyGenerics(Type._GetTypeFromTypeFunc(intf)); newInterfaces[i] = intf; } var newConstructors = unconstructedTypeType.constructors.ToArray(); for (var i = 0; i < newConstructors.Length; i++) { var constructor = newConstructors[i]; var parameters = constructor.GetParameters(); for (var j = 0; j < parameters.Length; j++) { var parameter = parameters[j]; var parameterType = reifyGenerics(parameter.ParameterType); parameter = new ParameterInfo(parameter.Name, parameterType, j, parameter.Attributes, parameter.DefaultValue, parameter.attributes); parameters[j] = parameter; } newConstructors[i] = new ConstructorInfo(constructor.Name, generic.prototype[constructor.Name].As <JsFunction>(), parameters, constructor.Attributes, constructor.attributes); } var newProperties = unconstructedTypeType.properties.ToArray(); for (var i = 0; i < newProperties.Length; i++) { var property = newProperties[i]; var propertyTypeType = property.PropertyType; var propertyType = reifyGenerics(propertyTypeType); newProperties[i] = new PropertyInfo(property.Name, propertyType, property.GetGetMethod(), property.GetSetMethod(), property.GetIndexParameters(), property.attributes); } var newMethods = unconstructedTypeType.methods.ToArray(); for (var i = 0; i < newMethods.Length; i++) { var method = newMethods[i]; var returnTypeType = method.ReturnType; var returnType = reifyGenerics(returnTypeType); var parameters = method.GetParameters(); for (var j = 0; j < parameters.Length; j++) { var parameter = parameters[j]; var parameterType = reifyGenerics(parameter.ParameterType); parameter = new ParameterInfo(parameter.Name, parameterType, j, parameter.Attributes, parameter.DefaultValue, parameter.attributes); parameters[j] = parameter; } method = new MethodInfo(method.Name, method.jsMethod, parameters, returnType, method.Attributes, method.attributes); newMethods[i] = method; } type.Init( newTypeName, unconstructedTypeType.typeAttributes, generic, unconstructedType.BaseType, newInterfaces, typeArguments, unconstructedTypeType.fields, newMethods, newConstructors, newProperties, unconstructedTypeType.events, false, unconstructedTypeType.IsAbstract, unconstructedTypeType.IsInterface, false, true, false, unconstructedTypeType.IsEnum, null, unconstructedType); return(type.As <JsObject>()); }); }, SpecialNames.TypeInitializerTypeFunction, SpecialNames.TypeInitializerPrototype); Jsni.call(generic.TypeInitializer, Jsni.@this(), generic, generic.prototype); result = generic; cache[keyString] = result; } return(result.As <JsTypeFunction>()); }
public static JsTypeFunction Define(JsFunction assembly, JsTypeFunction enclosingType, string name, bool isGenericType, JsArray typeParameters, JsObject prototype, JsFunction typeInitializer) { JsTypeFunction typeFunction = null; var isTypeInitialized = false; // Create constructor function, which is a superconstructor that takes in the actual // constructor as the first argument, and the rest of the arguments are passed directly // to that constructor. These subconstructors are not Javascript constructors -- they // are not called via new, they exist for initialization only. typeFunction = Jsni.function((constructor, args) => { if (constructor != null || !(Jsni.instanceof(Jsni.@this(), typeFunction))) { if (!isGenericType || typeFunction.UnconstructedType != null) { typeFunction.member(SpecialNames.StaticInitializer).invoke(); } } if (constructor != null) { constructor.apply(Jsni.@this(), args.As <JsArray>()); } if (!Jsni.instanceof(Jsni.@this(), typeFunction)) { return(typeFunction); } else { return(Jsni.@this()); } }).As <JsTypeFunction>(); typeFunction.GetAssembly = assembly; assembly.member(SpecialNames.AssemblyTypesArray).member("push").invoke(typeFunction); typeFunction.memberset("toString", Jsni.function(() => name.As <JsObject>())); typeFunction.EnclosingType = enclosingType; typeFunction.TypeName = name; typeFunction.prototype = Jsni.@new(prototype); typeFunction.IsPrototypeInitialized = false; typeFunction.TypeInitializer = Jsni.procedure((_t, p) => { var t = _t.As <JsTypeFunction>(); if (isGenericType) { var unconstructedType = t.UnconstructedType ?? t; t.GenericTypeFunction = Jsni.function(() => { return(Jsni.reference(SpecialNames.MakeGenericTypeConstructor).As <JsFunction>().call(unconstructedType, unconstructedType, Jsni.arguments()).As <JsFunction>().invoke()); }); } t.GetTypeFromType = Jsni.function(() => { return(Type._GetTypeFromTypeFunc(Jsni.@this().As <JsTypeFunction>()).As <JsObject>()); }); p.memberset(SpecialNames.TypeName, t.member(SpecialNames.TypeName)); p.___type = t; t.BaseType = prototype.As <JsTypeFunction>(); typeInitializer.apply(Jsni.@this(), Jsni.arguments().As <JsArray>()); }); typeFunction.CallTypeInitializer = Jsni.procedure(() => { typeFunction.TypeInitializer.apply(enclosingType, Jsni.array(typeFunction, typeFunction.prototype).concat(typeParameters)); }); return(typeFunction); }
internal static JsTypeFunction MakeGenericTypeFactory(JsTypeFunction unconstructedType, JsArray typeArgs) { var cache = Jsni.member(unconstructedType, SpecialNames.TypeCache); JsObject result = null; if (typeArgs.length > 0) { if (cache == null) { cache = new JsObject(); unconstructedType.memberset(SpecialNames.TypeCache, cache); } JsObject currentCache = cache; for (var i = 0; i < typeArgs.length - 1; i++) { var nextCache = currentCache[typeArgs[i].member(SpecialNames.TypeName)]; if (nextCache == null) { nextCache = new JsObject(); currentCache[typeArgs[i].member(SpecialNames.TypeName)] = nextCache; } currentCache = nextCache; } cache = currentCache; result = cache[typeArgs[typeArgs.length - 1].member(SpecialNames.TypeName)]; } else { result = cache; } // JsObject keyString; // First two if statements are optimizations for performance reasons to avoid heap allocation when possible. /* * if (typeArgs.length == 0) * keyString = ""; * else if (typeArgs.length == 1) * keyString = typeArgs[0].member(SpecialNames.TypeName); * else * { * var keyArray = Jsni.call<JsArray>(x => x.slice(0), typeArgs, 0.As<JsNumber>()).As<JsArray>(); * var keyParts = new JsArray(); * for (var i = 0; i < keyArray.length; i++) * { * keyParts[i] = keyArray[i].member(SpecialNames.TypeName); * } * keyString = keyParts.join(", "); * } * * var result = cache[keyString]; */ if (result == null) { var keyArray = Jsni.call <JsArray>(x => x.slice(0), typeArgs, 0.As < JsNumber > ()).As <JsArray>(); var keyParts = new JsArray(); for (var i = 0; i < keyArray.length; i++) { keyParts[i] = keyArray[i].member(SpecialNames.TypeName); } var keyString = keyParts.join(", "); var lastIndexOfDollar = unconstructedType.TypeName.LastIndexOf('`'); if (lastIndexOfDollar == -1) { lastIndexOfDollar = unconstructedType.TypeName.Length; } var newTypeName = unconstructedType.TypeName.Substring(0, lastIndexOfDollar) + "<" + keyString + ">"; var prototype = unconstructedType.BaseType; if (prototype.member("$")) { var baseArgs = unconstructedType.BaseTypeArgs.slice(0); for (var i = 0; i < baseArgs.length; i++) { var baseArg = (JsTypeFunction)baseArgs[i]; if (baseArg.IsTypeParameter) { for (var j = 0; j < unconstructedType.TypeArgs.length; j++) { var typeArg = unconstructedType.TypeArgs[j]; if (typeArg == baseArg) { baseArgs[i] = typeArgs[j]; } } } } prototype = prototype.member("$").apply(null, baseArgs).As <JsTypeFunction>(); } var typeInitializer = Jsni.procedure((_t, p) => { var t = _t.As <JsTypeFunction>(); p.___type = t; t.As <JsTypeFunction>().BaseType = unconstructedType; t.As <JsTypeFunction>().GetTypeFromType = Jsni.function(() => Type._GetTypeFromTypeFunc(Jsni.@this().As <JsTypeFunction>()).As <JsObject>()); t.As <JsTypeFunction>().TypeName = newTypeName; t.As <JsTypeFunction>().CreateTypeField = Jsni.function(() => { var unconstructedTypeType = Type._GetTypeFromTypeFunc(unconstructedType); var type = new Type(newTypeName, new Attribute[0]); t.Type = type; type.thisType = t; var typeParameters = unconstructedTypeType.typeArguments; var typeArguments = InitializeArray(typeArgs, Jsni.type <JsTypeFunction>()).As <JsTypeFunction[]>(); Func <Type, JsTypeFunction> reifyGenerics = null; reifyGenerics = theType => { if (theType == null) { return(null); } if (theType.IsArray) { var elementType = theType.GetElementType(); var arrayType = MakeArrayType(reifyGenerics(elementType)); return(arrayType); } if (theType.IsGenericParameter) { for (int i = 0; i < typeArguments.Length; i++) { var typeParameter = typeParameters[i]; var typeArgument = typeArguments[i]; if (typeParameter.TypeName == theType.FullName) { return(typeArgument); } } } else if (theType.IsGenericTypeDefinition) { return(MakeGenericTypeFactory(theType.thisType, theType.GenericTypeArguments.Select(x => reifyGenerics(x)).ToArray().As <JsArray>())); } else if (theType.IsGenericType) { JsTypeFunction[] newTypeArguments = null; for (var i = 0; i < theType.typeArguments.Length; i++) { var theTypeArgument = theType.typeArguments[i]; for (var j = 0; j < typeParameters.Length; j++) { var typeParameter = typeParameters[j]; var typeArgument = typeArguments[j]; if (theTypeArgument == typeParameter) { if (newTypeArguments == null) { newTypeArguments = new JsTypeFunction[theType.typeArguments.Length]; for (var k = 0; k < theType.typeArguments.Length; k++) { newTypeArguments[k] = theType.typeArguments[k]; } } newTypeArguments[i] = typeArgument; } } } if (newTypeArguments != null) { return(MakeGenericTypeFactory(theType.unconstructedType, newTypeArguments.As <JsArray>())); } else { return(theType.thisType); } } return(theType.thisType); }; var newInterfaces = unconstructedTypeType.interfaces.ToArray(); for (var i = 0; i < newInterfaces.Length; i++) { var intf = newInterfaces[i]; intf = reifyGenerics(Type._GetTypeFromTypeFunc(intf)); newInterfaces[i] = intf; } var newConstructors = unconstructedTypeType.constructors.ToArray(); for (var i = 0; i < newConstructors.Length; i++) { var constructor = newConstructors[i]; var parameters = constructor.GetParameters(); for (var j = 0; j < parameters.Length; j++) { var parameter = parameters[j]; var parameterType = reifyGenerics(parameter.ParameterType); parameter = new ParameterInfo(parameter.Name, parameterType, j, parameter.Attributes, parameter.DefaultValue, parameter.attributes); parameters[j] = parameter; } newConstructors[i] = new ConstructorInfo(constructor.Name, t.prototype[constructor.Name].As <JsFunction>(), parameters, constructor.Attributes, constructor.attributes); } var newProperties = unconstructedTypeType.properties.ToArray(); for (var i = 0; i < newProperties.Length; i++) { var property = newProperties[i]; var propertyTypeType = property.PropertyType; var propertyType = reifyGenerics(propertyTypeType); newProperties[i] = new PropertyInfo(property.Name, propertyType, property.GetGetMethod(), property.GetSetMethod(), property.GetIndexParameters(), property.attributes); } var newMethods = unconstructedTypeType.methods.ToArray(); for (var i = 0; i < newMethods.Length; i++) { var method = newMethods[i]; var returnTypeType = method.ReturnType; var returnType = reifyGenerics(returnTypeType); var parameters = method.GetParameters(); for (var j = 0; j < parameters.Length; j++) { var parameter = parameters[j]; var parameterType = reifyGenerics(parameter.ParameterType); parameter = new ParameterInfo(parameter.Name, parameterType, j, parameter.Attributes, parameter.DefaultValue, parameter.attributes); parameters[j] = parameter; } method = new MethodInfo(method.Name, method.jsMethod, parameters, returnType, method.Attributes, method.attributes); newMethods[i] = method; } type.Init( newTypeName, (int)((unconstructedTypeType.typeFlags | TypeFlags.GenericType) & ~TypeFlags.GenericTypeDefenition), t, prototype, newInterfaces, typeArguments, unconstructedTypeType.fields, newMethods, newConstructors, newProperties, unconstructedTypeType.events, null, unconstructedType); return(type.As <JsObject>()); }); }, SpecialNames.TypeInitializerTypeFunction, SpecialNames.TypeInitializerPrototype); var generic = Define(unconstructedType.GetAssembly, unconstructedType.EnclosingType, newTypeName, true, Jsni.array(), prototype, typeInitializer); generic.memberset(SpecialNames.UnconstructedType, unconstructedType); // unconstructedType.$TypeInitializer.apply(this, [generic, generic.prototype].concat(Array.prototype.slice.call(arguments, 0))); unconstructedType.member(SpecialNames.TypeInitializer).apply( unconstructedType, Jsni.array(generic, generic.prototype).member("concat").invoke(keyArray).As <JsArray>() ); Jsni.call(generic.TypeInitializer, Jsni.@this(), generic, generic.prototype); result = generic; if (typeArgs.length == 0) { unconstructedType.memberset(SpecialNames.TypeCache, result); } else { cache[typeArgs[typeArgs.length - 1].member(SpecialNames.TypeName)] = result; } } return(result.As <JsTypeFunction>()); }
public static extern JsObject call(this JsObject target, JsObject thisReference, params JsObject[] arguments);
public static extern JsObject memberset(this JsObject target, string name, JsObject value);
public static extern JsObject apply <T>(Action <T> method, JsObject thisReference, JsArray arguments);
public static extern JsObject invoke(this JsObject target, params JsObject[] arguments);
/// <summary> /// Deletes a property from a Javascript object. Compiles to the Javascript `delete` expression. /// `Jsni.delete(o.foo)` is compiled to `delete o.foo`. It is imperative that the expression /// passed to this method represents a member reference expression (since the `delete` keyword /// makes the same restriction -- it's how it identifies both the property to delete and its /// containing object.) /// </summary> /// <param name="o"></param> public static extern void delete(JsObject o);
public static T FromJsonObject <T>(this JsObject o) { return((T)FromJsonObject(o, typeof(T))); }