Exemple #1
0
        protected override void WriteEvent(
            Method eventMethod,
            string declaringTypeFullName,
            string boundTypeFullName,
            bool isInterfaceMember,
            CodeWriter code)
        {
            if (!isInterfaceMember && !eventMethod.IsAbstract)
            {
                string listenerTypeFullName = eventMethod.Parameters[0].ParameterType;
                Type   listenerType;
                if (!this.listenerMap.TryGetValue(listenerTypeFullName, out listenerType))
                {
                    throw new InvalidOperationException(
                              "Listener delegate type not found: " + listenerTypeFullName);
                }

                string boundEventTypeFullName = this.GetBoundEventTypeForListenerType(listenerType);
                string eventTypeName          = GetTypeName(boundEventTypeFullName, declaringTypeFullName);
                string eventName = eventMethod.Name.Substring(
                    "Add".Length, eventMethod.Name.Length - "AddListener".Length);
                string listenerMapType = "System.Collections.Generic.Dictionary<" +
                                         $"System.EventHandler<{eventTypeName}>, {listenerTypeFullName}>";
                code.Code($"{(eventMethod.IsStatic ? "static " : "")}{listenerMapType} __{eventName}ListenerMap =");
                code.Code($"\tnew {listenerMapType}();");
                code.Code();
            }

            base.WriteEvent(eventMethod, declaringTypeFullName, boundTypeFullName, isInterfaceMember, code);
        }
Exemple #2
0
        protected override void WriteEventAdder(
            string eventName, Member eventMember, string declaringTypeFullName, string forward, CodeWriter code)
        {
            Method eventMethod = eventMember as Method;
            Event  eventEvent  = eventMember as Event;
            bool   isStatic    = (eventMethod != null && eventMethod.IsStatic) ||
                                 (eventEvent != null && eventEvent.IsStatic);

            string listenerTypeFullName = (eventMethod != null ? eventMethod.Parameters[0].ParameterType :
                                           eventEvent != null ? eventEvent.EventHandlerType : "???");
            string sender = isStatic ?
                            "typeof(" + GetTypeName(declaringTypeFullName, declaringTypeFullName) + ")" : "this";

            code.Code("add");
            code.Code("{");
            code.Code($"\tif (__{eventName}ListenerMap.ContainsKey(value)) return;");
            code.Code($"\t{listenerTypeFullName} listener = (sender, e) => {{");

            // TODO: IOS event listeners currently fail to get removed at the native code layer,
            // because the Xamarin binding layer creates unique blocks.
            // This check for presence in the map is a workaround until a better solution is found.
            code.Code($"\t\tif (__{eventName}ListenerMap.ContainsKey(value)) value({sender}, e);");

            code.Code("\t};");
            code.Code($"\t{forward}.Add{eventName}Listener(listener);");
            code.Code($"\t__{eventName}ListenerMap[value] = listener;");
            code.Code("}");
        }
Exemple #3
0
        void WriteTypeScriptBindingForConstructor(
            Type declaringType, Constructor constructor, CodeWriter code)
        {
            string parameters = String.Join(", ", constructor.Parameters.Select(
                                                p => p.Name + ": " + this.GetJavaScriptTypeName(p.ParameterType, declaringType)));

            code.Code($"constructor({parameters});");
        }
Exemple #4
0
 protected override void WritePropertySetter(
     Property property, string mappedPropertyType, string forward, CodeWriter code)
 {
     // The Objective Sharpie binder /sometimes/ binds static property setters as normal methods.
     if (!property.SetMethod.Name.StartsWith("set_"))
     {
         code.Code("set");
         code.Code("{");
         code.Code($"\t{forward}.{property.SetMethod.Name}(" +
                   this.CastArgument("value", mappedPropertyType, property.PropertyType) + ");");
         code.Code("}");
     }
     else
     {
         base.WritePropertySetter(property, mappedPropertyType, forward, code);
     }
 }
Exemple #5
0
        protected override void WriteEventRemover(
            string eventName, Member eventMember, string declaringTypeFullName, string forward, CodeWriter code)
        {
            Event  eventEvent             = (Event)eventMember;
            string boundEventTypeFullName = this.GetBoundEventTypeForListenerType(eventEvent.EventHandlerType);

            code.Code("remove");
            code.Code("{");
            code.Code($"\tSystem.EventHandler<{this.PluginAlias}{boundEventTypeFullName}> handler;");
            code.Code($"\tif (__{eventName}ListenerMap.TryGetValue(value, out handler))");
            code.Code("\t{");
            code.Code($"\t\t{forward}.{eventName} -= handler;");
            code.Code($"\t\t__{eventName}ListenerMap.Remove(value);");
            code.Code("\t}");
            code.Code("}");
        }
Exemple #6
0
        void WriteEventListener(
            string eventName,
            string boundEventTypeFullName,
            string eventTypeName,
            Type listenerType,
            CodeWriter code)
        {
            string listenerMethodName = listenerType.Members.Cast <Method>().Single().Name;

            code.Code($"class __{eventName}Listener : global::Java.Lang.Object, {listenerType.FullName}");
            code.Code("{");
            code.Code("\tpublic object Sender { get; set; }");
            code.Code($"\tpublic System.EventHandler<{eventTypeName}> Handler {{ get; set; }}");
            code.Code($"\tpublic void {listenerMethodName}({boundEventTypeFullName} e)");
            code.Code("\t{");
            code.Code("\t\tHandler(Sender, e);");
            code.Code("\t}");
            code.Code("}");
            code.Code();
        }
