public static Metadata ConvertMetadata(IMetadataReaderSession provider) { var types = new Dictionary <string, MetadataType>(); var typeDefs = new Dictionary <MetadataType, ITypeInformation>(); var metadata = new Metadata(); var resourceUrls = new List <string>(); var avaresValues = new List <AvaresInfo>(); var ignoredResExt = new[] { ".resources", ".rd.xml", "!AvaloniaResources" }; bool skipRes(string res) => ignoredResExt.Any(r => res.EndsWith(r, StringComparison.OrdinalIgnoreCase)); PreProcessTypes(types, metadata); foreach (var asm in provider.Assemblies) { var aliases = new Dictionary <string, string[]>(); ProcessWellKnownAliases(asm, aliases); ProcessCustomAttributes(asm, aliases); var asmTypes = asm.Types.ToArray(); foreach (var type in asmTypes.Where(x => !x.IsInterface && x.IsPublic)) { var mt = types[type.FullName] = ConvertTypeInfomation(type); typeDefs[mt] = type; metadata.AddType("clr-namespace:" + type.Namespace + ";assembly=" + asm.Name, mt); string[] nsAliases = null; string usingNamespace = $"using:{type.Namespace}"; if (!aliases.TryGetValue(type.Namespace, out nsAliases)) { nsAliases = new string[] { usingNamespace }; aliases[type.Namespace] = nsAliases; } else if (!nsAliases.Contains(usingNamespace)) { aliases[type.Namespace] = nsAliases.Union(new string[] { usingNamespace }).ToArray(); } foreach (var alias in nsAliases) { metadata.AddType(alias, mt); } } ProcessAvaloniaResources(asm, asmTypes, avaresValues); resourceUrls.AddRange(asm.ManifestResourceNames.Where(r => !skipRes(r)).Select(r => $"resm:{r}?assembly={asm.Name}")); } foreach (var type in types.Values) { ITypeInformation typeDef; typeDefs.TryGetValue(type, out typeDef); var ctors = typeDef?.Methods .Where(m => m.IsPublic && !m.IsStatic && m.Name == ".ctor" && m.Parameters.Count == 1); if (typeDef?.IsEnum ?? false) { foreach (var value in typeDef.EnumValues) { var p = new MetadataProperty(value, type, type, false, true, true, false); type.Properties.Add(p); } } int level = 0; while (typeDef != null) { var currentType = types.GetValueOrDefault(typeDef.FullName); foreach (var prop in typeDef.Properties) { if (!prop.HasPublicGetter && !prop.HasPublicSetter) { continue; } var p = new MetadataProperty(prop.Name, types.GetValueOrDefault(prop.TypeFullName), currentType, false, prop.IsStatic, prop.HasPublicGetter, prop.HasPublicSetter); type.Properties.Add(p); } foreach (var eventDef in typeDef.Events) { var e = new MetadataEvent(eventDef.Name, types.GetValueOrDefault(eventDef.TypeFullName), types.GetValueOrDefault(typeDef.FullName), false); type.Events.Add(e); } //check for attached properties only on top level if (level == 0) { foreach (var methodDef in typeDef.Methods) { if (methodDef.Name.StartsWith("Set", StringComparison.OrdinalIgnoreCase) && methodDef.IsStatic && methodDef.IsPublic && methodDef.Parameters.Count == 2) { var name = methodDef.Name.Substring(3); type.Properties.Add(new MetadataProperty(name, types.GetValueOrDefault(methodDef.Parameters[1].TypeFullName), types.GetValueOrDefault(typeDef.FullName), true, false, true, true)); } } foreach (var fieldDef in typeDef.Fields) { if (fieldDef.IsStatic && fieldDef.IsPublic) { if ((fieldDef.IsRoutedEvent || fieldDef.Name.EndsWith("Event", StringComparison.OrdinalIgnoreCase))) { var name = fieldDef.Name; if (fieldDef.Name.EndsWith("Event", StringComparison.OrdinalIgnoreCase)) { name = name.Substring(0, name.Length - "Event".Length); } type.Events.Add(new MetadataEvent(name, types.GetValueOrDefault(fieldDef.ReturnTypeFullName), types.GetValueOrDefault(typeDef.FullName), true)); } else if (type.IsStatic) { type.Properties.Add(new MetadataProperty(fieldDef.Name, null, type, false, true, true, false)); } } } } if (typeDef.FullName == "Avalonia.AvaloniaObject") { type.IsAvaloniaObjectType = true; } typeDef = typeDef.GetBaseType(); level++; } type.HasAttachedProperties = type.Properties.Any(p => p.IsAttached); type.HasAttachedEvents = type.Events.Any(e => e.IsAttached); type.HasStaticGetProperties = type.Properties.Any(p => p.IsStatic && p.HasGetter); type.HasSetProperties = type.Properties.Any(p => !p.IsStatic && p.HasSetter); if (ctors?.Any() == true) { bool supportType = ctors.Any(m => m.Parameters[0].TypeFullName == "System.Type"); bool supportObject = ctors.Any(m => m.Parameters[0].TypeFullName == "System.Object" || m.Parameters[0].TypeFullName == "System.String"); if (types.TryGetValue(ctors.First().Parameters[0].TypeFullName, out MetadataType parType) && parType.HasHintValues) { type.SupportCtorArgument = MetadataTypeCtorArgument.HintValues; type.HasHintValues = true; type.HintValues = parType.HintValues; } else if (supportType && supportObject) { type.SupportCtorArgument = MetadataTypeCtorArgument.TypeAndObject; } else if (supportType) { type.SupportCtorArgument = MetadataTypeCtorArgument.Type; } else if (supportObject) { type.SupportCtorArgument = MetadataTypeCtorArgument.Object; } } } PostProcessTypes(types, metadata, resourceUrls, avaresValues); return(metadata); }
private static void PostProcessTypes(Dictionary <string, MetadataType> types, Metadata metadata, IEnumerable <string> resourceUrls, List <AvaresInfo> avaResValues) { bool rhasext(string resource, string ext) => resource.StartsWith("resm:") ? resource.Contains(ext + "?assembly=") : resource.EndsWith(ext); var allresourceUrls = avaResValues.Select(v => v.GlobalUrl).Concat(resourceUrls).ToArray(); var resType = new MetadataType() { Name = "avares://,resm:", IsStatic = true, HasHintValues = true, HintValues = allresourceUrls }; types.Add(resType.Name, resType); var xamlResType = new MetadataType() { Name = "avares://*.xaml,resm:*.xaml", HasHintValues = true, HintValues = resType.HintValues.Where(r => rhasext(r, ".xaml") || rhasext(r, ".paml") || rhasext(r, ".axaml")).ToArray() }; var styleResType = new MetadataType() { Name = "Style avares://*.xaml,resm:*.xaml", HasHintValues = true, HintValues = avaResValues.Where(v => v.ReturnTypeFullName.StartsWith("Avalonia.Styling.Style")) .Select(v => v.GlobalUrl) .Concat(resourceUrls.Where(r => rhasext(r, ".xaml") || rhasext(r, ".paml") || rhasext(r, ".axaml"))) .ToArray() }; types.Add(styleResType.Name, styleResType); IEnumerable <string> filterLocalRes(MetadataType type, string currentAssemblyName) { var localResPrefix = $"avares://{currentAssemblyName}"; var resmSuffix = $"?assembly={currentAssemblyName}"; foreach (var hint in type.HintValues ?? Array.Empty <string>()) { if (hint.StartsWith("avares://")) { if (hint.StartsWith(localResPrefix)) { yield return(hint.Substring(localResPrefix.Length)); } } else if (hint.StartsWith("resm:")) { if (hint.EndsWith(resmSuffix)) { yield return(hint.Substring(0, hint.Length - resmSuffix.Length)); } } } } resType.XamlContextHintValuesFunc = (a, t, p) => filterLocalRes(xamlResType, a); xamlResType.XamlContextHintValuesFunc = (a, t, p) => filterLocalRes(xamlResType, a); styleResType.XamlContextHintValuesFunc = (a, t, p) => filterLocalRes(styleResType, a); types.Add(xamlResType.Name, xamlResType); var allProps = new Dictionary <string, MetadataProperty>(); foreach (var type in types.Where(t => t.Value.IsAvaloniaObjectType)) { foreach (var v in type.Value.Properties.Where(p => p.HasSetter && p.HasGetter)) { allProps[v.Name] = v; } } string[] allAvaloniaProps = allProps.Keys.ToArray(); if (!types.TryGetValue("Avalonia.Markup.Xaml.MarkupExtensions.BindingExtension", out MetadataType bindingExtType)) { if (types.TryGetValue("Avalonia.Data.Binding", out MetadataType origBindingType)) { //avalonia 0.10 has implicit binding extension bindingExtType = origBindingType.CloneAs("BindingExtension", "Avalonia.Markup.Xaml.MarkupExtensions.BindingExtension"); bindingExtType.IsMarkupExtension = true; types.Add(bindingExtType.FullName, bindingExtType); metadata.AddType(Utils.AvaloniaNamespace, bindingExtType); } } types.TryGetValue("Avalonia.Controls.Control", out MetadataType controlType); types.TryGetValue(typeof(Type).FullName, out MetadataType typeType); var dataContextType = new MetadataType() { Name = "{BindingPath}", FullName = "{BindingPath}", HasHintValues = true, HintValues = new[] { "$parent", "$parent[", "$self" }, }; //bindings related hints if (types.TryGetValue("Avalonia.Markup.Xaml.MarkupExtensions.BindingExtension", out MetadataType bindingType)) { bindingType.SupportCtorArgument = MetadataTypeCtorArgument.None; var pathProp = bindingType.Properties.FirstOrDefault(p => p.Name == "Path"); if (pathProp != null) { pathProp.Type = dataContextType; } bindingType.Properties.Add(new MetadataProperty("", dataContextType, bindingType, false, false, true, true)); } if (types.TryGetValue("Avalonia.Data.TemplateBinding", out MetadataType templBinding)) { var tbext = new MetadataType() { Name = "TemplateBindingExtension", IsMarkupExtension = true, Properties = templBinding.Properties, SupportCtorArgument = MetadataTypeCtorArgument.HintValues, HasHintValues = allAvaloniaProps?.Any() ?? false, HintValues = allAvaloniaProps }; types["TemplateBindingExtension"] = tbext; metadata.AddType(Utils.AvaloniaNamespace, tbext); } if (types.TryGetValue("Portable.Xaml.Markup.TypeExtension", out MetadataType typeExtension)) { typeExtension.SupportCtorArgument = MetadataTypeCtorArgument.Type; } //TODO: may be make it to load from assembly resources string[] commonResKeys = new string[] { //common brushes "ThemeBackgroundBrush", "ThemeBorderLowBrush", "ThemeBorderMidBrush", "ThemeBorderHighBrush", "ThemeControlLowBrush", "ThemeControlMidBrush", "ThemeControlHighBrush", "ThemeControlHighlightLowBrush", "ThemeControlHighlightMidBrush", "ThemeControlHighlightHighBrush", "ThemeForegroundBrush", "ThemeForegroundLowBrush", "HighlightBrush", "ThemeAccentBrush", "ThemeAccentBrush2", "ThemeAccentBrush3", "ThemeAccentBrush4", "ErrorBrush", "ErrorLowBrush", //some other usefull "ThemeBorderThickness", "ThemeDisabledOpacity", "FontSizeSmall", "FontSizeNormal", "FontSizeLarge" }; if (types.TryGetValue("Avalonia.Markup.Xaml.MarkupExtensions.DynamicResourceExtension", out MetadataType dynRes)) { dynRes.SupportCtorArgument = MetadataTypeCtorArgument.HintValues; dynRes.HasHintValues = true; dynRes.HintValues = commonResKeys; } if (types.TryGetValue("Avalonia.Markup.Xaml.MarkupExtensions.StaticResourceExtension", out MetadataType stRes)) { stRes.SupportCtorArgument = MetadataTypeCtorArgument.HintValues; stRes.HasHintValues = true; stRes.HintValues = commonResKeys; } //brushes if (types.TryGetValue("Avalonia.Media.IBrush", out MetadataType brushType) && types.TryGetValue("Avalonia.Media.Brushes", out MetadataType brushes)) { brushType.HasHintValues = true; brushType.HintValues = brushes.Properties.Where(p => p.IsStatic && p.HasGetter).Select(p => p.Name).ToArray(); } if (types.TryGetValue("Avalonia.Styling.Selector", out MetadataType styleSelector)) { styleSelector.HasHintValues = true; styleSelector.IsCompositeValue = true; List <string> hints = new List <string>(); //some reserved words hints.AddRange(new[] { "/template/", ":is()", ">", "#", "." }); //some pseudo classes hints.AddRange(new[] { ":pointerover", ":pressed", ":disabled", ":focus", ":selected", ":vertical", ":horizontal", ":checked", ":unchecked", ":indeterminate" }); hints.AddRange(types.Where(t => t.Value.IsAvaloniaObjectType).Select(t => t.Value.Name.Replace(":", "|"))); styleSelector.HintValues = hints.ToArray(); } string[] bitmaptypes = new[] { ".jpg", ".bmp", ".png", ".ico" }; bool isbitmaptype(string resource) => bitmaptypes.Any(ext => rhasext(resource, ext)); if (types.TryGetValue("Avalonia.Media.Imaging.IBitmap", out MetadataType ibitmapType)) { ibitmapType.HasHintValues = true; ibitmapType.HintValues = allresourceUrls.Where(r => isbitmaptype(r)).ToArray(); ibitmapType.XamlContextHintValuesFunc = (a, t, p) => filterLocalRes(ibitmapType, a); } if (types.TryGetValue("Avalonia.Media.IImage", out MetadataType iImageType)) { iImageType.HasHintValues = true; iImageType.HintValues = allresourceUrls.Where(r => isbitmaptype(r)).ToArray(); iImageType.XamlContextHintValuesFunc = (a, t, p) => filterLocalRes(ibitmapType, a); } if (types.TryGetValue("Avalonia.Controls.WindowIcon", out MetadataType winIcon)) { winIcon.HasHintValues = true; winIcon.HintValues = allresourceUrls.Where(r => rhasext(r, ".ico")).ToArray(); winIcon.XamlContextHintValuesFunc = (a, t, p) => filterLocalRes(winIcon, a); } if (types.TryGetValue("Avalonia.Markup.Xaml.Styling.StyleInclude", out MetadataType styleIncludeType)) { var source = styleIncludeType.Properties.FirstOrDefault(p => p.Name == "Source"); if (source != null) { source.Type = styleResType; } } if (types.TryGetValue("Avalonia.Markup.Xaml.Styling.StyleIncludeExtension", out MetadataType styleIncludeExtType)) { var source = styleIncludeExtType.Properties.FirstOrDefault(p => p.Name == "Source"); if (source != null) { source.Type = xamlResType; } } if (types.TryGetValue(typeof(Uri).FullName, out MetadataType uriType)) { uriType.HasHintValues = true; uriType.HintValues = allresourceUrls.ToArray(); uriType.XamlContextHintValuesFunc = (a, t, p) => filterLocalRes(uriType, a); } if (typeType != null) { var typeArguments = new MetadataType() { Name = "TypeArguments", IsXamlDirective = true, IsValidForXamlContextFunc = (a, t, p) => t?.IsGeneric == true, Properties = { new MetadataProperty("", typeType, null, false, false, false, true) } }; metadata.AddType(Utils.Xaml2006Namespace, typeArguments); } }
private static void PreProcessTypes(Dictionary <string, MetadataType> types, Metadata metadata) { MetadataType xDataType, xCompiledBindings, boolType, typeType; var toAdd = new List <MetadataType> { (boolType = new MetadataType() { Name = typeof(bool).FullName, HasHintValues = true, HintValues = new[] { "True", "False" } }), new MetadataType() { Name = typeof(System.Uri).FullName }, (typeType = new MetadataType() { Name = typeof(System.Type).FullName }), new MetadataType() { Name = "Avalonia.Media.IBrush" }, new MetadataType() { Name = "Avalonia.Media.Imaging.IBitmap" }, new MetadataType() { Name = "Avalonia.Media.IImage" }, }; foreach (var t in toAdd) { types.Add(t.Name, t); } var portableXamlExtTypes = new[] { new MetadataType() { Name = "StaticExtension", SupportCtorArgument = MetadataTypeCtorArgument.Object, HasSetProperties = true, IsMarkupExtension = true, }, new MetadataType() { Name = "TypeExtension", SupportCtorArgument = MetadataTypeCtorArgument.TypeAndObject, HasSetProperties = true, IsMarkupExtension = true, }, new MetadataType() { Name = "NullExtension", HasSetProperties = true, IsMarkupExtension = true, }, new MetadataType() { Name = "Class", IsXamlDirective = true }, new MetadataType() { Name = "Name", IsXamlDirective = true }, new MetadataType() { Name = "Key", IsXamlDirective = true }, xDataType = new MetadataType() { Name = "DataType", IsXamlDirective = true, Properties = { new MetadataProperty("", typeType, null, false, false, false, true) }, }, xCompiledBindings = new MetadataType() { Name = "CompileBindings", IsXamlDirective = true, Properties = { new MetadataProperty("", boolType, null, false, false, false, true) }, }, }; //as in avalonia 0.9 Portablexaml is missing we need to hardcode some extensions foreach (var t in portableXamlExtTypes) { metadata.AddType(Utils.Xaml2006Namespace, t); } types.Add(xDataType.Name, xDataType); types.Add(xCompiledBindings.Name, xCompiledBindings); metadata.AddType("", new MetadataType() { Name = "xmlns", IsXamlDirective = true }); }
public static Metadata ConvertMetadata(IMetadataReaderSession provider) { var types = new Dictionary <string, MetadataType>(); var typeDefs = new Dictionary <MetadataType, ITypeInformation>(); var metadata = new Metadata(); var resourceUrls = new List <string>(); var avaresValues = new List <AvaresInfo>(); var ignoredResExt = new[] { ".resources", ".rd.xml" }; bool skipRes(string res) => ignoredResExt.Any(r => res.EndsWith(r, StringComparison.OrdinalIgnoreCase)); PreProcessTypes(types, metadata); foreach (var asm in provider.Assemblies) { var aliases = new Dictionary <string, string[]>(); ProcessWellKnownAliases(asm, aliases); ProcessCustomAttributes(asm, aliases); foreach (var type in asm.Types.Where(x => !x.IsInterface && x.IsPublic)) { var mt = types[type.FullName] = ConvertTypeInfomation(type); typeDefs[mt] = type; metadata.AddType("clr-namespace:" + type.Namespace + ";assembly=" + asm.Name, mt); string[] nsAliases = null; if (aliases.TryGetValue(type.Namespace, out nsAliases)) { foreach (var alias in nsAliases) { metadata.AddType(alias, mt); } } } const string avaresToken = "Build:"; //or "Populate:" should work both ways foreach (var resType in asm.Types.Where(t => t.FullName == "CompiledAvaloniaXaml.!AvaloniaResources" || t.Name == "CompiledAvaloniaXaml.!AvaloniaResources")) { foreach (var res in resType.Methods.Where(m => m.Name.StartsWith(avaresToken))) { var localUrl = res.Name.Replace(avaresToken, ""); var avres = new AvaresInfo { Assembly = asm, LocalUrl = localUrl, GlobalUrl = $"avares://{asm.Name}{localUrl}", ReturnTypeFullName = res.ReturnTypeFullName ?? "" }; avaresValues.Add(avres); } } resourceUrls.AddRange(asm.ManifestResourceNames.Where(r => !skipRes(r)).Select(r => $"resm:{r}?assembly={asm.Name}")); } foreach (var type in types.Values) { ITypeInformation typeDef; typeDefs.TryGetValue(type, out typeDef); var ctors = typeDef?.Methods .Where(m => m.IsPublic && !m.IsStatic && m.Name == ".ctor" && m.Parameters.Count == 1); int level = 0; while (typeDef != null) { foreach (var prop in typeDef.Properties) { if (!prop.HasPublicGetter && !prop.HasPublicSetter) { continue; } var p = new MetadataProperty(prop.Name, types.GetValueOrDefault(prop.TypeFullName), types.GetValueOrDefault(typeDef.FullName), false, prop.IsStatic, prop.HasPublicGetter, prop.HasPublicSetter); type.Properties.Add(p); } //check for attached properties only on top level if (level == 0) { foreach (var methodDef in typeDef.Methods) { if (methodDef.Name.StartsWith("Set") && methodDef.IsStatic && methodDef.IsPublic && methodDef.Parameters.Count == 2) { var name = methodDef.Name.Substring(3); type.Properties.Add(new MetadataProperty(name, types.GetValueOrDefault(methodDef.Parameters[1].TypeFullName), types.GetValueOrDefault(typeDef.FullName), true, false, true, true)); } } } if (typeDef.FullName == "Avalonia.AvaloniaObject") { type.IsAvaloniaObjectType = true; } typeDef = typeDef.GetBaseType(); level++; } type.HasAttachedProperties = type.Properties.Any(p => p.IsAttached); type.HasStaticGetProperties = type.Properties.Any(p => p.IsStatic && p.HasGetter); type.HasSetProperties = type.Properties.Any(p => !p.IsStatic && p.HasSetter); if (ctors?.Any() == true) { bool supportType = ctors.Any(m => m.Parameters[0].TypeFullName == "System.Type"); bool supportObject = ctors.Any(m => m.Parameters[0].TypeFullName == "System.Object" || m.Parameters[0].TypeFullName == "System.String"); if (types.TryGetValue(ctors.First().Parameters[0].TypeFullName, out MetadataType parType) && parType.HasHintValues) { type.SupportCtorArgument = MetadataTypeCtorArgument.HintValues; type.HasHintValues = true; type.HintValues = parType.HintValues; } else if (supportType && supportObject) { type.SupportCtorArgument = MetadataTypeCtorArgument.TypeAndObject; } else if (supportType) { type.SupportCtorArgument = MetadataTypeCtorArgument.Type; } else if (supportObject) { type.SupportCtorArgument = MetadataTypeCtorArgument.Object; } } } PostProcessTypes(types, metadata, resourceUrls, avaresValues); return(metadata); }
private static void PostProcessTypes(Dictionary <string, MetadataType> types, Metadata metadata, IEnumerable <string> resourceUrls) { bool rhasext(string resource, string ext) => resource.Contains(ext + "?assembly="); var resmType = new MetadataType() { Name = "resm:", IsStatic = true, HasHintValues = true, HintValues = resourceUrls.ToArray() }; types.Add(resmType.Name, resmType); metadata.AddType(Utils.AvaloniaNamespace, resmType); var xamlResmType = new MetadataType() { Name = "resm:*.xaml", HasHintValues = true, HintValues = resourceUrls.Where(r => rhasext(r, ".xaml") || rhasext(r, ".paml")).ToArray() }; types.Add(xamlResmType.Name, xamlResmType); metadata.AddType(Utils.AvaloniaNamespace, xamlResmType); MetadataType avProperty; if (types.TryGetValue("Avalonia.AvaloniaProperty", out avProperty)) { var allProps = new Dictionary <string, MetadataProperty>(); foreach (var type in types.Where(t => t.Value.IsAvaloniaObjectType)) { foreach (var v in type.Value.Properties.Where(p => p.HasSetter && p.HasGetter)) { allProps[v.Name] = v; } } avProperty.HasHintValues = true; avProperty.HintValues = allProps.Keys.ToArray(); } //bindings related hints if (types.TryGetValue("Avalonia.Markup.Xaml.MarkupExtensions.BindingExtension", out MetadataType bindingType)) { bindingType.SupportCtorArgument = MetadataTypeCtorArgument.None; } if (types.TryGetValue("Avalonia.Data.TemplateBinding", out MetadataType templBinding)) { var tbext = new MetadataType() { Name = "TemplateBindingExtension", IsMarkupExtension = true, Properties = templBinding.Properties, SupportCtorArgument = MetadataTypeCtorArgument.HintValues, HasHintValues = avProperty?.HasHintValues ?? false, HintValues = avProperty?.HintValues }; types["TemplateBindingExtension"] = tbext; metadata.AddType(Utils.AvaloniaNamespace, tbext); } if (types.TryGetValue("Portable.Xaml.Markup.TypeExtension", out MetadataType typeExtension)) { typeExtension.SupportCtorArgument = MetadataTypeCtorArgument.Type; } //TODO: may be make it to load from assembly resources string[] commonResKeys = new string[] { //common brushes "ThemeBackgroundBrush", "ThemeBorderLowBrush", "ThemeBorderMidBrush", "ThemeBorderHighBrush", "ThemeControlLowBrush", "ThemeControlMidBrush", "ThemeControlHighBrush", "ThemeControlHighlightLowBrush", "ThemeControlHighlightMidBrush", "ThemeControlHighlightHighBrush", "ThemeForegroundBrush", "ThemeForegroundLowBrush", "HighlightBrush", "ThemeAccentBrush", "ThemeAccentBrush2", "ThemeAccentBrush3", "ThemeAccentBrush4", "ErrorBrush", "ErrorLowBrush", //some other usefull "ThemeBorderThickness", "ThemeDisabledOpacity", "FontSizeSmall", "FontSizeNormal", "FontSizeLarge" }; if (types.TryGetValue("Avalonia.Markup.Xaml.MarkupExtensions.DynamicResourceExtension", out MetadataType dynRes)) { dynRes.SupportCtorArgument = MetadataTypeCtorArgument.HintValues; dynRes.HasHintValues = true; dynRes.HintValues = commonResKeys; } if (types.TryGetValue("Avalonia.Markup.Xaml.MarkupExtensions.StaticResourceExtension", out MetadataType stRes)) { stRes.SupportCtorArgument = MetadataTypeCtorArgument.HintValues; stRes.HasHintValues = true; stRes.HintValues = commonResKeys; } //brushes if (types.TryGetValue("Avalonia.Media.IBrush", out MetadataType brushType) && types.TryGetValue("Avalonia.Media.Brushes", out MetadataType brushes)) { brushType.HasHintValues = true; brushType.HintValues = brushes.Properties.Where(p => p.IsStatic && p.HasGetter).Select(p => p.Name).ToArray(); } if (types.TryGetValue("Avalonia.Styling.Selector", out MetadataType styleSelector)) { styleSelector.HasHintValues = true; styleSelector.IsCompositeValue = true; List <string> hints = new List <string>(); //some reserved words hints.AddRange(new[] { "/template/", ":is()", ">", "#", "." }); //some pseudo classes hints.AddRange(new[] { ":pointerover", ":pressed", ":disabled", ":focus", ":selected", ":vertical", ":horizontal", ":checked", ":unchecked", ":indeterminate" }); hints.AddRange(types.Where(t => t.Value.IsAvaloniaObjectType).Select(t => t.Value.Name.Replace(":", "|"))); styleSelector.HintValues = hints.ToArray(); } string[] bitmaptypes = new[] { ".jpg", ".bmp", ".png", ".ico" }; bool isbitmaptype(string resource) => bitmaptypes.Any(ext => rhasext(resource, ext)); if (types.TryGetValue("Avalonia.Media.Imaging.IBitmap", out MetadataType ibitmapType)) { ibitmapType.HasHintValues = true; ibitmapType.HintValues = resourceUrls.Where(r => isbitmaptype(r)).ToArray(); } if (types.TryGetValue("Avalonia.Controls.WindowIcon", out MetadataType winIcon)) { winIcon.HasHintValues = true; winIcon.HintValues = resourceUrls.Where(r => rhasext(r, ".ico")).ToArray(); } if (types.TryGetValue("Avalonia.Markup.Xaml.Styling.StyleInclude", out MetadataType styleIncludeType)) { var source = styleIncludeType.Properties.FirstOrDefault(p => p.Name == "Source"); if (source != null) { source.Type = xamlResmType; } } if (types.TryGetValue("Avalonia.Markup.Xaml.Styling.StyleIncludeExtension", out MetadataType styleIncludeExtType)) { var source = styleIncludeExtType.Properties.FirstOrDefault(p => p.Name == "Source"); if (source != null) { source.Type = xamlResmType; } } if (types.TryGetValue(typeof(Uri).FullName, out MetadataType uriType)) { uriType.HasHintValues = true; uriType.HintValues = resourceUrls.ToArray(); } }
public static Metadata ConvertMetadata(IMetadataReaderSession provider) { var types = new Dictionary <string, MetadataType>(); var typeDefs = new Dictionary <MetadataType, ITypeInformation>(); var metadata = new Metadata(); types.Add(typeof(bool).FullName, new MetadataType() { Name = typeof(bool).FullName, IsEnum = true, EnumValues = new[] { "True", "False" } }); foreach (var asm in provider.Assemblies) { var aliases = new Dictionary <string, string>(); foreach ( var attr in asm.CustomAttributes.Where(a => a.TypeFullName == "Avalonia.Metadata.XmlnsDefinitionAttribute")) { aliases[attr.ConstructorArguments[1].Value.ToString()] = attr.ConstructorArguments[0].Value.ToString(); } foreach (var type in asm.Types.Where(x => !x.IsInterface && x.IsPublic)) { var mt = types[type.FullName] = ConvertTypeInfomation(type); typeDefs[mt] = type; metadata.AddType("clr-namespace:" + type.Namespace + ";assembly=" + asm.Name, mt); string alias = null; if (aliases.TryGetValue(type.Namespace, out alias)) { metadata.AddType(alias, mt); } } } foreach (var type in types.Values) { ITypeInformation typeDef; typeDefs.TryGetValue(type, out typeDef); while (typeDef != null) { foreach (var prop in typeDef.Properties) { if (prop.IsStatic || !prop.HasPublicSetter) { continue; } var p = new MetadataProperty { Name = prop.Name }; p.Type = types.GetValueOrDefault(prop.TypeFullName); type.Properties.Add(p); } foreach (var methodDef in typeDef.Methods) { if (methodDef.Name.StartsWith("Set") && methodDef.IsStatic && methodDef.IsPublic && methodDef.Parameters.Count == 2) { type.Properties.Add(new MetadataProperty() { Name = methodDef.Name.Substring(3), IsAttached = true, Type = types.GetValueOrDefault(methodDef.Parameters[1].TypeFullName) }); } } typeDef = typeDef.GetBaseType(); } type.HasAttachedProperties = type.Properties.Any(p => p.IsAttached); } return(metadata); }