private void WriteAction(string methodName, ActionNode actionNode, StringBuilder controllersOutput, bool knockout) { controllersOutput.AppendLine(); if (actionNode.Documentation != null && actionNode.Documentation.Any() || actionNode.Parameters.Any(x => x.Documentation != null && x.Documentation.Any()) || (actionNode.Return?.Documentation != null && actionNode.Return.Documentation.Any())) { controllersOutput.AppendLine($"{Tab}/**"); AppendFormatDocumentation(controllersOutput, actionNode.Documentation); foreach (var parameter in actionNode.Parameters) { AppendFormatDocumentation(controllersOutput, parameter.Documentation, $"@param {parameter.Name}"); } if (actionNode.Return != null) { AppendFormatDocumentation(controllersOutput, actionNode.Return.Documentation, "@return"); } controllersOutput.AppendLine($"{Tab} */"); } controllersOutput.Append($"{Tab}{methodName}(params:{{"); foreach (var parameter in actionNode.Parameters) { if (parameter != actionNode.Parameters.First()) { controllersOutput.Append(", "); } controllersOutput.Append(parameter.Name); if (!parameter.IsRequired) controllersOutput.Append("?"); controllersOutput.Append(": "); WriteTypedNode(parameter, controllersOutput, true, prefixModule: PrefixModules.All, allowObservable: true); } controllersOutput.Append("}"); //if ((actionNode.Type == ActionMethod.Post || actionNode.Type == ActionMethod.Put) // && actionNode.Parameters.All(x => x.Position != ParameterPosition.Body && x.Position != ParameterPosition.FormData)) //{ // if (actionNode.Parameters.Count > 0) // { // controllersOutput.Append(", "); // } // controllersOutput.Append("data: any"); //} controllersOutput.AppendLine(") {"); controllersOutput.Append($"{Tab}{Tab}return helpers.fetch"); if (actionNode.Return == null) { controllersOutput.Append("Void"); } else { controllersOutput.Append(actionNode.Return.IsCollection ? "List" : "Single"); if ((actionNode.Return.Type.IsObservable&& knockout) || actionNode.Return.Type.Type == TypeIdentifier.DateTime) { controllersOutput.Append("T"); } controllersOutput.Append("<"); if (actionNode.Return.Type.Type == TypeIdentifier.DateTime) { controllersOutput.Append("string, Date"); } else { if (actionNode.Return.IsCollection) { WriteType(actionNode.Return.Type, controllersOutput, false, PrefixModules.All, allowObservable: false); } else { WriteTypedNode(actionNode.Return, controllersOutput, false, PrefixModules.All, allowObservable: false); } if (actionNode.Return.Type.IsObservable&& knockout) { controllersOutput.Append(", koViews."); controllersOutput.Append(actionNode.Return.Type.Name); } } controllersOutput.Append(">"); } if (actionNode.Parameters.Any(x => x.Position == ParameterPosition.Path)) { var route = actionNode.Route.Replace("{", "${params.").Replace("?",""); controllersOutput.Append($"(`{route}`"); } else { controllersOutput.Append($"('{actionNode.Route}'"); } if (actionNode.Parameters.Any(x => x.Position == ParameterPosition.Query)) { controllersOutput.Append(" + helpers.getQueryString({ "); bool first = true; foreach (var parameter in actionNode.Parameters.Where(x => x.Position == ParameterPosition.Query)) { if (first) { first = false; } else { controllersOutput.Append(", "); } controllersOutput.Append($"{parameter.Name}: params.{parameter.Name}"); if (parameter.Type.Type == TypeIdentifier.DateTime) { controllersOutput.Append($" && params.{parameter.Name}.toISOString()"); } } controllersOutput.Append(" })"); } controllersOutput.Append(", \""); switch (actionNode.Type) { case ActionMethod.Delete: controllersOutput.Append("DELETE"); break; case ActionMethod.Get: controllersOutput.Append("GET"); break; case ActionMethod.Post: controllersOutput.Append("POST"); break; case ActionMethod.Put: controllersOutput.Append("PUT"); break; } controllersOutput.Append("\""); if (actionNode.Return != null) { if (actionNode.Return.Type.Type == TypeIdentifier.DateTime) { controllersOutput.Append(", view => new Date(view)"); } else if (actionNode.Return.Type.IsObservable&& knockout) { controllersOutput.Append(", view => new koViews."); controllersOutput.Append(actionNode.Return.Type.Name); controllersOutput.Append("(view)"); } } var body = actionNode.Parameters.FirstOrDefault(x => x.Position == ParameterPosition.Body); if (body != null) { controllersOutput.Append(", JSON.stringify(params."); controllersOutput.Append(body.Name); if (body.Type.IsObservable) { controllersOutput.Append(".toJs()"); } controllersOutput.Append(")"); } else { controllersOutput.Append(", null"); } controllersOutput.AppendLine(");"); controllersOutput.AppendLine($"{Tab}}}"); }
public ActionNode ReadAction(string routePrefix, MethodInfo methodInfo, ActionsGroupNode actionsGroup) { var actionNode = new ActionNode {Group = actionsGroup}; string route = null; if (methodInfo.GetCustomAttribute<HttpGetAttribute>() != null) { actionNode.Type = ActionMethod.Get; route = methodInfo.GetCustomAttribute<HttpGetAttribute>().Template; } else if (methodInfo.GetCustomAttribute<HttpPostAttribute>() != null) { actionNode.Type = ActionMethod.Post; route = methodInfo.GetCustomAttribute<HttpPostAttribute>().Template; } else if (methodInfo.GetCustomAttribute<HttpPutAttribute>() != null) { actionNode.Type = ActionMethod.Put; route = methodInfo.GetCustomAttribute<HttpPutAttribute>().Template; } else if (methodInfo.GetCustomAttribute<HttpDeleteAttribute>() != null) { actionNode.Type = ActionMethod.Delete; route = methodInfo.GetCustomAttribute<HttpDeleteAttribute>().Template; } var routeAttribute = methodInfo.GetCustomAttribute<RouteAttribute>(); if (routeAttribute != null) { route = routeAttribute.Template; } if (route == null) { return null; } if (actionNode.Type == ActionMethod.Unknown) { if (methodInfo.Name.StartsWith("Get", StringComparison.OrdinalIgnoreCase)) actionNode.Type = ActionMethod.Get; else if (methodInfo.Name.StartsWith("Post", StringComparison.OrdinalIgnoreCase)) actionNode.Type = ActionMethod.Post; else if (methodInfo.Name.StartsWith("Put", StringComparison.OrdinalIgnoreCase)) actionNode.Type = ActionMethod.Put; else if (methodInfo.Name.StartsWith("Delete", StringComparison.OrdinalIgnoreCase)) actionNode.Type = 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}"; } actionNode.Name = methodInfo.Name; 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.Version); actionNode.Parameters.Add(parameter); if (parameter.Position == ParameterPosition.Body) { parameter.Type.SetWritable(); } } Type returnType; var returnTypeAttribute = methodInfo.GetCustomAttribute<ProducesResponseTypeAttribute>(); if (returnTypeAttribute != null) { returnType = returnTypeAttribute.Type; } else { returnType = methodInfo.ReturnType; if (returnType.GetTypeInfo().IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>)) { returnType = returnType.GenericTypeArguments[0]; } if (returnType.GetTypeInfo().IsGenericType && returnType.GetGenericTypeDefinition() == typeof(IHttpActionResult<>)) { returnType = returnType.GenericTypeArguments[0]; } if (returnType.GetInterfaces().Contains(typeof(IActionResult)) || returnType == typeof(IActionResult) || returnType == typeof(Task)) { returnType = null; } } if (returnType != null && returnType != typeof(void)) { var returnDocumentation = methodNode?.Element("returns"); actionNode.Return = ReadReturn(returnType, actionsGroup.Assembly, returnDocumentation, actionNode.Version); } return actionNode; }