Exemple #7
0
        protected override void WriteOutErrorConstructor(
            Constructor constructor,
            string declaringTypeFullName,
            string boundTypeFullName,
            CodeWriter code)
        {
            string context    = this.GetImplicitContext(constructor, code);
            int    skip       = context != null ? 1 : 0;
            string parameters = String.Join(", ", constructor.Parameters.Skip(skip)
                                            .Take(constructor.Parameters.Count - 1 - skip).Select(
                                                (p, i) => GetParameterTypeName(p.ParameterType, declaringTypeFullName, null, i) + " " + p.Name));
            string visibility = declaringTypeFullName.EndsWith("Event") ? "internal" : "public";

            code.Code($"{visibility} {GetNameFromTypeFullName(declaringTypeFullName)}({parameters})");
            code.Code("{");
            code.Code("\tFoundation.NSError error;");

            if (context != null && constructor.Parameters.Count > 1)
            {
                context += ", ";
            }

            string arguments = (context != null ? context : String.Empty) +
                               String.Join(", ", constructor.Parameters.Skip(skip)
                                           .Take(constructor.Parameters.Count - 1 - skip).Select(
                                               (p, i) => this.CastArgument(
                                                   p.Name,
                                                   this.GetParameterTypeName(p.ParameterType, declaringTypeFullName, null, i),
                                                   p.ParameterType))) + (constructor.Parameters.Count > 1 + skip ? ", " : "") + "out error";

            code.Code($"\tforward = new {boundTypeFullName}({arguments});");
            code.Code("\tif (error != null) throw new Foundation.NSErrorException(error);");

            code.Code("}");
        }
Exemple #8
0
        void WriteTypeScriptBindingForField(Type declaringType, Member fieldOrProperty, CodeWriter code)
        {
            EnumValue enumValue = fieldOrProperty as EnumValue;
            Field     field     = fieldOrProperty as Field;
            Property  property  = fieldOrProperty as Property;

            if (enumValue != null)
            {
                code.Code($"{Uncapitalize(enumValue.Name)} = {enumValue.Value},");
            }
            else if (field != null)
            {
                string typeName = this.GetJavaScriptTypeName(field.FieldType, declaringType);
                code.Code($"{Uncapitalize(field.Name)}: {typeName};");
            }
            else if (property != null)
            {
                string typeName = this.GetJavaScriptTypeName(property.PropertyType, declaringType);
                string modifier = property.SetMethod == null ? "readonly " : "";
                code.Code($"{modifier}{Uncapitalize(property.Name)}: {typeName};");
            }
        }
Exemple #9
0
        protected override void WriteEvent(
            Event eventMember,
            string declaringTypeFullName,
            string boundTypeFullName,
            bool isInterfaceMember,
            CodeWriter code)
        {
            if (!isInterfaceMember)
            {
                string boundEventTypeFullName = this.GetBoundEventTypeForListenerType(eventMember.EventHandlerType);
                string eventTypeName          = GetTypeName(boundEventTypeFullName, declaringTypeFullName);
                string listenerMapType        = "System.Collections.Generic.Dictionary<" +
                                                $"System.EventHandler<{eventTypeName}>, " +
                                                $"System.EventHandler<{this.PluginAlias}{boundEventTypeFullName}>>";
                code.Code($"{(eventMember.IsStatic ? "static " : "")}" +
                          $"{listenerMapType} __{eventMember.Name}ListenerMap =");
                code.Code($"\tnew {listenerMapType}();");
                code.Code();
            }

            base.WriteEvent(eventMember, declaringTypeFullName, boundTypeFullName, isInterfaceMember, code);
        }
Exemple #10
0
        protected override void WriteEventRemover(
            string eventName, Member eventMember, string declaringTypeFullName, string forward, CodeWriter code)
        {
            Method eventMethod = eventMember as Method;
            Event  eventEvent  = eventMember as Event;

            string listenerTypeFullName = (eventMethod != null ? eventMethod.Parameters[0].ParameterType :
                                           eventEvent != null ? eventEvent.EventHandlerType : "???");

            code.Code("remove");
            code.Code("{");
            code.Code($"\t{listenerTypeFullName} listener;");
            code.Code($"\tif (__{eventName}ListenerMap.TryGetValue(value, out listener))");
            code.Code("\t{");
            code.Code($"\t\t{forward}.Remove{eventName}Listener(listener);");
            code.Code($"\t\t__{eventName}ListenerMap.Remove(value);");
            code.Code("\t}");
            code.Code("}");
        }
Exemple #11
0
        protected override void WriteEventAdder(
            string eventName, Member eventMember, string declaringTypeFullName, string forward, CodeWriter code)
        {
            Event  eventEvent             = (Event)eventMember;
            string sender                 = eventEvent.IsStatic ? "typeof(" + declaringTypeFullName + ")" : "this";
            string boundEventTypeFullName = this.GetBoundEventTypeForListenerType(eventEvent.EventHandlerType);

            code.Code("add");
            code.Code("{");
            code.Code($"\tif (__{eventName}ListenerMap.ContainsKey(value)) return;");
            code.Code($"\tSystem.EventHandler<{this.PluginAlias}{boundEventTypeFullName}> handler = ");
            code.Code($"\t\t(sender, e) => value({sender}, e);");
            code.Code($"\t{forward}.{eventName} += handler;");
            code.Code($"\t__{eventName}ListenerMap[value] = handler;");
            code.Code("}");
        }
