예제 #1
0
        public static MrType GetComposableFactoryType(MrType type)
        {
            var factories = GetFactories(type);
            var ca        = factories.FirstOrDefault(f => f.Kind == "ComposableAttribute");

            return(ca?.Type);
        }
예제 #2
0
파일: Program.cs 프로젝트: asklar/DumpWinMD
        private void WriteType(MrType t)
        {
            var name = "";

            var gargs   = t.GetGenericArguments();
            var gparams = t.GetGenericTypeParameters();

            name = GetSimpleTypeName(t, gargs, gparams);

            writer.WriteStartElement("type");
            if (t.IsArray)
            {
                writer.WriteAttributeString("array", "true");
                name = name.Replace("[]", "");
            }

            writer.WriteAttributeString("name", name);

            if (!gargs.IsEmpty)
            {
                writer.WriteAttributeString("generic", "true");
                writer.WriteStartElement("params");
                foreach (var p in gparams)
                {
                    WriteType(p);
                }
                writer.WriteEndElement();
            }
            else
            {
            }
            writer.WriteEndElement();
        }
예제 #3
0
        public static string GetCppWinRTType(MrType t)
        {
            var primitiveTypes = new Dictionary <string, string>()
            {
                { "System.String", "winrt::hstring" },
                { "System.Boolean", "bool" },
                { "System.Int32", "int32_t" },
                { "System.Int64", "int64_t" },
                { "System.Double", "double" },
                { "System.Single", "float" },
                { "System.Uri", "winrt::Windows::Foundation::Uri" },
                { "System.Object", "winrt::Windows::Foundation::IInspectable" },
            };

            if (t.GetFullName() == $"{XamlNames.XamlNamespace}.Controls.Maps.MapStyle")
            {
                // MapStyle has a bug where it doesn't support coercion from int
            }
            else if (t.IsEnum)
            {
                return("int32_t");
            }
            else if (t.GetFullName() == "System.Nullable`1")
            {
                return(GetCppWinRTType(t.GetGenericTypeParameters().First()));
            }
            if (primitiveTypes.ContainsKey(t.GetFullName()))
            {
                return(primitiveTypes[t.GetFullName()]);
            }



            return($"winrt::{t.GetFullName().Replace(".", "::")}");
        }
예제 #4
0
        private static IEnumerable <MrProperty> GetAttachedDPCandidates(MrType dpType, MrType type)
        {
            type.GetMethodsAndConstructors(out var methods, out var ctors);
            return(type.GetProperties().Where(prop =>
            {
                if (prop.GetName().EndsWith("Property") && prop.GetPropertyType() == dpType)
                {
                    var propName = prop.GetName().Substring(0, prop.GetName().LastIndexOf("Property"));
                    return methods.Any(x => x.GetName() == $"Set{propName}" && x.GetParsedMethodAttributes().IsStatic);
                }

                return false;
            }));
        }
예제 #5
0
        private static List <FactoryInfo> GetFactories(MrType t)
        {
            var d = new List <FactoryInfo>();

            foreach (var ca in t.GetCustomAttributes())
            {
                ca.GetNameAndNamespace(out var name, out var ns);
                if (ns != "Windows.Foundation.Metadata")
                {
                    continue;
                }
                ca.GetArguments(out var _fixed, out var named);

                var factoryInfo = new FactoryInfo();
                factoryInfo.Kind = name;
                // factoryInfo.Type = GetSystemType(signature);
                if (name == "ActivatableAttribute")
                {
                    factoryInfo.Activatable = true;
                }
                else if (name == "StaticAttribute")
                {
                    factoryInfo.Statics = true;
                    factoryInfo.Type    = (MrType)_fixed[0].Value;
                }
                else if (name == "ComposableAttribute")
                {
                    factoryInfo.Composable = true;
                    factoryInfo.Type       = (MrType)_fixed[0].Value;
                }
                else
                {
                    continue;
                }
                d.Add(factoryInfo);
            }
            return(d);
        }
