Browse Source

fix: Name Generation for Identical View Class Names (#93)

* fix: Name Generation for Identical View Class Names
* nit: Formatting
pull/10407/head
Artyom V. Gorchakov 4 years ago
committed by GitHub
parent
commit
88b52d8900
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      README.md
  2. 3
      src/Avalonia.NameGenerator.Sandbox/App.xaml.cs
  3. 38
      src/Avalonia.NameGenerator.Sandbox/Controls/SignUpView.xaml
  4. 53
      src/Avalonia.NameGenerator.Sandbox/Controls/SignUpView.xaml.cs
  5. 32
      src/Avalonia.NameGenerator.Sandbox/Views/SignUpView.xaml
  6. 31
      src/Avalonia.NameGenerator.Sandbox/Views/SignUpView.xaml.cs
  7. 2
      src/Avalonia.NameGenerator.Tests/Views/View.cs
  8. 29
      src/Avalonia.NameGenerator.Tests/XamlXNameResolverTests.cs
  9. 2
      src/Avalonia.NameGenerator/Domain/ICodeGenerator.cs
  10. 48
      src/Avalonia.NameGenerator/Domain/INameResolver.cs
  11. 6
      src/Avalonia.NameGenerator/Generator.cs
  12. 13
      src/Avalonia.NameGenerator/Generator/AvaloniaNameGenerator.cs
  13. 3
      src/Avalonia.NameGenerator/Generator/InitializeComponentCodeGenerator.cs
  14. 4
      src/Avalonia.NameGenerator/Generator/OnlyPropertiesCodeGenerator.cs
  15. 15
      src/Avalonia.NameGenerator/Generator/XamlXNameResolver.cs
  16. 81
      src/Avalonia.NameGenerator/GeneratorOptions.cs

6
README.md

@ -110,6 +110,11 @@ The `x:Name` generator can be configured via MsBuild properties that you can put
The generator will process only XAML files with base classes' namespaces matching the specified glob pattern(s).
Example: `MyApp.Presentation.*`, `MyApp.Presentation.Views;MyApp.Presentation.Controls`
- `AvaloniaNameGeneratorViewFileNamingStrategy`
Possible values: `ClassName`, `NamespaceAndClassName`
Default value: `NamespaceAndClassName`
Determines how the automatically generated view files should be [named](https://github.com/AvaloniaUI/Avalonia.NameGenerator/issues/92).
The default values are given by:
```xml
@ -119,6 +124,7 @@ The default values are given by:
<AvaloniaNameGeneratorDefaultFieldModifier>internal</AvaloniaNameGeneratorDefaultFieldModifier>
<AvaloniaNameGeneratorFilterByPath>*</AvaloniaNameGeneratorFilterByPath>
<AvaloniaNameGeneratorFilterByNamespace>*</AvaloniaNameGeneratorFilterByNamespace>
<AvaloniaNameGeneratorViewFileNamingStrategy>NamespaceAndClassName</AvaloniaNameGeneratorViewFileNamingStrategy>
</PropertyGroup>
<!-- ... -->
</Project>

3
src/Avalonia.NameGenerator.Sandbox/App.xaml.cs

@ -1,6 +1,5 @@
using Avalonia.Markup.Xaml;
using Avalonia.NameGenerator.Sandbox.ViewModels;
using Avalonia.NameGenerator.Sandbox.Views;
namespace Avalonia.NameGenerator.Sandbox;
@ -10,7 +9,7 @@ public class App : Application
public override void OnFrameworkInitializationCompleted()
{
var view = new SignUpView
var view = new Views.SignUpView
{
ViewModel = new SignUpViewModel()
};

38
src/Avalonia.NameGenerator.Sandbox/Controls/SignUpView.xaml

@ -0,0 +1,38 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Avalonia.NameGenerator.Sandbox.Controls"
x:Class="Avalonia.NameGenerator.Sandbox.Controls.SignUpView">
<StackPanel>
<controls:CustomTextBox Margin="0 10 0 0"
x:Name="UserNameTextBox"
Watermark="Please, enter user name..."
UseFloatingWatermark="True" />
<TextBlock x:Name="UserNameValidation"
Foreground="Red"
FontSize="12" />
<TextBox Margin="0 10 0 0"
x:Name="PasswordTextBox"
Watermark="Please, enter your password..."
UseFloatingWatermark="True"
PasswordChar="*" />
<TextBlock x:Name="PasswordValidation"
Foreground="Red"
FontSize="12" />
<TextBox Margin="0 10 0 0"
x:Name="ConfirmPasswordTextBox"
Watermark="Please, confirm the password..."
UseFloatingWatermark="True"
PasswordChar="*" />
<TextBlock x:Name="ConfirmPasswordValidation"
TextWrapping="Wrap"
Foreground="Red"
FontSize="12" />
<Button Margin="0 10 0 5"
Content="Sign up"
x:Name="SignUpButton" />
<TextBlock x:Name="CompoundValidation"
TextWrapping="Wrap"
Foreground="Red"
FontSize="12" />
</StackPanel>
</UserControl>

53
src/Avalonia.NameGenerator.Sandbox/Controls/SignUpView.xaml.cs

@ -0,0 +1,53 @@
using System;
using System.Reactive.Disposables;
using Avalonia.NameGenerator.Sandbox.ViewModels;
using Avalonia.ReactiveUI;
using ReactiveUI;
using ReactiveUI.Validation.Extensions;
using ReactiveUI.Validation.Formatters;
namespace Avalonia.NameGenerator.Sandbox.Controls;
/// <summary>
/// This is a sample view class with typed x:Name references generated using
/// .NET 5 source generators. The class has to be partial because x:Name
/// references are living in a separate partial class file. See also:
/// https://devblogs.microsoft.com/dotnet/new-c-source-generator-samples/
/// </summary>
public partial class SignUpView : ReactiveUserControl<SignUpViewModel>
{
public SignUpView()
{
// The InitializeComponent method is also generated automatically
// and lives in the autogenerated part of the partial class.
InitializeComponent();
this.WhenActivated(disposables =>
{
this.Bind(ViewModel, x => x.UserName, x => x.UserNameTextBox.Text)
.DisposeWith(disposables);
this.Bind(ViewModel, x => x.Password, x => x.PasswordTextBox.Text)
.DisposeWith(disposables);
this.Bind(ViewModel, x => x.ConfirmPassword, x => x.ConfirmPasswordTextBox.Text)
.DisposeWith(disposables);
this.BindCommand(ViewModel, x => x.SignUp, x => x.SignUpButton)
.DisposeWith(disposables);
this.BindValidation(ViewModel, x => x.UserName, x => x.UserNameValidation.Text)
.DisposeWith(disposables);
this.BindValidation(ViewModel, x => x.Password, x => x.PasswordValidation.Text)
.DisposeWith(disposables);
this.BindValidation(ViewModel, x => x.ConfirmPassword, x => x.ConfirmPasswordValidation.Text)
.DisposeWith(disposables);
var newLineFormatter = new SingleLineFormatter(Environment.NewLine);
this.BindValidation(ViewModel, x => x.CompoundValidation.Text, newLineFormatter)
.DisposeWith(disposables);
// The references to text boxes below are also auto generated.
// Use Ctrl+Click in order to view the generated sources.
UserNameTextBox.Text = "Joseph!";
PasswordTextBox.Text = "1234";
ConfirmPasswordTextBox.Text = "1234";
});
}
}

32
src/Avalonia.NameGenerator.Sandbox/Views/SignUpView.xaml

@ -4,36 +4,6 @@
x:Class="Avalonia.NameGenerator.Sandbox.Views.SignUpView">
<StackPanel Margin="10">
<TextBlock Text="Sign Up" />
<controls:CustomTextBox Margin="0 10 0 0"
x:Name="UserNameTextBox"
Watermark="Please, enter user name..."
UseFloatingWatermark="True" />
<TextBlock x:Name="UserNameValidation"
Foreground="Red"
FontSize="12" />
<TextBox Margin="0 10 0 0"
x:Name="PasswordTextBox"
Watermark="Please, enter your password..."
UseFloatingWatermark="True"
PasswordChar="*" />
<TextBlock x:Name="PasswordValidation"
Foreground="Red"
FontSize="12" />
<TextBox Margin="0 10 0 0"
x:Name="ConfirmPasswordTextBox"
Watermark="Please, confirm the password..."
UseFloatingWatermark="True"
PasswordChar="*" />
<TextBlock x:Name="ConfirmPasswordValidation"
TextWrapping="Wrap"
Foreground="Red"
FontSize="12" />
<Button Margin="0 10 0 5"
Content="Sign up"
x:Name="SignUpButton" />
<TextBlock x:Name="CompoundValidation"
TextWrapping="Wrap"
Foreground="Red"
FontSize="12" />
<controls:SignUpView x:Name="SignUpControl" />
</StackPanel>
</Window>

31
src/Avalonia.NameGenerator.Sandbox/Views/SignUpView.xaml.cs

@ -1,10 +1,7 @@
using System;
using System.Reactive.Disposables;
using System.Reactive.Disposables;
using Avalonia.NameGenerator.Sandbox.ViewModels;
using Avalonia.ReactiveUI;
using ReactiveUI;
using ReactiveUI.Validation.Extensions;
using ReactiveUI.Validation.Formatters;
namespace Avalonia.NameGenerator.Sandbox.Views;
@ -23,31 +20,9 @@ public partial class SignUpView : ReactiveWindow<SignUpViewModel>
InitializeComponent();
this.WhenActivated(disposables =>
{
this.Bind(ViewModel, x => x.UserName, x => x.UserNameTextBox.Text)
this.WhenAnyValue(view => view.ViewModel)
.BindTo(this, view => view.SignUpControl.ViewModel)
.DisposeWith(disposables);
this.Bind(ViewModel, x => x.Password, x => x.PasswordTextBox.Text)
.DisposeWith(disposables);
this.Bind(ViewModel, x => x.ConfirmPassword, x => x.ConfirmPasswordTextBox.Text)
.DisposeWith(disposables);
this.BindCommand(ViewModel, x => x.SignUp, x => x.SignUpButton)
.DisposeWith(disposables);
this.BindValidation(ViewModel, x => x.UserName, x => x.UserNameValidation.Text)
.DisposeWith(disposables);
this.BindValidation(ViewModel, x => x.Password, x => x.PasswordValidation.Text)
.DisposeWith(disposables);
this.BindValidation(ViewModel, x => x.ConfirmPassword, x => x.ConfirmPasswordValidation.Text)
.DisposeWith(disposables);
var newLineFormatter = new SingleLineFormatter(Environment.NewLine);
this.BindValidation(ViewModel, x => x.CompoundValidation.Text, newLineFormatter)
.DisposeWith(disposables);
// The references to text boxes below are also auto generated.
// Use Ctrl+Click in order to view the generated sources.
UserNameTextBox.Text = "Joseph!";
PasswordTextBox.Text = "1234";
ConfirmPasswordTextBox.Text = "1234";
});
}
}

2
src/Avalonia.NameGenerator.Tests/Views/View.cs

@ -3,9 +3,7 @@ using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Controls;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

29
src/Avalonia.NameGenerator.Tests/XamlXNameResolverTests.cs

@ -24,7 +24,7 @@ public class XamlXNameResolverTests
Assert.NotEmpty(controls);
Assert.Equal(1, controls.Count);
Assert.Equal("UserNameTextBox", controls[0].Name);
Assert.Equal(typeof(TextBox).FullName, controls[0].TypeName);
Assert.Contains(typeof(TextBox).FullName!, controls[0].TypeName);
}
[Theory]
@ -40,9 +40,9 @@ public class XamlXNameResolverTests
Assert.Equal("UserNameTextBox", controls[0].Name);
Assert.Equal("PasswordTextBox", controls[1].Name);
Assert.Equal("SignUpButton", controls[2].Name);
Assert.Equal(typeof(TextBox).FullName, controls[0].TypeName);
Assert.Equal(typeof(TextBox).FullName, controls[1].TypeName);
Assert.Equal(typeof(Button).FullName, controls[2].TypeName);
Assert.Contains(typeof(TextBox).FullName!, controls[0].TypeName);
Assert.Contains(typeof(TextBox).FullName!, controls[1].TypeName);
Assert.Contains(typeof(Button).FullName!, controls[2].TypeName);
}
[Fact]
@ -56,9 +56,9 @@ public class XamlXNameResolverTests
Assert.Equal("ClrNamespaceRoutedViewHost", controls[0].Name);
Assert.Equal("UriRoutedViewHost", controls[1].Name);
Assert.Equal("UserNameTextBox", controls[2].Name);
Assert.Equal(typeof(RoutedViewHost).FullName, controls[0].TypeName);
Assert.Equal(typeof(RoutedViewHost).FullName, controls[1].TypeName);
Assert.Equal("Controls.CustomTextBox", controls[2].TypeName);
Assert.Contains(typeof(RoutedViewHost).FullName!, controls[0].TypeName);
Assert.Contains(typeof(RoutedViewHost).FullName!, controls[1].TypeName);
Assert.Contains("Controls.CustomTextBox", controls[2].TypeName);
}
[Fact]
@ -70,17 +70,12 @@ public class XamlXNameResolverTests
var currentControl = controls[0];
Assert.Equal("Root", currentControl.Name);
Assert.Equal("Sample.App.BaseView", currentControl.TypeName);
Assert.Equal(1, currentControl.GenericTypeArguments.Count);
Assert.Equal(typeof(string).FullName, currentControl.GenericTypeArguments[0]);
Assert.Equal("global::Sample.App.BaseView<global::System.String>", currentControl.PrintableTypeName);
Assert.Equal("global::Sample.App.BaseView<global::System.String>", currentControl.TypeName);
currentControl = controls[1];
Assert.Equal("NotAsRootNode", currentControl.Name);
Assert.Equal("Sample.App.BaseView", currentControl.TypeName);
Assert.Equal(1, currentControl.GenericTypeArguments.Count);
Assert.Equal(typeof(int).FullName, currentControl.GenericTypeArguments[0]);
Assert.Equal("global::Sample.App.BaseView<global::System.Int32>", currentControl.PrintableTypeName);
Assert.Contains("Sample.App.BaseView", currentControl.TypeName);
Assert.Equal("global::Sample.App.BaseView<global::System.Int32>", currentControl.TypeName);
}
[Fact]
@ -102,8 +97,8 @@ public class XamlXNameResolverTests
Assert.Equal(2, controls.Count);
Assert.Equal("UserNameTextBox", controls[0].Name);
Assert.Equal("NamedListBox", controls[1].Name);
Assert.Equal(typeof(TextBox).FullName, controls[0].TypeName);
Assert.Equal(typeof(ListBox).FullName, controls[1].TypeName);
Assert.Contains(typeof(TextBox).FullName!, controls[0].TypeName);
Assert.Contains(typeof(ListBox).FullName!, controls[1].TypeName);
}
[Fact]

2
src/Avalonia.NameGenerator/Domain/ICodeGenerator.cs

@ -5,5 +5,5 @@ namespace Avalonia.NameGenerator.Domain;
internal interface ICodeGenerator
{
string GenerateCode(string className, string nameSpace, IXamlType XamlType, IEnumerable<ResolvedName> names);
string GenerateCode(string className, string nameSpace, IXamlType xamlType, IEnumerable<ResolvedName> names);
}

48
src/Avalonia.NameGenerator/Domain/INameResolver.cs

@ -1,6 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using XamlX.Ast;
namespace Avalonia.NameGenerator.Domain;
@ -10,48 +8,4 @@ internal interface INameResolver
IReadOnlyList<ResolvedName> ResolveNames(XamlDocument xaml);
}
internal class ResolvedName
{
public ResolvedName(string typeName, string name, string fieldModifier, IReadOnlyList<string> genericTypeArguments)
{
TypeName = typeName;
Name = name;
FieldModifier = fieldModifier;
GenericTypeArguments = genericTypeArguments;
}
public string TypeName { get; }
public string Name { get; }
public string FieldModifier { get; }
public IReadOnlyList<string> GenericTypeArguments { get; }
public string PrintableTypeName =>
GenericTypeArguments.Count == 0
? $"global::{TypeName}"
: $@"global::{TypeName}<{string.Join(", ", GenericTypeArguments.Select(arg => $"global::{arg}"))}>";
public void Deconstruct(out string typeName, out string name, out string fieldModifier)
{
typeName = TypeName;
name = Name;
fieldModifier = FieldModifier;
}
public override bool Equals(object obj)
{
if (obj is not ResolvedName name)
{
return false;
}
return name.TypeName == TypeName
&& name.Name == Name
&& name.FieldModifier == FieldModifier
&& name.GenericTypeArguments.SequenceEqual(GenericTypeArguments);
}
public override int GetHashCode()
{
return (TypeName, Name, FieldModifier).GetHashCode();
}
}
internal record ResolvedName(string TypeName, string Name, string FieldModifier);

6
src/Avalonia.NameGenerator/Generator.cs

@ -21,7 +21,7 @@ public class AvaloniaNameSourceGenerator : ISourceGenerator
{
var generator = CreateNameGenerator(context);
var partials = generator.GenerateNameReferences(context.AdditionalFiles);
foreach (var partial in partials) context.AddSource(partial.FileName, partial.Content);
foreach (var (fileName, content) in partials) context.AddSource(fileName, content);
}
catch (Exception exception)
{
@ -33,7 +33,6 @@ public class AvaloniaNameSourceGenerator : ISourceGenerator
{
var options = new GeneratorOptions(context);
var types = new RoslynTypeSystem((CSharpCompilation)context.Compilation);
var defaultFieldModifier = options.AvaloniaNameGeneratorDefaultFieldModifier.ToString().ToLowerInvariant();
ICodeGenerator generator = options.AvaloniaNameGeneratorBehavior switch {
Behavior.OnlyProperties => new OnlyPropertiesCodeGenerator(),
Behavior.InitializeComponent => new InitializeComponentCodeGenerator(types),
@ -42,10 +41,11 @@ public class AvaloniaNameSourceGenerator : ISourceGenerator
var compiler = MiniCompiler.CreateDefault(types, MiniCompiler.AvaloniaXmlnsDefinitionAttribute);
return new AvaloniaNameGenerator(
options.AvaloniaNameGeneratorViewFileNamingStrategy,
new GlobPatternGroup(options.AvaloniaNameGeneratorFilterByPath),
new GlobPatternGroup(options.AvaloniaNameGeneratorFilterByNamespace),
new XamlXViewResolver(types, compiler, true, type => ReportInvalidType(context, type)),
new XamlXNameResolver(defaultFieldModifier),
new XamlXNameResolver(options.AvaloniaNameGeneratorDefaultFieldModifier),
generator);
}

13
src/Avalonia.NameGenerator/Generator/AvaloniaNameGenerator.cs

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.NameGenerator.Domain;
@ -7,6 +8,7 @@ namespace Avalonia.NameGenerator.Generator;
internal class AvaloniaNameGenerator : INameGenerator
{
private readonly ViewFileNamingStrategy _naming;
private readonly IGlobPattern _pathPattern;
private readonly IGlobPattern _namespacePattern;
private readonly IViewResolver _classes;
@ -14,12 +16,14 @@ internal class AvaloniaNameGenerator : INameGenerator
private readonly ICodeGenerator _code;
public AvaloniaNameGenerator(
ViewFileNamingStrategy naming,
IGlobPattern pathPattern,
IGlobPattern namespacePattern,
IViewResolver classes,
INameResolver names,
ICodeGenerator code)
{
_naming = naming;
_pathPattern = pathPattern;
_namespacePattern = namespacePattern;
_classes = classes;
@ -44,9 +48,16 @@ internal class AvaloniaNameGenerator : INameGenerator
from view in resolveViews
let names = _names.ResolveNames(view.Xaml)
let code = _code.GenerateCode(view.ClassName, view.Namespace, view.XamlType, names)
let fileName = $"{view.ClassName}.g.cs"
let fileName = ResolveViewFileName(view, _naming)
select new GeneratedPartialClass(fileName, code);
return query.ToList();
}
private static string ResolveViewFileName(ResolvedView view, ViewFileNamingStrategy strategy) => strategy switch
{
ViewFileNamingStrategy.ClassName => $"{view.ClassName}.g.cs",
ViewFileNamingStrategy.NamespaceAndClassName => $"{view.Namespace}.{view.ClassName}.g.cs",
_ => throw new ArgumentOutOfRangeException(nameof(strategy), strategy, "Unknown naming strategy!")
};
}

3
src/Avalonia.NameGenerator/Generator/InitializeComponentCodeGenerator.cs

@ -32,8 +32,7 @@ internal class InitializeComponentCodeGenerator: ICodeGenerator
var initializations = new List<string>();
foreach (var resolvedName in names)
{
var (_, name, fieldModifier) = resolvedName;
string typeName = resolvedName.PrintableTypeName;
var (typeName, name, fieldModifier) = resolvedName;
properties.Add($" {fieldModifier} {typeName} {name};");
initializations.Add($" {name} = this.FindControl<{typeName}>(\"{name}\");");
}

4
src/Avalonia.NameGenerator/Generator/OnlyPropertiesCodeGenerator.cs

@ -11,8 +11,8 @@ internal class OnlyPropertiesCodeGenerator : ICodeGenerator
{
var namedControls = names
.Select(info => " " +
$"{info.FieldModifier} {info.PrintableTypeName} {info.Name} => " +
$"this.FindControl<{info.PrintableTypeName}>(\"{info.Name}\");")
$"{info.FieldModifier} {info.TypeName} {info.Name} => " +
$"this.FindControl<{info.TypeName}>(\"{info.Name}\");")
.ToList();
var lines = string.Join("\n", namedControls);
return $@"// <auto-generated />

15
src/Avalonia.NameGenerator/Generator/XamlXNameResolver.cs

@ -1,9 +1,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Avalonia.NameGenerator.Domain;
using XamlX;
using XamlX.Ast;
@ -14,9 +12,9 @@ internal class XamlXNameResolver : INameResolver, IXamlAstVisitor
private readonly List<ResolvedName> _items = new();
private readonly string _defaultFieldModifier;
public XamlXNameResolver(string defaultFieldModifier = "internal")
public XamlXNameResolver(DefaultFieldModifier defaultFieldModifier = DefaultFieldModifier.Internal)
{
_defaultFieldModifier = defaultFieldModifier;
_defaultFieldModifier = defaultFieldModifier.ToString().ToLowerInvariant();
}
public IReadOnlyList<ResolvedName> ResolveNames(XamlDocument xaml)
@ -50,10 +48,13 @@ internal class XamlXNameResolver : INameResolver, IXamlAstVisitor
propertyValueNode.Values[0] is XamlAstTextNode text)
{
var fieldModifier = TryGetFieldModifier(objectNode);
string typeName = $@"{clrType.Namespace}.{clrType.Name}";
IReadOnlyList<string> typeAgs = clrType.GenericArguments.Select(arg => arg.FullName).ToImmutableList();
var typeName = $@"{clrType.Namespace}.{clrType.Name}";
var typeAgs = clrType.GenericArguments.Select(arg => arg.FullName).ToImmutableList();
var genericTypeName = typeAgs.Count == 0
? $"global::{typeName}"
: $@"global::{typeName}<{string.Join(", ", typeAgs.Select(arg => $"global::{arg}"))}>";
var resolvedName = new ResolvedName(typeName, text.Text, fieldModifier, typeAgs);
var resolvedName = new ResolvedName(genericTypeName, text.Text, fieldModifier);
if (_items.Contains(resolvedName))
continue;
_items.Add(resolvedName);

81
src/Avalonia.NameGenerator/GeneratorOptions.cs

@ -9,6 +9,7 @@ public enum BuildProperties
AvaloniaNameGeneratorDefaultFieldModifier = 1,
AvaloniaNameGeneratorFilterByPath = 2,
AvaloniaNameGeneratorFilterByNamespace = 3,
AvaloniaNameGeneratorViewFileNamingStrategy = 4,
}
public enum DefaultFieldModifier
@ -25,69 +26,49 @@ public enum Behavior
InitializeComponent = 1,
}
public enum ViewFileNamingStrategy
{
ClassName = 0,
NamespaceAndClassName = 1,
}
public class GeneratorOptions
{
private readonly GeneratorExecutionContext _context;
public GeneratorOptions(GeneratorExecutionContext context) => _context = context;
public Behavior AvaloniaNameGeneratorBehavior
{
get
{
const Behavior defaultBehavior = Behavior.InitializeComponent;
var propertyValue = _context
.GetMsBuildProperty(
nameof(BuildProperties.AvaloniaNameGeneratorBehavior),
defaultBehavior.ToString());
public Behavior AvaloniaNameGeneratorBehavior => GetEnumProperty(
BuildProperties.AvaloniaNameGeneratorBehavior,
Behavior.InitializeComponent);
if (!Enum.TryParse(propertyValue, true, out Behavior behavior))
return defaultBehavior;
return behavior;
}
}
public DefaultFieldModifier AvaloniaNameGeneratorDefaultFieldModifier => GetEnumProperty(
BuildProperties.AvaloniaNameGeneratorDefaultFieldModifier,
DefaultFieldModifier.Internal);
public DefaultFieldModifier AvaloniaNameGeneratorDefaultFieldModifier
{
get
{
const DefaultFieldModifier defaultFieldModifier = DefaultFieldModifier.Internal;
var propertyValue = _context
.GetMsBuildProperty(
nameof(BuildProperties.AvaloniaNameGeneratorDefaultFieldModifier),
defaultFieldModifier.ToString());
public ViewFileNamingStrategy AvaloniaNameGeneratorViewFileNamingStrategy => GetEnumProperty(
BuildProperties.AvaloniaNameGeneratorViewFileNamingStrategy,
ViewFileNamingStrategy.NamespaceAndClassName);
if (!Enum.TryParse(propertyValue, true, out DefaultFieldModifier modifier))
return defaultFieldModifier;
return modifier;
}
}
public string[] AvaloniaNameGeneratorFilterByPath => GetStringArrayProperty(
BuildProperties.AvaloniaNameGeneratorFilterByPath,
"*");
public string[] AvaloniaNameGeneratorFilterByPath
{
get
{
var propertyValue = _context.GetMsBuildProperty(
nameof(BuildProperties.AvaloniaNameGeneratorFilterByPath),
"*");
public string[] AvaloniaNameGeneratorFilterByNamespace => GetStringArrayProperty(
BuildProperties.AvaloniaNameGeneratorFilterByNamespace,
"*");
if (propertyValue.Contains(";"))
return propertyValue.Split(';');
return new[] {propertyValue};
}
private string[] GetStringArrayProperty(BuildProperties name, string defaultValue)
{
var key = name.ToString();
var value = _context.GetMsBuildProperty(key, defaultValue);
return value.Contains(";") ? value.Split(';') : new[] {value};
}
public string[] AvaloniaNameGeneratorFilterByNamespace
private TEnum GetEnumProperty<TEnum>(BuildProperties name, TEnum defaultValue) where TEnum : struct
{
get
{
var propertyValue = _context.GetMsBuildProperty(
nameof(BuildProperties.AvaloniaNameGeneratorFilterByNamespace),
"*");
if (propertyValue.Contains(";"))
return propertyValue.Split(';');
return new[] {propertyValue};
}
var key = name.ToString();
var value = _context.GetMsBuildProperty(key, defaultValue.ToString());
return Enum.TryParse(value, true, out TEnum behavior) ? behavior : defaultValue;
}
}
Loading…
Cancel
Save