Exemple #12
0
        protected override string GetImplicitContext(Member member, CodeWriter code)
        {
            Constructor constructor = member as Constructor;
            Method      method      = member as Method;

            if ((constructor != null && constructor.Parameters.Count > 0 &&
                 constructor.Parameters[0].ParameterType == "UIKit.UIApplication") ||
                (method != null && method.Parameters.Count > 0 &&
                 method.Parameters[0].ParameterType == "UIKit.UIApplication"))
            {
                code.Code($"[{typeof(ImplicitContextAttribute).FullName}(\"{ImplicitContextAttribute.Application}\")]");
                return(typeof(IOSApiAdapter).Namespace + ".PluginContext.Application");
            }
            else if ((constructor != null && constructor.Parameters.Count > 0 &&
                      constructor.Parameters[0].ParameterType == "UIKit.UIWindow") ||
                     (method != null && method.Parameters.Count > 0 &&
                      method.Parameters[0].ParameterType == "UIKit.UIWindow"))
            {
                code.Code($"[{typeof(ImplicitContextAttribute).FullName}(\"{ImplicitContextAttribute.Window}\")]");
                return(typeof(IOSApiAdapter).Namespace + ".PluginContext.CurrentWindow");
            }

            return(null);
        }
Exemple #13
0
        protected override void WriteInnerTypes(Class outerClass, string outerClassFullName, CodeWriter code)
        {
            base.WriteInnerTypes(outerClass, outerClassFullName, code);

            List <Type> inferredInnerTypes;

            if (this.innerTypeMap.TryGetValue(outerClass.FullName, out inferredInnerTypes))
            {
                foreach (Type innerType in inferredInnerTypes)
                {
                    string innerName = innerType.Name.Substring(innerType.Name.LastIndexOf('_') + 1);

                    code.Code();
                    this.WriteType(innerType, outerClassFullName + "+" + innerName, code);
                }
            }
        }
Exemple #14
0
        void WriteTypeScriptBindingsForProperty(Type declaringType, Property property, CodeWriter code)
        {
            CodeWriter body         = code.Indent();
            string     propertyName = property.Name;

            if (propertyName.StartsWith("Is"))
            {
                propertyName = propertyName.Substring(2);
            }

            bool isInterfaceMember = declaringType is Interface;

            string simpleName = declaringType.Name.Substring(declaringType.Name.IndexOf('+') + 1);

            if (property.GetMethod != null)
            {
                string propertyDeclaration;
                string returnType = this.GetJavaScriptTypeName(property.PropertyType, declaringType);
                if (this.ForceAsyncAPIs)
                {
                    propertyDeclaration =
                        (property.Name.StartsWith("Is") ? Uncapitalize(property.Name) : "get" + property.Name) +
                        "Async";
                    returnType = MakePromiseTypeName(returnType);
                }
                else
                {
                    propertyDeclaration = "get " + Uncapitalize(property.Name);
                }

                code.Code((property.IsStatic ? "static " : String.Empty) +
                          $"{propertyDeclaration}(): {returnType}" + (isInterfaceMember ? ";" : "{"));
                if (!isInterfaceMember)
                {
                    string retCast = "";
                    if (property.PropertyType == "System.Boolean")
                    {
                        retCast = ".then(result => !!result)";
                    }
                    else if (property.PropertyType == "System.Guid")
                    {
                        retCast = ".then(result => (typeof(result) === \"string\" ? " +
                                  "result.toUpperCase() : result && result.value))";
                    }
                    else if (property.PropertyType == "System.Uri")
                    {
                        retCast = ".then(result => (typeof(result) === \"string\" ? " +
                                  "result : result && result.value))";
                    }

                    if (property.IsStatic)
                    {
                        body.Code("return bridge.getStaticProperty(" +
                                  $"{simpleName}.type, \"{propertyName}\"){retCast};");
                    }
                    else
                    {
                        body.Code($"return bridge.getProperty(this, \"{propertyName}\"){retCast};");
                    }

                    code.Code("}");
                }
            }

            if (property.SetMethod != null)
            {
                string propertyDeclaration;
                string returnType;
                string returnStatement;
                if (this.ForceAsyncAPIs)
                {
                    propertyDeclaration = "set" + propertyName + "Async";
                    returnType          = ": " + MakePromiseTypeName("void");
                    returnStatement     = "return ";
                }
                else
                {
                    propertyDeclaration = "set " + Uncapitalize(property.Name);
                    returnType          = String.Empty;
                    returnStatement     = String.Empty;
                }

                string typeName = this.GetJavaScriptTypeName(property.PropertyType, declaringType);
                code.Code((property.IsStatic ? "static " : String.Empty) +
                          $"{propertyDeclaration}(value: {typeName}){returnType}" + (isInterfaceMember ? ";" : "{"));
                if (!isInterfaceMember)
                {
                    string value = "value";
                    if (property.PropertyType == "System.Guid")
                    {
                        value = "(typeof(value) === \"string\" ? { \"type\": \"<uuid>\", \"value\": value } : null)";
                    }
                    else if (property.PropertyType == "System.Uri")
                    {
                        value = "(typeof(value) === \"string\" ? { \"type\": \"<uri>\", \"value\": value } : null)";
                    }

                    if (property.IsStatic)
                    {
                        body.Code($"{returnStatement}bridge.setStaticProperty(" +
                                  $"{simpleName}.type, \"{propertyName}\", {value});");
                    }
                    else
                    {
                        body.Code($"{ returnStatement}bridge.setProperty(this, \"{propertyName}\", {value});");
                    }

                    code.Code("}");
                }
            }
        }