예제 #6
0
파일: Program.cs 프로젝트: asklar/DumpWinMD
        private static string MapManagedTypeToWinRtType(MrType t)
        {
            var map = new Dictionary <string, string> {
                { typeof(Object).FullName, "Windows.Foundation.IInspectable" },
                { "System.Collections.Generic.IList`1", "Windows.Foundation.Collections.IVector`1" },
                { "System.Collections.Generic.IReadOnlyList`1", "Windows.Foundation.Collections.IVectorView`1" },
                { "System.Collections.Generic.IDictionary`2", "Windows.Foundation.Collections.IMap`2" },
                { "System.Collections.Generic.IReadOnlyDictionary`2", "Windows.Foundation.Collections.IMapView`2" },
            };

            if (map.ContainsKey(t.GetFullName()))
            {
                return(map[t.GetFullName()]);
            }
            if (t.GetNamespace() == "System")
            {
                return(t.GetName());
            }
            else
            {
                return(t.GetFullName());
            }
        }
예제 #7
0
파일: Program.cs 프로젝트: asklar/DumpWinMD
        private static string GetSimpleTypeName(MrType t, ImmutableArray <MrType> gargs, ImmutableArray <MrType> gparams)
        {
            string name;

            if (t.IsTypeCode)
            {
                name = t.TypeCode.ToString();
            }
            else if (t.GetNamespace() == "System")
            {
                name = MapManagedTypeToWinRtType(t);
            }
            else if (!gargs.IsEmpty || !gparams.IsEmpty)
            {
                name = MapManagedTypeToWinRtType(t);
                name = name.Substring(0, name.IndexOf('`'));
            }
            else
            {
                name = t.GetFullName();
            }

            return(name);
        }
예제 #8
0
파일: Program.cs 프로젝트: asklar/DumpWinMD
 string GetTypeKind(MrType t)
 {
     if (t.IsClass && t.GetInvokeMethod() != null && t.GetBaseType().GetName() == "MulticastDelegate")
     {
         return("delegate");
     }
     if (t.IsClass)
     {
         return("class");
     }
     else if (t.IsInterface)
     {
         return("interface");
     }
     else if (t.IsEnum)
     {
         return("enum");
     }
     else if (t.IsStruct)
     {
         return("struct");
     }
     throw new ArgumentException();
 }
예제 #9
0
파일: Program.cs 프로젝트: asklar/DumpWinMD
 private static bool IsExclusiveInterface(MrType t)
 {
     return(t.IsInterface && t.GetCustomAttributes().Any(IsExclusiveToAttribute));
 }
예제 #10
0
파일: Program.cs 프로젝트: asklar/DumpWinMD
 private static bool IsAttribute(MrType t)
 {
     return(t.GetBaseType() != null && t.GetBaseType().GetFullName() == typeof(Attribute).FullName);
 }
