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}}}");
        }
Example #2
0
        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;
        }