public ActionsGroupNode ReadController(Type type, AssemblyNode assemblyNode) { var name = type.Name.Replace("Controller", string.Empty); name = NameCleaner.Replace(name, string.Empty); var controller = new ActionsGroupNode(assemblyNode, name); var routePrefixAttribute = type.GetTypeInfo().GetCustomAttribute <RouteAttribute>(false) ?? type.GetTypeInfo().GetCustomAttribute <RouteAttribute>(); string routePrefix = routePrefixAttribute != null ? routePrefixAttribute.Template : "todo"; controller.Documentation = documentation.GetDocumentation(type); foreach (var methodInfo in type.GetMethods().Where(x => x.IsPublic)) { if (methodInfo.GetCustomAttribute <NonActionAttribute>() != null) { continue; } if (methodInfo.IsSpecialName) { continue; } var action = ReadAction(routePrefix, methodInfo, controller); if (action != null) { controller.Actions.Add(action); } } return(controller); }
private void WriteController(ActionsGroupNode controllerNode, bool knockout) { var dependencies = new Dependencies { PrefixModules = PrefixModules.All }; var controllersOutput = new StringBuilder(); AppendFormatDocumentation(controllersOutput, controllerNode.Documentation); controllersOutput.AppendLine($"export class {controllerNode.Name}Controller {{"); controllersOutput.AppendLine("\tconstructor(private client: helpers.ApiClient) {}"); WriteActions(controllerNode, controllersOutput, knockout, dependencies); controllersOutput.AppendLine("}"); controllersOutput.AppendLine(); var moduleName = StringHelpers.ToCamelCase(controllerNode.Name); var result = new StringBuilder(); result.AppendLine("/* This is a generated file. Do not modify or all the changes will be lost. */"); result.AppendLine($"import * as helpers from \"{serviceHelpersModule}\";"); if (knockout) { if (dependencies.Views) { result.AppendLine("import * as views from \"../views\";"); } if (dependencies.Enums) { result.AppendLine("import * as enums from \"../enums\";"); } if (dependencies.KoViews) { result.AppendLine("import * as koViews from \"./views\";"); } } else { if (dependencies.Enums) { result.AppendLine("import * as enums from \"./enums\";"); } if (dependencies.Views) { result.AppendLine("import * as views from \"./views\";"); } } result.AppendLine(); result.Append(controllersOutput); OutputModules.Add(knockout ? $"ko/{moduleName}" : moduleName, result.ToString()); }
private void WriteActions(ActionsGroupNode controllerNode, StringBuilder controllersOutput, bool knockout, Dependencies dependencies) { var actions = controllerNode.Actions.OrderBy(x => x.Name).ThenBy(x => x.Parameters.Count).ToArray(); foreach (var actionNode in actions) { var methodName = StringHelpers.ToCamelCase(actionNode.Name); var sameName = actions.Where(x => x.Name == actionNode.Name).ToList(); if (sameName.Count > 1) { methodName += sameName.IndexOf(actionNode) + 1; } WriteAction(methodName, actionNode, controllersOutput, knockout, dependencies); } }
public ActionNode?ReadAction(string routePrefix, MethodInfo methodInfo, ActionsGroupNode actionsGroup) { string? route = null; ActionMethod actionMethod = ActionMethod.Unknown; if (methodInfo.GetCustomAttribute <HttpGetAttribute>() != null) { actionMethod = ActionMethod.Get; route = methodInfo.GetCustomAttribute <HttpGetAttribute>().Template; } else if (methodInfo.GetCustomAttribute <HttpPostAttribute>() != null) { actionMethod = ActionMethod.Post; route = methodInfo.GetCustomAttribute <HttpPostAttribute>().Template; } else if (methodInfo.GetCustomAttribute <HttpPutAttribute>() != null) { actionMethod = ActionMethod.Put; route = methodInfo.GetCustomAttribute <HttpPutAttribute>().Template; } else if (methodInfo.GetCustomAttribute <HttpDeleteAttribute>() != null) { actionMethod = ActionMethod.Delete; route = methodInfo.GetCustomAttribute <HttpDeleteAttribute>().Template; } else if (methodInfo.GetCustomAttribute <HttpPatchAttribute>() != null) { actionMethod = ActionMethod.Patch; route = methodInfo.GetCustomAttribute <HttpPatchAttribute>().Template; } var routeAttribute = methodInfo.GetCustomAttribute <RouteAttribute>(); if (routeAttribute != null) { route = routeAttribute.Template; } if (route == null) { return(null); } if (actionMethod == ActionMethod.Unknown) { if (methodInfo.Name.StartsWith("Get", StringComparison.OrdinalIgnoreCase)) { actionMethod = ActionMethod.Get; } else if (methodInfo.Name.StartsWith("Post", StringComparison.OrdinalIgnoreCase)) { actionMethod = ActionMethod.Post; } else if (methodInfo.Name.StartsWith("Put", StringComparison.OrdinalIgnoreCase)) { actionMethod = ActionMethod.Put; } else if (methodInfo.Name.StartsWith("Delete", StringComparison.OrdinalIgnoreCase)) { actionMethod = ActionMethod.Delete; } else { return(null); } } // Remove type info from route route = Regex.Replace(route, @"{(\w+\??)(?::\w+)?}", "{$1}"); if (route.StartsWith("~")) { route = Regex.Replace(route, @"^~/?", string.Empty); } else { route = $"{routePrefix}/{route}"; } route = route.Replace("[controller]", actionsGroup.Name); var actionNode = new ActionNode(actionsGroup, methodInfo.Name, route); actionNode.Type = actionMethod; actionNode.Route = route; var versionMatch = Regex.Match(route, @"api/v([\d\.])+"); actionNode.Version = versionMatch.Success ? versionMatch.Groups[1].Value : null; var authorizeAttribute = methodInfo.GetCustomAttribute <AuthorizeAttribute>(); if (authorizeAttribute != null) { actionNode.Authorization = authorizeAttribute.Policy ?? authorizeAttribute.Roles; } // Read documentation var methodNode = documentation.GetMethodDocumentation(methodInfo); var summary = methodNode?.Element("summary"); if (summary != null) { actionNode.Documentation = summary.Value; } Dictionary <string, XElement>?parameterNodes = null; if (methodNode != null) { parameterNodes = methodNode.Elements("param").ToDictionary(x => x.Attribute("name").Value); } var routeParameters = new Dictionary <string, bool>(); var routeParametersMatches = Regex.Matches(route, @"{(\w+)(\?)?(?:\:\w+)?}"); foreach (Match match in routeParametersMatches) { var parameter = match.Groups[1].Value; var optional = match.Groups[2].Value == "?"; routeParameters.Add(parameter, optional); } foreach (var parameterInfo in methodInfo.GetParameters()) { var parameter = ReadParameter(parameterInfo, parameterNodes != null && parameterNodes.ContainsKey(parameterInfo.Name) ? parameterNodes[parameterInfo.Name] : null, actionsGroup.Assembly, routeParameters, actionNode); actionNode.Parameters.Add(parameter); if (parameter.Position == ParameterPosition.Body) { parameter.Type.Class?.SetWritable(); } } ContextualType returnType = methodInfo.ReturnParameter.ToContextualParameter(); if (returnType.Type.IsGenericType && returnType.Type.GetGenericTypeDefinition() == typeof(Task <>)) { returnType = returnType.GenericArguments[0]; } if (returnType.Type.IsGenericType && returnType.Type.GetGenericTypeDefinition() == typeof(ActionResult <>)) { returnType = returnType.GenericArguments[0]; } if (!returnType.Type.GetInterfaces().Contains(typeof(IActionResult)) && returnType.Type != typeof(IActionResult) && returnType.Type != typeof(Task) && returnType.Type != typeof(void)) { var returnDocumentation = methodNode?.Element("returns"); actionNode.Return = ReadReturn(returnType, actionsGroup.Assembly, returnDocumentation, actionNode); } return(actionNode); }