예제 #11
0
        private static void WriteTypes(MrAssembly testAssembly, StringBuilder result)
        {
            foreach (var mrType in testAssembly.GetAllTypes())
            {
                result.AppendLine();

                if (mrType.IsPublic)
                {
                    result.Append("public ");
                }

                var classKind = "";
                if (mrType.IsStruct)
                {
                    classKind = "struct";
                }
                else if (mrType.IsClass)
                {
                    classKind = "class";
                }
                else if (mrType.IsInterface)
                {
                    classKind = "interface";
                }
                else if (mrType.IsEnum)
                {
                    classKind = "enum";
                }
                else
                {
                    Assert.IsTrue(false);
                }

                result.Append($"{classKind} {mrType.GetPrettyFullName()}");

                if (mrType.GetBaseType() != null)
                {
                    result.Append($" : {mrType.GetBaseType().GetPrettyFullName()}");
                }

                result.AppendLine();
                result.AppendLine($"    {mrType.Attributes.ToString()}");

                var customAttributes = mrType.GetCustomAttributes();
                foreach (var customAttribute in customAttributes)
                {
                    customAttribute.GetNameAndNamespace(out var name, out var ns);
                    customAttribute.GetArguments(out var fixedArguments, out var namedArguments);

                    if (fixedArguments.IsEmpty && namedArguments.IsEmpty)
                    {
                        result.AppendLine($"    [{name}]");
                    }
                    else
                    {
                        var allArguments = fixedArguments
                                           .Select(fa => $"{fa.Item2.ToString()}")
                                           .Union(namedArguments.Select(na => $"{na.Item1}={na.Item2}"));

                        result.AppendLine($"    [{name}({string.Join(", ", allArguments)})]");
                    }
                }

                var interfaces = mrType.GetInterfaces();

                foreach (var iface in interfaces)
                {
                    result.AppendLine($"    {iface.GetPrettyFullName()}");
                }


                mrType.GetMethodsAndConstructors(out var methods, out var constructors);

                foreach (var constructor in constructors)
                {
                    result.Append($"    {constructor.DeclaringType.GetPrettyFullName()}(");

                    var parameters = constructor.GetParameters();
                    WriteParameters(parameters, result);
                    result.AppendLine(")");
                }

                foreach (var property in mrType.GetProperties())
                {
                    var propertyName = property.GetName();

                    MrType itemPropertyType = null;
                    if (propertyName == "Item")
                    {
                        itemPropertyType = property.GetItemType(publicishOnly: true);
                    }

                    if (itemPropertyType == null)
                    {
                        result.Append($"    {property.GetPropertyType().GetPrettyFullName()} {propertyName} {{ get; ");
                        if (property.Setter != null)
                        {
                            result.Append($"set; ");
                        }
                        result.AppendLine("}");
                    }
                    else
                    {
                        result.AppendLine($"    {property.GetPropertyType().GetPrettyFullName()} this.[{itemPropertyType}]");
                    }
                }

                foreach (var ev in mrType.GetEvents())
                {
                    result.AppendLine($"    {ev.GetEventType().GetPrettyFullName()} {ev.GetName()} {{ add; remove; }}");
                }

                foreach (var method in methods)
                {
                    result.Append("    ");
                    WriteMethodAttributes(method.MethodDefinition.Attributes, result);

                    result.Append($"{method.ReturnType} {method.GetName()}(");
                    var parameters = method.GetParameters();
                    WriteParameters(parameters, result);
                    result.AppendLine(")");
                }

                foreach (var field in mrType.GetFields())
                {
                    if (mrType.IsEnum)
                    {
                        if (!field.IsSpecialName) // Ignore special value__ field
                        {
                            var value = field.GetConstantValue(out var constantTypeCode);
                            result.AppendLine($"    {field.GetName()} = {value},");
                        }
                    }
                    else
                    {
                        result.AppendLine($"    {field.GetFieldType().GetPrettyFullName()} {field.GetName()};");
                    }
                }
            }
        }
