@@ -13,6 +13,17 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
1313 {
1414 context . RegisterPostInitializationOutput ( EmitConsoleAppTemplateSource ) ;
1515
16+ // ConsoleApp.Create(Action<IServiceCollection> configure)
17+ var hasDependencyInjection = context . MetadataReferencesProvider
18+ . Where ( x =>
19+ {
20+ return x . Display ? . EndsWith ( "Microsoft.Extensions.DependencyInjection.Abstractions.dll" ) ?? false ;
21+ } )
22+ . Collect ( )
23+ . Select ( ( x , ct ) => x . Any ( ) ) ;
24+
25+ context . RegisterSourceOutput ( hasDependencyInjection , EmitConsoleAppCreateConfigure ) ;
26+
1627 // ConsoleApp.Run
1728 var runSource = context . SyntaxProvider
1829 . CreateSyntaxProvider ( ( node , ct ) =>
@@ -81,13 +92,22 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
8192 . Where ( x =>
8293 {
8394 var model = x . Model . GetTypeInfo ( ( x . Node . Expression as MemberAccessExpressionSyntax ) ! . Expression , x . CancellationToken ) ;
84- return model . Type ? . Name == "ConsoleAppBuilder" ;
95+ return model . Type ? . Name is "ConsoleAppBuilder" ;
8596 } )
8697 . WithTrackingName ( "ConsoleApp.Builder.1_Where" )
8798 . Collect ( )
8899 . Select ( ( x , ct ) => new CollectBuilderContext ( x , ct ) )
89100 . WithTrackingName ( "ConsoleApp.Builder.2_Collect" ) ;
90101
102+ // WIP
103+ //var registerCommands = context.SyntaxProvider.ForAttributeWithMetadataName("ConsoleAppFramework.RegisterCommandsAttribute",
104+ // (node, token) => true,
105+ // (ctx, token) => ctx)
106+ // .Collect()
107+ // .Select((x, token) => new CollectBuilderContext(default, token));
108+
109+ //var lr = builderSource.Combine(registerCommands); // combine with registerCommands
110+
91111 context . RegisterSourceOutput ( builderSource , EmitConsoleAppBuilder ) ;
92112 }
93113
@@ -673,26 +693,37 @@ static void EmitConsoleAppBuilder(SourceProductionContext sourceProductionContex
673693 emitter . EmitHelp ( help , commandIds ! ) ;
674694 }
675695 sourceProductionContext . AddSource ( "ConsoleApp.Builder.Help.g.cs" , help . ToString ( ) ) ;
696+ }
676697
677- // emit Create(IServiceCollection) if exists Microsoft.Extensions.DependencyInjection.ServiceCollection
678- if ( collectBuilderContext . HasDependencyInjectionReference )
698+ static void EmitConsoleAppCreateConfigure ( SourceProductionContext sourceProductionContext , bool hasDependencyInjection )
699+ {
700+ var code = """
701+ // <auto-generated/>
702+ #nullable enable
703+ namespace ConsoleAppFramework;
704+
705+ using System;
706+ using Microsoft.Extensions.DependencyInjection;
707+
708+ internal static partial class ConsoleApp
709+ {
710+ public static ConsoleAppBuilder Create(Action<IServiceCollection> configure)
711+ {
712+ var services = new ServiceCollection();
713+ configure(services);
714+ ConsoleApp.ServiceProvider = services.BuildServiceProvider();
715+ return ConsoleApp.Create();
716+ }
717+ }
718+ """ ;
719+
720+ // emit empty if not exists
721+ if ( ! hasDependencyInjection )
679722 {
680- var runBuilder = new SourceBuilder ( 0 ) ;
681- runBuilder . AppendLine ( GeneratedCodeHeader ) ;
682- runBuilder . AppendLine ( "using Microsoft.Extensions.DependencyInjection" ) ;
683- runBuilder . AppendLine ( ) ;
684- using ( runBuilder . BeginBlock ( "internal static partial class ConsoleApp" ) )
685- {
686- using ( runBuilder . BeginBlock ( "public static ConsoleAppBuilder Create(Action<IServiceCollection> configure)" ) )
687- {
688- runBuilder . AppendLine ( "var services = new ServiceCollection();" ) ;
689- runBuilder . AppendLine ( "configure(services);" ) ;
690- runBuilder . AppendLine ( "ConsoleApp.ServiceProvider = services.BuildServiceProvider();" ) ;
691- runBuilder . AppendLine ( "return ConsoleApp.Create();" ) ;
692- }
693- }
694- sourceProductionContext . AddSource ( "ConsoleApp.Builder.Run.g.cs" , runBuilder . ToString ( ) ) ;
723+ code = "" ;
695724 }
725+
726+ sourceProductionContext . AddSource ( "ConsoleApp.Create.g.cs" , code ) ;
696727 }
697728
698729 class CommanContext ( Command ? command , bool isAsync , DiagnosticReporter diagnosticReporter , InvocationExpressionSyntax node ) : IEquatable < CommanContext >
@@ -720,18 +751,12 @@ class CollectBuilderContext : IEquatable<CollectBuilderContext>
720751 public CancellationToken CancellationToken { get ; }
721752 public bool HasRun { get ; }
722753 public bool HasRunAsync { get ; }
723- public bool HasDependencyInjectionReference { get ; }
724754
725755 public CollectBuilderContext ( ImmutableArray < BuilderContext > contexts , CancellationToken cancellationToken )
726756 {
727757 this . DiagnosticReporter = new DiagnosticReporter ( ) ;
728758 this . CancellationToken = cancellationToken ;
729759
730- if ( contexts . Length == 0 )
731- {
732- return ;
733- }
734-
735760 // validation, invoke in loop is not allowed.
736761 foreach ( var item in contexts )
737762 {
@@ -832,18 +857,58 @@ public CollectBuilderContext(ImmutableArray<BuilderContext> contexts, Cancellati
832857 this . Commands = commands1 . Concat ( commands2 ! ) . ToArray ( ) ! ; // not null if no diagnostics
833858 this . HasRun = methodGroup [ "Run" ] . Any ( ) ;
834859 this . HasRunAsync = methodGroup [ "RunAsync" ] . Any ( ) ;
835-
836- var model = contexts [ 0 ] . Model ;
837- var serviceCollectionSymbol = model . Compilation . GetTypeByMetadataName ( "Microsoft.Extensions.DependencyInjection.ServiceCollection" ) ;
838- this . HasDependencyInjectionReference = serviceCollectionSymbol != null ;
860+ }
861+
862+ // from ForAttributeWithMetadataName
863+ public void AddRegisterAttributes ( ImmutableArray < GeneratorAttributeSyntaxContext > contexts )
864+ {
865+ if ( contexts . Length == 0 )
866+ {
867+ return ;
868+ }
869+
870+ //var names = new HashSet<string>();
871+
872+ //var commands2 = methodGroup["Add<T>"]
873+ // .SelectMany(x =>
874+ // {
875+ // var wellKnownTypes = new WellKnownTypes(x.Model.Compilation);
876+ // var parser = new Parser(DiagnosticReporter, x.Node, x.Model, wellKnownTypes, DelegateBuildType.None, globalFilters);
877+ // var commands = parser.ParseAndValidateForBuilderClassRegistration();
878+
879+ // // validation command name duplicate
880+ // foreach (var command in commands)
881+ // {
882+ // if (command != null && !names.Add(command.Name))
883+ // {
884+ // DiagnosticReporter.ReportDiagnostic(DiagnosticDescriptors.DuplicateCommandName, x.Node.GetLocation(), command!.Name);
885+ // return [null];
886+ // }
887+ // }
888+
889+ // return commands;
890+ // });
891+
892+ //if (DiagnosticReporter.HasDiagnostics)
893+ //{
894+ // return;
895+ //}
896+
897+ //// set properties
898+ //this.Commands = commands1.Concat(commands2!).ToArray()!; // not null if no diagnostics
899+ //this.HasRun = methodGroup["Run"].Any();
900+ //this.HasRunAsync = methodGroup["RunAsync"].Any();
901+
902+ //var model = contexts[0].Model;
903+ //var serviceCollectionSymbol = model.Compilation.GetTypeByMetadataName("Microsoft.Extensions.DependencyInjection.ServiceCollection");
904+ //this.HasDependencyInjectionReference = serviceCollectionSymbol != null;
839905 }
840906
841907 public bool Equals ( CollectBuilderContext other )
842908 {
843909 if ( DiagnosticReporter . HasDiagnostics || other . DiagnosticReporter . HasDiagnostics ) return false ;
844910 if ( HasRun != other . HasRun ) return false ;
845911 if ( HasRunAsync != other . HasRunAsync ) return false ;
846- if ( HasDependencyInjectionReference != other . HasDependencyInjectionReference ) return false ;
847912
848913 return Commands . AsSpan ( ) . SequenceEqual ( other . Commands ) ;
849914 }
0 commit comments