|
3 | 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; |
4 | 4 | using System.Collections.Immutable; |
5 | 5 | using System.ComponentModel.Design; |
| 6 | +using System.Linq.Expressions; |
6 | 7 | using System.Reflection; |
| 8 | +using System.Runtime.CompilerServices; |
7 | 9 |
|
8 | 10 | namespace ConsoleAppFramework; |
9 | 11 |
|
@@ -136,7 +138,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) |
136 | 138 |
|
137 | 139 | var expr = invocationExpression.Expression as MemberAccessExpressionSyntax; |
138 | 140 | var methodName = expr?.Name.Identifier.Text; |
139 | | - if (methodName is "Add" or "UseFilter" or "Run" or "RunAsync") |
| 141 | + if (methodName is "Add" or "UseFilter" or "Run" or "RunAsync" or "AddGlobalOption" or "AddRequiredGlobalOption") |
140 | 142 | { |
141 | 143 | return true; |
142 | 144 | } |
@@ -292,6 +294,8 @@ static void EmitConsoleAppBuilder(SourceProductionContext sourceProductionContex |
292 | 294 | using (help.BeginBlock("internal static partial class ConsoleApp")) |
293 | 295 | using (help.BeginBlock("internal partial class ConsoleAppBuilder")) |
294 | 296 | { |
| 297 | + // TODO: collectBuilderContext.GlobalOptions |
| 298 | + |
295 | 299 | var emitter = new Emitter(); |
296 | 300 | emitter.EmitHelp(help, commandIds!); |
297 | 301 | } |
@@ -369,6 +373,8 @@ class CollectBuilderContext : IEquatable<CollectBuilderContext> |
369 | 373 | FilterInfo[]? globalFilters { get; } |
370 | 374 | ConsoleAppFrameworkGeneratorOptions generatorOptions { get; } |
371 | 375 |
|
| 376 | + public GlobalOptionInfo[] GlobalOptions { get; } = []; |
| 377 | + |
372 | 378 | public CollectBuilderContext(ConsoleAppFrameworkGeneratorOptions generatorOptions, ImmutableArray<(BuilderContext, string?, SymbolKind?)> contexts, CancellationToken cancellationToken) |
373 | 379 | { |
374 | 380 | this.DiagnosticReporter = new DiagnosticReporter(); |
@@ -475,6 +481,82 @@ public CollectBuilderContext(ConsoleAppFrameworkGeneratorOptions generatorOption |
475 | 481 | return commands; |
476 | 482 | }); |
477 | 483 |
|
| 484 | + GlobalOptions = methodGroup["AddGlobalOption"].Select(x => (context: x.Item1, required: false)) |
| 485 | + .Concat(methodGroup["AddRequiredGlobalOption"].Select(x => (context: x.Item1, required: true))) |
| 486 | + .Select(x => |
| 487 | + { |
| 488 | + var node = x.context.Node; |
| 489 | + var model = x.context.Model; |
| 490 | + |
| 491 | + EquatableTypeSymbol typeSymbol = default!; |
| 492 | + string name = ""; |
| 493 | + string description = ""; |
| 494 | + bool isRequired = x.required; |
| 495 | + object? defaultValue = null; |
| 496 | + |
| 497 | + if (node.Expression is MemberAccessExpressionSyntax memberAccess && memberAccess.Name is GenericNameSyntax genericName) |
| 498 | + { |
| 499 | + var typeArgument = genericName.TypeArgumentList.Arguments[0]; |
| 500 | + typeSymbol = new(model.GetTypeInfo(typeArgument).Type!); // TODO: not ! |
| 501 | + } |
| 502 | + |
| 503 | + var arguments = node.ArgumentList.Arguments; |
| 504 | + if (arguments.Count >= 2) // string name |
| 505 | + { |
| 506 | + var constant = model.GetConstantValue(arguments[1].Expression); // TODO: check |
| 507 | + name = constant.Value!.ToString(); |
| 508 | + } |
| 509 | + |
| 510 | + |
| 511 | + // TODO: use named argument??? |
| 512 | + |
| 513 | + if (arguments.Count >= 3) // string description = "" |
| 514 | + { |
| 515 | + // is defaultValue??? |
| 516 | + |
| 517 | + |
| 518 | + var constant = model.GetConstantValue(arguments[2].Expression); |
| 519 | + description = constant.Value!.ToString(); |
| 520 | + } |
| 521 | + |
| 522 | + if (!isRequired) |
| 523 | + { |
| 524 | + if (arguments.Count >= 4) // T defaultValue = default(T) |
| 525 | + { |
| 526 | + var constant = model.GetConstantValue(arguments[3].Expression); |
| 527 | + defaultValue = constant.Value!; |
| 528 | + } |
| 529 | + else |
| 530 | + { |
| 531 | + // set defaultValue from |
| 532 | + var symbol = model.GetSymbolInfo(node).Symbol; |
| 533 | + if (symbol is IMethodSymbol methodSymbol) |
| 534 | + { |
| 535 | + var parameter = methodSymbol.Parameters[3]; |
| 536 | + if (parameter.HasExplicitDefaultValue) |
| 537 | + { |
| 538 | + defaultValue = parameter.ExplicitDefaultValue; |
| 539 | + } |
| 540 | + else |
| 541 | + { |
| 542 | + |
| 543 | + } |
| 544 | + } |
| 545 | + } |
| 546 | + } |
| 547 | + |
| 548 | + return new GlobalOptionInfo |
| 549 | + { |
| 550 | + Type = typeSymbol, |
| 551 | + IsRequired = isRequired, |
| 552 | + Name = name, |
| 553 | + Description = description, |
| 554 | + DefaultValue = defaultValue |
| 555 | + }; |
| 556 | + }) |
| 557 | + .Where(x => x != null) |
| 558 | + .ToArray(); |
| 559 | + |
478 | 560 | if (DiagnosticReporter.HasDiagnostics) |
479 | 561 | { |
480 | 562 | return; |
|
0 commit comments