Exemple #15
0
        protected override void WriteAsyncMethod(
            Method method,
            string declaringTypeFullName,
            string boundTypeFullName,
            bool isInterfaceMember,
            CodeWriter code)
        {
            string methodName = method.Name;

            if ((method.Parameters.Count == 1 || method.Parameters.Count == 2) &&
                method.Parameters.All(p => p.ParameterType.StartsWith("System.Action")))
            {
                if (methodName.EndsWith("AndThen"))
                {
                    methodName = methodName.Substring(0, methodName.Length - "AndThen".Length);
                }
                else if (methodName.EndsWith("Then"))
                {
                    methodName = methodName.Substring(0, methodName.Length - "Then".Length);
                }
                else if (methodName.EndsWith("WithResult"))
                {
                    methodName = methodName.Substring(0, methodName.Length - "WithResult".Length);
                }
                else if (methodName.EndsWith("Result"))
                {
                    methodName = methodName.Substring(0, methodName.Length - "Result".Length);
                }
            }

            string context = this.GetImplicitContext(method, code);
            int    skip    = context != null ? 1 : 0;

            bool hasCatchCallback       = false;
            int  callbackParameterIndex = method.Parameters.Count - 1;

            if (method.Parameters[callbackParameterIndex].ParameterType == "System.Action<Foundation.NSError>")
            {
                --callbackParameterIndex;
                hasCatchCallback = true;
            }

            if (callbackParameterIndex < 0 ||
                !method.Parameters[callbackParameterIndex].ParameterType.StartsWith("System.Action"))
            {
                throw new InvalidOperationException("Invalid async method signature: " + method);
            }

            bool   hasReturnValue        = false;
            string returnValueType       = "void";
            string returnType            = "System.Threading.Tasks.Task";
            string thenCallbackType      = method.Parameters[callbackParameterIndex].ParameterType;
            string callbackParameterType = null;
            int    ltIndex = thenCallbackType.IndexOf('<');

            if (ltIndex > 0)
            {
                hasReturnValue        = true;
                callbackParameterType =
                    thenCallbackType.Substring(ltIndex + 1, thenCallbackType.Length - ltIndex - 2);
                returnValueType = GetMemberTypeName(callbackParameterType, declaringTypeFullName, method.Name);
                returnType     += "<" + returnValueType + ">";
            }

            bool   isAbstract     = isInterfaceMember || method.IsAbstract;
            int    parameterCount = method.Parameters.Count - (hasCatchCallback ? 2 : 1) - skip;
            string parameters     = String.Join(", ", method.Parameters.Skip(skip).Take(parameterCount).Select(
                                                    (p, i) => GetParameterTypeName(p.ParameterType, declaringTypeFullName, method.Name, i) + " " + p.Name));

            code.Code($"{(isInterfaceMember ? "" : "public ")}{(method.IsStatic ? "static " : "")}" +
                      $"{(isAbstract && !isInterfaceMember ? "abstract" : "async")} {returnType} " +
                      $"{methodName}({parameters}){(isAbstract ? ";" : "")}");

            if (!isAbstract)
            {
                code.Code("{");
                if (hasReturnValue)
                {
                    code.Code($"\tvar asyncResult = default({returnValueType});");
                }

                code.Code("\tvar completion = new System.Threading.Tasks.TaskCompletionSource<bool>();");
                code.Code($"\t{thenCallbackType} success = ({(hasReturnValue ? "result" : "")}) =>");

                if (hasReturnValue)
                {
                    code.Code("\t{");
                    code.Code($"\t\tasyncResult = " +
                              this.CastArgument("result", callbackParameterType, returnValueType) + ";");
                    code.Code("\t\tcompletion.SetResult(true);");
                    code.Code("\t};");
                }
                else
                {
                    code.Code("\t\tcompletion.SetResult(true);");
                }

                if (hasCatchCallback)
                {
                    code.Code("\tSystem.Action<Foundation.NSError> failure = (error) =>");
                    code.Code("\t\tcompletion.SetException(new Foundation.NSErrorException(error));");
                }

                if (context != null && method.Parameters.Count > 1)
                {
                    context += ", ";
                }

                string arguments = (context != null ? context : String.Empty) +
                                   String.Join(", ", method.Parameters.Skip(skip).Select(
                                                   (p, i) => this.CastArgument(
                                                       p.Name,
                                                       this.GetParameterTypeName(p.ParameterType, declaringTypeFullName, method.Name, i),
                                                       p.ParameterType)));
                string forward = (method.IsStatic ? boundTypeFullName : "Forward");
                code.Code($"\t{forward}.{method.Name}({arguments});");

                code.Code("\tawait completion.Task;");

                if (hasReturnValue)
                {
                    code.Code("\treturn asyncResult;");
                }

                code.Code("}");
            }
        }
