void DumpTypes(string path) { var output = Path.ChangeExtension(path, "xml"); writer = XmlWriter.Create(output, new XmlWriterSettings() { Indent = true }); writer.WriteStartDocument(); var context = new MrLoadContext(true); context.FakeTypeRequired += (sender, e) => { var ctx = sender as MrLoadContext; if (e.AssemblyName == "Windows.Foundation.FoundationContract") { e.ReplacementType = ctx.GetTypeFromAssembly(e.TypeName, "Windows"); } }; var windows_winmd = context.LoadAssemblyFromPath(@"C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.19041.0\Windows.winmd"); //, "Windows.winmd"); var assembly = context.LoadAssemblyFromPath(path); // @"C:\rnw\vnext\target\x86\Debug\Microsoft.ReactNative\Microsoft.ReactNative.winmd"); context.FinishLoading(); var types = assembly.GetAllTypes().Skip(1); var namespaces = assembly.GetAllTypes().Skip(1).Select(x => x.GetNamespace()).Distinct(); writer.WriteStartElement("assembly"); writer.WriteAttributeString("namespace", namespaces.FirstOrDefault()); foreach (var t in types) { if (IsExclusiveInterface(t) || IsAttribute(t)) { continue; } writer.WriteStartElement(GetTypeKind(t)); writer.WriteAttributeString("name", t.GetName()); if (!t.IsInterface && t.IsAbstract) { writer.WriteAttributeString("abstract", "true"); } var attrs = GetCustomAttrs(t); WriteAttrs(attrs); Debug.WriteLine($"{GetTypeKind(t)} {t.GetName()} {attrs.GetValueOrDefault("docstring")} {attrs.GetValueOrDefault("docdefault")}"); var kind = GetTypeKind(t); var baseTypesToSkip = new string[] { typeof(MulticastDelegate).FullName, typeof(ValueType).FullName, typeof(Enum).FullName, typeof(object).FullName, typeof(Attribute).FullName, }; if (t.GetBaseType() != null && !baseTypesToSkip.Contains(t.GetBaseType().GetFullName())) { writer.WriteStartElement("extends"); WriteType(t.GetBaseType()); writer.WriteEndElement(); } var ifaces = t.GetInterfaces().Where(x => !IsExclusiveInterface(x)); if (ifaces.Count() > 0) { writer.WriteStartElement(t.IsClass ? "implements" : "extends"); foreach (var i in ifaces) { WriteType(i); } writer.WriteEndElement(); } foreach (var m in t.GetProperties()) { var mattrs = GetCustomAttrs(m); var mattrsGetter = GetCustomAttrs(m.Getter); foreach (var kv in mattrsGetter) { mattrs[kv.Key] = kv.Value; } writer.WriteStartElement("property"); writer.WriteAttributeString("name", m.GetName()); bool isStatic = (m.Getter.MethodDefinition.Attributes & System.Reflection.MethodAttributes.Static) == System.Reflection.MethodAttributes.Static; if (isStatic) { writer.WriteAttributeString("static", isStatic.ToString().ToLower()); } bool isReadonly = m.Setter == null || !m.Setter.GetParsedMethodAttributes().IsPublic; if (isReadonly) { writer.WriteAttributeString("isReadonly", isReadonly.ToString().ToLower()); } WriteAttrs(mattrs); WriteType(m.GetPropertyType()); writer.WriteEndElement(); Debug.WriteLine($" prop {m.GetPropertyType().GetPrettyFullName()} {m.GetName()} {mattrs.GetValueOrDefault("docstring")} {mattrs.GetValueOrDefault("docdefault")}"); } t.GetMethodsAndConstructors(out var methods, out var ctors); if (GetTypeKind(t) != "delegate") { foreach (var m in methods) { var mattrs = GetCustomAttrs(m); writer.WriteStartElement("method"); writer.WriteAttributeString("name", m.GetName()); bool isStatic = m.MethodDefinition.Attributes.HasFlag(System.Reflection.MethodAttributes.Static); if (isStatic) { writer.WriteAttributeString("static", isStatic.ToString().ToLower()); } bool isAbstract = !t.IsInterface && m.MethodDefinition.Attributes.HasFlag(System.Reflection.MethodAttributes.Abstract); if (isAbstract) { writer.WriteAttributeString("abstract", isAbstract.ToString().ToLower()); } WriteAttrs(mattrs); WriteMethodSignature(m); writer.WriteEndElement(); Debug.WriteLine($" method {m.GetName()} {mattrs.GetValueOrDefault("docstring")} {mattrs.GetValueOrDefault("docdefault")}"); } foreach (var m in ctors) { var mattrs = GetCustomAttrs(m); writer.WriteStartElement("ctor"); writer.WriteAttributeString("name", m.DeclaringType.GetName()); WriteAttrs(mattrs); WriteMethodSignature(m, false); writer.WriteEndElement(); Debug.WriteLine($" ctor {m.GetName()} {mattrs.GetValueOrDefault("docstring")} {mattrs.GetValueOrDefault("docdefault")}"); } } else { var m = t.GetInvokeMethod(); var mattrs = GetCustomAttrs(m); WriteAttrs(mattrs); WriteMethodSignature(m); } foreach (var m in t.GetFields().Where(x => !x.IsSpecialName)) { var mattrs = GetCustomAttrs(m); writer.WriteStartElement("field"); writer.WriteAttributeString("name", m.GetName()); var constant = m.GetConstantValue(out var type); if (constant != null) { writer.WriteAttributeString("value", constant.ToString()); } WriteAttrs(mattrs); writer.WriteEndElement(); Debug.WriteLine($" field {m.GetName()} {mattrs.GetValueOrDefault("docstring")} {mattrs.GetValueOrDefault("docdefault")}"); } foreach (var m in t.GetEvents()) { var mattrs = GetCustomAttrs(m); writer.WriteStartElement("event"); writer.WriteAttributeString("name", m.GetName()); WriteAttrs(mattrs); writer.WriteEndElement(); Debug.WriteLine($" event {m.GetName()} {mattrs.GetValueOrDefault("docstring")} {mattrs.GetValueOrDefault("docdefault")}"); } writer.WriteEndElement(); } writer.WriteEndElement(); writer.WriteEndDocument(); writer.Flush(); writer.Close(); }
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."); }