From cad1c1447441867ffd330153e7e6c4e4c85b80e5 Mon Sep 17 00:00:00 2001
From: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com>
Date: Tue, 28 May 2024 21:20:09 +0300
Subject: [PATCH] asd
---
.../CliFx.Analyzers.Tests.csproj | 6 +-
CliFx.Analyzers/CliFx.Analyzers.csproj | 2 +-
CliFx.Tests/CliFx.Tests.csproj | 8 +-
CliFx/ApplicationConfiguration.cs | 9 +-
CliFx/CliApplication.cs | 16 ++-
CliFx/CliApplicationBuilder.cs | 108 ++++------------
CliFx/CliFx.csproj | 2 +-
CliFx/CommandBinder.cs | 53 ++++----
CliFx/Extensibility/BindingConverter.cs | 14 ++-
CliFx/Extensibility/BindingValidator.cs | 13 +-
CliFx/FallbackDefaultCommand.cs | 11 +-
CliFx/Formatting/HelpContext.cs | 4 +-
CliFx/Infrastructure/DefaultTypeActivator.cs | 5 +-
CliFx/Infrastructure/DelegateTypeActivator.cs | 5 +-
CliFx/Infrastructure/ITypeActivator.cs | 10 +-
CliFx/Input/CommandInput.cs | 4 -
CliFx/Input/OptionInput.cs | 5 -
CliFx/Schema/ApplicationSchema.cs | 38 +++---
CliFx/Schema/BindablePropertyDescriptor.cs | 40 ------
CliFx/Schema/CommandSchema.cs | 119 +++++-------------
CliFx/Schema/IInputSchema.cs | 36 ++++++
CliFx/Schema/IMemberSchema.cs | 26 ----
CliFx/Schema/IPropertyDescriptor.cs | 23 ----
CliFx/Schema/NullPropertyDescriptor.cs | 20 ---
CliFx/Schema/OptionSchema.cs | 111 ++++++----------
CliFx/Schema/ParameterSchema.cs | 68 +++++-----
CliFx/Schema/PropertyDescriptor.cs | 31 +++++
27 files changed, 300 insertions(+), 487 deletions(-)
delete mode 100644 CliFx/Schema/BindablePropertyDescriptor.cs
create mode 100644 CliFx/Schema/IInputSchema.cs
delete mode 100644 CliFx/Schema/IMemberSchema.cs
delete mode 100644 CliFx/Schema/IPropertyDescriptor.cs
delete mode 100644 CliFx/Schema/NullPropertyDescriptor.cs
create mode 100644 CliFx/Schema/PropertyDescriptor.cs
diff --git a/CliFx.Analyzers.Tests/CliFx.Analyzers.Tests.csproj b/CliFx.Analyzers.Tests/CliFx.Analyzers.Tests.csproj
index bbb4ed3..5520438 100644
--- a/CliFx.Analyzers.Tests/CliFx.Analyzers.Tests.csproj
+++ b/CliFx.Analyzers.Tests/CliFx.Analyzers.Tests.csproj
@@ -14,10 +14,10 @@
-
+
-
-
+
+
diff --git a/CliFx.Analyzers/CliFx.Analyzers.csproj b/CliFx.Analyzers/CliFx.Analyzers.csproj
index 72d720a..10b7043 100644
--- a/CliFx.Analyzers/CliFx.Analyzers.csproj
+++ b/CliFx.Analyzers/CliFx.Analyzers.csproj
@@ -21,7 +21,7 @@
-
+
\ No newline at end of file
diff --git a/CliFx.Tests/CliFx.Tests.csproj b/CliFx.Tests/CliFx.Tests.csproj
index 53d6aa5..d1ea433 100644
--- a/CliFx.Tests/CliFx.Tests.csproj
+++ b/CliFx.Tests/CliFx.Tests.csproj
@@ -17,10 +17,10 @@
-
-
-
-
+
+
+
+
diff --git a/CliFx/ApplicationConfiguration.cs b/CliFx/ApplicationConfiguration.cs
index 5aa9842..ea464c2 100644
--- a/CliFx/ApplicationConfiguration.cs
+++ b/CliFx/ApplicationConfiguration.cs
@@ -1,5 +1,4 @@
-using System;
-using System.Collections.Generic;
+using CliFx.Schema;
namespace CliFx;
@@ -7,15 +6,15 @@ namespace CliFx;
/// Configuration of an application.
///
public class ApplicationConfiguration(
- IReadOnlyList commandTypes,
+ ApplicationSchema schema,
bool isDebugModeAllowed,
bool isPreviewModeAllowed
)
{
///
- /// Command types defined in the application.
+ /// Application schema.
///
- public IReadOnlyList CommandTypes { get; } = commandTypes;
+ public ApplicationSchema Schema { get; } = schema;
///
/// Whether debug mode is allowed in the application.
diff --git a/CliFx/CliApplication.cs b/CliFx/CliApplication.cs
index 945feef..a67d821 100644
--- a/CliFx/CliApplication.cs
+++ b/CliFx/CliApplication.cs
@@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
-using System.Runtime.InteropServices;
using System.Threading.Tasks;
using CliFx.Exceptions;
using CliFx.Formatting;
@@ -175,15 +174,14 @@ public class CliApplication(
{
try
{
- var applicationSchema = ApplicationSchema.Resolve(Configuration.CommandTypes);
-
- var commandInput = CommandInput.Parse(
- commandLineArguments,
- environmentVariables,
- applicationSchema.GetCommandNames()
+ return await RunAsync(
+ Configuration.Schema,
+ CommandInput.Parse(
+ commandLineArguments,
+ environmentVariables,
+ Configuration.Schema.GetCommandNames()
+ )
);
-
- return await RunAsync(applicationSchema, commandInput);
}
// To prevent the app from showing the annoying troubleshooting dialog on Windows,
// we handle all exceptions ourselves and print them to the console.
diff --git a/CliFx/CliApplicationBuilder.cs b/CliFx/CliApplicationBuilder.cs
index c8d90b9..107a84f 100644
--- a/CliFx/CliApplicationBuilder.cs
+++ b/CliFx/CliApplicationBuilder.cs
@@ -1,9 +1,8 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
-using System.Reflection;
-using CliFx.Attributes;
using CliFx.Infrastructure;
using CliFx.Schema;
using CliFx.Utils;
@@ -16,7 +15,7 @@ namespace CliFx;
///
public partial class CliApplicationBuilder
{
- private readonly HashSet _commandTypes = [];
+ private readonly HashSet _commandSchemas = [];
private bool _isDebugModeAllowed = true;
private bool _isPreviewModeAllowed = true;
@@ -30,71 +29,12 @@ public partial class CliApplicationBuilder
///
/// Adds a command to the application.
///
- public CliApplicationBuilder AddCommand(Type commandType)
+ public CliApplicationBuilder AddCommand(CommandSchema commandSchema)
{
- _commandTypes.Add(commandType);
+ _commandSchemas.Add(commandSchema);
return this;
}
- ///
- /// Adds a command to the application.
- ///
- public CliApplicationBuilder AddCommand()
- where TCommand : ICommand => AddCommand(typeof(TCommand));
-
- ///
- /// Adds multiple commands to the application.
- ///
- public CliApplicationBuilder AddCommands(IEnumerable commandTypes)
- {
- foreach (var commandType in commandTypes)
- AddCommand(commandType);
-
- return this;
- }
-
- ///
- /// Adds commands from the specified assembly to the application.
- ///
- ///
- /// This method looks for public non-abstract classes that implement
- /// and are annotated by .
- ///
- public CliApplicationBuilder AddCommandsFrom(Assembly commandAssembly)
- {
- foreach (
- var commandType in commandAssembly.ExportedTypes.Where(CommandSchema.IsCommandType)
- )
- AddCommand(commandType);
-
- return this;
- }
-
- ///
- /// Adds commands from the specified assemblies to the application.
- ///
- ///
- /// This method looks for public non-abstract classes that implement
- /// and are annotated by .
- ///
- public CliApplicationBuilder AddCommandsFrom(IEnumerable commandAssemblies)
- {
- foreach (var commandAssembly in commandAssemblies)
- AddCommandsFrom(commandAssembly);
-
- return this;
- }
-
- ///
- /// Adds commands from the calling assembly to the application.
- ///
- ///
- /// This method looks for public non-abstract classes that implement
- /// and are annotated by .
- ///
- public CliApplicationBuilder AddCommandsFromThisAssembly() =>
- AddCommandsFrom(Assembly.GetCallingAssembly());
-
///
/// Specifies whether debug mode (enabled with the [debug] directive) is allowed in the application.
///
@@ -189,15 +129,6 @@ public partial class CliApplicationBuilder
// Null returns are handled by DelegateTypeActivator
UseTypeActivator(serviceProvider.GetService!);
- ///
- /// Configures the application to use the specified service provider for activating types.
- /// This method takes a delegate that receives the list of all added command types, so that you can
- /// easily register them with the service provider.
- ///
- public CliApplicationBuilder UseTypeActivator(
- Func, IServiceProvider> getServiceProvider
- ) => UseTypeActivator(getServiceProvider(_commandTypes.ToArray()));
-
///
/// Creates a configured instance of .
///
@@ -211,7 +142,7 @@ public partial class CliApplicationBuilder
);
var configuration = new ApplicationConfiguration(
- _commandTypes.ToArray(),
+ new ApplicationSchema(_commandSchemas.ToArray()),
_isDebugModeAllowed,
_isPreviewModeAllowed
);
@@ -241,15 +172,17 @@ public partial class CliApplicationBuilder
return entryAssemblyName;
}
+ [UnconditionalSuppressMessage(
+ "SingleFile",
+ "IL3000:Avoid accessing Assembly file path when publishing as a single file",
+ Justification = "The return value of the method is checked to ensure the assembly location is available."
+ )]
private static string GetDefaultExecutableName()
{
- var entryAssemblyFilePath = EnvironmentEx.EntryAssembly?.Location;
var processFilePath = EnvironmentEx.ProcessPath;
- if (
- string.IsNullOrWhiteSpace(entryAssemblyFilePath)
- || string.IsNullOrWhiteSpace(processFilePath)
- )
+ // Process file path should generally always be available
+ if (string.IsNullOrWhiteSpace(processFilePath))
{
throw new InvalidOperationException(
"Failed to infer the default application executable name. "
@@ -257,15 +190,22 @@ public partial class CliApplicationBuilder
);
}
- // If the process path matches the entry assembly path, it's a legacy .NET Framework app
- // or a self-contained .NET Core app.
+ var entryAssemblyFilePath = EnvironmentEx.EntryAssembly?.Location;
+
+ // Single file application: entry assembly is not on disk and doesn't have a file path
+ if (string.IsNullOrWhiteSpace(entryAssemblyFilePath))
+ {
+ return Path.GetFileNameWithoutExtension(processFilePath);
+ }
+
+ // Legacy .NET Framework application: entry assembly has the same file path as the process
if (PathEx.AreEqual(entryAssemblyFilePath, processFilePath))
{
return Path.GetFileNameWithoutExtension(entryAssemblyFilePath);
}
- // If the process path has the same name and parent directory as the entry assembly path,
- // but different extension, it's a framework-dependent .NET Core app launched through the apphost.
+ // .NET Core application launched through the native application host:
+ // entry assembly has the same file path as the process, but with a different extension.
if (
PathEx.AreEqual(Path.ChangeExtension(entryAssemblyFilePath, "exe"), processFilePath)
|| PathEx.AreEqual(
@@ -277,7 +217,7 @@ public partial class CliApplicationBuilder
return Path.GetFileNameWithoutExtension(entryAssemblyFilePath);
}
- // Otherwise, it's a framework-dependent .NET Core app launched through the .NET CLI
+ // .NET Core application launched through the .NET CLI
return "dotnet " + Path.GetFileName(entryAssemblyFilePath);
}
diff --git a/CliFx/CliFx.csproj b/CliFx/CliFx.csproj
index 8fa2e0b..67fbfe4 100644
--- a/CliFx/CliFx.csproj
+++ b/CliFx/CliFx.csproj
@@ -25,7 +25,7 @@
-
+
diff --git a/CliFx/CommandBinder.cs b/CliFx/CommandBinder.cs
index 5ea4dba..a815626 100644
--- a/CliFx/CommandBinder.cs
+++ b/CliFx/CommandBinder.cs
@@ -16,14 +16,12 @@ internal class CommandBinder(ITypeActivator typeActivator)
{
private readonly IFormatProvider _formatProvider = CultureInfo.InvariantCulture;
- private object? ConvertSingle(IMemberSchema memberSchema, string? rawValue, Type targetType)
+ private object? ConvertSingle(IInputSchema inputSchema, string? rawValue, Type targetType)
{
// Custom converter
- if (memberSchema.ConverterType is not null)
+ if (inputSchema.Converter is not null)
{
- var converter = typeActivator.CreateInstance(
- memberSchema.ConverterType
- );
+ var converter = typeActivator.CreateInstance(inputSchema.Converter);
return converter.Convert(rawValue);
}
@@ -71,7 +69,7 @@ internal class CommandBinder(ITypeActivator typeActivator)
if (nullableUnderlyingType is not null)
{
return !string.IsNullOrWhiteSpace(rawValue)
- ? ConvertSingle(memberSchema, rawValue, nullableUnderlyingType)
+ ? ConvertSingle(inputSchema, rawValue, nullableUnderlyingType)
: null;
}
@@ -98,7 +96,7 @@ internal class CommandBinder(ITypeActivator typeActivator)
throw CliFxException.InternalError(
$"""
- {memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} has an unsupported underlying property type.
+ {inputSchema.GetKind()} {inputSchema.GetFormattedIdentifier()} has an unsupported underlying property type.
There is no known way to convert a string value into an instance of type `{targetType.FullName}`.
To fix this, either change the property to use a supported type or configure a custom converter.
"""
@@ -106,14 +104,14 @@ internal class CommandBinder(ITypeActivator typeActivator)
}
private object? ConvertMultiple(
- IMemberSchema memberSchema,
+ IInputSchema inputSchema,
IReadOnlyList rawValues,
Type targetEnumerableType,
Type targetElementType
)
{
var array = rawValues
- .Select(v => ConvertSingle(memberSchema, v, targetElementType))
+ .Select(v => ConvertSingle(inputSchema, v, targetElementType))
.ToNonGenericArray(targetElementType);
var arrayType = array.GetType();
@@ -133,30 +131,27 @@ internal class CommandBinder(ITypeActivator typeActivator)
throw CliFxException.InternalError(
$"""
- {memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} has an unsupported underlying property type.
+ {inputSchema.GetKind()} {inputSchema.GetFormattedIdentifier()} has an unsupported underlying property type.
There is no known way to convert an array of `{targetElementType.FullName}` into an instance of type `{targetEnumerableType.FullName}`.
To fix this, change the property to use a type which can be assigned from an array or a type which has a constructor that accepts an array.
"""
);
}
- private object? ConvertMember(IMemberSchema memberSchema, IReadOnlyList rawValues)
+ private object? ConvertMember(IInputSchema inputSchema, IReadOnlyList rawValues)
{
try
{
// Non-scalar
var enumerableUnderlyingType =
- memberSchema.Property.Type.TryGetEnumerableUnderlyingType();
+ inputSchema.Property.Type.TryGetEnumerableUnderlyingType();
- if (
- enumerableUnderlyingType is not null
- && memberSchema.Property.Type != typeof(string)
- )
+ if (enumerableUnderlyingType is not null && inputSchema.Property.Type != typeof(string))
{
return ConvertMultiple(
- memberSchema,
+ inputSchema,
rawValues,
- memberSchema.Property.Type,
+ inputSchema.Property.Type,
enumerableUnderlyingType
);
}
@@ -165,9 +160,9 @@ internal class CommandBinder(ITypeActivator typeActivator)
if (rawValues.Count <= 1)
{
return ConvertSingle(
- memberSchema,
+ inputSchema,
rawValues.SingleOrDefault(),
- memberSchema.Property.Type
+ inputSchema.Property.Type
);
}
}
@@ -181,7 +176,7 @@ internal class CommandBinder(ITypeActivator typeActivator)
throw CliFxException.UserError(
$"""
- {memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} cannot be set from the provided argument(s):
+ {inputSchema.GetKind()} {inputSchema.GetFormattedIdentifier()} cannot be set from the provided argument(s):
{rawValues.Select(v => '<' + v + '>').JoinToString(" ")}
Error: {errorMessage}
""",
@@ -192,17 +187,17 @@ internal class CommandBinder(ITypeActivator typeActivator)
// Mismatch (scalar but too many values)
throw CliFxException.UserError(
$"""
- {memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} expects a single argument, but provided with multiple:
+ {inputSchema.GetKind()} {inputSchema.GetFormattedIdentifier()} expects a single argument, but provided with multiple:
{rawValues.Select(v => '<' + v + '>').JoinToString(" ")}
"""
);
}
- private void ValidateMember(IMemberSchema memberSchema, object? convertedValue)
+ private void ValidateMember(IInputSchema inputSchema, object? convertedValue)
{
var errors = new List();
- foreach (var validatorType in memberSchema.ValidatorTypes)
+ foreach (var validatorType in inputSchema.Validators)
{
var validator = typeActivator.CreateInstance(validatorType);
var error = validator.Validate(convertedValue);
@@ -215,7 +210,7 @@ internal class CommandBinder(ITypeActivator typeActivator)
{
throw CliFxException.UserError(
$"""
- {memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} has been provided with an invalid value.
+ {inputSchema.GetKind()} {inputSchema.GetFormattedIdentifier()} has been provided with an invalid value.
Error(s):
{errors.Select(e => "- " + e.Message).JoinToString(Environment.NewLine)}
"""
@@ -224,15 +219,15 @@ internal class CommandBinder(ITypeActivator typeActivator)
}
private void BindMember(
- IMemberSchema memberSchema,
+ IInputSchema inputSchema,
ICommand commandInstance,
IReadOnlyList rawValues
)
{
- var convertedValue = ConvertMember(memberSchema, rawValues);
- ValidateMember(memberSchema, convertedValue);
+ var convertedValue = ConvertMember(inputSchema, rawValues);
+ ValidateMember(inputSchema, convertedValue);
- memberSchema.Property.SetValue(commandInstance, convertedValue);
+ inputSchema.Property.SetValue(commandInstance, convertedValue);
}
private void BindParameters(
diff --git a/CliFx/Extensibility/BindingConverter.cs b/CliFx/Extensibility/BindingConverter.cs
index b0b8a97..ae332aa 100644
--- a/CliFx/Extensibility/BindingConverter.cs
+++ b/CliFx/Extensibility/BindingConverter.cs
@@ -1,8 +1,16 @@
namespace CliFx.Extensibility;
-// Used internally to simplify the usage from reflection
-internal interface IBindingConverter
+///
+/// Defines a custom conversion for binding command-line arguments to command inputs.
+///
+///
+/// To implement your own converter, inherit from instead.
+///
+public interface IBindingConverter
{
+ ///
+ /// Parses the value from a raw command-line argument.
+ ///
object? Convert(string? rawValue);
}
@@ -12,7 +20,7 @@ internal interface IBindingConverter
public abstract class BindingConverter : IBindingConverter
{
///
- /// Parses value from a raw command-line argument.
+ /// Parses the value from a raw command-line argument.
///
public abstract T Convert(string? rawValue);
diff --git a/CliFx/Extensibility/BindingValidator.cs b/CliFx/Extensibility/BindingValidator.cs
index 9b3e394..a87562d 100644
--- a/CliFx/Extensibility/BindingValidator.cs
+++ b/CliFx/Extensibility/BindingValidator.cs
@@ -1,8 +1,17 @@
namespace CliFx.Extensibility;
-// Used internally to simplify the usage from reflection
-internal interface IBindingValidator
+///
+/// Defines a custom validation rules for values bound from command-line arguments.
+///
+///
+/// To implement your own validator, inherit from instead.
+///
+public interface IBindingValidator
{
+ ///
+ /// Validates the value bound to a parameter or an option.
+ /// Returns null if validation is successful, or an error in case of failure.
+ ///
BindingValidationError? Validate(object? value);
}
diff --git a/CliFx/FallbackDefaultCommand.cs b/CliFx/FallbackDefaultCommand.cs
index c55a89e..ef175f1 100644
--- a/CliFx/FallbackDefaultCommand.cs
+++ b/CliFx/FallbackDefaultCommand.cs
@@ -9,12 +9,15 @@ namespace CliFx;
// Fallback command used when the application doesn't have one configured.
// This command is only used as a stub for help text.
[Command]
-internal class FallbackDefaultCommand : ICommand
+internal partial class FallbackDefaultCommand : ICommand
{
- public static CommandSchema Schema { get; } =
- CommandSchema.Resolve(typeof(FallbackDefaultCommand));
-
// Never actually executed
[ExcludeFromCodeCoverage]
public ValueTask ExecuteAsync(IConsole console) => default;
}
+
+internal partial class FallbackDefaultCommand
+{
+ public static CommandSchema Schema { get; } =
+ new(typeof(FallbackDefaultCommand), null, null, [], []);
+}
diff --git a/CliFx/Formatting/HelpContext.cs b/CliFx/Formatting/HelpContext.cs
index f33319d..c898ec6 100644
--- a/CliFx/Formatting/HelpContext.cs
+++ b/CliFx/Formatting/HelpContext.cs
@@ -7,7 +7,7 @@ internal class HelpContext(
ApplicationMetadata applicationMetadata,
ApplicationSchema applicationSchema,
CommandSchema commandSchema,
- IReadOnlyDictionary commandDefaultValues
+ IReadOnlyDictionary commandDefaultValues
)
{
public ApplicationMetadata ApplicationMetadata { get; } = applicationMetadata;
@@ -16,6 +16,6 @@ internal class HelpContext(
public CommandSchema CommandSchema { get; } = commandSchema;
- public IReadOnlyDictionary CommandDefaultValues { get; } =
+ public IReadOnlyDictionary CommandDefaultValues { get; } =
commandDefaultValues;
}
diff --git a/CliFx/Infrastructure/DefaultTypeActivator.cs b/CliFx/Infrastructure/DefaultTypeActivator.cs
index 78e5afb..5410f51 100644
--- a/CliFx/Infrastructure/DefaultTypeActivator.cs
+++ b/CliFx/Infrastructure/DefaultTypeActivator.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using CliFx.Exceptions;
namespace CliFx.Infrastructure;
@@ -10,7 +11,9 @@ namespace CliFx.Infrastructure;
public class DefaultTypeActivator : ITypeActivator
{
///
- public object CreateInstance(Type type)
+ public object CreateInstance(
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type
+ )
{
try
{
diff --git a/CliFx/Infrastructure/DelegateTypeActivator.cs b/CliFx/Infrastructure/DelegateTypeActivator.cs
index faf0987..772a460 100644
--- a/CliFx/Infrastructure/DelegateTypeActivator.cs
+++ b/CliFx/Infrastructure/DelegateTypeActivator.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using CliFx.Exceptions;
namespace CliFx.Infrastructure;
@@ -9,7 +10,9 @@ namespace CliFx.Infrastructure;
public class DelegateTypeActivator(Func createInstance) : ITypeActivator
{
///
- public object CreateInstance(Type type) =>
+ public object CreateInstance(
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type
+ ) =>
createInstance(type)
?? throw CliFxException.InternalError(
$"""
diff --git a/CliFx/Infrastructure/ITypeActivator.cs b/CliFx/Infrastructure/ITypeActivator.cs
index 8a17838..f3c55ae 100644
--- a/CliFx/Infrastructure/ITypeActivator.cs
+++ b/CliFx/Infrastructure/ITypeActivator.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using CliFx.Exceptions;
namespace CliFx.Infrastructure;
@@ -11,12 +12,17 @@ public interface ITypeActivator
///
/// Creates an instance of the specified type.
///
- object CreateInstance(Type type);
+ object CreateInstance(
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type
+ );
}
internal static class TypeActivatorExtensions
{
- public static T CreateInstance(this ITypeActivator activator, Type type)
+ public static T CreateInstance(
+ this ITypeActivator activator,
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type
+ )
{
if (!typeof(T).IsAssignableFrom(type))
{
diff --git a/CliFx/Input/CommandInput.cs b/CliFx/Input/CommandInput.cs
index 408a06e..74b6bdc 100644
--- a/CliFx/Input/CommandInput.cs
+++ b/CliFx/Input/CommandInput.cs
@@ -33,10 +33,6 @@ internal partial class CommandInput(
public bool IsDebugDirectiveSpecified => Directives.Any(d => d.IsDebugDirective);
public bool IsPreviewDirectiveSpecified => Directives.Any(d => d.IsPreviewDirective);
-
- public bool IsHelpOptionSpecified => Options.Any(o => o.IsHelpOption);
-
- public bool IsVersionOptionSpecified => Options.Any(o => o.IsVersionOption);
}
internal partial class CommandInput
diff --git a/CliFx/Input/OptionInput.cs b/CliFx/Input/OptionInput.cs
index 257340a..74c4d42 100644
--- a/CliFx/Input/OptionInput.cs
+++ b/CliFx/Input/OptionInput.cs
@@ -1,5 +1,4 @@
using System.Collections.Generic;
-using CliFx.Schema;
namespace CliFx.Input;
@@ -9,10 +8,6 @@ internal class OptionInput(string identifier, IReadOnlyList values)
public IReadOnlyList Values { get; } = values;
- public bool IsHelpOption => OptionSchema.HelpOption.MatchesIdentifier(Identifier);
-
- public bool IsVersionOption => OptionSchema.VersionOption.MatchesIdentifier(Identifier);
-
public string GetFormattedIdentifier() =>
Identifier switch
{
diff --git a/CliFx/Schema/ApplicationSchema.cs b/CliFx/Schema/ApplicationSchema.cs
index 54d5bd5..488ce9a 100644
--- a/CliFx/Schema/ApplicationSchema.cs
+++ b/CliFx/Schema/ApplicationSchema.cs
@@ -5,33 +5,39 @@ using CliFx.Utils.Extensions;
namespace CliFx.Schema;
-internal partial class ApplicationSchema(IReadOnlyList commands)
+///
+/// Describes the structure of a command-line application.
+///
+public class ApplicationSchema(IReadOnlyList commands)
{
+ ///
+ /// Commands defined in the application.
+ ///
public IReadOnlyList Commands { get; } = commands;
- public IReadOnlyList GetCommandNames() =>
+ internal IReadOnlyList GetCommandNames() =>
Commands.Select(c => c.Name).WhereNotNullOrWhiteSpace().ToArray();
- public CommandSchema? TryFindDefaultCommand() => Commands.FirstOrDefault(c => c.IsDefault);
+ internal CommandSchema? TryFindDefaultCommand() => Commands.FirstOrDefault(c => c.IsDefault);
- public CommandSchema? TryFindCommand(string commandName) =>
+ internal CommandSchema? TryFindCommand(string commandName) =>
Commands.FirstOrDefault(c => c.MatchesName(commandName));
private IReadOnlyList GetDescendantCommands(
- IReadOnlyList potentialParentCommandSchemas,
+ IReadOnlyList potentialDescendantCommands,
string? parentCommandName
)
{
var result = new List();
- foreach (var potentialParentCommandSchema in potentialParentCommandSchemas)
+ foreach (var potentialDescendantCommand in potentialDescendantCommands)
{
// Default commands can't be descendant of anything
- if (string.IsNullOrWhiteSpace(potentialParentCommandSchema.Name))
+ if (string.IsNullOrWhiteSpace(potentialDescendantCommand.Name))
continue;
// Command can't be its own descendant
- if (potentialParentCommandSchema.MatchesName(parentCommandName))
+ if (potentialDescendantCommand.MatchesName(parentCommandName))
continue;
var isDescendant =
@@ -39,22 +45,22 @@ internal partial class ApplicationSchema(IReadOnlyList commands)
string.IsNullOrWhiteSpace(parentCommandName)
||
// Otherwise a command is a descendant if it starts with the same name segments
- potentialParentCommandSchema.Name.StartsWith(
+ potentialDescendantCommand.Name.StartsWith(
parentCommandName + ' ',
StringComparison.OrdinalIgnoreCase
);
if (isDescendant)
- result.Add(potentialParentCommandSchema);
+ result.Add(potentialDescendantCommand);
}
return result;
}
- public IReadOnlyList GetDescendantCommands(string? parentCommandName) =>
+ internal IReadOnlyList GetDescendantCommands(string? parentCommandName) =>
GetDescendantCommands(Commands, parentCommandName);
- public IReadOnlyList GetChildCommands(string? parentCommandName)
+ internal IReadOnlyList GetChildCommands(string? parentCommandName)
{
var descendants = GetDescendantCommands(parentCommandName);
@@ -62,16 +68,8 @@ internal partial class ApplicationSchema(IReadOnlyList commands)
// Filter out descendants of descendants, leave only direct children
foreach (var descendant in descendants)
- {
result.RemoveRange(GetDescendantCommands(descendants, descendant.Name));
- }
return result;
}
}
-
-internal partial class ApplicationSchema
-{
- public static ApplicationSchema Resolve(IReadOnlyList commandTypes) =>
- new(commandTypes.Select(CommandSchema.Resolve).ToArray());
-}
diff --git a/CliFx/Schema/BindablePropertyDescriptor.cs b/CliFx/Schema/BindablePropertyDescriptor.cs
deleted file mode 100644
index 8f7e35d..0000000
--- a/CliFx/Schema/BindablePropertyDescriptor.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-using CliFx.Utils.Extensions;
-
-namespace CliFx.Schema;
-
-internal class BindablePropertyDescriptor(PropertyInfo property) : IPropertyDescriptor
-{
- public Type Type => property.PropertyType;
-
- public object? GetValue(ICommand commandInstance) => property.GetValue(commandInstance);
-
- public void SetValue(ICommand commandInstance, object? value) =>
- property.SetValue(commandInstance, value);
-
- public IReadOnlyList