Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace runtime reflection with compile-time source generator #8

Merged
merged 52 commits into from
Jun 11, 2024

Conversation

wjrogers
Copy link
Member

@wjrogers wjrogers commented Sep 15, 2023

Add a new project, XO.Console.Cli.Analyzers, that generates source for both commands and parameters types at compile time. Support declarative configuration of command hierarchies using a scheme similar to the 'click' Python library.

TODO

  • Restore option and attribute name validation
  • Expand test suite
  • Update usage documentation
  • Add package README.md
  • Document breaking changes
  • Don't generate CommandParametersFactory if there are no types defined
  • AddCommandApp(this IServiceCollection services)

Enable the Trimmable analyzers, decorate reflection-based methods with
attributes, and remove or rework incompatible features.

* Remove 'AddCommandsFromAssembly' and friends because they are not
  compatible with trimming.

* Remove support for TypeConverter-based parsing of parameter values.

* Remove support for reflection-based Parse() and ctor(string) parsing
  of parameter values, but replace the most common cases with
  hard-coded default converters.
Move types that model application configuration or state to the new
namespace XO.Console.Cli.Model. Types in this namespace may be public,
but should not be part of the core consumer-facing API.
Differentiate types by 'Implementation' vs 'Infrastructure' instead of
by access modifier.
Make CommandBuilder public, and shuffle around interfaces to remove the
torturous default interface implementation of 'AddCommand' and friends.
The code generated by the analyzer project depends on the core library,
so it's very difficult to debug generator failures when the core
library won't build because the generator's failing! Instead,
hand-write a factory implementation for CommandParameters.
Improve declarative configuration to support sub-commands using a scheme
similar to the 'click' Python library: apply CommandBranchAttribute to
a custom subclass of CommandAttribute, then use the custom attribute
class to declare sub-commands.

* Add a 'Description' property to CommandAttribute instead of using the
  built-in DescriptionAttribute. All declarative configuration for a
  command comes from a single instance of CommandAttribute (or, for
  sub-commands, a subclass thereof).

* CommandAttribute is NOT required for imperative runtime configuration
  and has no effect on it. No surprises or magic when adding commands
  at runtime!

* Improve source generator feedback and performance.
Use experience from writing the CommandBuilder source generator to
improve performance and reliability.
@codecov
Copy link

codecov bot commented Sep 15, 2023

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

Thanks for integrating Codecov - We've got you covered ☂️

wjrogers added 23 commits May 21, 2024 13:59
Instead of generating the same builder-pattern code a user would write,
construct each ConfiguredCommand directly.
Clarify the generator pipeline and the interaction between each step,
improve caching efficiency where possible, and split the code up into
separate files for readability. Simplify the code generation logic for
declaratively-configured commands.
DescribeParameters returns the complete list of arguments and options
for derived parameters types, so the parser needs to keep track of
which ones have already been added to the state. Add a string
identifying the declaring type and property name to the generated
parameters models.
@wjrogers
Copy link
Member Author

Breaking Changes

  • For a given command, declarative configuration with CommandAttribute and imperative configuration with ICommandBuilder are mutually exclusive. CommandAttribute automatically adds the target command type to the application, and it has new properties that provide access to all command configuration options. (You can still mix declarative and imperative configuration of different commands in the same application. Be sure to omit CommandAttribute from any type you want to configure through the builder.)
  • Instead of using DescriptionAttribute to set the help text for commands, arguments, and options, use the Description property of CommandAttribute, CommandArgumentAttribute, and CommandOptionAttribute, respectively.
  • Support for typed global options has been removed. ICommandContext provides access to the raw string values of global options.
  • Some infrastructure types have been moved, renamed, or deleted.

@wjrogers wjrogers marked this pull request as ready for review June 11, 2024 04:01
@wjrogers wjrogers merged commit 4356713 into main Jun 11, 2024
3 checks passed
@wjrogers wjrogers deleted the feature-trimmable branch June 11, 2024 04:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant