Add xml documentation

This commit is contained in:
Alexey Golub
2019-08-13 21:59:57 +03:00
parent 384482a47c
commit 743241cb3b
36 changed files with 482 additions and 7 deletions

View File

@@ -1,20 +1,34 @@
using System; using System;
using CliFx.Internal;
namespace CliFx.Attributes namespace CliFx.Attributes
{ {
/// <summary>
/// Annotates a type that defines a command.
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false)] [AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class CommandAttribute : Attribute public class CommandAttribute : Attribute
{ {
/// <summary>
/// Command name.
/// </summary>
public string Name { get; } public string Name { get; }
/// <summary>
/// Command description, which is used in help text.
/// </summary>
public string Description { get; set; } public string Description { get; set; }
/// <summary>
/// Initializes an instance of <see cref="CommandAttribute"/>.
/// </summary>
public CommandAttribute(string name) public CommandAttribute(string name)
{ {
Name = name; Name = name;
} }
/// <summary>
/// Initializes an instance of <see cref="CommandAttribute"/>.
/// </summary>
public CommandAttribute() public CommandAttribute()
: this(null) : this(null)
{ {

View File

@@ -2,35 +2,65 @@
namespace CliFx.Attributes namespace CliFx.Attributes
{ {
/// <summary>
/// Annotates a property that defines a command option.
/// </summary>
[AttributeUsage(AttributeTargets.Property)] [AttributeUsage(AttributeTargets.Property)]
public class CommandOptionAttribute : Attribute public class CommandOptionAttribute : Attribute
{ {
/// <summary>
/// Option name.
/// </summary>
public string Name { get; } public string Name { get; }
/// <summary>
/// Option short name.
/// </summary>
public char? ShortName { get; } public char? ShortName { get; }
/// <summary>
/// Option group name.
/// </summary>
public string GroupName { get; set; } public string GroupName { get; set; }
/// <summary>
/// Whether an option is required.
/// </summary>
public bool IsRequired { get; set; } public bool IsRequired { get; set; }
/// <summary>
/// Option description, which is used in help text.
/// </summary>
public string Description { get; set; } public string Description { get; set; }
/// <summary>
/// Initializes an instance of <see cref="CommandOptionAttribute"/>.
/// </summary>
public CommandOptionAttribute(string name, char? shortName) public CommandOptionAttribute(string name, char? shortName)
{ {
Name = name; Name = name;
ShortName = shortName; ShortName = shortName;
} }
/// <summary>
/// Initializes an instance of <see cref="CommandOptionAttribute"/>.
/// </summary>
public CommandOptionAttribute(string name, char shortName) public CommandOptionAttribute(string name, char shortName)
: this(name, (char?) shortName) : this(name, (char?) shortName)
{ {
} }
/// <summary>
/// Initializes an instance of <see cref="CommandOptionAttribute"/>.
/// </summary>
public CommandOptionAttribute(string name) public CommandOptionAttribute(string name)
: this(name, null) : this(name, null)
{ {
} }
/// <summary>
/// Initializes an instance of <see cref="CommandOptionAttribute"/>.
/// </summary>
public CommandOptionAttribute(char shortName) public CommandOptionAttribute(char shortName)
: this(null, shortName) : this(null, shortName)
{ {

View File

@@ -10,6 +10,9 @@ using CliFx.Services;
namespace CliFx namespace CliFx
{ {
/// <summary>
/// Default implementation of <see cref="ICliApplication"/>.
/// </summary>
public partial class CliApplication : ICliApplication public partial class CliApplication : ICliApplication
{ {
private readonly ApplicationMetadata _applicationMetadata; private readonly ApplicationMetadata _applicationMetadata;
@@ -22,6 +25,9 @@ namespace CliFx
private readonly ICommandInitializer _commandInitializer; private readonly ICommandInitializer _commandInitializer;
private readonly ICommandHelpTextRenderer _commandHelpTextRenderer; private readonly ICommandHelpTextRenderer _commandHelpTextRenderer;
/// <summary>
/// Initializes an instance of <see cref="CliApplication"/>.
/// </summary>
public CliApplication(ApplicationMetadata applicationMetadata, IReadOnlyList<Type> commandTypes, public CliApplication(ApplicationMetadata applicationMetadata, IReadOnlyList<Type> commandTypes,
IConsole console, ICommandInputParser commandInputParser, ICommandSchemaResolver commandSchemaResolver, IConsole console, ICommandInputParser commandInputParser, ICommandSchemaResolver commandSchemaResolver,
ICommandFactory commandFactory, ICommandInitializer commandInitializer, ICommandHelpTextRenderer commandHelpTextRenderer) ICommandFactory commandFactory, ICommandInitializer commandInitializer, ICommandHelpTextRenderer commandHelpTextRenderer)
@@ -98,6 +104,7 @@ namespace CliFx
return result; return result;
} }
/// <inheritdoc />
public async Task<int> RunAsync(IReadOnlyList<string> commandLineArguments) public async Task<int> RunAsync(IReadOnlyList<string> commandLineArguments)
{ {
try try

View File

@@ -9,6 +9,9 @@ using CliFx.Services;
namespace CliFx namespace CliFx
{ {
/// <summary>
/// Default implementation of <see cref="ICliApplicationBuilder"/>.
/// </summary>
public class CliApplicationBuilder : ICliApplicationBuilder public class CliApplicationBuilder : ICliApplicationBuilder
{ {
private readonly HashSet<Type> _commandTypes = new HashSet<Type>(); private readonly HashSet<Type> _commandTypes = new HashSet<Type>();
@@ -19,12 +22,14 @@ namespace CliFx
private IConsole _console; private IConsole _console;
private ICommandFactory _commandFactory; private ICommandFactory _commandFactory;
/// <inheritdoc />
public ICliApplicationBuilder WithCommand(Type commandType) public ICliApplicationBuilder WithCommand(Type commandType)
{ {
_commandTypes.Add(commandType); _commandTypes.Add(commandType);
return this; return this;
} }
/// <inheritdoc />
public ICliApplicationBuilder WithCommandsFrom(Assembly commandAssembly) public ICliApplicationBuilder WithCommandsFrom(Assembly commandAssembly)
{ {
var commandTypes = commandAssembly.ExportedTypes.Where(t => t.Implements(typeof(ICommand))); var commandTypes = commandAssembly.ExportedTypes.Where(t => t.Implements(typeof(ICommand)));
@@ -35,30 +40,35 @@ namespace CliFx
return this; return this;
} }
/// <inheritdoc />
public ICliApplicationBuilder UseTitle(string title) public ICliApplicationBuilder UseTitle(string title)
{ {
_title = title; _title = title;
return this; return this;
} }
public ICliApplicationBuilder UseExecutableName(string exeName) /// <inheritdoc />
public ICliApplicationBuilder UseExecutableName(string executableName)
{ {
_executableName = exeName; _executableName = executableName;
return this; return this;
} }
/// <inheritdoc />
public ICliApplicationBuilder UseVersionText(string version) public ICliApplicationBuilder UseVersionText(string version)
{ {
_versionText = version; _versionText = version;
return this; return this;
} }
/// <inheritdoc />
public ICliApplicationBuilder UseConsole(IConsole console) public ICliApplicationBuilder UseConsole(IConsole console)
{ {
_console = console; _console = console;
return this; return this;
} }
/// <inheritdoc />
public ICliApplicationBuilder UseCommandFactory(ICommandFactory factory) public ICliApplicationBuilder UseCommandFactory(ICommandFactory factory)
{ {
_commandFactory = factory; _commandFactory = factory;
@@ -86,6 +96,7 @@ namespace CliFx
UseCommandFactory(new CommandFactory()); UseCommandFactory(new CommandFactory());
} }
/// <inheritdoc />
public ICliApplication Build() public ICliApplication Build()
{ {
// Use defaults for required parameters that were not configured // Use defaults for required parameters that were not configured

View File

@@ -2,17 +2,29 @@
namespace CliFx.Exceptions namespace CliFx.Exceptions
{ {
/// <summary>
/// Thrown when an input command option can't be converted.
/// </summary>
public class CannotConvertCommandOptionException : CliFxException public class CannotConvertCommandOptionException : CliFxException
{ {
/// <summary>
/// Initializes an instance of <see cref="CannotConvertCommandOptionException"/>.
/// </summary>
public CannotConvertCommandOptionException() public CannotConvertCommandOptionException()
{ {
} }
/// <summary>
/// Initializes an instance of <see cref="CannotConvertCommandOptionException"/>.
/// </summary>
public CannotConvertCommandOptionException(string message) public CannotConvertCommandOptionException(string message)
: base(message) : base(message)
{ {
} }
/// <summary>
/// Initializes an instance of <see cref="CannotConvertCommandOptionException"/>.
/// </summary>
public CannotConvertCommandOptionException(string message, Exception innerException) public CannotConvertCommandOptionException(string message, Exception innerException)
: base(message, innerException) : base(message, innerException)
{ {

View File

@@ -2,18 +2,30 @@
namespace CliFx.Exceptions namespace CliFx.Exceptions
{ {
/// <summary>
/// Domain exception thrown within CliFx.
/// </summary>
public abstract class CliFxException : Exception public abstract class CliFxException : Exception
{ {
/// <summary>
/// Initializes an instance of <see cref="CliFxException"/>.
/// </summary>
protected CliFxException(string message) protected CliFxException(string message)
: base(message) : base(message)
{ {
} }
/// <summary>
/// Initializes an instance of <see cref="CliFxException"/>.
/// </summary>
protected CliFxException(string message, Exception innerException) protected CliFxException(string message, Exception innerException)
: base(message, innerException) : base(message, innerException)
{ {
} }
/// <summary>
/// Initializes an instance of <see cref="CliFxException"/>.
/// </summary>
protected CliFxException() protected CliFxException()
{ {
} }

View File

@@ -2,26 +2,45 @@
namespace CliFx.Exceptions namespace CliFx.Exceptions
{ {
/// <summary>
/// Thrown when a command cannot proceed with normal execution due to error.
/// Use this exception if you want to specify an exit code to use when the process terminates.
/// </summary>
public class CommandErrorException : CliFxException public class CommandErrorException : CliFxException
{ {
/// <summary>
/// Process exit code.
/// </summary>
public int ExitCode { get; } public int ExitCode { get; }
/// <summary>
/// Initializes an instance of <see cref="CommandErrorException"/>.
/// </summary>
public CommandErrorException(int exitCode, string message, Exception innerException) public CommandErrorException(int exitCode, string message, Exception innerException)
: base(message, innerException) : base(message, innerException)
{ {
ExitCode = exitCode; ExitCode = exitCode;
} }
/// <summary>
/// Initializes an instance of <see cref="CommandErrorException"/>.
/// </summary>
public CommandErrorException(int exitCode, Exception innerException) public CommandErrorException(int exitCode, Exception innerException)
: this(exitCode, null, innerException) : this(exitCode, null, innerException)
{ {
} }
/// <summary>
/// Initializes an instance of <see cref="CommandErrorException"/>.
/// </summary>
public CommandErrorException(int exitCode, string message) public CommandErrorException(int exitCode, string message)
: this(exitCode, message, null) : this(exitCode, message, null)
{ {
} }
/// <summary>
/// Initializes an instance of <see cref="CommandErrorException"/>.
/// </summary>
public CommandErrorException(int exitCode) public CommandErrorException(int exitCode)
: this(exitCode, null, null) : this(exitCode, null, null)
{ {

View File

@@ -2,17 +2,29 @@
namespace CliFx.Exceptions namespace CliFx.Exceptions
{ {
/// <summary>
/// Thrown when a required command option was not set.
/// </summary>
public class MissingCommandOptionException : CliFxException public class MissingCommandOptionException : CliFxException
{ {
/// <summary>
/// Initializes an instance of <see cref="MissingCommandOptionException"/>.
/// </summary>
public MissingCommandOptionException() public MissingCommandOptionException()
{ {
} }
/// <summary>
/// Initializes an instance of <see cref="MissingCommandOptionException"/>.
/// </summary>
public MissingCommandOptionException(string message) public MissingCommandOptionException(string message)
: base(message) : base(message)
{ {
} }
/// <summary>
/// Initializes an instance of <see cref="MissingCommandOptionException"/>.
/// </summary>
public MissingCommandOptionException(string message, Exception innerException) public MissingCommandOptionException(string message, Exception innerException)
: base(message, innerException) : base(message, innerException)
{ {

View File

@@ -5,8 +5,14 @@ using CliFx.Services;
namespace CliFx namespace CliFx
{ {
/// <summary>
/// Extensions for <see cref="CliFx"/>.
/// </summary>
public static class Extensions public static class Extensions
{ {
/// <summary>
/// Adds multiple commands to the application.
/// </summary>
public static ICliApplicationBuilder WithCommands(this ICliApplicationBuilder builder, IReadOnlyList<Type> commandTypes) public static ICliApplicationBuilder WithCommands(this ICliApplicationBuilder builder, IReadOnlyList<Type> commandTypes)
{ {
foreach (var commandType in commandTypes) foreach (var commandType in commandTypes)
@@ -15,6 +21,9 @@ namespace CliFx
return builder; return builder;
} }
/// <summary>
/// Adds commands from specified assemblies to the application.
/// </summary>
public static ICliApplicationBuilder WithCommandsFrom(this ICliApplicationBuilder builder, IReadOnlyList<Assembly> commandAssemblies) public static ICliApplicationBuilder WithCommandsFrom(this ICliApplicationBuilder builder, IReadOnlyList<Assembly> commandAssemblies)
{ {
foreach (var commandAssembly in commandAssemblies) foreach (var commandAssembly in commandAssemblies)
@@ -23,9 +32,15 @@ namespace CliFx
return builder; return builder;
} }
/// <summary>
/// Adds commands from calling assembly to the application.
/// </summary>
public static ICliApplicationBuilder WithCommandsFromThisAssembly(this ICliApplicationBuilder builder) => public static ICliApplicationBuilder WithCommandsFromThisAssembly(this ICliApplicationBuilder builder) =>
builder.WithCommandsFrom(Assembly.GetCallingAssembly()); builder.WithCommandsFrom(Assembly.GetCallingAssembly());
/// <summary>
/// Configures application to use specified factory method for creating new instances of <see cref="ICommand"/>.
/// </summary>
public static ICliApplicationBuilder UseCommandFactory(this ICliApplicationBuilder builder, Func<Type, ICommand> factoryMethod) => public static ICliApplicationBuilder UseCommandFactory(this ICliApplicationBuilder builder, Func<Type, ICommand> factoryMethod) =>
builder.UseCommandFactory(new DelegateCommandFactory(factoryMethod)); builder.UseCommandFactory(new DelegateCommandFactory(factoryMethod));
} }

View File

@@ -3,8 +3,15 @@ using System.Threading.Tasks;
namespace CliFx namespace CliFx
{ {
/// <summary>
/// Entry point for a command line application.
/// </summary>
public interface ICliApplication public interface ICliApplication
{ {
/// <summary>
/// Runs application with specified command line arguments.
/// Returns exit code.
/// </summary>
Task<int> RunAsync(IReadOnlyList<string> commandLineArguments); Task<int> RunAsync(IReadOnlyList<string> commandLineArguments);
} }
} }

View File

@@ -4,22 +4,50 @@ using CliFx.Services;
namespace CliFx namespace CliFx
{ {
/// <summary>
/// Builds an instance of <see cref="ICliApplication"/>.
/// </summary>
public interface ICliApplicationBuilder public interface ICliApplicationBuilder
{ {
/// <summary>
/// Adds a command of specified type to the application.
/// </summary>
ICliApplicationBuilder WithCommand(Type commandType); ICliApplicationBuilder WithCommand(Type commandType);
/// <summary>
/// Adds commands from specified assembly to the application.
/// </summary>
ICliApplicationBuilder WithCommandsFrom(Assembly commandAssembly); ICliApplicationBuilder WithCommandsFrom(Assembly commandAssembly);
/// <summary>
/// Sets application title, which appears in the help text.
/// </summary>
ICliApplicationBuilder UseTitle(string title); ICliApplicationBuilder UseTitle(string title);
ICliApplicationBuilder UseExecutableName(string exeName); /// <summary>
/// Sets application executable name, which appears in the help text.
/// </summary>
ICliApplicationBuilder UseExecutableName(string executableName);
/// <summary>
/// Sets application version text, which appears in the help text and when the user requests version information.
/// </summary>
ICliApplicationBuilder UseVersionText(string version); ICliApplicationBuilder UseVersionText(string version);
/// <summary>
/// Configures application to use specified implementation of <see cref="IConsole"/>.
/// </summary>
ICliApplicationBuilder UseConsole(IConsole console); ICliApplicationBuilder UseConsole(IConsole console);
/// <summary>
/// Configures application to use specified implementation of <see cref="ICommandFactory"/>.
/// </summary>
ICliApplicationBuilder UseCommandFactory(ICommandFactory factory); ICliApplicationBuilder UseCommandFactory(ICommandFactory factory);
/// <summary>
/// Creates an instance of <see cref="ICliApplication"/> using configured parameters.
/// Default values are used in place of parameters that were not specified.
/// </summary>
ICliApplication Build(); ICliApplication Build();
} }
} }

View File

@@ -3,8 +3,15 @@ using CliFx.Services;
namespace CliFx namespace CliFx
{ {
/// <summary>
/// Point of interaction between a user and command line interface.
/// </summary>
public interface ICommand public interface ICommand
{ {
/// <summary>
/// Executes command using specified implementation of <see cref="IConsole"/>.
/// This method is called when the command is invoked by a user through command line interface.
/// </summary>
Task ExecuteAsync(IConsole console); Task ExecuteAsync(IConsole console);
} }
} }

View File

@@ -1,13 +1,28 @@
namespace CliFx.Models namespace CliFx.Models
{ {
/// <summary>
/// Metadata associated with an application.
/// </summary>
public class ApplicationMetadata public class ApplicationMetadata
{ {
/// <summary>
/// Application title.
/// </summary>
public string Title { get; } public string Title { get; }
/// <summary>
/// Application executable name.
/// </summary>
public string ExecutableName { get; } public string ExecutableName { get; }
/// <summary>
/// Application version text.
/// </summary>
public string VersionText { get; } public string VersionText { get; }
/// <summary>
/// Initializes an instance of <see cref="ApplicationMetadata"/>.
/// </summary>
public ApplicationMetadata(string title, string executableName, string versionText) public ApplicationMetadata(string title, string executableName, string versionText)
{ {
Title = title; Title = title;

View File

@@ -4,33 +4,55 @@ using CliFx.Internal;
namespace CliFx.Models namespace CliFx.Models
{ {
/// <summary>
/// Parsed command line input.
/// </summary>
public partial class CommandInput public partial class CommandInput
{ {
/// <summary>
/// Specified command name.
/// </summary>
public string CommandName { get; } public string CommandName { get; }
/// <summary>
/// Specified options.
/// </summary>
public IReadOnlyList<CommandOptionInput> Options { get; } public IReadOnlyList<CommandOptionInput> Options { get; }
/// <summary>
/// Initializes an instance of <see cref="CommandInput"/>.
/// </summary>
public CommandInput(string commandName, IReadOnlyList<CommandOptionInput> options) public CommandInput(string commandName, IReadOnlyList<CommandOptionInput> options)
{ {
CommandName = commandName; CommandName = commandName;
Options = options; Options = options;
} }
/// <summary>
/// Initializes an instance of <see cref="CommandInput"/>.
/// </summary>
public CommandInput(IReadOnlyList<CommandOptionInput> options) public CommandInput(IReadOnlyList<CommandOptionInput> options)
: this(null, options) : this(null, options)
{ {
} }
/// <summary>
/// Initializes an instance of <see cref="CommandInput"/>.
/// </summary>
public CommandInput(string commandName) public CommandInput(string commandName)
: this(commandName, new CommandOptionInput[0]) : this(commandName, new CommandOptionInput[0])
{ {
} }
/// <summary>
/// Initializes an instance of <see cref="CommandInput"/>.
/// </summary>
public CommandInput() public CommandInput()
: this(null, new CommandOptionInput[0]) : this(null, new CommandOptionInput[0])
{ {
} }
/// <inheritdoc />
public override string ToString() public override string ToString()
{ {
var buffer = new StringBuilder(); var buffer = new StringBuilder();
@@ -53,6 +75,9 @@ namespace CliFx.Models
public partial class CommandInput public partial class CommandInput
{ {
/// <summary>
/// Empty input.
/// </summary>
public static CommandInput Empty { get; } = new CommandInput(); public static CommandInput Empty { get; } = new CommandInput();
} }
} }

View File

@@ -3,28 +3,47 @@ using System.Text;
namespace CliFx.Models namespace CliFx.Models
{ {
/// <summary>
/// Parsed option from command line input.
/// </summary>
public class CommandOptionInput public class CommandOptionInput
{ {
/// <summary>
/// Specified option alias.
/// </summary>
public string Alias { get; } public string Alias { get; }
/// <summary>
/// Specified values.
/// </summary>
public IReadOnlyList<string> Values { get; } public IReadOnlyList<string> Values { get; }
/// <summary>
/// Initializes an instance of <see cref="CommandOptionInput"/>.
/// </summary>
public CommandOptionInput(string alias, IReadOnlyList<string> values) public CommandOptionInput(string alias, IReadOnlyList<string> values)
{ {
Alias = alias; Alias = alias;
Values = values; Values = values;
} }
/// <summary>
/// Initializes an instance of <see cref="CommandOptionInput"/>.
/// </summary>
public CommandOptionInput(string alias, string value) public CommandOptionInput(string alias, string value)
: this(alias, new[] {value}) : this(alias, new[] {value})
{ {
} }
/// <summary>
/// Initializes an instance of <see cref="CommandOptionInput"/>.
/// </summary>
public CommandOptionInput(string alias) public CommandOptionInput(string alias)
: this(alias, new string[0]) : this(alias, new string[0])
{ {
} }
/// <inheritdoc />
public override string ToString() public override string ToString()
{ {
var buffer = new StringBuilder(); var buffer = new StringBuilder();

View File

@@ -4,20 +4,44 @@ using CliFx.Internal;
namespace CliFx.Models namespace CliFx.Models
{ {
/// <summary>
/// Schema of a defined command option.
/// </summary>
public class CommandOptionSchema public class CommandOptionSchema
{ {
/// <summary>
/// Underlying property.
/// </summary>
public PropertyInfo Property { get; } public PropertyInfo Property { get; }
/// <summary>
/// Option name.
/// </summary>
public string Name { get; } public string Name { get; }
/// <summary>
/// Option short name.
/// </summary>
public char? ShortName { get; } public char? ShortName { get; }
/// <summary>
/// Option group name.
/// </summary>
public string GroupName { get; } public string GroupName { get; }
/// <summary>
/// Whether an option is required.
/// </summary>
public bool IsRequired { get; } public bool IsRequired { get; }
/// <summary>
/// Option description.
/// </summary>
public string Description { get; } public string Description { get; }
/// <summary>
/// Initializes an instance of <see cref="CommandOptionSchema"/>.
/// </summary>
public CommandOptionSchema(PropertyInfo property, string name, char? shortName, public CommandOptionSchema(PropertyInfo property, string name, char? shortName,
string groupName, bool isRequired, string description) string groupName, bool isRequired, string description)
{ {
@@ -29,6 +53,7 @@ namespace CliFx.Models
Description = description; Description = description;
} }
/// <inheritdoc />
public override string ToString() public override string ToString()
{ {
var buffer = new StringBuilder(); var buffer = new StringBuilder();

View File

@@ -5,16 +5,34 @@ using CliFx.Internal;
namespace CliFx.Models namespace CliFx.Models
{ {
/// <summary>
/// Schema of a defined command.
/// </summary>
public class CommandSchema public class CommandSchema
{ {
/// <summary>
/// Underlying type.
/// </summary>
public Type Type { get; } public Type Type { get; }
/// <summary>
/// Command name.
/// </summary>
public string Name { get; } public string Name { get; }
/// <summary>
/// Command description.
/// </summary>
public string Description { get; } public string Description { get; }
/// <summary>
/// Command options.
/// </summary>
public IReadOnlyList<CommandOptionSchema> Options { get; } public IReadOnlyList<CommandOptionSchema> Options { get; }
/// <summary>
/// Initializes an instance of <see cref="CommandSchema"/>.
/// </summary>
public CommandSchema(Type type, string name, string description, IReadOnlyList<CommandOptionSchema> options) public CommandSchema(Type type, string name, string description, IReadOnlyList<CommandOptionSchema> options)
{ {
Type = type; Type = type;
@@ -23,6 +41,7 @@ namespace CliFx.Models
Options = options; Options = options;
} }
/// <inheritdoc />
public override string ToString() public override string ToString()
{ {
var buffer = new StringBuilder(); var buffer = new StringBuilder();

View File

@@ -5,10 +5,19 @@ using CliFx.Internal;
namespace CliFx.Models namespace CliFx.Models
{ {
/// <summary>
/// Extensions for <see cref="Models"/>.
/// </summary>
public static class Extensions public static class Extensions
{ {
/// <summary>
/// Gets whether a command was specified in the input.
/// </summary>
public static bool IsCommandSpecified(this CommandInput commandInput) => !commandInput.CommandName.IsNullOrWhiteSpace(); public static bool IsCommandSpecified(this CommandInput commandInput) => !commandInput.CommandName.IsNullOrWhiteSpace();
/// <summary>
/// Gets whether help was requested in the input.
/// </summary>
public static bool IsHelpRequested(this CommandInput commandInput) public static bool IsHelpRequested(this CommandInput commandInput)
{ {
var firstOptionAlias = commandInput.Options.FirstOrDefault()?.Alias; var firstOptionAlias = commandInput.Options.FirstOrDefault()?.Alias;
@@ -18,6 +27,9 @@ namespace CliFx.Models
string.Equals(firstOptionAlias, "?", StringComparison.Ordinal); string.Equals(firstOptionAlias, "?", StringComparison.Ordinal);
} }
/// <summary>
/// Gets whether version information was requested in the input.
/// </summary>
public static bool IsVersionRequested(this CommandInput commandInput) public static bool IsVersionRequested(this CommandInput commandInput)
{ {
var firstOptionAlias = commandInput.Options.FirstOrDefault()?.Alias; var firstOptionAlias = commandInput.Options.FirstOrDefault()?.Alias;
@@ -25,11 +37,20 @@ namespace CliFx.Models
return string.Equals(firstOptionAlias, "version", StringComparison.OrdinalIgnoreCase); return string.Equals(firstOptionAlias, "version", StringComparison.OrdinalIgnoreCase);
} }
/// <summary>
/// Gets whether this command is the default command, i.e. without a name.
/// </summary>
public static bool IsDefault(this CommandSchema commandSchema) => commandSchema.Name.IsNullOrWhiteSpace(); public static bool IsDefault(this CommandSchema commandSchema) => commandSchema.Name.IsNullOrWhiteSpace();
/// <summary>
/// Finds a command that has specified name, or null if not found.
/// </summary>
public static CommandSchema FindByName(this IReadOnlyList<CommandSchema> commandSchemas, string commandName) => public static CommandSchema FindByName(this IReadOnlyList<CommandSchema> commandSchemas, string commandName) =>
commandSchemas.FirstOrDefault(c => string.Equals(c.Name, commandName, StringComparison.OrdinalIgnoreCase)); commandSchemas.FirstOrDefault(c => string.Equals(c.Name, commandName, StringComparison.OrdinalIgnoreCase));
/// <summary>
/// Finds parent command to the command that has specified name, or null if not found.
/// </summary>
public static CommandSchema FindParent(this IReadOnlyList<CommandSchema> commandSchemas, string commandName) public static CommandSchema FindParent(this IReadOnlyList<CommandSchema> commandSchemas, string commandName)
{ {
// If command has no name, it's the default command so it doesn't have a parent // If command has no name, it's the default command so it doesn't have a parent
@@ -51,6 +72,9 @@ namespace CliFx.Models
return commandSchemas.FirstOrDefault(c => c.IsDefault()); return commandSchemas.FirstOrDefault(c => c.IsDefault());
} }
/// <summary>
/// Finds an option that matches specified alias, or null if not found.
/// </summary>
public static CommandOptionSchema FindByAlias(this IReadOnlyList<CommandOptionSchema> optionSchemas, string alias) public static CommandOptionSchema FindByAlias(this IReadOnlyList<CommandOptionSchema> optionSchemas, string alias)
{ {
foreach (var optionSchema in optionSchemas) foreach (var optionSchema in optionSchemas)

View File

@@ -2,14 +2,29 @@
namespace CliFx.Models namespace CliFx.Models
{ {
/// <summary>
/// Source information used to generate help text.
/// </summary>
public class HelpTextSource public class HelpTextSource
{ {
/// <summary>
/// Application metadata.
/// </summary>
public ApplicationMetadata ApplicationMetadata { get; } public ApplicationMetadata ApplicationMetadata { get; }
/// <summary>
/// Schemas of commands available in the application.
/// </summary>
public IReadOnlyList<CommandSchema> AvailableCommandSchemas { get; } public IReadOnlyList<CommandSchema> AvailableCommandSchemas { get; }
/// <summary>
/// Schema of the command for which help text is to be generated.
/// </summary>
public CommandSchema TargetCommandSchema { get; } public CommandSchema TargetCommandSchema { get; }
/// <summary>
/// Initializes an instance of <see cref="HelpTextSource"/>.
/// </summary>
public HelpTextSource(ApplicationMetadata applicationMetadata, public HelpTextSource(ApplicationMetadata applicationMetadata,
IReadOnlyList<CommandSchema> availableCommandSchemas, IReadOnlyList<CommandSchema> availableCommandSchemas,
CommandSchema targetCommandSchema) CommandSchema targetCommandSchema)

View File

@@ -2,8 +2,12 @@
namespace CliFx.Services namespace CliFx.Services
{ {
/// <summary>
/// Default implementation of <see cref="ICommandFactory"/>.
/// </summary>
public class CommandFactory : ICommandFactory public class CommandFactory : ICommandFactory
{ {
/// <inheritdoc />
public ICommand CreateCommand(Type commandType) => (ICommand) Activator.CreateInstance(commandType); public ICommand CreateCommand(Type commandType) => (ICommand) Activator.CreateInstance(commandType);
} }
} }

View File

@@ -6,8 +6,12 @@ using CliFx.Models;
namespace CliFx.Services namespace CliFx.Services
{ {
/// <summary>
/// Default implementation of <see cref="ICommandHelpTextRenderer"/>.
/// </summary>
public partial class CommandHelpTextRenderer : ICommandHelpTextRenderer public partial class CommandHelpTextRenderer : ICommandHelpTextRenderer
{ {
/// <inheritdoc />
public void RenderHelpText(IConsole console, HelpTextSource source) => new Impl(console, source).RenderHelpText(); public void RenderHelpText(IConsole console, HelpTextSource source) => new Impl(console, source).RenderHelpText();
} }

View File

@@ -7,20 +7,30 @@ using CliFx.Models;
namespace CliFx.Services namespace CliFx.Services
{ {
/// <summary>
/// Default implementation of <see cref="ICommandInitializer"/>.
/// </summary>
public class CommandInitializer : ICommandInitializer public class CommandInitializer : ICommandInitializer
{ {
private readonly ICommandOptionInputConverter _commandOptionInputConverter; private readonly ICommandOptionInputConverter _commandOptionInputConverter;
/// <summary>
/// Initializes an instance of <see cref="CommandInitializer"/>.
/// </summary>
public CommandInitializer(ICommandOptionInputConverter commandOptionInputConverter) public CommandInitializer(ICommandOptionInputConverter commandOptionInputConverter)
{ {
_commandOptionInputConverter = commandOptionInputConverter; _commandOptionInputConverter = commandOptionInputConverter;
} }
/// <summary>
/// Initializes an instance of <see cref="CommandInitializer"/>.
/// </summary>
public CommandInitializer() public CommandInitializer()
: this(new CommandOptionInputConverter()) : this(new CommandOptionInputConverter())
{ {
} }
/// <inheritdoc />
public void InitializeCommand(ICommand command, CommandSchema schema, CommandInput input) public void InitializeCommand(ICommand command, CommandSchema schema, CommandInput input)
{ {
// Set command options // Set command options

View File

@@ -6,9 +6,13 @@ using CliFx.Models;
namespace CliFx.Services namespace CliFx.Services
{ {
/// <summary>
/// Default implementation of <see cref="ICommandInputParser"/>.
/// </summary>
public class CommandInputParser : ICommandInputParser public class CommandInputParser : ICommandInputParser
{ {
// TODO: refactor // TODO: refactor
/// <inheritdoc />
public CommandInput ParseInput(IReadOnlyList<string> commandLineArguments) public CommandInput ParseInput(IReadOnlyList<string> commandLineArguments)
{ {
// Initialize command name placeholder // Initialize command name placeholder

View File

@@ -8,15 +8,24 @@ using CliFx.Models;
namespace CliFx.Services namespace CliFx.Services
{ {
/// <summary>
/// Default implementation of <see cref="ICommandOptionInputConverter"/>.
/// </summary>
public class CommandOptionInputConverter : ICommandOptionInputConverter public class CommandOptionInputConverter : ICommandOptionInputConverter
{ {
private readonly IFormatProvider _formatProvider; private readonly IFormatProvider _formatProvider;
/// <summary>
/// Initializes an instance of <see cref="CommandOptionInputConverter"/>.
/// </summary>
public CommandOptionInputConverter(IFormatProvider formatProvider) public CommandOptionInputConverter(IFormatProvider formatProvider)
{ {
_formatProvider = formatProvider; _formatProvider = formatProvider;
} }
/// <summary>
/// Initializes an instance of <see cref="CommandOptionInputConverter"/>.
/// </summary>
public CommandOptionInputConverter() public CommandOptionInputConverter()
: this(CultureInfo.InvariantCulture) : this(CultureInfo.InvariantCulture)
{ {
@@ -232,6 +241,7 @@ namespace CliFx.Services
} }
// TODO: refactor this // TODO: refactor this
/// <inheritdoc />
public object ConvertOption(CommandOptionInput option, Type targetType) public object ConvertOption(CommandOptionInput option, Type targetType)
{ {
if (targetType != typeof(string) && targetType.IsEnumerable()) if (targetType != typeof(string) && targetType.IsEnumerable())

View File

@@ -7,6 +7,9 @@ using CliFx.Models;
namespace CliFx.Services namespace CliFx.Services
{ {
/// <summary>
/// Default implementation of <see cref="ICommandSchemaResolver"/>.
/// </summary>
public class CommandSchemaResolver : ICommandSchemaResolver public class CommandSchemaResolver : ICommandSchemaResolver
{ {
private CommandOptionSchema GetCommandOptionSchema(PropertyInfo optionProperty) private CommandOptionSchema GetCommandOptionSchema(PropertyInfo optionProperty)
@@ -24,7 +27,7 @@ namespace CliFx.Services
attribute.Description); attribute.Description);
} }
// TODO: validate stuff like duplicate names, multiple default commands, etc /// <inheritdoc />
public CommandSchema GetCommandSchema(Type commandType) public CommandSchema GetCommandSchema(Type commandType)
{ {
if (!commandType.Implements(typeof(ICommand))) if (!commandType.Implements(typeof(ICommand)))

View File

@@ -2,15 +2,22 @@
namespace CliFx.Services namespace CliFx.Services
{ {
/// <summary>
/// Implementation of <see cref="ICommandFactory"/> that uses a factory method to create commands.
/// </summary>
public class DelegateCommandFactory : ICommandFactory public class DelegateCommandFactory : ICommandFactory
{ {
private readonly Func<Type, ICommand> _factoryMethod; private readonly Func<Type, ICommand> _factoryMethod;
/// <summary>
/// Initializes an instance of <see cref="DelegateCommandFactory"/>.
/// </summary>
public DelegateCommandFactory(Func<Type, ICommand> factoryMethod) public DelegateCommandFactory(Func<Type, ICommand> factoryMethod)
{ {
_factoryMethod = factoryMethod; _factoryMethod = factoryMethod;
} }
/// <inheritdoc />
public ICommand CreateCommand(Type commandType) => _factoryMethod(commandType); public ICommand CreateCommand(Type commandType) => _factoryMethod(commandType);
} }
} }

View File

@@ -5,12 +5,20 @@ using CliFx.Models;
namespace CliFx.Services namespace CliFx.Services
{ {
/// <summary>
/// Extensions for <see cref="Services"/>
/// </summary>
public static class Extensions public static class Extensions
{ {
/// <summary>
/// Resolves command schemas for commands of specified types.
/// </summary>
public static IReadOnlyList<CommandSchema> GetCommandSchemas(this ICommandSchemaResolver resolver, public static IReadOnlyList<CommandSchema> GetCommandSchemas(this ICommandSchemaResolver resolver,
IReadOnlyList<Type> commandTypes) => IReadOnlyList<Type> commandTypes) => commandTypes.Select(resolver.GetCommandSchema).ToArray();
commandTypes.Select(resolver.GetCommandSchema).ToArray();
/// <summary>
/// Sets console foreground color, executes specified action, and sets the color back to the original value.
/// </summary>
public static void WithForegroundColor(this IConsole console, ConsoleColor foregroundColor, Action action) public static void WithForegroundColor(this IConsole console, ConsoleColor foregroundColor, Action action)
{ {
var lastColor = console.ForegroundColor; var lastColor = console.ForegroundColor;
@@ -21,6 +29,9 @@ namespace CliFx.Services
console.ForegroundColor = lastColor; console.ForegroundColor = lastColor;
} }
/// <summary>
/// Sets console background color, executes specified action, and sets the color back to the original value.
/// </summary>
public static void WithBackgroundColor(this IConsole console, ConsoleColor backgroundColor, Action action) public static void WithBackgroundColor(this IConsole console, ConsoleColor backgroundColor, Action action)
{ {
var lastColor = console.BackgroundColor; var lastColor = console.BackgroundColor;
@@ -31,6 +42,9 @@ namespace CliFx.Services
console.BackgroundColor = lastColor; console.BackgroundColor = lastColor;
} }
/// <summary>
/// Sets console foreground and background colors, executes specified action, and sets the colors back to the original values.
/// </summary>
public static void WithColors(this IConsole console, ConsoleColor foregroundColor, ConsoleColor backgroundColor, Action action) => public static void WithColors(this IConsole console, ConsoleColor foregroundColor, ConsoleColor backgroundColor, Action action) =>
console.WithForegroundColor(foregroundColor, () => console.WithBackgroundColor(backgroundColor, action)); console.WithForegroundColor(foregroundColor, () => console.WithBackgroundColor(backgroundColor, action));
} }

View File

@@ -2,8 +2,14 @@
namespace CliFx.Services namespace CliFx.Services
{ {
/// <summary>
/// Initializes new instances of <see cref="ICommand"/>.
/// </summary>
public interface ICommandFactory public interface ICommandFactory
{ {
/// <summary>
/// Initializes an instance of <see cref="ICommand"/> of specified type.
/// </summary>
ICommand CreateCommand(Type commandType); ICommand CreateCommand(Type commandType);
} }
} }

View File

@@ -2,8 +2,14 @@
namespace CliFx.Services namespace CliFx.Services
{ {
/// <summary>
/// Renders help text to the console.
/// </summary>
public interface ICommandHelpTextRenderer public interface ICommandHelpTextRenderer
{ {
/// <summary>
/// Renders help text using specified console and source information.
/// </summary>
void RenderHelpText(IConsole console, HelpTextSource source); void RenderHelpText(IConsole console, HelpTextSource source);
} }
} }

View File

@@ -2,8 +2,14 @@
namespace CliFx.Services namespace CliFx.Services
{ {
/// <summary>
/// Populates <see cref="ICommand"/> instances with input according to its schema.
/// </summary>
public interface ICommandInitializer public interface ICommandInitializer
{ {
/// <summary>
/// Populates an instance of <see cref="ICommand"/> with specified input according to specified schema.
/// </summary>
void InitializeCommand(ICommand command, CommandSchema schema, CommandInput input); void InitializeCommand(ICommand command, CommandSchema schema, CommandInput input);
} }
} }

View File

@@ -3,8 +3,14 @@ using CliFx.Models;
namespace CliFx.Services namespace CliFx.Services
{ {
/// <summary>
/// Parses command line arguments.
/// </summary>
public interface ICommandInputParser public interface ICommandInputParser
{ {
/// <summary>
/// Parses specified command line arguments.
/// </summary>
CommandInput ParseInput(IReadOnlyList<string> commandLineArguments); CommandInput ParseInput(IReadOnlyList<string> commandLineArguments);
} }
} }

View File

@@ -3,8 +3,14 @@ using CliFx.Models;
namespace CliFx.Services namespace CliFx.Services
{ {
/// <summary>
/// Converts input command options.
/// </summary>
public interface ICommandOptionInputConverter public interface ICommandOptionInputConverter
{ {
/// <summary>
/// Converts an option to specified target type.
/// </summary>
object ConvertOption(CommandOptionInput option, Type targetType); object ConvertOption(CommandOptionInput option, Type targetType);
} }
} }

View File

@@ -3,8 +3,14 @@ using CliFx.Models;
namespace CliFx.Services namespace CliFx.Services
{ {
/// <summary>
/// Resolves command schemas.
/// </summary>
public interface ICommandSchemaResolver public interface ICommandSchemaResolver
{ {
/// <summary>
/// Resolves schema of a command of specified type.
/// </summary>
CommandSchema GetCommandSchema(Type commandType); CommandSchema GetCommandSchema(Type commandType);
} }
} }

View File

@@ -3,24 +3,54 @@ using System.IO;
namespace CliFx.Services namespace CliFx.Services
{ {
/// <summary>
/// Abstraction for interacting with the console.
/// </summary>
public interface IConsole public interface IConsole
{ {
/// <summary>
/// Input stream (stdin).
/// </summary>
TextReader Input { get; } TextReader Input { get; }
/// <summary>
/// Whether the input stream is redirected.
/// </summary>
bool IsInputRedirected { get; } bool IsInputRedirected { get; }
/// <summary>
/// Output stream (stdout).
/// </summary>
TextWriter Output { get; } TextWriter Output { get; }
/// <summary>
/// Whether the output stream is redirected.
/// </summary>
bool IsOutputRedirected { get; } bool IsOutputRedirected { get; }
/// <summary>
/// Error stream (stderr).
/// </summary>
TextWriter Error { get; } TextWriter Error { get; }
/// <summary>
/// Whether the error stream is redirected.
/// </summary>
bool IsErrorRedirected { get; } bool IsErrorRedirected { get; }
/// <summary>
/// Current foreground color.
/// </summary>
ConsoleColor ForegroundColor { get; set; } ConsoleColor ForegroundColor { get; set; }
/// <summary>
/// Current background color.
/// </summary>
ConsoleColor BackgroundColor { get; set; } ConsoleColor BackgroundColor { get; set; }
/// <summary>
/// Resets foreground and background color to default values.
/// </summary>
void ResetColor(); void ResetColor();
} }
} }

View File

@@ -3,32 +3,44 @@ using System.IO;
namespace CliFx.Services namespace CliFx.Services
{ {
/// <summary>
/// Implementation of <see cref="IConsole"/> that wraps around <see cref="Console"/>.
/// </summary>
public class SystemConsole : IConsole public class SystemConsole : IConsole
{ {
/// <inheritdoc />
public TextReader Input => Console.In; public TextReader Input => Console.In;
/// <inheritdoc />
public bool IsInputRedirected => Console.IsInputRedirected; public bool IsInputRedirected => Console.IsInputRedirected;
/// <inheritdoc />
public TextWriter Output => Console.Out; public TextWriter Output => Console.Out;
/// <inheritdoc />
public bool IsOutputRedirected => Console.IsOutputRedirected; public bool IsOutputRedirected => Console.IsOutputRedirected;
/// <inheritdoc />
public TextWriter Error => Console.Error; public TextWriter Error => Console.Error;
/// <inheritdoc />
public bool IsErrorRedirected => Console.IsErrorRedirected; public bool IsErrorRedirected => Console.IsErrorRedirected;
/// <inheritdoc />
public ConsoleColor ForegroundColor public ConsoleColor ForegroundColor
{ {
get => Console.ForegroundColor; get => Console.ForegroundColor;
set => Console.ForegroundColor = value; set => Console.ForegroundColor = value;
} }
/// <inheritdoc />
public ConsoleColor BackgroundColor public ConsoleColor BackgroundColor
{ {
get => Console.BackgroundColor; get => Console.BackgroundColor;
set => Console.BackgroundColor = value; set => Console.BackgroundColor = value;
} }
/// <inheritdoc />
public void ResetColor() => Console.ResetColor(); public void ResetColor() => Console.ResetColor();
} }
} }

View File

@@ -3,24 +3,40 @@ using System.IO;
namespace CliFx.Services namespace CliFx.Services
{ {
/// <summary>
/// Implementation of <see cref="IConsole"/> that routes data to specified streams.
/// Does not leak to <see cref="Console"/> in any way.
/// Provides an isolated instance of <see cref="IConsole"/> which is useful for testing purposes.
/// </summary>
public class TestConsole : IConsole public class TestConsole : IConsole
{ {
/// <inheritdoc />
public TextReader Input { get; } public TextReader Input { get; }
/// <inheritdoc />
public bool IsInputRedirected => true; public bool IsInputRedirected => true;
/// <inheritdoc />
public TextWriter Output { get; } public TextWriter Output { get; }
/// <inheritdoc />
public bool IsOutputRedirected => true; public bool IsOutputRedirected => true;
/// <inheritdoc />
public TextWriter Error { get; } public TextWriter Error { get; }
/// <inheritdoc />
public bool IsErrorRedirected => true; public bool IsErrorRedirected => true;
/// <inheritdoc />
public ConsoleColor ForegroundColor { get; set; } = ConsoleColor.Gray; public ConsoleColor ForegroundColor { get; set; } = ConsoleColor.Gray;
/// <inheritdoc />
public ConsoleColor BackgroundColor { get; set; } = ConsoleColor.Black; public ConsoleColor BackgroundColor { get; set; } = ConsoleColor.Black;
/// <summary>
/// Initializes an instance of <see cref="TestConsole"/>.
/// </summary>
public TestConsole(TextReader input, TextWriter output, TextWriter error) public TestConsole(TextReader input, TextWriter output, TextWriter error)
{ {
Input = input; Input = input;
@@ -28,16 +44,25 @@ namespace CliFx.Services
Error = error; Error = error;
} }
/// <summary>
/// Initializes an instance of <see cref="TestConsole"/> using output stream (stdout) and error stream (stderr).
/// Input stream (stdin) is considered empty.
/// </summary>
public TestConsole(TextWriter output, TextWriter error) public TestConsole(TextWriter output, TextWriter error)
: this(TextReader.Null, output, error) : this(TextReader.Null, output, error)
{ {
} }
/// <summary>
/// Initializes an instance of <see cref="TestConsole"/> using output stream (stdout).
/// Input stream (stdin) and error stream (stderr) are considered empty.
/// </summary>
public TestConsole(TextWriter output) public TestConsole(TextWriter output)
: this(output, TextWriter.Null) : this(output, TextWriter.Null)
{ {
} }
/// <inheritdoc />
public void ResetColor() public void ResetColor()
{ {
ForegroundColor = ConsoleColor.Gray; ForegroundColor = ConsoleColor.Gray;