Exemple #16
0
        protected override void WriteOutErrorMethod(
            Method method,
            string declaringTypeFullName,
            string boundTypeFullName,
            bool isInterfaceMember,
            bool isMarshalByValueType,
            CodeWriter code)
        {
            string methodName = method.Name;

            if (method.Parameters.Count == 1)
            {
                if (methodName.EndsWith("WithError"))
                {
                    methodName = methodName.Substring(0, methodName.Length - "WithError".Length);
                }
                else if (methodName.EndsWith("Error"))
                {
                    methodName = methodName.Substring(0, methodName.Length - "Error".Length);
                }
            }

            string context = this.GetImplicitContext(method, code);
            int    skip    = context != null ? 1 : 0;

            bool   isAbstract = isInterfaceMember || method.IsAbstract;
            string parameters = String.Join(", ", method.Parameters.Skip(skip)
                                            .Take(method.Parameters.Count - 1 - skip).Select(
                                                (p, i) => GetParameterTypeName(p.ParameterType, declaringTypeFullName, method.Name, i) + " " + p.Name));

            code.Code($"{(isInterfaceMember ? "" : "public ")}{(method.IsStatic ? "static " : "")}" +
                      $"{(isAbstract && !isInterfaceMember ? "abstract " : "")}" +
                      $"{GetMemberTypeName(method.ReturnType, declaringTypeFullName, method.Name)} " +
                      $"{methodName}({parameters}){(isAbstract ? ";" : "")}");

            if (!isAbstract)
            {
                code.Code("{");
                code.Code("\tFoundation.NSError error;");

                if (isMarshalByValueType && !method.IsStatic)
                {
                    code.Code($"\t{this.PluginAlias}{boundTypeFullName} Forward = " +
                              $"new {this.PluginAlias}{boundTypeFullName}();");
                    code.Code("\tthis.CopyValuesTo(Forward);");
                }

                if (context != null && method.Parameters.Count > 1)
                {
                    context += ", ";
                }

                string arguments = (context != null ? context : String.Empty) +
                                   String.Join(", ", method.Parameters.Skip(skip)
                                               .Take(method.Parameters.Count - 1 - skip).Select(
                                                   (p, i) => this.CastArgument(
                                                       p.Name,
                                                       this.GetParameterTypeName(p.ParameterType, declaringTypeFullName, method.Name, i),
                                                       p.ParameterType))) + (method.Parameters.Count > 1 + skip ? ", " : "") + "out error";
                string forward = (method.IsStatic ? boundTypeFullName : "Forward");

                if (method.ReturnType == "System.Void")
                {
                    code.Code($"\t{forward}.{method.Name}({arguments});");
                    code.Code("\tif (error != null) throw new Foundation.NSErrorException(error);");


                    if (isMarshalByValueType && !method.IsStatic)
                    {
                        code.Code("\tthis.CopyValuesFrom(Forward);");
                    }
                }
                else
                {
                    code.Code($"\tvar result = " +
                              this.CastArgument(
                                  $"{forward}.{method.Name}({arguments})",
                                  method.ReturnType, this.GetMemberTypeName(method.ReturnType, declaringTypeFullName, method.Name)) +
                              ";");
                    code.Code("\tif (error != null) throw new Foundation.NSErrorException(error);");

                    if (isMarshalByValueType && !method.IsStatic)
                    {
                        code.Code("\tthis.CopyValuesFrom(Forward);");
                    }

                    code.Code("\treturn result;");
                }

                code.Code("}");
            }
        }
Exemple #17
0
        protected override void WriteAsyncMethod(
            Method method,
            string declaringTypeFullName,
            string boundTypeFullName,
            bool isInterfaceMember,
            CodeWriter code)
        {
            string context = this.GetImplicitContext(method, code);
            int    skip    = context != null ? 1 : 0;

            string asyncReturnType;
            string asyncTaskReturnType;

            if (method.ReturnType.StartsWith("Windows.Foundation.IAsyncAction"))
            {
                asyncReturnType     = "void";
                asyncTaskReturnType = "System.Threading.Tasks.Task";
            }
            else
            {
                asyncReturnType     = method.ReturnType.Substring(method.ReturnType.IndexOf('<') + 1);
                asyncReturnType     = asyncReturnType.Substring(0, asyncReturnType.Length - 1);
                asyncTaskReturnType = "System.Threading.Tasks.Task<" +
                                      GetMemberTypeName(asyncReturnType, declaringTypeFullName, method.Name) + ">";
            }

            bool   isAbstract = isInterfaceMember || method.IsAbstract;
            string parameters = String.Join(", ", method.Parameters.Skip(skip).Select(
                                                (p, i) => GetParameterTypeName(p.ParameterType, declaringTypeFullName, method.Name, i) +
                                                " " + p.Name));

            code.Code($"{(isInterfaceMember ? "" : "public ")}{(method.IsStatic ? "static " : "")}" +
                      $"{(isAbstract && !isInterfaceMember ? "abstract " : "async ")}{asyncTaskReturnType} " +
                      $"{method.Name}({parameters}){(isAbstract ? ";" : "")}");

            if (!isAbstract)
            {
                code.Code("{");

                if (context != null && method.Parameters.Count > 1)
                {
                    context += ", ";
                }

                string arguments = (context != null ? context : String.Empty) +
                                   String.Join(", ", method.Parameters.Skip(skip).Select(
                                                   (p, i) => this.CastArgument(
                                                       p.Name,
                                                       this.GetParameterTypeName(p.ParameterType, declaringTypeFullName, method.Name, i),
                                                       p.ParameterType,
                                                       true)));
                string forward = (method.IsStatic ? this.PluginAlias + boundTypeFullName : "Forward");
                if (asyncReturnType == "void")
                {
                    code.Code($"\tawait System.WindowsRuntimeSystemExtensions.AsTask(" +
                              $"{forward}.{method.Name}({arguments}));");
                }
                else
                {
                    code.Code($"\tvar result = await " +
                              "System.WindowsRuntimeSystemExtensions.AsTask(" +
                              $"{forward}.{method.Name}({arguments}));");
                    code.Code("\treturn " + this.CastArgument(
                                  $"result",
                                  asyncReturnType,
                                  this.GetMemberTypeName(asyncReturnType, declaringTypeFullName, method.Name)) + ";");
                }
                code.Code("}");
            }
        }
