mirror of
https://github.com/Tyrrrz/CliFx.git
synced 2025-10-25 15:19:17 +00:00
asd
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using CliFx.SourceGeneration.SemanticModel;
|
||||
using CliFx.SourceGeneration.Utils.Extensions;
|
||||
using Microsoft.CodeAnalysis;
|
||||
@@ -21,13 +20,13 @@ public class CommandSchemaGenerator : IIncrementalGenerator
|
||||
(n, _) => n is TypeDeclarationSyntax,
|
||||
(x, _) =>
|
||||
{
|
||||
// Predicate ensures that these casts are safe
|
||||
var typeDeclarationSyntax = (TypeDeclarationSyntax)x.TargetNode;
|
||||
var namedTypeSymbol = (INamedTypeSymbol)x.TargetSymbol;
|
||||
// Predicate above ensures that these casts are safe
|
||||
var commandTypeSyntax = (TypeDeclarationSyntax)x.TargetNode;
|
||||
var commandTypeSymbol = (INamedTypeSymbol)x.TargetSymbol;
|
||||
|
||||
// Check if the target type and all its containing types are partial
|
||||
if (
|
||||
typeDeclarationSyntax
|
||||
commandTypeSyntax
|
||||
.AncestorsAndSelf()
|
||||
.Any(a =>
|
||||
a is TypeDeclarationSyntax t
|
||||
@@ -39,14 +38,14 @@ public class CommandSchemaGenerator : IIncrementalGenerator
|
||||
null,
|
||||
Diagnostic.Create(
|
||||
DiagnosticDescriptors.CommandMustBePartial,
|
||||
typeDeclarationSyntax.Identifier.GetLocation()
|
||||
commandTypeSyntax.Identifier.GetLocation()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Check if the target type implements ICommand
|
||||
var hasCommandInterface = namedTypeSymbol.AllInterfaces.Any(i =>
|
||||
i.DisplayNameMatches("CliFx.ICommand")
|
||||
var hasCommandInterface = commandTypeSymbol.AllInterfaces.Any(i =>
|
||||
i.DisplayNameMatches(KnownSymbolNames.CliFxCommandInterface)
|
||||
);
|
||||
|
||||
if (!hasCommandInterface)
|
||||
@@ -55,220 +54,22 @@ public class CommandSchemaGenerator : IIncrementalGenerator
|
||||
null,
|
||||
Diagnostic.Create(
|
||||
DiagnosticDescriptors.CommandMustImplementInterface,
|
||||
namedTypeSymbol.Locations.First()
|
||||
commandTypeSymbol.Locations.First()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Get the command name
|
||||
// Resolve the command
|
||||
var commandAttribute = x.Attributes.First(a =>
|
||||
a.AttributeClass?.DisplayNameMatches(KnownSymbolNames.CliFxCommandAttribute)
|
||||
== true
|
||||
);
|
||||
|
||||
var commandName =
|
||||
commandAttribute.ConstructorArguments.FirstOrDefault().Value as string;
|
||||
var command = CommandSymbol.FromSymbol(commandTypeSymbol, commandAttribute);
|
||||
|
||||
var commandDescription =
|
||||
commandAttribute
|
||||
.NamedArguments.FirstOrDefault(a =>
|
||||
string.Equals(a.Key, "Description", StringComparison.Ordinal)
|
||||
)
|
||||
.Value.Value as string;
|
||||
// TODO: validate command
|
||||
|
||||
// Get all parameter inputs
|
||||
var parameterSymbols = namedTypeSymbol
|
||||
.GetMembers()
|
||||
.OfType<IPropertySymbol>()
|
||||
.Select(p =>
|
||||
{
|
||||
var parameterAttribute = p.GetAttributes()
|
||||
.FirstOrDefault(a =>
|
||||
a.AttributeClass?.DisplayNameMatches(
|
||||
KnownSymbolNames.CliFxCommandParameterAttribute
|
||||
) == true
|
||||
);
|
||||
|
||||
if (parameterAttribute is null)
|
||||
return null;
|
||||
|
||||
var isSequence = false; // TODO
|
||||
|
||||
var order = parameterAttribute.ConstructorArguments.First().Value as int?;
|
||||
|
||||
var isRequired =
|
||||
parameterAttribute
|
||||
.NamedArguments.FirstOrDefault(a =>
|
||||
string.Equals(a.Key, "IsRequired", StringComparison.Ordinal)
|
||||
)
|
||||
.Value.Value as bool?
|
||||
?? true;
|
||||
|
||||
var name =
|
||||
parameterAttribute
|
||||
.NamedArguments.FirstOrDefault(a =>
|
||||
string.Equals(a.Key, "Name", StringComparison.Ordinal)
|
||||
)
|
||||
.Value.Value as string;
|
||||
|
||||
var description =
|
||||
parameterAttribute
|
||||
.NamedArguments.FirstOrDefault(a =>
|
||||
string.Equals(a.Key, "Description", StringComparison.Ordinal)
|
||||
)
|
||||
.Value.Value as string;
|
||||
|
||||
var converter =
|
||||
parameterAttribute
|
||||
.NamedArguments.FirstOrDefault(a =>
|
||||
string.Equals(a.Key, "Converter", StringComparison.Ordinal)
|
||||
)
|
||||
.Value.Value as ITypeSymbol;
|
||||
|
||||
var validators = parameterAttribute
|
||||
.NamedArguments.FirstOrDefault(a =>
|
||||
string.Equals(a.Key, "Validators", StringComparison.Ordinal)
|
||||
)
|
||||
.Value.Values.CastArray<ITypeSymbol>();
|
||||
|
||||
return new CommandParameterSymbol(
|
||||
new PropertyDescriptor(
|
||||
new TypeDescriptor(
|
||||
p.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)
|
||||
),
|
||||
p.Name
|
||||
),
|
||||
isSequence,
|
||||
order,
|
||||
isRequired,
|
||||
name,
|
||||
description,
|
||||
converter
|
||||
?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)
|
||||
?.Pipe(n => new TypeDescriptor(n)),
|
||||
validators
|
||||
.Select(v =>
|
||||
v.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)
|
||||
)
|
||||
.Select(n => new TypeDescriptor(n))
|
||||
.ToArray()
|
||||
);
|
||||
})
|
||||
.WhereNotNull()
|
||||
.ToArray();
|
||||
|
||||
// Get all option inputs
|
||||
var optionSymbols = namedTypeSymbol
|
||||
.GetMembers()
|
||||
.OfType<IPropertySymbol>()
|
||||
.Select(p =>
|
||||
{
|
||||
var optionAttribute = p.GetAttributes()
|
||||
.FirstOrDefault(a =>
|
||||
a.AttributeClass?.DisplayNameMatches(
|
||||
KnownSymbolNames.CliFxCommandOptionAttribute
|
||||
) == true
|
||||
);
|
||||
|
||||
if (optionAttribute is null)
|
||||
return null;
|
||||
|
||||
var isSequence = false; // TODO
|
||||
|
||||
var name =
|
||||
optionAttribute
|
||||
.ConstructorArguments.Where(a =>
|
||||
a.Type?.SpecialType == SpecialType.System_String
|
||||
)
|
||||
.Select(a => a.Value)
|
||||
.FirstOrDefault() as string;
|
||||
|
||||
var shortName =
|
||||
optionAttribute
|
||||
.ConstructorArguments.Where(a =>
|
||||
a.Type?.SpecialType == SpecialType.System_Char
|
||||
)
|
||||
.Select(a => a.Value)
|
||||
.FirstOrDefault() as char?;
|
||||
|
||||
var environmentVariable =
|
||||
optionAttribute
|
||||
.NamedArguments.FirstOrDefault(a =>
|
||||
string.Equals(
|
||||
a.Key,
|
||||
"EnvironmentVariable",
|
||||
StringComparison.Ordinal
|
||||
)
|
||||
)
|
||||
.Value.Value as string;
|
||||
|
||||
var isRequired =
|
||||
optionAttribute
|
||||
.NamedArguments.Where(a => a.Key == "IsRequired")
|
||||
.Select(a => a.Value.Value)
|
||||
.FirstOrDefault() as bool?
|
||||
?? p.IsRequired;
|
||||
|
||||
var description =
|
||||
optionAttribute
|
||||
.NamedArguments.FirstOrDefault(a =>
|
||||
string.Equals(a.Key, "Description", StringComparison.Ordinal)
|
||||
)
|
||||
.Value.Value as string;
|
||||
|
||||
var converter =
|
||||
optionAttribute
|
||||
.NamedArguments.FirstOrDefault(a =>
|
||||
string.Equals(a.Key, "Converter", StringComparison.Ordinal)
|
||||
)
|
||||
.Value.Value as ITypeSymbol;
|
||||
|
||||
var validators = optionAttribute
|
||||
.NamedArguments.FirstOrDefault(a =>
|
||||
string.Equals(a.Key, "Validators", StringComparison.Ordinal)
|
||||
)
|
||||
.Value.Values.CastArray<ITypeSymbol>();
|
||||
|
||||
return new CommandOptionSymbol(
|
||||
new PropertyDescriptor(
|
||||
new TypeDescriptor(
|
||||
p.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)
|
||||
),
|
||||
p.Name
|
||||
),
|
||||
isSequence,
|
||||
name,
|
||||
shortName,
|
||||
environmentVariable,
|
||||
isRequired,
|
||||
description,
|
||||
converter
|
||||
?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)
|
||||
?.Pipe(n => new TypeDescriptor(n)),
|
||||
validators
|
||||
.Select(v =>
|
||||
v.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)
|
||||
)
|
||||
.Select(n => new TypeDescriptor(n))
|
||||
.ToArray()
|
||||
);
|
||||
})
|
||||
.WhereNotNull()
|
||||
.ToArray();
|
||||
|
||||
return (
|
||||
new CommandSymbol(
|
||||
new TypeDescriptor(
|
||||
namedTypeSymbol.ToDisplayString(
|
||||
SymbolDisplayFormat.FullyQualifiedFormat
|
||||
)
|
||||
),
|
||||
commandName,
|
||||
commandDescription,
|
||||
parameterSymbols.Concat<CommandInputSymbol>(optionSymbols).ToArray()
|
||||
),
|
||||
null
|
||||
);
|
||||
return (command, null);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -276,58 +77,54 @@ public class CommandSchemaGenerator : IIncrementalGenerator
|
||||
var diagnostics = values.Select((v, _) => v.Item2).WhereNotNull();
|
||||
context.RegisterSourceOutput(diagnostics, (x, d) => x.ReportDiagnostic(d));
|
||||
|
||||
// Generate source
|
||||
// Generate command schemas
|
||||
var symbols = values.Select((v, _) => v.Item1).WhereNotNull();
|
||||
context.RegisterSourceOutput(
|
||||
symbols,
|
||||
(x, c) =>
|
||||
{
|
||||
var source =
|
||||
x.AddSource(
|
||||
$"{c.Type.FullyQualifiedName}.CommandSchema.Generated.cs",
|
||||
// lang=csharp
|
||||
$$"""
|
||||
using System.Linq;
|
||||
using CliFx.Schema;
|
||||
using CliFx.Extensibility;
|
||||
|
||||
namespace {{c.Type.Namespace}};
|
||||
|
||||
partial class {{c.Type.Name}}
|
||||
{
|
||||
public static CommandSchema<{{ c.Type.FullyQualifiedName }}> Schema { get; } = new(
|
||||
{{ c.Name }},
|
||||
{{ c.Description }},
|
||||
[
|
||||
{{ c.Inputs.Select(i => i switch {
|
||||
CommandParameterSymbol parameter =>
|
||||
public static CliFx.Schema.CommandSchema<{{c.Type.FullyQualifiedName}}> Schema { get; } = {{c.GenerateSchemaInitializationCode()}};
|
||||
}
|
||||
"""
|
||||
)
|
||||
);
|
||||
|
||||
// Generate extension methods
|
||||
var symbolsCollected = symbols.Collect();
|
||||
context.RegisterSourceOutput(
|
||||
symbolsCollected,
|
||||
(x, cs) =>
|
||||
x.AddSource(
|
||||
"CommandSchemaExtensions.Generated.cs",
|
||||
// lang=csharp
|
||||
$$"""
|
||||
new CommandParameterSchema<{{ c.Type.FullyQualifiedName }}, {{ i.Property.Type.FullyQualifiedName }}>(
|
||||
new PropertyBinding<{{ c.Type.FullyQualifiedName }}, {{ i.Property.Type.FullyQualifiedName }}>(
|
||||
obj => obj.{{ i.Property.Name }},
|
||||
(obj, value) => obj.{{ i.Property.Name }} = value
|
||||
),
|
||||
p.Order,
|
||||
p.IsRequired,
|
||||
p.Name,
|
||||
p.Description,
|
||||
new {{ i.ConverterType.FullyQualifiedName }}(),
|
||||
[
|
||||
{{ i.ValidatorTypes.Select(v =>
|
||||
// lang=csharp
|
||||
$"new {v.FullyQualifiedName}()").JoinToString(",\n")
|
||||
}}
|
||||
]
|
||||
)
|
||||
""",
|
||||
CommandOptionSymbol option => ""
|
||||
}).JoinToString(",\n")
|
||||
}}
|
||||
]
|
||||
}
|
||||
""";
|
||||
namespace CliFx;
|
||||
|
||||
x.AddSource($"{c.TypeName}.CommandSchema.Generated.cs", source);
|
||||
static partial class GeneratedExtensions
|
||||
{
|
||||
public static CliFx.CliApplicationBuilder AddCommandsFromThisAssembly(this CliFx.CliApplicationBuilder builder)
|
||||
{
|
||||
{{
|
||||
cs.Select(c => c.Type.FullyQualifiedName)
|
||||
.Select(t =>
|
||||
// lang=csharp
|
||||
$"builder.AddCommand({t}.Schema);"
|
||||
)
|
||||
.JoinToString("\n")
|
||||
}}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace CliFx.SourceGeneration.SemanticModel;
|
||||
|
||||
@@ -54,3 +55,12 @@ internal partial class CommandInputSymbol : IEquatable<CommandInputSymbol>
|
||||
public override int GetHashCode() =>
|
||||
HashCode.Combine(Property, IsSequence, Description, ConverterType, ValidatorTypes);
|
||||
}
|
||||
|
||||
internal partial class CommandInputSymbol
|
||||
{
|
||||
public static bool IsSequenceType(ITypeSymbol type) =>
|
||||
type.AllInterfaces.Any(i =>
|
||||
i.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T
|
||||
)
|
||||
&& type.SpecialType != SpecialType.System_String;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CliFx.SourceGeneration.Utils.Extensions;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace CliFx.SourceGeneration.SemanticModel;
|
||||
|
||||
@@ -55,3 +58,33 @@ internal partial class CommandOptionSymbol : IEquatable<CommandOptionSymbol>
|
||||
public override int GetHashCode() =>
|
||||
HashCode.Combine(base.GetHashCode(), Name, ShortName, EnvironmentVariable, IsRequired);
|
||||
}
|
||||
|
||||
internal partial class CommandOptionSymbol
|
||||
{
|
||||
public static CommandOptionSymbol FromSymbol(
|
||||
IPropertySymbol property,
|
||||
AttributeData attribute
|
||||
) =>
|
||||
new(
|
||||
PropertyDescriptor.FromSymbol(property),
|
||||
IsSequenceType(property.Type),
|
||||
attribute
|
||||
.ConstructorArguments.FirstOrDefault(a =>
|
||||
a.Type?.SpecialType == SpecialType.System_String
|
||||
)
|
||||
.Value as string,
|
||||
attribute
|
||||
.ConstructorArguments.FirstOrDefault(a =>
|
||||
a.Type?.SpecialType == SpecialType.System_Char
|
||||
)
|
||||
.Value as char?,
|
||||
attribute.GetNamedArgumentValue("EnvironmentVariable", default(string)),
|
||||
attribute.GetNamedArgumentValue("IsRequired", property.IsRequired),
|
||||
attribute.GetNamedArgumentValue("Description", default(string)),
|
||||
TypeDescriptor.FromSymbol(attribute.GetNamedArgumentValue<ITypeSymbol?>("Converter")),
|
||||
attribute
|
||||
.GetNamedArgumentValues<ITypeSymbol>("Validators")
|
||||
.Select(TypeDescriptor.FromSymbol)
|
||||
.ToArray()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CliFx.SourceGeneration.Utils.Extensions;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace CliFx.SourceGeneration.SemanticModel;
|
||||
|
||||
@@ -51,3 +54,24 @@ internal partial class CommandParameterSymbol : IEquatable<CommandParameterSymbo
|
||||
public override int GetHashCode() =>
|
||||
HashCode.Combine(base.GetHashCode(), Order, Name, IsRequired);
|
||||
}
|
||||
|
||||
internal partial class CommandParameterSymbol
|
||||
{
|
||||
public static CommandParameterSymbol FromSymbol(
|
||||
IPropertySymbol property,
|
||||
AttributeData attribute
|
||||
) =>
|
||||
new(
|
||||
PropertyDescriptor.FromSymbol(property),
|
||||
IsSequenceType(property.Type),
|
||||
(int)attribute.ConstructorArguments.First().Value!,
|
||||
attribute.GetNamedArgumentValue("Name", default(string)),
|
||||
attribute.GetNamedArgumentValue("IsRequired", true),
|
||||
attribute.GetNamedArgumentValue("Description", default(string)),
|
||||
TypeDescriptor.FromSymbol(attribute.GetNamedArgumentValue<ITypeSymbol>("Converter")),
|
||||
attribute
|
||||
.GetNamedArgumentValues<ITypeSymbol>("Validators")
|
||||
.Select(TypeDescriptor.FromSymbol)
|
||||
.ToArray()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CliFx.SourceGeneration.Utils.Extensions;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace CliFx.SourceGeneration.SemanticModel;
|
||||
|
||||
@@ -24,6 +26,73 @@ internal partial class CommandSymbol(
|
||||
|
||||
public IReadOnlyList<CommandOptionSymbol> Options =>
|
||||
Inputs.OfType<CommandOptionSymbol>().ToArray();
|
||||
|
||||
private string GeneratePropertyBindingInitializationCode(PropertyDescriptor property) =>
|
||||
// lang=csharp
|
||||
$$"""
|
||||
new CliFx.Schema.PropertyBinding<{{Type.FullyQualifiedName}}, {{property
|
||||
.Type
|
||||
.FullyQualifiedName}}>(
|
||||
(obj) => obj.{{property.Name}},
|
||||
(obj, value) => obj.{{property.Name}} = value
|
||||
)
|
||||
""";
|
||||
|
||||
private string GenerateSchemaInitializationCode(CommandInputSymbol input) =>
|
||||
input switch
|
||||
{
|
||||
CommandParameterSymbol parameter
|
||||
=>
|
||||
// lang=csharp
|
||||
$$"""
|
||||
new CliFx.Schema.CommandParameterSchema<{{Type.FullyQualifiedName}}, {{parameter
|
||||
.Property
|
||||
.Type
|
||||
.FullyQualifiedName}}>(
|
||||
{{GeneratePropertyBindingInitializationCode(parameter.Property)}},
|
||||
{{parameter.IsSequence}},
|
||||
{{parameter.Order}},
|
||||
"{{parameter.Name}}",
|
||||
{{parameter.IsRequired}},
|
||||
"{{parameter.Description}}",
|
||||
// TODO,
|
||||
// TODO
|
||||
);
|
||||
""",
|
||||
CommandOptionSymbol option
|
||||
=>
|
||||
// lang=csharp
|
||||
$$"""
|
||||
new CliFx.Schema.CommandOptionSchema<{{Type.FullyQualifiedName}}, {{option
|
||||
.Property
|
||||
.Type
|
||||
.FullyQualifiedName}}>(
|
||||
{{GeneratePropertyBindingInitializationCode(option.Property)}},
|
||||
{{option.IsSequence}},
|
||||
"{{option.Name}}",
|
||||
'{{option.ShortName}}',
|
||||
"{{option.EnvironmentVariable}}",
|
||||
{{option.IsRequired}},
|
||||
"{{option.Description}}",
|
||||
// TODO,
|
||||
// TODO
|
||||
);
|
||||
""",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(input), input, null)
|
||||
};
|
||||
|
||||
public string GenerateSchemaInitializationCode() =>
|
||||
// lang=csharp
|
||||
$$"""
|
||||
new CliFx.Schema.CommandSchema<{{Type.FullyQualifiedName}}>(
|
||||
"{{Name}}",
|
||||
"{{Description}}",
|
||||
new CliFx.Schema.CommandInputSchema[]
|
||||
{
|
||||
{{Inputs.Select(GenerateSchemaInitializationCode).JoinToString(",\n")}}
|
||||
}
|
||||
)
|
||||
""";
|
||||
}
|
||||
|
||||
internal partial class CommandSymbol : IEquatable<CommandSymbol>
|
||||
@@ -55,3 +124,44 @@ internal partial class CommandSymbol : IEquatable<CommandSymbol>
|
||||
|
||||
public override int GetHashCode() => HashCode.Combine(Type, Name, Description, Inputs);
|
||||
}
|
||||
|
||||
internal partial class CommandSymbol
|
||||
{
|
||||
public static CommandSymbol FromSymbol(INamedTypeSymbol symbol, AttributeData attribute)
|
||||
{
|
||||
var inputs = new List<CommandInputSymbol>();
|
||||
foreach (var property in symbol.GetMembers().OfType<IPropertySymbol>())
|
||||
{
|
||||
var parameterAttribute = property
|
||||
.GetAttributes()
|
||||
.FirstOrDefault(a =>
|
||||
a.AttributeClass?.Name == KnownSymbolNames.CliFxCommandParameterAttribute
|
||||
);
|
||||
|
||||
if (parameterAttribute is not null)
|
||||
{
|
||||
inputs.Add(CommandParameterSymbol.FromSymbol(property, parameterAttribute));
|
||||
continue;
|
||||
}
|
||||
|
||||
var optionAttribute = property
|
||||
.GetAttributes()
|
||||
.FirstOrDefault(a =>
|
||||
a.AttributeClass?.Name == KnownSymbolNames.CliFxCommandOptionAttribute
|
||||
);
|
||||
|
||||
if (optionAttribute is not null)
|
||||
{
|
||||
inputs.Add(CommandOptionSymbol.FromSymbol(property, optionAttribute));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return new CommandSymbol(
|
||||
TypeDescriptor.FromSymbol(symbol),
|
||||
attribute.ConstructorArguments.FirstOrDefault().Value as string,
|
||||
attribute.GetNamedArgumentValue("Description", default(string)),
|
||||
inputs
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace CliFx.SourceGeneration.SemanticModel;
|
||||
|
||||
@@ -35,3 +36,9 @@ internal partial class PropertyDescriptor : IEquatable<PropertyDescriptor>
|
||||
|
||||
public override int GetHashCode() => HashCode.Combine(Type, Name);
|
||||
}
|
||||
|
||||
internal partial class PropertyDescriptor
|
||||
{
|
||||
public static PropertyDescriptor FromSymbol(IPropertySymbol symbol) =>
|
||||
new(TypeDescriptor.FromSymbol(symbol.Type), symbol.Name);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using CliFx.SourceGeneration.Utils.Extensions;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace CliFx.SourceGeneration.SemanticModel;
|
||||
|
||||
@@ -38,3 +39,9 @@ internal partial class TypeDescriptor : IEquatable<TypeDescriptor>
|
||||
|
||||
public override int GetHashCode() => FullyQualifiedName.GetHashCode();
|
||||
}
|
||||
|
||||
internal partial class TypeDescriptor
|
||||
{
|
||||
public static TypeDescriptor FromSymbol(ITypeSymbol symbol) =>
|
||||
new(symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace CliFx.SourceGeneration.Utils.Extensions;
|
||||
@@ -13,6 +16,22 @@ internal static class RoslynExtensions
|
||||
StringComparison.Ordinal
|
||||
);
|
||||
|
||||
public static T GetNamedArgumentValue<T>(
|
||||
this AttributeData attribute,
|
||||
string name,
|
||||
T defaultValue = default
|
||||
) =>
|
||||
attribute.NamedArguments.FirstOrDefault(i => i.Key == name).Value.Value is T valueAsT
|
||||
? valueAsT
|
||||
: defaultValue;
|
||||
|
||||
public static IReadOnlyList<T> GetNamedArgumentValues<T>(
|
||||
this AttributeData attribute,
|
||||
string name
|
||||
)
|
||||
where T : class =>
|
||||
attribute.NamedArguments.FirstOrDefault(i => i.Key == name).Value.Values.CastArray<T>();
|
||||
|
||||
public static IncrementalValuesProvider<T> WhereNotNull<T>(
|
||||
this IncrementalValuesProvider<T?> values
|
||||
)
|
||||
|
||||
@@ -125,10 +125,7 @@ public abstract class CommandInputSchema(
|
||||
/// </remarks>
|
||||
public abstract class CommandInputSchema<
|
||||
TCommand,
|
||||
[DynamicallyAccessedMembers(
|
||||
DynamicallyAccessedMemberTypes.PublicMethods
|
||||
)]
|
||||
TProperty
|
||||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TProperty
|
||||
>(
|
||||
PropertyBinding<TCommand, TProperty> property,
|
||||
bool isSequence,
|
||||
|
||||
@@ -63,10 +63,7 @@ public class CommandOptionSchema(
|
||||
/// </remarks>
|
||||
public class CommandOptionSchema<
|
||||
TCommand,
|
||||
[DynamicallyAccessedMembers(
|
||||
DynamicallyAccessedMemberTypes.PublicMethods
|
||||
)]
|
||||
TProperty
|
||||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TProperty
|
||||
>(
|
||||
PropertyBinding<TCommand, TProperty> property,
|
||||
bool isSequence,
|
||||
|
||||
@@ -42,10 +42,7 @@ public class CommandParameterSchema(
|
||||
/// </remarks>
|
||||
public class CommandParameterSchema<
|
||||
TCommand,
|
||||
[DynamicallyAccessedMembers(
|
||||
DynamicallyAccessedMemberTypes.PublicMethods
|
||||
)]
|
||||
TProperty
|
||||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TProperty
|
||||
>(
|
||||
PropertyBinding<TCommand, TProperty> property,
|
||||
bool isSequence,
|
||||
|
||||
@@ -9,10 +9,7 @@ namespace CliFx.Schema;
|
||||
/// Provides read and write access to a CLR property.
|
||||
/// </summary>
|
||||
public class PropertyBinding(
|
||||
[DynamicallyAccessedMembers(
|
||||
DynamicallyAccessedMemberTypes.PublicMethods
|
||||
)]
|
||||
Type type,
|
||||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type,
|
||||
Func<object, object?> getValue,
|
||||
Action<object, object?> setValue
|
||||
)
|
||||
@@ -20,9 +17,7 @@ public class PropertyBinding(
|
||||
/// <summary>
|
||||
/// Underlying CLR type of the property.
|
||||
/// </summary>
|
||||
[DynamicallyAccessedMembers(
|
||||
DynamicallyAccessedMemberTypes.PublicMethods
|
||||
)]
|
||||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
|
||||
public Type Type { get; } = type;
|
||||
|
||||
/// <summary>
|
||||
@@ -63,10 +58,7 @@ public class PropertyBinding(
|
||||
/// </remarks>
|
||||
public class PropertyBinding<
|
||||
TObject,
|
||||
[DynamicallyAccessedMembers(
|
||||
DynamicallyAccessedMemberTypes.PublicMethods
|
||||
)]
|
||||
TProperty
|
||||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TProperty
|
||||
>(Func<TObject, TProperty?> getValue, Action<TObject, TProperty?> setValue)
|
||||
: PropertyBinding(
|
||||
typeof(TProperty),
|
||||
|
||||
Reference in New Issue
Block a user