|
|
@ -288,6 +288,24 @@ namespace Avalonia.Build.Tasks |
|
|
if (precompileText != "true") |
|
|
if (precompileText != "true") |
|
|
throw new XamlParseException("Invalid value for x:Precompile", precompileDirective); |
|
|
throw new XamlParseException("Invalid value for x:Precompile", precompileDirective); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var classModifierDirective = initialRoot.Children.OfType<XamlAstXmlDirective>() |
|
|
|
|
|
.FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "ClassModifier"); |
|
|
|
|
|
bool? classModifierPublic = null; |
|
|
|
|
|
if (classModifierDirective != null) |
|
|
|
|
|
{ |
|
|
|
|
|
var classModifierText = (classModifierDirective.Values[0] as XamlAstTextNode)?.Text.Trim() |
|
|
|
|
|
.ToLowerInvariant(); |
|
|
|
|
|
if ("Public".Equals(classModifierText, StringComparison.OrdinalIgnoreCase)) |
|
|
|
|
|
classModifierPublic = true; |
|
|
|
|
|
// XAML spec uses "Public" and "NotPublic" values,
|
|
|
|
|
|
// When WPF documentation uses "public" and "internal".
|
|
|
|
|
|
else if ("NotPublic".Equals(classModifierText, StringComparison.OrdinalIgnoreCase) |
|
|
|
|
|
|| "Internal".Equals(classModifierText, StringComparison.OrdinalIgnoreCase)) |
|
|
|
|
|
classModifierPublic = false; |
|
|
|
|
|
else |
|
|
|
|
|
throw new XamlParseException("Invalid value for x:ClassModifier. Expected value are: Public, NotPublic (internal).", precompileDirective); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
var classDirective = initialRoot.Children.OfType<XamlAstXmlDirective>() |
|
|
var classDirective = initialRoot.Children.OfType<XamlAstXmlDirective>() |
|
|
.FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Class"); |
|
|
.FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Class"); |
|
|
@ -297,8 +315,21 @@ namespace Avalonia.Build.Tasks |
|
|
if (classDirective.Values.Count != 1 || !(classDirective.Values[0] is XamlAstTextNode tn)) |
|
|
if (classDirective.Values.Count != 1 || !(classDirective.Values[0] is XamlAstTextNode tn)) |
|
|
throw new XamlParseException("x:Class should have a string value", classDirective); |
|
|
throw new XamlParseException("x:Class should have a string value", classDirective); |
|
|
classType = typeSystem.TargetAssembly.FindType(tn.Text); |
|
|
classType = typeSystem.TargetAssembly.FindType(tn.Text); |
|
|
|
|
|
|
|
|
if (classType == null) |
|
|
if (classType == null) |
|
|
throw new XamlParseException($"Unable to find type `{tn.Text}`", classDirective); |
|
|
throw new XamlParseException($"Unable to find type `{tn.Text}`", classDirective); |
|
|
|
|
|
|
|
|
|
|
|
var isClassPublic = typeSystem.GetTypeReference(classType).Resolve().IsPublic; |
|
|
|
|
|
classModifierPublic ??= isClassPublic; |
|
|
|
|
|
|
|
|
|
|
|
// We do not really need x:ClassModifier support for x:Class, but we can at least use it for validation here.
|
|
|
|
|
|
if (classModifierPublic != isClassPublic) |
|
|
|
|
|
{ |
|
|
|
|
|
throw new XamlParseException( |
|
|
|
|
|
"XAML file x:ClassModifier doesn't match the x:Class type modifiers.", |
|
|
|
|
|
precompileDirective); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
compiler.OverrideRootType(parsed, |
|
|
compiler.OverrideRootType(parsed, |
|
|
new XamlAstClrTypeReference(classDirective, classType, false)); |
|
|
new XamlAstClrTypeReference(classDirective, classType, false)); |
|
|
initialRoot.Children.Remove(classDirective); |
|
|
initialRoot.Children.Remove(classDirective); |
|
|
@ -312,6 +343,8 @@ namespace Avalonia.Build.Tasks |
|
|
var classTypeDefinition = |
|
|
var classTypeDefinition = |
|
|
classType == null ? null : typeSystem.GetTypeReference(classType).Resolve(); |
|
|
classType == null ? null : typeSystem.GetTypeReference(classType).Resolve(); |
|
|
|
|
|
|
|
|
|
|
|
// All XAML files are public by default.
|
|
|
|
|
|
classModifierPublic ??= true; |
|
|
|
|
|
|
|
|
var populateBuilder = classTypeDefinition == null ? |
|
|
var populateBuilder = classTypeDefinition == null ? |
|
|
builder : |
|
|
builder : |
|
|
@ -319,10 +352,11 @@ namespace Avalonia.Build.Tasks |
|
|
|
|
|
|
|
|
((List<XamlDocumentResource>)parsedXamlDocuments).Add(new XamlDocumentResource( |
|
|
((List<XamlDocumentResource>)parsedXamlDocuments).Add(new XamlDocumentResource( |
|
|
parsed, res.Uri, res, classType, |
|
|
parsed, res.Uri, res, classType, |
|
|
|
|
|
classModifierPublic.Value, |
|
|
populateBuilder, |
|
|
populateBuilder, |
|
|
compiler.DefinePopulateMethod(populateBuilder, parsed, populateName, |
|
|
compiler.DefinePopulateMethod(populateBuilder, parsed, populateName, |
|
|
classTypeDefinition == null), |
|
|
classTypeDefinition == null && classModifierPublic.Value), |
|
|
buildName == null ? null : compiler.DefineBuildMethod(builder, parsed, buildName, true))); |
|
|
buildName == null ? null : compiler.DefineBuildMethod(builder, parsed, buildName, classModifierPublic.Value))); |
|
|
} |
|
|
} |
|
|
catch (Exception e) |
|
|
catch (Exception e) |
|
|
{ |
|
|
{ |
|
|
@ -368,7 +402,7 @@ namespace Avalonia.Build.Tasks |
|
|
document.PopulateMethod, |
|
|
document.PopulateMethod, |
|
|
document.BuildMethod, |
|
|
document.BuildMethod, |
|
|
builder.DefineSubType(compilerConfig.WellKnownTypes.Object, "NamespaceInfo:" + res.Name, |
|
|
builder.DefineSubType(compilerConfig.WellKnownTypes.Object, "NamespaceInfo:" + res.Name, |
|
|
true), |
|
|
document.IsPublic), |
|
|
(closureName, closureBaseType) => |
|
|
(closureName, closureBaseType) => |
|
|
populateBuilder.DefineSubType(closureBaseType, closureName, false), |
|
|
populateBuilder.DefineSubType(closureBaseType, closureName, false), |
|
|
(closureName, returnType, parameterTypes) => |
|
|
(closureName, returnType, parameterTypes) => |
|
|
@ -502,7 +536,8 @@ namespace Avalonia.Build.Tasks |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (document.BuildMethod != null || classTypeDefinition != null) |
|
|
if (document.IsPublic |
|
|
|
|
|
&& (document.BuildMethod != null || classTypeDefinition != null)) |
|
|
{ |
|
|
{ |
|
|
var compiledBuildMethod = document.BuildMethod == null ? |
|
|
var compiledBuildMethod = document.BuildMethod == null ? |
|
|
null : |
|
|
null : |
|
|
|