Exemple #18
0
        void WriteTypeScriptBindingsForType(
            Type type,
            IEnumerable <Type> importTypes,
            CodeWriter code)
        {
            string simpleTypeName;

            if (!type.IsNested)
            {
                if (!(type is Enum))
                {
                    foreach (Type importType in importTypes)
                    {
                        code.Code($"import {importType.Name} = require(\"./{importType.Name}\");");
                    }

                    if (!(type is Interface))
                    {
                        code.Code();
                        code.Code($"import {{ bridge, NativeObject, NativeReference{(this.ES6 ? "" : ", Promise")} }} " +
                                  $"from \"{this.BridgeModuleName}\";");
                    }
                    else if (!this.ES6)
                    {
                        code.Code();
                        code.Code($"import {{ Promise }} from \"{this.BridgeModuleName}\";");
                    }
                }

                code.Code();

                simpleTypeName = type.Name;
            }
            else
            {
                // TODO: Support multi-level nesting
                simpleTypeName = type.Name.Replace('+', '.');
            }

            simpleTypeName = simpleTypeName.Substring(simpleTypeName.LastIndexOf('.') + 1);

            PluginInfo.AssemblyClassInfo classInfo = this.PluginInfo.Assembly.Classes
                                                     .FirstOrDefault(c => c.Name == type.Name || c.Name == type.FullName);
            bool marshalByValue = (classInfo != null && classInfo.MarshalByValue == "true");

            if (type is Class || type is Struct)
            {
                string extendsTypeName = (marshalByValue ? "NativeObject" : "NativeReference");
                code.Code($"{(type.IsNested ? "export " : "")}class {simpleTypeName} extends {extendsTypeName} {{");
                code.Code($"\tstatic type: string = \"{type.FullName}\";");
            }
            else if (type is Interface)
            {
                code.Code($"{(type.IsNested ? "export " : "")}interface {simpleTypeName} {{");
            }
            else if (type is Enum)
            {
                code.Code($"{(type.IsNested ? "export " : "")}enum {simpleTypeName} {{");
            }
            else
            {
                throw new NotSupportedException("Type type not supported: " + type.GetType().Name);
            }

            CodeWriter            members          = code.Indent();
            Func <Property, bool> isStructProperty = p =>
                                                     p.GetMethod != null && !p.IsStatic;

            if (type is Enum)
            {
                foreach (EnumValue field in type.Members.Cast <EnumValue>().OrderBy(f => (int)f.Value))
                {
                    this.WriteTypeScriptBindingForField(type, field, members);
                }
            }
            else if (marshalByValue)
            {
                // Give the C3P JS marshaller hints about how to convert certain marshal-by-value fields.
                IEnumerable <Property> properties = type.Members.OfType <Property>().Where(isStructProperty);
                string[] guidFields = properties.Where(p => p.PropertyType == "System.Guid")
                                      .Select(p => p.Name).ToArray();
                if (guidFields.Length > 0)
                {
                    members.Code("static typeConversions: any = { " +
                                 String.Join(", ", guidFields.Select(f => $"\"{Uncapitalize(f)}\": \"uuid\"")) + " };");
                }

                bool isFirstField = true;
                foreach (Property property in properties)
                {
                    if (isFirstField)
                    {
                        members.Code();
                        isFirstField = false;
                    }

                    this.WriteTypeScriptBindingForField(type, property, members);
                }
            }

            if (marshalByValue)
            {
                members.Code();
                members.Code(
                    "constructor() {",
                    $"\tsuper({simpleTypeName}.type);",
                    "}");
            }
            else if (type is Class)
            {
                string implicitContextArgument = null;

                foreach (Constructor constructor in type.Members.OfType <Constructor>())
                {
                    members.Code();
                    this.WriteTypeScriptBindingForConstructor(type, constructor, members);

                    if (implicitContextArgument == null)
                    {
                        implicitContextArgument = GetImplicitContextArgument(constructor);
                    }
                }

                string argsWithContext = (implicitContextArgument == null ? "args" :
                                          "[" + implicitContextArgument + "].concat(args)");

                members.Code();
                members.Code("constructor(handle: Promise<number>);");
                members.Code();
                members.Code(
                    $"constructor(...args: any[]) {{",
                    $"\tsuper(",
                    $"\t\t{simpleTypeName}.type,",
                    $"\t\t(args.length === 1 && args[0] instanceof Promise ? args[0] :",
                    $"\t\t\tbridge.createInstance({type.Name}.type, {argsWithContext})));",
                    $"}}");
                members.Code();
                members.Code("dispose(): Promise<void> {");
                members.Code("\tvar releaseNativeInstance: () => Promise<void> = ");
                members.Code("\t\tbridge.releaseInstance.bind(undefined, this.type, this.handle);");
                members.Code("\treturn super.dispose().then(function () { return releaseNativeInstance(); });");
                members.Code("}");
            }

            foreach (Property property in type.Members.OfType <Property>()
                     .Where(p => !marshalByValue || !isStructProperty(p)))
            {
                members.Code();
                this.WriteTypeScriptBindingsForProperty(type, property, members);
            }

            foreach (Event eventMember in type.Members.OfType <Event>())
            {
                members.Code();
                this.WriteTypeScriptBindingForEvent(type, eventMember, members);
            }

            foreach (Method method in type.Members.OfType <Method>())
            {
                members.Code();
                this.WriteTypeScriptBindingForMethod(type, method, members);
            }

            code.Code("}");

            if (!(type is Enum) && !(type is Interface))
            {
                code.Code($"bridge.registerType({simpleTypeName}.type, <any>{simpleTypeName});");
            }

            if (type.Members.OfType <Type>().Count() != 0)
            {
                code.Code();
                code.Code($"module {type.Name} {{");

                foreach (Type nestedType in type.Members.OfType <Type>())
                {
                    code.Code();
                    this.WriteTypeScriptBindingsForType(nestedType, null, code.Indent());
                }

                code.Code("}");
            }

            if (!type.IsNested)
            {
                code.Code();
                code.Code($"export = {type.Name};");
            }
        }
