2525namespace Intent . Modules . AzureFunctions . Templates . Isolated . Program
2626{
2727 [ IntentManaged ( Mode . Fully , Body = Mode . Merge ) ]
28- public partial class ProgramTemplate : CSharpTemplateBase < object > , ICSharpFileBuilderTemplate
28+ public partial class ProgramTemplate : CSharpTemplateBase < object > , ICSharpFileBuilderTemplate , IProgramTemplate , IProgramFile
2929 {
3030 public const string TemplateId = "Intent.AzureFunctions.Isolated.Program" ;
3131
@@ -131,16 +131,16 @@ public ProgramTemplate(IOutputTarget outputTarget, object model = null) : base(T
131131 globalExceptionConfigStatement . AddStatement < CSharpLambdaBlock , CSharpStatement > ( globalExceptionStatement ) ;
132132 }
133133
134- var hostConfigStatement = new CSharpStatement ( "new HostBuilder()" )
135- . AddInvocation ( "ConfigureFunctionsWebApplication" , i => i
134+ var hostConfigStatement = new CSharpMethodChainStatement ( "new HostBuilder()" )
135+ . AddChainStatement ( new CSharpInvocationStatement ( "ConfigureFunctionsWebApplication" ) . WithoutSemicolon ( )
136136 . OnNewLine ( )
137137 . AddArgument ( globalExceptionConfigStatement )
138138 )
139- . AddInvocation ( "ConfigureServices" , cs => cs
139+ . AddChainStatement ( new CSharpInvocationStatement ( "ConfigureServices" ) . WithoutSemicolon ( )
140140 . OnNewLine ( )
141141 . AddArgument ( configStatements )
142142 )
143- . AddInvocation ( "Build" , i => i . OnNewLine ( ) ) ;
143+ . AddChainStatement ( new CSharpInvocationStatement ( "Build" ) . OnNewLine ( ) ) ;
144144
145145 tls . AddStatement ( new CSharpAssignmentStatement ( "var host" , hostConfigStatement ) ) ;
146146 tls . AddStatement ( "host.Run();" , s => s . SeparatedFromPrevious ( ) ) ;
@@ -496,6 +496,10 @@ private record ServiceConfigurationContext(string Configuration, string Services
496496 [ IntentManaged ( Mode . Fully ) ]
497497 public CSharpFile CSharpFile { get ; }
498498
499+ public bool UsesMinimalHostingModel => true ;
500+
501+ public IProgramFile ProgramFile => this ;
502+
499503 [ IntentManaged ( Mode . Fully ) ]
500504 protected override CSharpFileConfig DefineFileConfig ( )
501505 {
@@ -507,5 +511,131 @@ public override string TransformText()
507511 {
508512 return CSharpFile . ToString ( ) ;
509513 }
514+
515+ public IProgramFile ConfigureHostBuilderChainStatement ( string methodName , IEnumerable < string > parameters , IProgramFile . HostBuilderChainStatementConfiguration configure = null , int priority = 0 )
516+ {
517+ var parametersAsArray = parameters . ToArray ( ) ;
518+
519+ var hostBuilder = ( IHasCSharpStatements ? ) CSharpFile . TopLevelStatements . Statements . FirstOrDefault ( ) ;
520+
521+ var hostBuilderChain = ( CSharpMethodChainStatement ) ( ( CSharpAssignmentStatement ) hostBuilder ) . Rhs ;
522+ var appConfigurationBlock = ( CSharpInvocationStatement ) hostBuilderChain
523+ . FindStatement ( stmt => stmt . ToString ( ) ! . StartsWith ( methodName ) ) ;
524+
525+ var lambda = EnsureWeHaveEditableLambdaBlock ( appConfigurationBlock ) ;
526+
527+ if ( appConfigurationBlock == null )
528+ {
529+ lambda = new EditableCSharpLambdaBlock ( "()" ) ;
530+
531+ appConfigurationBlock = new CSharpInvocationStatement ( methodName )
532+ . WithoutSemicolon ( )
533+ . AddArgument ( lambda ) ;
534+ appConfigurationBlock . AddMetadata ( "priority" , priority ) ;
535+
536+
537+ var insertAboveStatement = hostBuilderChain . Statements . FirstOrDefault ( s =>
538+ {
539+ if ( s . TryGetMetadata < int > ( "priority" , out var statmentPriority ) )
540+ {
541+ return statmentPriority > priority ;
542+ }
543+ else
544+ {
545+ return priority < 0 ;
546+ }
547+ } ) ;
548+ if ( insertAboveStatement == null )
549+ {
550+ insertAboveStatement = hostBuilderChain . Statements . Last ( ) ;
551+ }
552+ insertAboveStatement . InsertAbove ( appConfigurationBlock ) ;
553+ }
554+
555+ SetParameters ( lambda , parametersAsArray ) ;
556+ configure ? . Invoke ( lambda , ( IReadOnlyList < string > ) lambda . Metadata [ "parameters" ] ) ;
557+ return this ;
558+ }
559+
560+ static void SetParameters ( EditableCSharpLambdaBlock lambda , IReadOnlyList < string > requestedParameters )
561+ {
562+ if ( ! lambda . TryGetMetadata < List < string > > ( "parameters" , out var parameters ) )
563+ {
564+ parameters = new List < string > ( ) ;
565+ lambda . AddMetadata ( "parameters" , parameters ) ;
566+ }
567+
568+ if ( parameters . Count >= requestedParameters . Count )
569+ {
570+ return ;
571+ }
572+
573+ parameters . AddRange ( requestedParameters . Skip ( parameters . Count ) ) ;
574+
575+ lambda . UpdateText ( parameters . Count == 1
576+ ? parameters [ 0 ]
577+ : $ "({ string . Join ( ", " , parameters ) } )") ;
578+ }
579+
580+
581+ public IProgramFile AddHostBuilderConfigurationStatement < TStatement > ( TStatement statement , Action < TStatement > configure = null , int priority = 0 ) where TStatement : CSharpStatement
582+ {
583+ throw new NotImplementedException ( ) ;
584+ }
585+
586+ public IProgramFile ConfigureMainStatementsBlock ( Action < IHasCSharpStatements > configure )
587+ {
588+ throw new NotImplementedException ( ) ;
589+ }
590+
591+ public IProgramFile AddMethod ( string returnType , string name , Action < IStartupMethod > configure = null , int priority = 0 )
592+ {
593+ throw new NotImplementedException ( ) ;
594+ }
595+
596+ static EditableCSharpLambdaBlock EnsureWeHaveEditableLambdaBlock ( CSharpInvocationStatement appConfigurationBlock )
597+ {
598+ EditableCSharpLambdaBlock ? lambda ;
599+ var configBlockStatement = appConfigurationBlock ? . Statements . First ( ) ;
600+ if ( configBlockStatement is CSharpLambdaBlock lambdaConfig and not EditableCSharpLambdaBlock )
601+ {
602+ lambda = EditableCSharpLambdaBlock . CreateFrom ( lambdaConfig ) ;
603+ appConfigurationBlock ! . Statements . RemoveAt ( 0 ) ;
604+ appConfigurationBlock . AddArgument ( lambda ) ;
605+ }
606+ else
607+ {
608+ lambda = ( EditableCSharpLambdaBlock ? ) appConfigurationBlock ? . Statements . First ( ) ;
609+ }
610+
611+ return lambda ;
612+ }
613+
614+
615+ private class EditableCSharpLambdaBlock : CSharpLambdaBlock
616+ {
617+ public EditableCSharpLambdaBlock ( string invocation ) : base ( invocation ) { }
618+
619+ public void UpdateText ( string text ) => Text = text ;
620+
621+ public static EditableCSharpLambdaBlock CreateFrom ( CSharpLambdaBlock original )
622+ {
623+ var update = new EditableCSharpLambdaBlock ( original . Text ) ;
624+ if ( original . HasExpressionBody )
625+ {
626+ update . WithExpressionBody ( original . Statements . First ( ) ) ;
627+ }
628+ else
629+ {
630+ foreach ( var statement in original . Statements )
631+ {
632+ update . Statements . Add ( statement ) ;
633+ }
634+ }
635+
636+ return update ;
637+ }
638+ }
639+
510640 }
511641}
0 commit comments