예제 #12
0
        private void DumpTypes(Version version)
        {
            var start = DateTime.Now;

            Config = JsonDocument.Parse(File.ReadAllText(ConfigFileName), new JsonDocumentOptions()
            {
                AllowTrailingCommas = true, CommentHandling = JsonCommentHandling.Skip
            });

            var context = new MrLoadContext(true);

            context.FakeTypeRequired += (sender, e) =>
            {
                var ctx = sender as MrLoadContext;
                if (e.AssemblyName == "Windows.Foundation.FoundationContract" || e.AssemblyName == "Windows.Foundation.UniversalApiContract")
                {
                    e.ReplacementType = ctx.GetTypeFromAssembly(e.TypeName, "Windows");
                }
            };

            var windows_winmd = context.LoadAssemblyFromPath(Windows_winmd);
            var winmds        = winmdPaths.Select(winmdPath => context.LoadAssemblyFromPath(winmdPath)).ToList();

            // ToList realizes the list which is needs to happen before FinishLoading is called

            context.FinishLoading();

            var typesPerAssembly   = winmds.Select(winmd => winmd.GetAllTypes().Skip(1));
            var types              = typesPerAssembly.Count() != 0 ? typesPerAssembly.Aggregate((l1, l2) => l1.Union(l2)) : new MrType[] { };
            var windows_winmdTypes = windows_winmd.GetAllTypes().Skip(1);

            if (winmdPaths.Count != 0)
            {
                types = types.Union(windows_winmdTypes);
            }
            else
            {
                types = windows_winmdTypes;
            }
            Util.LoadContext = context;

            foreach (var entry in Config.RootElement.GetProperty("commands").EnumerateObject())
            {
                var commands = new List <Command>();
                foreach (var c in entry.Value.EnumerateArray())
                {
                    var command = new Command {
                        Name = c.GetProperty("name").GetString()
                    };
                    if (c.TryGetProperty("args", out var value))
                    {
                        command.TSArgTypes = ConvertJSONToTSType(value);
                    }
                    commands.Add(command);
                }
                Util.commands[GetTypeNameFromJsonProperty(entry)] = commands;
            }

            var fakeProps = new List <MrProperty>();

            foreach (var entry in Config.RootElement.GetProperty("propNameMapping").EnumerateObject())
            {
                Util.propNameMap[GetTypeNameFromJsonProperty(entry)] = entry.Value.GetString();
            }

            foreach (var entry in Config.RootElement.GetProperty("fakeProps").EnumerateArray())
            {
                var value    = GetTypeNameFromJson(entry);
                var typeName = value.Substring(0, value.LastIndexOf('.'));
                var propName = value.Substring(value.LastIndexOf('.') + 1);
                fakeProps.Add(GetProperty(context, typeName, propName));
            }
            ;

            var syntheticProps = new List <SyntheticProperty>();

            foreach (var entry in Config.RootElement.GetProperty("syntheticProps").EnumerateArray())
            {
                var    declaringTypes = entry.GetProperty("declaringType");
                string name           = entry.GetProperty("name").GetString();

                MrType propertyType = entry.TryGetProperty("propertyType", out var propTypeJson) ? context.GetType(GetTypeNameFromJson(propTypeJson)) : null;

                if (name.IndexOf('.') != -1)
                {
                    var propTypeName = name.Substring(0, name.LastIndexOf('.'));
                    var propName     = name.Substring(name.LastIndexOf('.') + 1);
                    var propType     = context.GetType(propTypeName);
                    var prop         = propType.GetProperties().First(p => p.GetName() == propName);
                    if (prop.GetPropertyType() != propertyType)
                    {
                        throw new ArgumentException($"The property type for {name} was expected to be {prop.GetPropertyType()}, but was specified as {propertyType}");
                    }
                }
                string fakePropertyType = entry.TryGetProperty("fakePropertyType", out var fakePropType) ? fakePropType.GetString() : null;
                string comment          = entry.TryGetProperty("comment", out var commentElement) ? commentElement.GetString() : "";
                if (declaringTypes.ValueKind == JsonValueKind.Array)
                {
                    foreach (var declaringType in declaringTypes.EnumerateArray())
                    {
                        var sp = new SyntheticProperty
                        {
                            Name             = name,
                            DeclaringType    = context.GetType(GetTypeNameFromJson(declaringType)),
                            PropertyType     = propertyType,
                            FakePropertyType = fakePropertyType,
                            Comment          = comment,
                        };
                        syntheticProps.Add(sp);
                    }
                }
                else
                {
                    var sp = new SyntheticProperty
                    {
                        Name             = name,
                        DeclaringType    = context.GetType(GetTypeNameFromJson(declaringTypes)),
                        PropertyType     = propertyType,
                        FakePropertyType = fakePropertyType,
                        Comment          = comment,
                    };
                    syntheticProps.Add(sp);
                }
            }

            Console.WriteLine("Generating projections for the following WinMD files:");
            Console.WriteLine($"- {Windows_winmd}");
            foreach (var path in winmdPaths)
            {
                Console.WriteLine($"- {Path.GetFullPath(path)}");
            }
            Console.WriteLine();

            var properties = new List <SyntheticProperty>();

            PrintVerbose("Enumerating attached properties");
            DiscoverAttachedProperties(context, types);

            PrintVerbose($"Parsing configuration from {ConfigFileName}");

            foreach (var entry in Config.RootElement.GetProperty("attachedProps").EnumerateObject())
            {
                var propName    = GetTypeNameFromJsonProperty(entry);
                var attachedDPs = Util.AttachedProperties.Where(p => Util.MinusPropertySuffix(Util.GetPropFullName(p)).StartsWith(propName));

                foreach (var attachedDP in attachedDPs)
                {
                    var type       = attachedDP.DeclaringType;
                    var simpleName = attachedDP.GetName().Substring(0, attachedDP.GetName().LastIndexOf("Property"));
                    type.GetMethodsAndConstructors(out var methods, out var ctors);
                    var propType = methods.First(m => m.GetName() == $"Get{simpleName}").ReturnType;

                    if (entry.Value.ValueKind == JsonValueKind.Array)
                    {
                        foreach (var onTypeEntry in entry.Value.EnumerateArray())
                        {
                            var sp = new SyntheticProperty
                            {
                                Name          = simpleName,
                                DeclaringType = context.GetType(GetTypeNameFromJson(onTypeEntry)),
                                PropertyType  = propType,
                                Property      = attachedDP,
                                Comment       = $"Attached property: ${propName}",
                            };
                            properties.Add(sp);
                        }
                    }
                    else
                    {
                        var onType = GetTypeNameFromJson(entry.Value);

                        var sp = new SyntheticProperty
                        {
                            Name          = simpleName,
                            DeclaringType = context.GetType(onType),
                            PropertyType  = propType,
                            Property      = attachedDP,
                            Comment       = $"Attached property: {propName}",
                        };
                        properties.Add(sp);
                    }
                }
            }

            foreach (var entry in Config.RootElement.GetProperty("typeMapping").EnumerateArray())
            {
                Util.TypeMapping[GetTypeNameFromJson(entry)] = new TypeMapping()
                {
                    VM = Enum.Parse <ViewManagerPropertyType>(entry.GetProperty("VM").GetString()),
                    TS = entry.GetProperty("TS").GetString(),
                };
            }

            var baseClassesToProject = new List <string>();

            foreach (var entry in Config.RootElement.GetProperty("baseClasses").EnumerateArray())
            {
                var name = GetTypeNameFromJson(entry);
                baseClassesToProject.Add(name);
            }
            ;

            var syntheticEvents = new List <SyntheticProperty>();

            foreach (var entry in Config.RootElement.GetProperty("syntheticEvents").EnumerateObject())
            {
                var val       = GetTypeNameFromJsonProperty(entry);
                var typeName  = val.Substring(0, val.LastIndexOf('.'));
                var eventName = val.Substring(val.LastIndexOf('.') + 1);

                syntheticEvents.Add(new SyntheticProperty()
                {
                    Name             = eventName,
                    DeclaringType    = context.GetType(typeName),
                    FakePropertyType = entry.Value.GetString(),
                });
            }


            var xamlTypes = types.Where(type => baseClassesToProject.Any(b =>
                                                                         Util.DerivesFrom(type, b)) || type.GetFullName() == XamlNames.TopLevelProjectedType).ToList();

            var generatedDirPath = Path.GetFullPath(cppOutPath ?? Path.Join(PackageRoot, @"windows\ReactNativeXaml\Codegen"));
            var packageSrcPath   = Path.GetFullPath(tsOutPath ?? Path.Join(PackageRoot, @"src"));


            PrintVerbose("Filtering types");
            var creatableTypes = xamlTypes.Where(x => Util.HasCtor(x)).ToList();

            PrintVerbose("Sorting types");
            creatableTypes.Sort((a, b) => a.GetFullName().CompareTo(b.GetFullName()));

            foreach (var entry in Config.RootElement.GetProperty("eventArgsMethods").EnumerateObject())
            {
                Util.eventArgsMethods.Add(GetTypeNameFromJsonProperty(entry), entry.Value.EnumerateArray().Select(x => x.GetString()));
            }

            var events = new List <MrEvent>();

            var eventArgProps = new List <SyntheticProperty>();

            PrintVerbose("Enumerating properties and events");
            foreach (var type in xamlTypes)
            {
                var props      = type.GetProperties();
                var propsToAdd = props.Where(p => Util.ShouldEmitPropertyMetadata(p));
                foreach (var p in propsToAdd)
                {
                    properties.Add(new SyntheticProperty()
                    {
                        Name          = Util.GetPropFullName(p),
                        DeclaringType = p.DeclaringType,
                        Property      = p,
                    });
                }

                var eventsToAdd = type.GetEvents().Where(e => Util.ShouldEmitEventMetadata(e));
                foreach (var e in eventsToAdd)
                {
                    var handlerDelegate = e.GetEventType();
                    var invoke          = handlerDelegate.GetInvokeMethod();
                    if (invoke != null)
                    {
                        var parameters = invoke.GetParameters();
                        if (parameters.Length == 2 && (parameters[1].GetParameterName().EndsWith("args") || parameters[1].GetParameterType().GetName().EndsWith("Args")))
                        {
                            Util.FoundEventArgsType(parameters[1].GetParameterType());
                        }
                        else if (parameters.Length == 1 && parameters[0].GetParameterType().GetName().EndsWith("Args"))
                        {
                            Util.FoundEventArgsType(parameters[0].GetParameterType());
                        }
                        else
                        {
                            throw new ArgumentException($"Couldn't infer event arg type for event {e.GetName()}");
                        }
                    }
                    else if (handlerDelegate.GetFullName() == "System.EventHandler`1")
                    {
                        var paramType = handlerDelegate.GetGenericTypeParameters();
                        if (paramType.Length != 1)
                        {
                            throw new ArgumentException($"Couldn't infer EventHandler generic type for event {e.GetName()}");
                        }
                        Util.FoundEventArgsType(paramType[0]);
                    }
                }
                events.AddRange(eventsToAdd);
            }



            foreach (var type in Util.eventArgsTypes)
            {
                var props      = type.GetProperties();
                var propsToAdd = props
                                 .Where(p => Util.IsInstanceProperty(p))
                                 .Select(p => new SyntheticProperty()
                {
                    Name          = p.GetName(),
                    DeclaringType = p.DeclaringType,
                    Property      = p,
                });
                eventArgProps.AddRange(propsToAdd);
                foreach (var p in propsToAdd.Where(p => p.Property.GetPropertyType().IsEnum).Select(p => p.Property.GetPropertyType()))
                {
                    Util.VisitEnum(p);
                }
            }

            properties.Sort(CompareProps);
            eventArgProps.Sort(CompareProps);

            PrintVerbose("Generating projection");


            foreach (var entry in Config.RootElement.GetProperty("fakeEnums").EnumerateArray())
            {
                var      typeName = GetTypeNameFromJson(entry.GetProperty("name"));
                FakeEnum fe;
                if (typeName.IndexOf('.') != -1)
                {
                    var type = context.GetType(typeName);
                    if (type.IsEnum)
                    {
                        var values = type.GetFields().Skip(1);
                        fe = new FakeEnum()
                        {
                            Name   = typeName.Substring(typeName.LastIndexOf('.') + 1),
                            Values = values.ToDictionary <MrField, string, int>(f => f.GetName(), f => (int)f.GetConstantValue(out var _)),
                        };
                    }
                    else
                    {
                        throw new ArgumentException($"Type {typeName} is not an enum");
                    }
                }
                else
                {
                    fe = new FakeEnum()
                    {
                        Name   = typeName,
                        Values = ToDictionary(entry.GetProperty("values").EnumerateObject()),
                    };
                }
                Util.fakeEnums.Add(fe);
            }

            var propsGen       = new TSProps(xamlTypes, properties, fakeProps, syntheticProps, syntheticEvents).TransformText();
            var typesGen       = new TSTypes(xamlTypes).TransformText();
            var typeCreatorGen = new TypeCreator(creatableTypes).TransformText();
            var propertiesGen  = new TypeProperties(properties, fakeProps, syntheticProps).TransformText();
            var enumsGen       = new TypeEnums().TransformText();

            var tsEnumsGen    = new TSEnums().TransformText();
            var eventsGen     = new TypeEvents(events, syntheticEvents).TransformText();
            var eventPropsGen = new EventArgsTypeProperties(eventArgProps).TransformText();
            var versionGen    = new VersionHeader()
            {
                Version = version
            }.TransformText();

            PrintVerbose("Updating files");
            if (!Directory.Exists(generatedDirPath))
            {
                Directory.CreateDirectory(generatedDirPath);
            }

            var changes = false;

            changes |= UpdateFile(Path.Join(generatedDirPath, "TypeCreator.g.cpp"), typeCreatorGen);
            changes |= UpdateFile(Path.Join(generatedDirPath, "TypeProperties.g.h"), propertiesGen);
            changes |= UpdateFile(Path.Join(generatedDirPath, "TypeEvents.g.h"), eventsGen);
            changes |= UpdateFile(Path.Join(generatedDirPath, "EventArgsTypeProperties.g.h"), eventPropsGen);
            changes |= UpdateFile(Path.Join(generatedDirPath, "TypeEnums.g.h"), enumsGen);

            changes |= UpdateFile(Path.Join(generatedDirPath, "Version.g.h"), versionGen);

            changes |= UpdateFile(Path.Join(packageSrcPath, "Enums.ts"), tsEnumsGen.Replace("\r\n", "\n"));
            changes |= UpdateFile(Path.Join(packageSrcPath, "Props.ts"), propsGen.Replace("\r\n", "\n"));
            changes |= UpdateFile(Path.Join(packageSrcPath, "Types.tsx"), typesGen.Replace("\r\n", "\n"));

            if (!changes)
            {
                PrintVerbose("\nNo changes were required.");
            }
            PrintVerbose($"Done in {(DateTime.Now - start).TotalSeconds}s.");
        }
        static void WriteType(MrType mrType, StringBuilder result, bool publicishOnly = true)
        {
            result.AppendLine();

            // Write out "public class Foo " or "enum Bar" etc

            if (mrType.IsPublic)
            {
                result.Append("public ");
            }
            if (mrType.IsInternal)
            {
                result.Append("internal ");
            }
            if (mrType.IsProtected) // Nested types can be 'protected internal'
            {
                result.Append("protected ");
            }

            if (mrType.IsPrivate)
            {
                result.Append("private ");
            }

            var classKind = "";

            if (mrType.IsStruct)
            {
                classKind = "struct";
            }
            else if (mrType.IsClass)
            {
                classKind = "class";
            }
            else if (mrType.IsInterface)
            {
                classKind = "interface";
            }
            else if (mrType.IsEnum)
            {
                classKind = "enum";
            }
            else
            {
                Assert.IsTrue(false);
            }

            result.Append($"{classKind} {mrType.GetPrettyFullName()}");

            // Write the base type (if this type has one)
            if (mrType.GetBaseType() != null)
            {
                result.Append($" : {mrType.GetBaseType().GetPrettyFullName()}");
            }

            if (mrType.IsNestedType)
            {
                result.Append(" (nested)");
            }

            // Write the standard attributes for this type

            result.AppendLine();
            result.AppendLine($"    {mrType.Attributes.ToString()}");

            // Write custom attributes on this type

            var customAttributes = mrType.GetCustomAttributes();

            foreach (var customAttribute in customAttributes)
            {
                customAttribute.GetNameAndNamespace(out var name, out var ns);
                customAttribute.GetArguments(out var fixedArguments, out var namedArguments);

                if (fixedArguments.IsEmpty && namedArguments.IsEmpty)
                {
                    result.AppendLine($"    [{name}]");
                }
                else
                {
                    var allArguments = fixedArguments
                                       .Select(fa => $"{fa.Item2.ToString()}")
                                       .Union(namedArguments.Select(na => $"{na.Item1}={na.Item2}"));

                    result.AppendLine($"    [{name}({string.Join(", ", allArguments)})]");
                }
            }

            // Write interfaces implemented by this type

            var interfaces = mrType.GetInterfaces(publicishOnly);

            foreach (var iface in interfaces)
            {
                result.AppendLine($"    {iface.GetPrettyFullName()}");
            }

            var nestedTypes = mrType.GetNestedTypes();

            foreach (var nestedType in nestedTypes)
            {
                result.AppendLine($"    nested {nestedType.GetPrettyName()}");
            }

            // Write constructors

            mrType.GetMethodsAndConstructors(out var methods, out var constructors, publicishOnly);

            foreach (var constructor in constructors)
            {
                var typeName = constructor.DeclaringType.GetPrettyName();
                if (mrType.IsNestedType)
                {
                    typeName = typeName.Split('+').Last();
                }

                result.Append("    ");
                WriteMethodAccess(constructor, result);
                result.Append($"{typeName}(");

                var parameters = constructor.GetParameters();
                WriteParameters(parameters, result);
                result.AppendLine(")");
            }

            // Write properties

            foreach (var property in mrType.GetProperties(publicishOnly))
            {
                var propertyName = property.GetName();

                MrType itemPropertyType = null;
                if (propertyName == "Item")
                {
                    itemPropertyType = property.GetItemType(publicishOnly: true);
                }

                if (itemPropertyType == null)
                {
                    result.Append($"    {property.GetPropertyType().GetPrettyFullName()} {propertyName} {{ ");

                    if (property.Getter != null)
                    {
                        WriteMethodAccess(property.Getter, result);
                        result.Append("get; ");
                    }

                    if (property.Setter != null)
                    {
                        WriteMethodAccess(property.Setter, result);
                        result.Append($"set; ");
                    }
                    result.AppendLine("}");
                }
                else
                {
                    result.Append("    ");
                    WriteMethodAccess(property.Getter, result);
                    result.AppendLine($"{property.GetPropertyType().GetPrettyFullName()} this.[{itemPropertyType}]");
                }
            }

            // Write events

            var typeEvents = mrType.GetEvents(publicishOnly);

            foreach (var ev in typeEvents)
            {
                result.Append($"    ");

                ev.GetAccessors(out var adder, out var remover);
                if (adder == null)
                {
                    result.Append("private ");
                }
                else
                {
                    WriteMethodAccess(adder, result);
                }

                result.AppendLine($"{ev.GetEventType().GetPrettyFullName()} {ev.GetName()} {{ add; remove; }}");
            }

            // Write methods

            foreach (var method in methods)
            {
                result.Append("    ");
                WriteMethodAccess(method, result);

                result.Append($"{method.ReturnType} {method.GetName()}(");
                var parameters = method.GetParameters();
                WriteParameters(parameters, result);
                result.AppendLine(")");
            }

            // See later comment where this is used
            List <string> typeEventNames = null;

            if (!publicishOnly)
            {
                typeEventNames = new List <string>();
                foreach (var ev in typeEvents)
                {
                    typeEventNames.Add(ev.GetName());
                }
            }


            // Write fields

            foreach (var field in mrType.GetFields(publicishOnly))
            {
                var name = field.GetName();

                // If we're showing private members, we're going to see private events twice;
                // once as an event and then again as a field.
                if (!publicishOnly)
                {
                    if (typeEventNames.Contains(name))
                    {
                        continue;
                    }
                }

                if (mrType.IsEnum)
                {
                    if (!field.IsSpecialName) // Ignore special value__ field
                    {
                        var value = field.GetConstantValue(out var constantTypeCode);
                        result.AppendLine($"    {field.GetName()} = {value},");
                    }
                }
                else
                {
                    result.AppendLine($"    {field.GetFieldType().GetPrettyFullName()} {field.GetName()};");
                }
            }
        }