Exemple #19
0
        void WriteTypeScriptBindingForMethod(Type declaringType, Method method, CodeWriter code)
        {
            string methodName = Uncapitalize(method.Name);
            string parameters = String.Join(", ", method.Parameters.Select(
                                                p => p.Name + ": " + this.GetJavaScriptTypeName(p.ParameterType, declaringType)));
            string returnType = this.GetJavaScriptTypeName(method.ReturnType, declaringType);

            if (this.ForceAsyncAPIs)
            {
                returnType = MakePromiseTypeName(returnType);

                if (!methodName.EndsWith("Async"))
                {
                    methodName += "Async";
                }
            }

            bool isInterfaceMethod = (declaringType is Interface);

            code.Code((method.IsStatic ? "static " : String.Empty) +
                      $"{methodName}({parameters}): {returnType}" +
                      (isInterfaceMethod ? ";" : " {"));

            if (!isInterfaceMethod)
            {
                CodeWriter body = code.Indent();

                string retCast = "";
                if (method.ReturnType == "System.Boolean" ||
                    method.ReturnType == "System.Threading.Tasks.Task<System.Boolean>")
                {
                    retCast = ".then(result => !!result)";
                }
                else if (method.ReturnType == "System.Void" ||
                         method.ReturnType == "System.Threading.Tasks.Task")
                {
                    retCast = ".then(result => undefined)";
                }
                else if (method.ReturnType == "System.Guid" ||
                         method.ReturnType == "System.Threading.Tasks.Task<System.Guid>")
                {
                    retCast = ".then(result => (typeof(result) === \"string\" ? " +
                              "result.toUpperCase() : result && result.value))";
                }

                string arguments = String.Join(", ", method.Parameters.Select(p =>
                                                                              p.ParameterType == "System.Guid" ?
                                                                              $"(typeof({p.Name}) === \"string\" ? {{ \"type\": \"<uuid>\", \"value\": {p.Name} }} : null)" :
                                                                              p.ParameterType == "System.Uri" ?
                                                                              $"(typeof({p.Name}) === \"string\" ? {{ \"type\": \"<uri>\", \"value\": {p.Name} }} : null)" :
                                                                              p.Name));
                string implicitContextArgument = GetImplicitContextArgument(method);
                if (implicitContextArgument != null)
                {
                    arguments = (arguments.Length > 0 ? implicitContextArgument + ", " + arguments : implicitContextArgument);
                }

                if (method.IsStatic)
                {
                    string simpleName = declaringType.Name.Substring(declaringType.Name.IndexOf('+') + 1);
                    body.Code("return bridge.invokeStaticMethod(" +
                              $"{simpleName}.type, \"{method.Name}\", [{arguments}]){retCast};");
                }
                else
                {
                    body.Code($"return bridge.invokeMethod(this, \"{method.Name}\", [{arguments}]){retCast};");
                }

                code.Code("}");
            }
        }
Exemple #20
0
        void WriteTypeScriptBindingForEvent(Type declaringType, Event eventMember, CodeWriter code)
        {
            bool   isInterfaceMember  = (declaringType is Interface);
            string eventHandlerPrefix = "System.EventHandler<";

            if (!eventMember.EventHandlerType.StartsWith(eventHandlerPrefix))
            {
                throw new NotSupportedException("Unsupported event handler type: " + eventMember.EventHandlerType);
            }

            string addMethodName    = $"add{eventMember.Name}Listener";
            string removeMethodName = $"remove{eventMember.Name}Listener";
            string returnType       = "void";

            if (this.ForceAsyncAPIs)
            {
                addMethodName    += "Async";
                removeMethodName += "Async";
                returnType        = "Promise<void>";
            }

            string eventType = eventMember.EventHandlerType.Substring(
                eventHandlerPrefix.Length, eventMember.EventHandlerType.Length - 1 - eventHandlerPrefix.Length);

            code.Code((eventMember.IsStatic ? "static " : String.Empty) +
                      $"{addMethodName}(listener: (e: {GetJavaScriptTypeName(eventType, declaringType)}) => void)" +
                      $": {returnType}" + (isInterfaceMember ? ";" : " {"));

            string simpleName = declaringType.Name.Substring(declaringType.Name.IndexOf('+') + 1);

            if (!isInterfaceMember)
            {
                if (eventMember.IsStatic)
                {
                    code.Code("\treturn bridge.addStaticEventListener(" +
                              $"{simpleName}.type, \"{eventMember.Name}\", listener);");
                }
                else
                {
                    code.Code($"\treturn bridge.addEventListener(this, \"{eventMember.Name}\", listener);");
                }

                code.Code("}");
            }

            code.Code();
            code.Code((eventMember.IsStatic ? "static " : String.Empty) +
                      $"{removeMethodName}(listener: (e: {GetJavaScriptTypeName(eventType, declaringType)}) => void)" +
                      $": {returnType}" + (isInterfaceMember ? ";" : " {"));

            if (!isInterfaceMember)
            {
                if (eventMember.IsStatic)
                {
                    code.Code("\treturn bridge.removeStaticEventListener(" +
                              $"{simpleName}.type, \"{eventMember.Name}\", listener);");
                }
                else
                {
                    code.Code($"\treturn bridge.removeEventListener(this, \"{eventMember.Name}\", listener);");
                }

                code.Code("}");
            }
        }
