public IEnumerable <ClassDeclarationSyntax> CreateAreaClasses(ILookup <string, ControllerDefinition> areaControllers) { foreach (var area in areaControllers.Where(a => !string.IsNullOrEmpty(a.Key)).OrderBy(a => a.Key)) { var areaClass = ClassDeclaration(area.Key + "AreaClass") .WithModifiers(SyntaxKind.PublicKeyword, SyntaxKind.PartialKeyword) .WithGeneratedNonUserCodeAttributes() .WithStringField("Name", area.Key, false, SyntaxKind.PublicKeyword, SyntaxKind.ReadOnlyKeyword) .AddMembers(area .OrderBy(c => c.Namespace == null).ThenBy(c => c.Name) .Select(c => SyntaxNodeHelpers.CreateFieldWithDefaultInitializer( c.Name, c.FullyQualifiedGeneratedName, c.FullyQualifiedR4ClassName ?? c.FullyQualifiedGeneratedName, SyntaxKind.PublicKeyword, SyntaxKind.ReadOnlyKeyword)) .ToArray <MemberDeclarationSyntax>()); yield return(areaClass); } }
public void Generate(CSharpCompilation compilation, string projectRoot) { // create static MVC class and add controller fields var mvcStaticClass = SyntaxNodeHelpers.CreateClass(_settings.HelpersPrefix, null, SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword, SyntaxKind.PartialKeyword) .WithAttributes(SyntaxNodeHelpers.CreateGeneratedCodeAttribute(), SyntaxNodeHelpers.CreateDebugNonUserCodeAttribute()); // R4MVC namespace used for the areas and Dummy class var r4Namespace = SyntaxNodeHelpers.CreateNamespace(_settings.R4MvcNamespace) // add the dummy class using in the derived controller partial class .WithDummyClass(); var areaClasses = new Dictionary <string, ClassDeclarationSyntax>(); var controllers = _controllerRewriter.RewriteControllers(compilation, R4MvcFileName); var controllerDetails = controllers .Where(c => !c.SyntaxTree.FilePath.EndsWith(".generated.cs")) .Select(c => { var @namespace = c.Ancestors().OfType <NamespaceDeclarationSyntax>().First().Name.ToFullString().Trim(); var model = compilation.GetSemanticModel(c.SyntaxTree); var controllerSymbol = model.GetDeclaredSymbol(c); var controllerName = controllerSymbol.Name.TrimEnd("Controller"); var areaName = _controllerGenerator.GetControllerArea(controllerSymbol); return(new { FilePath = c.SyntaxTree.FilePath, Namespace = @namespace, Name = controllerName, Area = areaName, Symbol = controllerSymbol, }); }); var namespaceGroups = controllerDetails.GroupBy(c => c.Namespace); var rootControllerNames = controllerDetails.Where(c => string.IsNullOrEmpty(c.Area)).Select(c => c.Name).ToArray(); var allViewFiles = _viewLocator.FindViews(projectRoot); var generatedControllers = new List <NamespaceDeclarationSyntax>(); foreach (var nameGroup in namespaceGroups) { var namespaceNode = SyntaxNodeHelpers.CreateNamespace(nameGroup.Key); foreach (var controller in nameGroup) { var areaKey = rootControllerNames.Contains(controller.Area) ? controller.Area + "Area" : controller.Area; var genControllerClass = _controllerGenerator.GeneratePartialController(controller.Symbol, areaKey, controller.Area, controller.Name, projectRoot); var r4ControllerClass = _controllerGenerator.GenerateR4Controller(controller.Symbol); namespaceNode = namespaceNode .AddMembers(genControllerClass, r4ControllerClass); if (_settings.SplitIntoMutipleFiles) { var controllerFile = NewCompilationUnit() .AddMembers(namespaceNode); CompleteAndWriteFile(controllerFile, controller.FilePath.TrimEnd(".cs") + ".generated.cs"); namespaceNode = SyntaxNodeHelpers.CreateNamespace(nameGroup.Key); } if (!string.IsNullOrEmpty(controller.Area)) { if (!areaClasses.ContainsKey(controller.Area)) { string areaClass = controller.Area + "AreaClass"; areaClasses[controller.Area] = SyntaxNodeHelpers.CreateClass(areaClass, null, SyntaxKind.PublicKeyword); // change to field and property mvcStaticClass = mvcStaticClass.AddMembers( SyntaxNodeHelpers.CreateFieldWithDefaultInitializer("s_" + areaKey, areaClass, SyntaxKind.StaticKeyword, SyntaxKind.ReadOnlyKeyword), SyntaxNodeHelpers.CreateProperty(areaKey, areaClass, IdentifierName("s_" + areaKey), SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword)); } areaClasses[controller.Area] = areaClasses[controller.Area].AddMembers( SyntaxNodeHelpers.CreateFieldWithDefaultInitializer( controller.Name, $"{nameGroup.Key}.{genControllerClass.Identifier}", $"{nameGroup.Key}.{r4ControllerClass.Identifier}", SyntaxKind.PublicKeyword, SyntaxKind.ReadOnlyKeyword)); } else { mvcStaticClass = mvcStaticClass.AddMembers( SyntaxNodeHelpers.CreateFieldWithDefaultInitializer( controller.Name, $"{nameGroup.Key}.{genControllerClass.Identifier}", $"{nameGroup.Key}.{r4ControllerClass.Identifier}", SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword, SyntaxKind.ReadOnlyKeyword)); } } if (!_settings.SplitIntoMutipleFiles) { generatedControllers.Add(namespaceNode); } } var views = _viewLocator.FindViews(projectRoot) .GroupBy(v => new { v.AreaName, v.ControllerName }); foreach (var viewSet in views) { if (controllerDetails.Any(c => c.Area == viewSet.Key.AreaName && c.Name == viewSet.Key.ControllerName)) { continue; } var className = !string.IsNullOrEmpty(viewSet.Key.AreaName) ? $"{viewSet.Key.AreaName}Area_{viewSet.Key.ControllerName}ControllerClass" : $"{viewSet.Key.ControllerName}ControllerClass"; var controllerClass = SyntaxNodeHelpers.CreateClass(className, null, SyntaxKind.PublicKeyword) .WithViewsClass(viewSet.Key.ControllerName, viewSet.Key.AreaName, viewSet); r4Namespace = r4Namespace.AddMembers(controllerClass); if (!string.IsNullOrEmpty(viewSet.Key.AreaName)) { areaClasses[viewSet.Key.AreaName] = areaClasses[viewSet.Key.AreaName].AddMembers( SyntaxNodeHelpers.CreateFieldWithDefaultInitializer( viewSet.Key.ControllerName, $"{_settings.R4MvcNamespace}.{className}", $"{_settings.R4MvcNamespace}.{className}", SyntaxKind.PublicKeyword, SyntaxKind.ReadOnlyKeyword)); } else { mvcStaticClass = mvcStaticClass.AddMembers( SyntaxNodeHelpers.CreateFieldWithDefaultInitializer( viewSet.Key.ControllerName, $"{_settings.R4MvcNamespace}.{className}", $"{_settings.R4MvcNamespace}.{className}", SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword, SyntaxKind.ReadOnlyKeyword)); } } r4Namespace = r4Namespace.AddMembers(areaClasses.Values.ToArray()); var staticFileNode = _staticFileGenerator.GenerateStaticFiles(projectRoot); var actionResultClass = SyntaxNodeHelpers.CreateClass(Constants.ActionResultClass, null, SyntaxKind.InternalKeyword, SyntaxKind.PartialKeyword) .WithBaseTypes("ActionResult", "IR4MvcActionResult") .WithMethods(ConstructorDeclaration(Constants.ActionResultClass) .WithModifiers(SyntaxKind.PublicKeyword) .AddParameterListParameters( Parameter(Identifier("area")).WithType(SyntaxNodeHelpers.PredefinedStringType()), Parameter(Identifier("controller")).WithType(SyntaxNodeHelpers.PredefinedStringType()), Parameter(Identifier("action")).WithType(SyntaxNodeHelpers.PredefinedStringType()), Parameter(Identifier("protocol")).WithType(SyntaxNodeHelpers.PredefinedStringType()) .WithDefault(EqualsValueClause(LiteralExpression(SyntaxKind.NullLiteralExpression)))) .WithBody( Block( ExpressionStatement( InvocationExpression( SyntaxNodeHelpers.MemberAccess("this", "InitMVCT4Result")) .WithArgumentList( IdentifierName("area"), IdentifierName("controller"), IdentifierName("action"), IdentifierName("protocol")))))) .WithAutoStringProperty("Controller", SyntaxKind.PublicKeyword) .WithAutoStringProperty("Action", SyntaxKind.PublicKeyword) .WithAutoStringProperty("Protocol", SyntaxKind.PublicKeyword) .WithAutoProperty("RouteValueDictionary", IdentifierName("RouteValueDictionary"), SyntaxKind.PublicKeyword); var jsonResultClass = SyntaxNodeHelpers.CreateClass(Constants.JsonResultClass, null, SyntaxKind.InternalKeyword, SyntaxKind.PartialKeyword) .WithBaseTypes("JsonResult", "IR4MvcActionResult") .WithMethods(ConstructorDeclaration(Constants.JsonResultClass) .WithModifiers(SyntaxKind.PublicKeyword) .AddParameterListParameters( Parameter(Identifier("area")).WithType(SyntaxNodeHelpers.PredefinedStringType()), Parameter(Identifier("controller")).WithType(SyntaxNodeHelpers.PredefinedStringType()), Parameter(Identifier("action")).WithType(SyntaxNodeHelpers.PredefinedStringType()), Parameter(Identifier("protocol")).WithType(SyntaxNodeHelpers.PredefinedStringType()) .WithDefault(EqualsValueClause(LiteralExpression(SyntaxKind.NullLiteralExpression)))) .WithInitializer(ConstructorInitializer(SyntaxKind.BaseConstructorInitializer, ArgumentList(SingletonSeparatedList(Argument(LiteralExpression(SyntaxKind.NullLiteralExpression)))))) .WithBody( Block( ExpressionStatement( InvocationExpression( SyntaxNodeHelpers.MemberAccess("this", "InitMVCT4Result")) .WithArgumentList( IdentifierName("area"), IdentifierName("controller"), IdentifierName("action"), IdentifierName("protocol")))))) .WithAutoStringProperty("Controller", SyntaxKind.PublicKeyword) .WithAutoStringProperty("Action", SyntaxKind.PublicKeyword) .WithAutoStringProperty("Protocol", SyntaxKind.PublicKeyword) .WithAutoProperty("RouteValueDictionary", IdentifierName("RouteValueDictionary"), SyntaxKind.PublicKeyword); var r4mvcNode = NewCompilationUnit() .AddMembers(generatedControllers.Cast <MemberDeclarationSyntax>().ToArray()) .AddMembers( staticFileNode, r4Namespace, mvcStaticClass, actionResultClass, jsonResultClass); CompleteAndWriteFile(r4mvcNode, Path.Combine(projectRoot, R4MvcGenerator.R4MvcFileName)); }
public void Generate(string projectRoot, IList <ControllerDefinition> controllers) { var areaControllers = controllers.ToLookup(c => c.Area); // Processing controllers, generating partial and derived controller classes for R4Mvc var generatedControllers = new List <NamespaceDeclarationSyntax>(); foreach (var namespaceGroup in controllers.Where(c => c.Namespace != null).GroupBy(c => c.Namespace).OrderBy(c => c.Key)) { var namespaceNode = NamespaceDeclaration(ParseName(namespaceGroup.Key)); foreach (var controller in namespaceGroup.OrderBy(c => c.Name)) { namespaceNode = namespaceNode.AddMembers( _controllerGenerator.GeneratePartialController(controller), _controllerGenerator.GenerateR4Controller(controller)); // If SplitIntoMultipleFiles is set, store the generated classes alongside the controller files. if (_settings.SplitIntoMultipleFiles) { var controllerFile = NewCompilationUnit() .AddMembers(namespaceNode); CompleteAndWriteFile(controllerFile, controller.GetFilePath().TrimEnd(".cs") + ".generated.cs"); namespaceNode = NamespaceDeclaration(ParseName(namespaceGroup.Key)); } } // If SplitIntoMultipleFiles is NOT set, bundle them all in R4Mvc if (!_settings.SplitIntoMultipleFiles) { generatedControllers.Add(namespaceNode); } } // R4MVC namespace used for the areas and Dummy class var r4Namespace = NamespaceDeclaration(ParseName(_settings.R4MvcNamespace)) // add the dummy class using in the derived controller partial class .WithDummyClass() .AddMembers(CreateViewOnlyControllerClasses(controllers).ToArray <MemberDeclarationSyntax>()) .AddMembers(CreateAreaClasses(areaControllers).ToArray <MemberDeclarationSyntax>()); // create static MVC class and add the area and controller fields var mvcStaticClass = ClassDeclaration(_settings.HelpersPrefix) .WithModifiers(SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword, SyntaxKind.PartialKeyword) .WithGeneratedNonUserCodeAttributes(); foreach (var area in areaControllers.Where(a => !string.IsNullOrEmpty(a.Key)).OrderBy(a => a.Key)) { mvcStaticClass = mvcStaticClass.WithStaticFieldBackedProperty(area.First().AreaKey, $"{_settings.R4MvcNamespace}.{area.Key}AreaClass", SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword); } foreach (var controller in areaControllers[string.Empty].OrderBy(c => c.Namespace == null).ThenBy(c => c.Name)) { mvcStaticClass = mvcStaticClass.AddMembers( SyntaxNodeHelpers.CreateFieldWithDefaultInitializer( controller.Name, controller.FullyQualifiedGeneratedName, controller.FullyQualifiedR4ClassName ?? controller.FullyQualifiedGeneratedName, SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword, SyntaxKind.ReadOnlyKeyword)); } // Generate a list of all static files from the wwwroot path var staticFileNode = _staticFileGenerator.GenerateStaticFiles(projectRoot); var r4mvcNode = NewCompilationUnit() .AddMembers( mvcStaticClass, r4Namespace, staticFileNode, ActionResultClass(), JsonResultClass(), ContentResultClass(), RedirectResultClass(), RedirectToActionResultClass(), RedirectToRouteResultClass()) .AddMembers(generatedControllers.ToArray <MemberDeclarationSyntax>()); CompleteAndWriteFile(r4mvcNode, Path.Combine(projectRoot, R4MvcGeneratorService.R4MvcFileName)); }