Exemple #21
0
        void GeneratePluginModule(ClrApi pluginApi, string scriptOutputPath)
        {
            using (CodeWriter code = new CodeWriter(Path.Combine(scriptOutputPath, "plugin.ts")))
            {
                code.Code("import { Platform, NativeModules } from \"react-native\";");
                code.Code();

                HashSet <string> allNamespaces = new HashSet <string>();

                if (this.PluginInfo.AndroidPlatform != null)
                {
                    code.Code("if (Platform.OS === \"android\") {");

                    foreach (var namespaceMapping in this.PluginInfo.AndroidPlatform.NamespaceMappings)
                    {
                        code.Code("\tNativeModules.C3P.registerNamespaceMapping(" +
                                  $"\"{namespaceMapping.Namespace}\", \"{namespaceMapping.Package}\");");
                        allNamespaces.Add(namespaceMapping.Namespace);
                    }

                    code.Code("}");
                }

                if (this.PluginInfo.IOSPlatform != null)
                {
                    code.Code("if (Platform.OS === \"ios\") {");

                    foreach (var namespaceMapping in this.PluginInfo.IOSPlatform.NamespaceMappings)
                    {
                        code.Code("\tNativeModules.C3P.registerNamespaceMapping(" +
                                  $"\"{namespaceMapping.Namespace}\", \"{namespaceMapping.Prefix}\");");
                        allNamespaces.Add(namespaceMapping.Namespace);
                    }

                    code.Code("}");
                }

                if (this.PluginInfo.WindowsPlatform != null)
                {
                    code.Code("if (Platform.OS === \"windows\") {");

                    foreach (var namespaceInfo in this.PluginInfo.WindowsPlatform.IncludeNamespaces)
                    {
                        code.Code("\tNativeModules.C3P.registerNamespaceMapping(" +
                                  $"\"{namespaceInfo.Namespace}\");");
                        allNamespaces.Add(namespaceInfo.Namespace);
                    }

                    code.Code("}");
                }

                code.Code();

                foreach (var classInfo in this.PluginInfo.Assembly.Classes.Where(c => c.MarshalByValue == "true"))
                {
                    code.Code($"NativeModules.C3P.registerMarshalByValueClass(\"{classInfo.Name}\");");
                }

                string[] includeNamespaces = allNamespaces.ToArray();

                code.Code();
                foreach (Type pluginType in pluginApi.Assemblies.Single().Types
                         .Where(t => includeNamespaces.Contains(t.Namespace)))
                {
                    code.Code($"import {pluginType.Name} = require(\"./{pluginType.Name}\");");
                }

                code.Code();
                code.Code("export = {");

                foreach (Type pluginType in pluginApi.Assemblies.Single().Types
                         .Where(t => includeNamespaces.Contains(t.Namespace)))
                {
                    code.Code($"\t{pluginType.Name}: {pluginType.Name},");
                }

                code.Code("}");
            }
        }
Exemple #22
0
        protected override void WriteAsyncMethod(
            Method method,
            string declaringTypeFullName,
            string boundTypeFullName,
            bool isInterfaceMember,
            CodeWriter code)
        {
            string asyncReturnType       = this.FindAsyncReturnType(boundTypeFullName, method.Name, declaringTypeFullName);
            string mappedAsyncReturnType = this.GetMemberTypeName(asyncReturnType, declaringTypeFullName, method.Name);
            string xamarinReturnType     = this.MapTypeName(asyncReturnType);

            if (asyncReturnType == "java.util.UUID")
            {
                // TODO: This special case shouldn't be necessary here.
                xamarinReturnType = "Java.Util.UUID";
            }

            string castFromType = xamarinReturnType;

            if (xamarinReturnType == null)
            {
                if (asyncReturnType.StartsWith("java.util.List<"))
                {
                    // Java lists inside a Future don't get automatically converted to
                    // the generic IList<> by Xamarin.
                    xamarinReturnType = "System.Collections.IList";
                    string itemType = asyncReturnType.Substring(asyncReturnType.IndexOf('<') + 1);
                    itemType     = itemType.Substring(0, itemType.Length - 1);
                    castFromType = xamarinReturnType + "<" + (this.MapTypeName(itemType) ?? itemType) + ">";
                }
                else
                {
                    xamarinReturnType = mappedAsyncReturnType;
                    castFromType      = xamarinReturnType;
                }
            }

            string context = this.GetImplicitContext(method, code);
            int    skip    = context != null ? 1 : 0;

            bool   isAbstract = isInterfaceMember || method.IsAbstract;
            string parameters = String.Join(", ", method.Parameters.Skip(skip).Select(
                                                (p, i) => GetParameterTypeName(p.ParameterType, declaringTypeFullName, method.Name, i) +
                                                " " + p.Name));

            code.Code($"{(isInterfaceMember ? "" : "public ")}{(method.IsStatic ? "static " : "")}" +
                      $"{(isAbstract && !isInterfaceMember ? "abstract" : "async")} " +
                      "System.Threading.Tasks.Task" +
                      (mappedAsyncReturnType != "void" ? "<" + mappedAsyncReturnType + ">" : "") +
                      $" {method.Name}({parameters}){(isAbstract ? ";" : "")}");

            if (!isAbstract)
            {
                code.Code("{");

                if (context != null && method.Parameters.Count > 1)
                {
                    context += ", ";
                }

                string arguments = (context != null ? context : String.Empty) +
                                   String.Join(", ", method.Parameters.Skip(skip).Select(
                                                   (p, i) => this.CastArgument(
                                                       p.Name,
                                                       this.GetParameterTypeName(p.ParameterType, declaringTypeFullName, method.Name, i),
                                                       p.ParameterType)));
                string forward = (method.IsStatic ? boundTypeFullName : "Forward");
                code.Code($"\tvar future = {forward}.{method.Name}({arguments});");

                if (mappedAsyncReturnType == "void")
                {
                    code.Code("\tawait Java.Util.Concurrent.IFutureExtensions.GetAsync(future);");
                }
                else
                {
                    code.Code($"\tvar result = ({xamarinReturnType})" +
                              "await Java.Util.Concurrent.IFutureExtensions.GetAsync(future);");
                    code.Code($"\treturn " + this.CastArgument($"result", castFromType, mappedAsyncReturnType) + ";");
                }

                code.Code("}");
            }
        }